Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump react-dom from 18.3.1 to 19.0.0 #5

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ jobs:
VITE_MAX_DICE_AMOUNT: ${{ vars.VITE_MAX_DICE_AMOUNT || 10 }}
VITE_MIN_CHIPS_AMOUNT: ${{ vars.VITE_MIN_CHIPS_AMOUNT || 10 }}
VITE_MAX_CHIPS_AMOUNT: ${{ vars.VITE_MAX_CHIPS_AMOUNT || 100 }}
VITE_TURNSTILE_SITE_KEY: ${{ secrets.VITE_TURNSTILE_SITE_KEY }}
VITE_CHUBGAME_URL: ${{ vars.VITE_CHUBGAME_URL || 'https://chubgame.com' }}
VITE_OAUTH_CLIENT_ID: ${{ secrets.VITE_OAUTH_CLIENT_ID }}
VITE_OAUTH_CLIENT_SECRET: ${{ secrets.VITE_OAUTH_CLIENT_SECRET }}
run: npm run build

# Upload build artifacts to GitHub Pages
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ npm run dev
|`VITE_MAX_DICE_AMOUNT`|Maximum number of dice allowed|`10`|
|`VITE_MIN_CHIPS_AMOUNT`|Minimum number of chips allowed|`1`|
|`VITE_MAX_CHIPS_AMOUNT`|Maximum number of chips allowed|`100`|
|`VITE_TURNSTILE_SITE_KEY`|CloudFlare Turnstile site key|`6Lc2Qb4cAAAAAAB9Z9Z9Z9Z9Z9Z9Z9Z9Z9Z9Z9Z9`|

## Game Logic

Expand Down
2 changes: 1 addition & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @Date: 2025-01-01 22:00:54
* @LastEditors: Phillweston
* @LastEditTime: 2025-01-05 12:20:35
* @FilePath: \DiceRollerSimulator-ThreeJS\eslint.config.js
* @FilePath: \DiceRoller-ChubGame\eslint.config.js
* @Description:
*
*/
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @Date: 2024-12-30 00:31:06
* @LastEditors: Phillweston
* @LastEditTime: 2025-01-05 15:32:44
* @FilePath: \DiceRollerSimulator-ThreeJS\index.html
* @FilePath: \DiceRoller-ChubGame\index.html
* @Description:
*
-->
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
"cannon": "^0.6.2",
"fireworks-js": "^2.10.8",
"postcss": "^8.4.41",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-dom": "^19.0.0",
"react-icons": "^5.4.0",
"tailwindcss": "^3.4.10",
"three": "^0.172.0"
Expand Down
2 changes: 1 addition & 1 deletion src/3d.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @Date: 2025-01-01 22:00:54
* @LastEditors: Phillweston
* @LastEditTime: 2025-01-05 12:27:41
* @FilePath: \DiceRollerSimulator-ThreeJS\src\3d.js
* @FilePath: \DiceRoller-ChubGame\src\3d.js
* @Description:
*
*/
Expand Down
203 changes: 183 additions & 20 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
* @Author: Phillweston 2436559745@qq.com
* @Date: 2025-01-01 22:00:54
* @LastEditors: Phillweston
* @LastEditTime: 2025-01-21 14:40:19
* @FilePath: \DiceRollerSimulator-ThreeJS\src\App.jsx
* @LastEditTime: 2025-02-16 14:40:19
* @FilePath: \DiceRoller-ChubGame\src\App.jsx
* @Description:
*
*/
import { useState, useEffect } from 'react';
import { createDices } from './3d.js';
import { FaCopy, FaInfoCircle, FaCoins, FaArrowLeft, FaPlay, FaForward, FaTimes, FaCheck, FaSave, FaBook, FaRedo } from 'react-icons/fa';
import { FaCopy, FaInfoCircle, FaCoins, FaArrowLeft, FaPlay, FaForward, FaTimes, FaCheck, FaSave, FaBook, FaRedo, FaLock } from 'react-icons/fa';
import { Fireworks } from 'fireworks-js';
import { PropTypes } from 'prop-types';
import gameImage from '../images/game.png';

