From 4142987c85461e3a36909bb44d8122196c8fddf3 Mon Sep 17 00:00:00 2001 From: devanshu Date: Tue, 7 Oct 2025 13:56:22 +0530 Subject: [PATCH 1/8] Fix ReferenceError by removing obsolete hint refs and updating cleanup logic --- src/App.js | 153 +++++++++++++---------------------------------------- 1 file changed, 38 insertions(+), 115 deletions(-) diff --git a/src/App.js b/src/App.js index 78ccb40..644158d 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,3 @@ -// src/App.js import { useEffect, useState, useMemo, useCallback, useRef } from "react"; import { nanoid } from "nanoid"; import "./App.css"; @@ -12,6 +11,7 @@ import CustomCursor from "./components/CustomCursor/CustomCursor"; import { cardImages } from "./data/cardImages"; import { numbers } from "./constants/numbers"; import { secureShuffleArray, pickRandomImages } from "./utils/logic"; +import { useHint } from "./utils/useHint"; function App() { const [cards, setCards] = useState([]); @@ -24,16 +24,8 @@ function App() { const [celebrationStatus, setCelebrationStatus] = useState(false); const [elapsedTime, setElapsedTime] = useState(undefined); const intervalRef = useRef(null); - const hintTimeoutRef = useRef(null); - const hintIntervalRef = useRef(null); - const hintLockedRef = useRef(false); - const [hintCount, setHintCount] = useState(3); - const [hintCooldown, setHintCooldown] = useState(0); - const [hintActive, setHintActive] = useState(false); const [animateCollapse, setAnimateCollapse] = useState(false); const [gameOverMessage, setGameOverMessage] = useState(false); - const REVEAL_DURATION = 2000; - const HINT_COOLDOWN = 5000; const soundEffect = useMemo(() => { const audio = new Audio(); @@ -70,6 +62,21 @@ function App() { } }, []); + const { + hintCount, + hintCooldown, + hintActive, + hintCards, + resetHints, + } = useHint({ + cards, + handleTime, + setChoiceOne, + setChoiceTwo, + setTurns, + setDisabled, + }); + const clearTimer = useCallback(() => { if (intervalRef.current) { clearInterval(intervalRef.current); @@ -77,81 +84,6 @@ function App() { } }, []); - const hintCards = useCallback(() => { - if (hintActive || hintLockedRef.current) return; - - if (!cards || cards.length === 0) return; - if (hintCount === 0) return; - - setHintCount((c) => c - 1); - hintLockedRef.current = true; - if (elapsedTime === undefined) handleTime(true); - const seconds = Math.floor(HINT_COOLDOWN / 1000); - setHintCooldown(seconds); - if (hintIntervalRef.current) clearInterval(hintIntervalRef.current); - hintIntervalRef.current = setInterval(() => { - setHintCooldown((s) => { - if (s <= 1) { - clearInterval(hintIntervalRef.current); - hintIntervalRef.current = null; - hintLockedRef.current = false; - return 0; - } - return s - 1; - }); - }, 1000); - - const available = cards.map((c, i) => ({ c, i })).filter(({ c }) => !c.matched); - if (available.length === 0) { - if (hintIntervalRef.current) { - clearInterval(hintIntervalRef.current); - hintIntervalRef.current = null; - } - setHintCooldown(0); - hintLockedRef.current = false; - return; - } - - if (available.length === 1) { - setHintActive(true); - setDisabled(true); - setChoiceOne(available[0].c); - setChoiceTwo(null); - - if (hintTimeoutRef.current) clearTimeout(hintTimeoutRef.current); - hintTimeoutRef.current = setTimeout(() => { - setChoiceOne(null); - setChoiceTwo(null); - setHintActive(false); - setDisabled(false); - }, REVEAL_DURATION); - - return; - } - - const idxA = crypto.getRandomValues(new Uint32Array(1))[0] % available.length; - - let idxB = crypto.getRandomValues(new Uint32Array(1))[0] % (available.length - 1); - if (idxB >= idxA) idxB += 1; - - const cardA = available[idxA].c; - const cardB = available[idxB].c; - - setHintActive(true); - setDisabled(true); - setChoiceOne(cardA); - setChoiceTwo(cardB); - setTurns(turns + 1); - - if (hintTimeoutRef.current) clearTimeout(hintTimeoutRef.current); - hintTimeoutRef.current = setTimeout(() => { - setChoiceOne(null); - setChoiceTwo(null); - setHintActive(false); - setDisabled(false); - }, REVEAL_DURATION); - }, [cards, hintCount, hintActive]); - const shuffledCards = useCallback(() => { const selected = pickRandomImages(cardImages, 6); const dup = [...selected, ...selected] @@ -171,18 +103,17 @@ function App() { setMatched(0); setCelebrationStatus(false); setElapsedTime(undefined); - clearTimer(); + setAnimateCollapse(true); setTimeout(() => setAnimateCollapse(false), 1200); setGameOverMessage(false); - }, [clearTimer]); + }, []); const handleNewGame = useCallback(() => { - setHintCount(3) - setHintCooldown(0); + resetHints(); playSound("audio/start.mp3"); shuffledCards(); - }, [playSound, shuffledCards]); + }, [playSound, shuffledCards, resetHints]); const handleChoice = useCallback( (card) => { @@ -215,7 +146,7 @@ function App() { } else if (choiceOne) { playSound("/audio/swap.wav"); } - }, [choiceOne, choiceTwo, resetTurn, playSound]); + }, [choiceOne, choiceTwo, resetTurn, playSound, hintActive]); useEffect(() => { if (matched === cards.length && turns) { @@ -246,18 +177,9 @@ function App() { setHighScore(hs); return () => { clearTimer(); - if (hintTimeoutRef.current) { - clearTimeout(hintTimeoutRef.current); - hintTimeoutRef.current = null; - } - if (hintIntervalRef.current) { - clearInterval(hintIntervalRef.current); - hintIntervalRef.current = null; - } - hintLockedRef.current = false; - setHintCooldown(0); + resetHints(); }; - }, [shuffledCards, clearTimer]); + }, [shuffledCards, clearTimer, resetHints]); return (
@@ -273,24 +195,25 @@ function App() { A&A Match
- -
- -

{hintCount === 1 ? "Hint Remaining: " : "Hints Remaining: "}{hintCount}

-
+ +
+ +

+ {hintCount === 1 ? "Hint Remaining: " : "Hints Remaining: "} + {hintCount} +

+
-
+
{cards.map((card) => ( Date: Tue, 7 Oct 2025 20:53:47 +0530 Subject: [PATCH 2/8] Refactor: cleaned up hint logic, fixed reference errors, and updated structure for stability --- package-lock.json | 55 -------------- public/index.html | 3 +- src/components/singlecard/SingleCard.js | 17 ++++- src/index.js | 9 +-- src/utils/useHint.js | 96 +++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 63 deletions(-) create mode 100644 src/utils/useHint.js diff --git a/package-lock.json b/package-lock.json index e959344..6ae3b5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4186,26 +4186,6 @@ "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "picocolors": "1.1.1", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@testing-library/jest-dom": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", @@ -4373,13 +4353,6 @@ "node": ">=10.13.0" } }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "license": "MIT", - "peer": true - }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -19438,20 +19411,6 @@ } } }, - "node_modules/tailwindcss/node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - } - }, "node_modules/tapable": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", @@ -19951,20 +19910,6 @@ "is-typedarray": "^1.0.0" } }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", diff --git a/public/index.html b/public/index.html index 24639aa..9ea38f4 100644 --- a/public/index.html +++ b/public/index.html @@ -2,8 +2,7 @@ - - + diff --git a/src/components/singlecard/SingleCard.js b/src/components/singlecard/SingleCard.js index 25269bd..cd025a4 100644 --- a/src/components/singlecard/SingleCard.js +++ b/src/components/singlecard/SingleCard.js @@ -13,8 +13,21 @@ export default function SingleCard({ card, handleChoice, flipped, disabled }) {
- card front blur background - card front + card front blur background +card front +
- +
{cards.map((card) => ( Date: Sat, 11 Oct 2025 22:42:11 +0530 Subject: [PATCH 5/8] fixed the app.js --- src/App.js | 180 ++++-------------------- src/components/singlecard/SingleCard.js | 82 +++-------- src/index.js | 8 +- 3 files changed, 51 insertions(+), 219 deletions(-) diff --git a/src/App.js b/src/App.js index d3902cf..fe02b2d 100644 --- a/src/App.js +++ b/src/App.js @@ -3,7 +3,7 @@ import { nanoid } from "nanoid"; import "./App.css"; import SingleCard from "./components/singlecard/SingleCard"; import Celebration from "./components/celebration/Celebration"; -import ToggleTheme from "./components/toggleTheme/toggleTheme"; +import toggleTheme from "./components/toggleTheme/toggleTheme"; import ShowConfetti from "./components/confetti/Confetti"; import GameOver from "./components/gameover/GameOver"; import CustomCursor from "./components/CustomCursor/CustomCursor"; @@ -13,24 +13,6 @@ import { numbers } from "./constants/numbers"; import { secureShuffleArray, pickRandomImages } from "./utils/logic"; import { useHint } from "./utils/useHint"; -const crypto = globalThis.crypto || globalThis.msCrypto; -import useTrackViewCounter from "./hooks/useTrackViewCounter"; - -import { useEffect, useState, useMemo, useCallback, useRef } from 'react'; -import { nanoid } from 'nanoid'; -import './App.css'; -import SingleCard from './components/singlecard/SingleCard'; -import Celebration from './components/celebration/Celebration'; -import ToggleTheme from './components/toggleTheme/toggleTheme'; -import ShowConfetti from './components/confetti/Confetti'; -import GameOver from './components/gameover/GameOver'; -import CustomCursor from './components/CustomCursor/CustomCursor'; - -import { cardImages } from './data/cardImages'; -import { numbers } from './constants/numbers'; -import { secureShuffleArray, pickRandomImages } from './utils/logic'; -import useTrackViewCounter from './hooks/useTrackViewCounter'; - function App() { const [cards, setCards] = useState([]); const [turns, setTurns] = useState(0); @@ -44,9 +26,6 @@ function App() { const intervalRef = useRef(null); const [animateCollapse, setAnimateCollapse] = useState(false); const [gameOverMessage, setGameOverMessage] = useState(false); - const viewCounter = useTrackViewCounter(); - const REVEAL_DURATION = 2000; - const HINT_COOLDOWN = 5000; const soundEffect = useMemo(() => { const audio = new Audio(); @@ -55,7 +34,7 @@ function App() { }, []); const playSound = useCallback( - src => { + (src) => { soundEffect.src = src; soundEffect.load(); soundEffect.play().catch(() => {}); @@ -66,15 +45,15 @@ function App() { const resetTurn = useCallback(() => { setChoiceOne(null); setChoiceTwo(null); - setTurns(prev => prev + 1); + setTurns((prev) => prev + 1); setDisabled(false); }, []); - const handleTime = useCallback(start => { + const handleTime = useCallback((start) => { if (start) { if (!intervalRef.current) { intervalRef.current = setInterval(() => { - setElapsedTime(prev => (prev || 0) + 1); + setElapsedTime((prev) => (prev || 0) + 1); }, 1000); } } else if (intervalRef.current) { @@ -105,101 +84,16 @@ function App() { } }, []); - const hintCards = useCallback(() => { - if (hintActive || hintLockedRef.current) return; - - if (!cards || cards.length === 0) return; - if (hintCount === 0) return; - - setHintCount(c => c - 1); - hintLockedRef.current = true; - if (elapsedTime === undefined) handleTime(true); - const seconds = Math.floor(HINT_COOLDOWN / 1000); - setHintCooldown(seconds); - if (hintIntervalRef.current) clearInterval(hintIntervalRef.current); - hintIntervalRef.current = setInterval(() => { - setHintCooldown(s => { - if (s <= 1) { - clearInterval(hintIntervalRef.current); - hintIntervalRef.current = null; - hintLockedRef.current = false; - return 0; - } - return s - 1; - }); - }, 1000); - - const available = cards - .map((c, i) => ({ c, i })) - .filter(({ c }) => !c.matched); - if (available.length === 0) { - if (hintIntervalRef.current) { - clearInterval(hintIntervalRef.current); - hintIntervalRef.current = null; - } - setHintCooldown(0); - hintLockedRef.current = false; - return; - } - - if (available.length === 1) { - setHintActive(true); - setDisabled(true); - setChoiceOne(available[0].c); - setChoiceTwo(null); - - if (hintTimeoutRef.current) clearTimeout(hintTimeoutRef.current); - hintTimeoutRef.current = setTimeout(() => { - setChoiceOne(null); - setChoiceTwo(null); - setHintActive(false); - setDisabled(false); - }, REVEAL_DURATION); - - return; - } - - const idxA = - crypto.getRandomValues(new Uint32Array(1))[0] % available.length; - - let idxB = - crypto.getRandomValues(new Uint32Array(1))[0] % (available.length - 1); - if (idxB >= idxA) idxB += 1; - - const cardA = available[idxA].c; - const cardB = available[idxB].c; - - setHintActive(true); - setDisabled(true); - setChoiceOne(cardA); - setChoiceTwo(cardB); - setTurns(turns + 1); - - if (hintTimeoutRef.current) clearTimeout(hintTimeoutRef.current); - hintTimeoutRef.current = setTimeout(() => { - setChoiceOne(null); - setChoiceTwo(null); - setHintActive(false); - setDisabled(false); - }, REVEAL_DURATION); - }, [cards, hintCount, hintActive]); - const shuffledCards = useCallback(() => { const selected = pickRandomImages(cardImages, 6); const dup = [...selected, ...selected] .sort(() => nanoid(16).localeCompare(nanoid(16))) .map((card) => { - // const crypto = globalThis.crypto || globalThis.msCrypto; - - .map(card => { - const crypto = globalThis.crypto || globalThis.msCrypto; - const rand = new Uint32Array(1); crypto.getRandomValues(rand); return { ...card, id: rand[0], matched: false }; }); - secureShuffleArray(numbers); setChoiceOne(null); setChoiceTwo(null); setCards(dup); @@ -216,14 +110,11 @@ function App() { const handleNewGame = useCallback(() => { resetHints(); playSound("audio/start.mp3"); - setHintCount(3); - setHintCooldown(0); - playSound('audio/start.mp3'); shuffledCards(); }, [playSound, shuffledCards, resetHints]); const handleChoice = useCallback( - card => { + (card) => { if (disabled) return; choiceOne ? setChoiceTwo(card) : setChoiceOne(card); if (elapsedTime === undefined) handleTime(true); @@ -237,36 +128,38 @@ function App() { if (choiceOne && choiceTwo) { setDisabled(true); if (choiceOne.src === choiceTwo.src) { - playSound('/audio/match.wav'); - setCards(prev => - prev.map(c => (c.src === choiceOne.src ? { ...c, matched: true } : c)) + playSound("/audio/match.wav"); + setCards((prev) => + prev.map((c) => + c.src === choiceOne.src ? { ...c, matched: true } : c + ) ); - setMatched(prev => prev + 2); + setMatched((prev) => prev + 2); resetTurn(); } else { - playSound('/audio/fail.wav'); + playSound("/audio/fail.wav"); const t = setTimeout(() => resetTurn(), 1000); return () => clearTimeout(t); } } else if (choiceOne) { - playSound('/audio/swap.wav'); + playSound("/audio/swap.wav"); } }, [choiceOne, choiceTwo, resetTurn, playSound, hintActive]); useEffect(() => { if (matched === cards.length && turns) { handleTime(false); - const storedHigh = globalThis.localStorage.getItem('highscore'); - const storedRun = globalThis.localStorage.getItem('runtime'); + const storedHigh = globalThis.localStorage.getItem("highscore"); + const storedRun = globalThis.localStorage.getItem("runtime"); const better = storedHigh === null || turns < Number(storedHigh) || (turns === Number(storedHigh) && elapsedTime < Number(storedRun)); if (better) { - globalThis.localStorage.setItem('highscore', turns); - globalThis.localStorage.setItem('runtime', elapsedTime); - playSound('audio/celebration.mp3'); + globalThis.localStorage.setItem("highscore", turns); + globalThis.localStorage.setItem("runtime", elapsedTime); + playSound("audio/celebration.mp3"); setCelebrationStatus(true); setHighScore(turns); setGameOverMessage(false); @@ -278,7 +171,7 @@ function App() { useEffect(() => { shuffledCards(); - const hs = Number(globalThis.localStorage.getItem('highscore') || 0); + const hs = Number(globalThis.localStorage.getItem("highscore") || 0); setHighScore(hs); return () => { clearTimer(); @@ -287,7 +180,7 @@ function App() { }, [shuffledCards, clearTimer, resetHints]); return ( -
+
{celebrationStatus && ( )} {celebrationStatus && } - A&A Match + A&A Match
@@ -311,29 +204,17 @@ function App() {

{hintCount === 1 ? "Hint Remaining: " : "Hints Remaining: "} -

- -
- -

- {hintCount === 1 ? 'Hint Remaining: ' : 'Hints Remaining: '} {hintCount}

- -
- {cards.map((card) => ( +
- {cards.map(card => ( + {cards.map((card) => (

Turns: {turns}

-
+

HighScore: {highScore}

-

Runtime: {globalThis.localStorage.getItem('runtime') || 0}

+

Runtime: {globalThis.localStorage.getItem("runtime") || 0}

-

Time Elapsed: {elapsedTime || 'Not started'}

- {viewCounter !== null &&

This memory got {viewCounter} views

} +

Time Elapsed: {elapsedTime || "Not started"}

{gameOverMessage && ( { - if (!disabled) { - handleChoice(card); - } - }; - return (
- card front blur background -card front - -
+ card front blur background + card front +
- return ( -
-
-
- card front blur background - card front -
- -
-
- ); -} +
+ ); + } -// PropTypes Validation SingleCard.propTypes = { card: PropTypes.shape({ src: PropTypes.string.isRequired, diff --git a/src/index.js b/src/index.js index 1b3a5f8..11d6fa7 100644 --- a/src/index.js +++ b/src/index.js @@ -1,15 +1,13 @@ import React from 'react'; -import { createRoot } from 'react-dom/client'; // <-- make sure this is 'react-dom/client' +import { createRoot } from 'react-dom/client'; import './index.css'; import App from './App'; const container = document.getElementById('root'); -const root = createRoot(container); // <-- create root +const root = createRoot(container); root.render( ); - , - document.getElementById('root') -); + From 7c11d5f5c00168a68c42ed0bedb33cfc9d4a3c05 Mon Sep 17 00:00:00 2001 From: devanshu Date: Sat, 11 Oct 2025 22:52:53 +0530 Subject: [PATCH 6/8] fixed the hint button and it's function --- src/utils/useHint.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/utils/useHint.js b/src/utils/useHint.js index 9c4cf4e..eee5975 100644 --- a/src/utils/useHint.js +++ b/src/utils/useHint.js @@ -32,7 +32,6 @@ export function useHint({ const seconds = Math.floor(HINT_COOLDOWN / 1000); setHintCooldown(seconds); - if (hintIntervalRef.current) clearInterval(hintIntervalRef.current); hintIntervalRef.current = setInterval(() => { setHintCooldown((s) => { @@ -46,6 +45,14 @@ export function useHint({ }); }, 1000); + const unmatchedSrcs = [...new Set(cards.filter(c => !c.matched).map(c => c.src))]; + if (unmatchedSrcs.length === 0) { + clearInterval(hintIntervalRef.current); + hintLockedRef.current = false; + setHintCooldown(0); + return; + } + const available = cards.filter(c => !c.matched); if (available.length === 0) { clearInterval(hintIntervalRef.current); @@ -54,19 +61,13 @@ export function useHint({ return; } - const cryptoObj = globalThis.crypto || globalThis.msCrypto; - - const idxA = cryptoObj.getRandomValues(new Uint32Array(1))[0] % available.length; - let idxB = cryptoObj.getRandomValues(new Uint32Array(1))[0] % (available.length - 1); - if (idxB >= idxA) idxB += 1; - - const cardA = available[idxA].c; - const cardB = available[idxB].c; + const randomSrc = unmatchedSrcs[Math.floor(Math.random() * unmatchedSrcs.length)]; + const pair = cards.filter(c => c.src === randomSrc && !c.matched); setHintActive(true); setDisabled(true); - setChoiceOne(cardA); - setChoiceTwo(cardB); + setChoiceOne(pair[0]); + setChoiceTwo(pair[1]); setTurns((t) => t + 1); if (hintTimeoutRef.current) clearTimeout(hintTimeoutRef.current); From b1b75b81a8a09354407d66a00bc9c5b76a157363 Mon Sep 17 00:00:00 2001 From: devanshu Date: Sun, 12 Oct 2025 00:56:40 +0530 Subject: [PATCH 7/8] add pickRandomImages function --- src/App.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/App.js b/src/App.js index fe02b2d..f7e2931 100644 --- a/src/App.js +++ b/src/App.js @@ -9,10 +9,12 @@ import GameOver from "./components/gameover/GameOver"; import CustomCursor from "./components/CustomCursor/CustomCursor"; import { cardImages } from "./data/cardImages"; -import { numbers } from "./constants/numbers"; -import { secureShuffleArray, pickRandomImages } from "./utils/logic"; import { useHint } from "./utils/useHint"; +const pickRandomImages = (arr, num) => { + const shuffled = [...arr].sort(() => 0.5 - Math.random()); + return shuffled.slice(0, num); +}; function App() { const [cards, setCards] = useState([]); const [turns, setTurns] = useState(0); From 8d81bf9e30bcbd3a915532f83dcca21f7978ce3f Mon Sep 17 00:00:00 2001 From: devanshu Date: Sun, 12 Oct 2025 01:14:31 +0530 Subject: [PATCH 8/8] Fix: Replace Math.random() with crypto.getRandomValues() to resolve security warning --- src/utils/useHint.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/utils/useHint.js b/src/utils/useHint.js index eee5975..4872249 100644 --- a/src/utils/useHint.js +++ b/src/utils/useHint.js @@ -61,7 +61,10 @@ export function useHint({ return; } - const randomSrc = unmatchedSrcs[Math.floor(Math.random() * unmatchedSrcs.length)]; + const rand = new Uint32Array(1); + crypto.getRandomValues(rand); + const randomIndex = rand[0] % unmatchedSrcs.length; + const randomSrc = unmatchedSrcs[randomIndex]; const pair = cards.filter(c => c.src === randomSrc && !c.matched); setHintActive(true);