const DEBUG_MODE = import.meta.env.VITE_DEBUG_MODE === 'true';
Expand All @@ -21,11 +22,16 @@ const CHECK_BALANCE_API = import.meta.env.VITE_CHECK_BALANCE_API;
const MAX_DICE_AMOUNT = parseInt(import.meta.env.VITE_MAX_DICE_AMOUNT, 10); // Parsing as an integer
const MIN_CHIPS_AMOUNT = parseInt(import.meta.env.VITE_MIN_CHIPS_AMOUNT, 10); // Parsing as an integer
const MAX_CHIPS_AMOUNT = parseInt(import.meta.env.VITE_MAX_CHIPS_AMOUNT, 100); // Parsing as an integer
const TURNSTILE_SITE_KEY = import.meta.env.VITE_TURNSTILE_SITE_KEY;
const CHUBGAME_URL = import.meta.env.VITE_CHUBGAME_URL;
const OAUTH_CLIENT_ID = import.meta.env.VITE_OAUTH_CLIENT_ID;
const OAUTH_CLIENT_SECRET = import.meta.env.VITE_OAUTH_CLIENT_SECRET;

const App = () => {
const [showWelcomeDialog, setShowWelcomeDialog] = useState(true);
const [diceAmount, setDiceAmount] = useState(6);
const [totalPoints, setTotalPoints] = useState(null);
const [showAuthenticationDialog, setShowAuthenticationDialog] = useState(false);
const [showTotalPointsDialog, setShowTotalPointsDialog] = useState(false);
const [showPromotionDialog, setShowPromotionDialog] = useState(false);
const [promotionCode, setPromotionCode] = useState('');
Expand All @@ -48,6 +54,13 @@ const App = () => {
const [resultData, setResultData] = useState(null);
const [showFinalDialog, setShowFinalDialog] = useState(false);
const [openedFromWelcome, setOpenedFromWelcome] = useState(false);
const [turnstileToken, setTurnstileToken] = useState('');

useEffect(() => {
if (window.location.pathname === '/oauth/callback') {
handleOAuthCallback();
}
}, []);

useEffect(() => {
const params = new URLSearchParams(window.location.search);
Expand Down Expand Up @@ -119,22 +132,90 @@ const App = () => {
};
}, [showResultDialog, resultData]);

const handleStartPvE = () => {
setSuccessPopup('Starting PvE game...');
setTimeout(() => setSuccessPopup(''), 3000); // Hide success popup after 3 seconds
setSinglePlayer(true);
const handleAuthentication = (isPvE) => {
setInfoPopup('You need to authenticate to play the game');
setTimeout(() => setInfoPopup(''), 3000); // Hide success popup after 3 seconds
setSinglePlayer(isPvE);
setShowWelcomeDialog(false);
setShowChipsDialog(true);
setShowAuthenticationDialog(true);
};

const handleStartPvP = () => {
setSuccessPopup('Starting PvP game...');
setTimeout(() => setSuccessPopup(''), 3000); // Hide success popup after 3 seconds
setSinglePlayer(false);
setShowWelcomeDialog(false);
setShowPromotionDialog(true);

const handleOAuthCallback = async () => {
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const state = params.get('state');
const storedState = localStorage.getItem('oauth_state');

if (!code || !state || state !== storedState) {
setErrorPopup('Invalid OAuth callback');
setTimeout(() => setErrorPopup(''), 3000); // Hide error popup after 3 seconds
return;
}

localStorage.removeItem('oauth_state');

const redirectUri = `${window.location.origin}/oauth/callback`;
const tokenUrl = new URL(`${CHUBGAME_URL}/oauth/token`);

try {
const response = await fetch(tokenUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
grant_type: 'authorization_code',
code: code,
redirect_uri: redirectUri,
client_id: OAUTH_CLIENT_ID,
client_secret: OAUTH_CLIENT_SECRET,
}),
});

const data = await response.json();

if (data.access_token) {
localStorage.setItem('oauth_access_token', data.access_token);
setSuccessPopup('Authentication successful, Starting game...');
setTimeout(() => setSuccessPopup(''), 3000); // Hide success popup after 3 seconds
setShowAuthenticationDialog(false);

if (singlePlayer) {
setShowChipsDialog(true);
} else {
setShowPromotionDialog(true);
}
} else {
setErrorPopup('API response error');
setTimeout(() => setErrorPopup(''), 3000); // Hide error popup after 3 seconds
}
} catch (error) {
console.error('Error during OAuth callback:', error);
setErrorPopup('Error during OAuth callback');
setTimeout(() => setErrorPopup(''), 3000); // Hide error popup after 3 seconds
}
};

const handleStartAuthentication = () => {
if (TURNSTILE_SITE_KEY && !turnstileToken) {
setErrorPopup('Human verification failed');
setTimeout(() => setErrorPopup(''), 3000); // Hide error popup after 3 seconds
return;
}

const redirectUri = `${window.location.origin}/oauth/callback`;
const oauthState = Math.random().toString(36).substring(2);
localStorage.setItem('oauth_state', oauthState);

const authUrl = new URL(`${CHUBGAME_URL}/oauth/authorize`);
authUrl.searchParams.append('response_type', 'code');
authUrl.searchParams.append('client_id', OAUTH_CLIENT_ID);
authUrl.searchParams.append('redirect_uri', redirectUri);
authUrl.searchParams.append('state', oauthState);

window.location.href = authUrl.toString();
}

const handleOpenRegulation = () => {
setShowRegulationDialog(true);
if (showWelcomeDialog) {
Expand Down Expand Up @@ -278,11 +359,18 @@ const App = () => {
};
}

const token = localStorage.getItem('oauth_access_token');
if (!token) {
console.error('OAuth access token not found');
return { success: false, message: 'OAuth access token not found' };
}

try {
const response = await fetch(SEND_DICE_DATA_API, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
credentials: 'include',
body: JSON.stringify({
Expand Down Expand Up @@ -321,11 +409,18 @@ const App = () => {
return { valid: true, amount: 5 };
}

const token = localStorage.getItem('oauth_access_token');
if (!token) {
console.error('OAuth access token not found');
return { valid: false, message: 'OAuth access token not found' };
}

try {
const response = await fetch(VALIDATE_PROMOTION_CODE_API, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
credentials: 'include',
body: JSON.stringify({ promotionCode: code, username }),
Expand Down Expand Up @@ -368,11 +463,18 @@ const App = () => {
return { valid: true, balance: 1000 }; // Example balance
}

const token = localStorage.getItem('oauth_access_token');
if (!token) {
console.error('OAuth access token not found');
return { valid: false, message: 'OAuth access token not found' };
}

try {
const response = await fetch(CHECK_BALANCE_API, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
credentials: 'include',
body: JSON.stringify({ username, chips }),
Expand Down Expand Up @@ -459,9 +561,33 @@ const App = () => {
}
};

const Turnstile = ({ siteKey, onVerify }) => {
useEffect(() => {
if (window.turnstile) {
window.turnstile.render('#turnstile-widget', {
sitekey: siteKey,
callback: onVerify,
});
}
}, [siteKey, onVerify]);

return <div id="turnstile-widget"></div>;
};

Turnstile.propTypes = {
siteKey: PropTypes.string.isRequired,
onVerify: PropTypes.func.isRequired,
};

const handleTurnstileVerify = (token) => {
console.log('Turnstile token:', token);
setTurnstileToken(token);
// Handle the verification token (e.g., send it to your server for validation)
};

return (
<div className="font-['Cherry_Bomb_One',system-ui] select-none">
{(showWelcomeDialog || showPromotionDialog || showChipsDialog || showRegulationDialog || showAboutDialog || showTotalPointsDialog || showResultDialog || showCopyDialog || showFinalDialog) && (
{(showWelcomeDialog || showAuthenticationDialog || showPromotionDialog || showChipsDialog || showRegulationDialog || showAboutDialog || showTotalPointsDialog || showResultDialog || showCopyDialog || showFinalDialog) && (
<div className="overlay fixed inset-0 bg-black bg-opacity-20 z-10"></div>
)}

Expand Down Expand Up @@ -499,13 +625,13 @@ const App = () => {
<FaTimes className="mr-2" /> Close
</button>
<button
onClick={handleStartPvE}
onClick={() => handleAuthentication(true)}
className="px-4 py-2 bg-green-500 text-white rounded transition-transform duration-300 hover:bg-yellow-500 hover:scale-105 active:bg-green-500 flex items-center"
>
<FaPlay className="mr-2" /> Start PvE
</button>
<button
onClick={handleStartPvP}
onClick={() => handleAuthentication(false)}
className="px-4 py-2 bg-blue-500 text-white rounded transition-transform duration-300 hover:bg-yellow-500 hover:scale-105 active:bg-green-500 flex items-center"
>
<FaPlay className="mr-2" /> Start PvP
Expand All @@ -515,10 +641,42 @@ const App = () => {
</div>
)}

{showAuthenticationDialog && (
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
<div className="bg-white p-4 rounded shadow-lg text-center fade-in">
<h2 className="text-4xl mb-4">User Authentication</h2>
<p className="text-xl mb-4">Click the following button to start the authentication, after success the game will proceed.</p>
<div className="mb-4 p-4 bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 flex items-center">
<FaInfoCircle className="mr-2" />
<p>You need to pass the CloudFlare Turnstile verification.</p>
</div>
{TURNSTILE_SITE_KEY && <Turnstile siteKey={TURNSTILE_SITE_KEY} onVerify={handleTurnstileVerify} />}
<div className="mt-4 flex justify-center space-x-4">
<button
onClick={() => {
setShowAuthenticationDialog(false);
setShowWelcomeDialog(true);
}}
className="mr-2 px-4 py-2 bg-gray-500 text-white rounded transition-transform duration-300 hover:bg-yellow-500 hover:scale-105 active:bg-green-500 flex items-center"
>
<FaArrowLeft className="mr-2" /> Back
</button>
<button
onClick={handleStartAuthentication}
className="px-4 py-2 bg-green-500 text-white rounded transition-transform duration-300 hover:bg-yellow-500 hover:scale-105 active:bg-green-500 flex items-center"
>
<FaLock className="mr-2" /> Authenticate
</button>
</div>
</div>
</div>
)}

{showPromotionDialog && (
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
<div className="bg-white p-4 rounded shadow-lg text-center fade-in">
<h2 className="text-xl mb-4">Enter Promotion Code</h2>
<h2 className="text-4xl mb-4">Enter Promotion Code</h2>
<p className="text-xl mb-4">For parent user, you neeed to click the Skip, for child user, you need to input the promotion code and click the Start.</p>
<div className="relative">
<input
type="text"
Expand Down Expand Up @@ -572,7 +730,12 @@ const App = () => {
{showChipsDialog && (
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
<div className="bg-white p-4 rounded shadow-lg text-center fade-in">
<h2 className="text-xl mb-4">Select or Enter Betting Chips</h2>
<h2 className="text-4xl mb-4">Select or Enter Chip Amount</h2>
<p className="text-xl mb-4">If you input the customized amount, it will replace the fixed amount selected.</p>
<div className="mb-4 p-4 bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 flex items-center">
<FaInfoCircle className="mr-2" />
<p>The maximum token amount is {MAX_CHIPS_AMOUNT}, the minimum token amount is {MIN_CHIPS_AMOUNT}.</p>
</div>
<div className="mb-4 flex">
<button
onClick={() => setSelectedChips('10')}
Expand Down
2 changes: 1 addition & 1 deletion src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @Date: 2025-01-01 22:00:54
* @LastEditors: Phillweston
* @LastEditTime: 2025-01-05 12:20:35
* @FilePath: \DiceRollerSimulator-ThreeJS\src\index.css
* @FilePath: \DiceRoller-ChubGame\src\index.css
* @Description:
*
*/
Expand Down
2 changes: 1 addition & 1 deletion src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @Date: 2025-01-01 22:00:54
* @LastEditors: Phillweston
* @LastEditTime: 2025-01-05 12:20:35
* @FilePath: \DiceRollerSimulator-ThreeJS\src\main.jsx
* @FilePath: \DiceRoller-ChubGame\src\main.jsx
* @Description:
*
*/
Expand Down