From c9b34e837ca864aaac59bb1969600e6ed80c2b7c Mon Sep 17 00:00:00 2001 From: xRxphael Date: Tue, 30 Apr 2024 15:45:19 +0200 Subject: [PATCH 1/3] added base session hook --- package.json | 3 +- pnpm-lock.yaml | 35 +++++++++-- src/App.tsx | 11 +++- src/Components/Modal/types.ts | 2 +- src/Hooks/useSessionTracker/index.ts | 87 ++++++++++++++++++++++++++++ tailwind.config.js | 6 +- 6 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 src/Hooks/useSessionTracker/index.ts diff --git a/package.json b/package.json index 716ea1e..514b43d 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "abcjs": "^6.3.0", "classnames": "^2.5.1", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "zustand": "^4.5.2" }, "devDependencies": { "@types/react": "^18.2.66", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bb48ff5..a226821 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ dependencies: react-dom: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) + zustand: + specifier: ^4.5.2 + version: 4.5.2(@types/react@18.2.66)(react@18.2.0) devDependencies: '@types/react': @@ -828,7 +831,6 @@ packages: /@types/prop-types@15.7.12: resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} - dev: true /@types/react-dom@18.2.22: resolution: {integrity: sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==} @@ -842,11 +844,9 @@ packages: '@types/prop-types': 15.7.12 '@types/scheduler': 0.23.0 csstype: 3.1.3 - dev: true /@types/scheduler@0.23.0: resolution: {integrity: sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==} - dev: true /@types/semver@7.5.8: resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} @@ -1246,7 +1246,6 @@ packages: /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - dev: true /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} @@ -2397,6 +2396,14 @@ packages: punycode: 2.3.1 dev: true + /use-sync-external-store@1.2.0(react@18.2.0): + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true @@ -2484,3 +2491,23 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true + + /zustand@4.5.2(@types/react@18.2.66)(react@18.2.0): + resolution: {integrity: sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==} + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0.6' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + dependencies: + '@types/react': 18.2.66 + react: 18.2.0 + use-sync-external-store: 1.2.0(react@18.2.0) + dev: false diff --git a/src/App.tsx b/src/App.tsx index 164c11f..92ad9dc 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,11 +3,14 @@ import Button from "./Components/Button"; import Modal from "./Components/Modal"; import NoteDisplay from "./Components/NoteDisplay"; import { IconSaxophone } from "./Components/Icons/IconSaxophone"; +import useSessionTracker from "./Hooks/useSessionTracker"; function App() { const [isStarted, setIsStarted] = useState(false); + const { startSession, formatCountdown, isEnded } = useSessionTracker(); + return ( -
+
{!isStarted ? ( { setIsStarted(true); + startSession(); }} > Continue @@ -40,7 +44,10 @@ function App() { } /> ) : ( - + <> + + {isEnded ? "Beendet" : formatCountdown()} + )}
diff --git a/src/Components/Modal/types.ts b/src/Components/Modal/types.ts index ab0b772..391f040 100644 --- a/src/Components/Modal/types.ts +++ b/src/Components/Modal/types.ts @@ -2,6 +2,6 @@ export interface Props { title: string; descriptionElement?: React.ReactElement; description?: string; - openButton: React.ReactElement; + openButton?: React.ReactElement; successButton: React.ReactElement; } diff --git a/src/Hooks/useSessionTracker/index.ts b/src/Hooks/useSessionTracker/index.ts new file mode 100644 index 0000000..c938622 --- /dev/null +++ b/src/Hooks/useSessionTracker/index.ts @@ -0,0 +1,87 @@ +import { useState, useEffect } from "react"; + +interface SessionMetrics { + successfulNotes: number; + missedNotes: number; +} + +const useSessionTracker = (): { + isStarted: boolean; + isEnded: boolean; + startSession: () => void; + endSession: () => void; + metrics: SessionMetrics; + addSuccessfulNote: () => void; + addMissedNote: () => void; + countdownTime: number; + formatCountdown: () => string; +} => { + const [isStarted, setIsStarted] = useState(false); + const [isEnded, setIsEnded] = useState(false); + const [startTime, setStartTime] = useState(null); + const [endTime, setEndTime] = useState(null); + const [metrics, setMetrics] = useState({ + successfulNotes: 0, + missedNotes: 0, + }); + const [countdownTime, setCountdownTime] = useState(120); + + const startSession = (): void => { + setIsStarted(true); + setStartTime(Date.now()); + setIsEnded(false); + setCountdownTime(120); + }; + + const endSession = (): void => { + setIsStarted(false); + setEndTime(Date.now()); + setIsEnded(true); + }; + + const addSuccessfulNote = (): void => { + setMetrics((prev) => ({ + ...prev, + successfulNotes: prev.successfulNotes + 1, + })); + }; + + const addMissedNote = (): void => { + setMetrics((prev) => ({ ...prev, missedNotes: prev.missedNotes + 1 })); + }; + + const formatCountdown = (): string => { + const minutes = Math.floor(countdownTime / 60); + const seconds = countdownTime % 60; + return `${minutes}:${seconds < 10 ? `0${seconds}` : seconds}`; + }; + + useEffect(() => { + if (isStarted && !isEnded && countdownTime >= 0) { + const countdownTimer = setInterval(() => { + setCountdownTime((prevTime) => { + if (prevTime === 0) { + setIsEnded(true); + return 0; + } + return prevTime - 1; + }); + }, 1000); + return (): void => clearInterval(countdownTimer); + } + }, [isStarted, isEnded, countdownTime]); + + return { + isStarted, + isEnded, + startSession, + endSession, + metrics, + addSuccessfulNote, + addMissedNote, + countdownTime, + formatCountdown, + }; +}; + +export default useSessionTracker; diff --git a/tailwind.config.js b/tailwind.config.js index 4ccdaa5..841310c 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -3,7 +3,11 @@ export default { darkMode: "class", content: ["./src/**/*.{html,tsx,ts,js,jsx,css,scss,sass}"], theme: { - extend: {}, + extend: { + colors: { + primary: "#121212", + }, + }, }, plugins: [], }; From 09497a3123a7e09b6524eb822bf2306c8b333cfe Mon Sep 17 00:00:00 2001 From: xRxphael Date: Wed, 1 May 2024 13:37:33 +0200 Subject: [PATCH 2/3] Added tailwind color variables, added SessionTracker and changed colors. --- src/App.tsx | 28 +++++++-- src/Components/Button/index.tsx | 8 ++- src/Components/ListboxSelector/index.tsx | 6 +- src/Components/Modal/index.tsx | 2 +- src/Components/NoteDisplay/index.tsx | 39 +++++++------ src/Hooks/useSessionTracker/index.ts | 73 ++++++++++-------------- src/Stores/SessionStore/index.tsx | 65 +++++++++++++++++++++ src/Stores/SessionStore/types.ts | 20 +++++++ src/Utils/AudioUtils/index.ts | 1 + src/Utils/NoteUtils/index.ts | 6 +- tailwind.config.js | 4 +- 11 files changed, 180 insertions(+), 72 deletions(-) create mode 100644 src/Stores/SessionStore/index.tsx create mode 100644 src/Stores/SessionStore/types.ts diff --git a/src/App.tsx b/src/App.tsx index 92ad9dc..d11b71c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,10 +7,11 @@ import useSessionTracker from "./Hooks/useSessionTracker"; function App() { const [isStarted, setIsStarted] = useState(false); - const { startSession, formatCountdown, isEnded } = useSessionTracker(); + const { startSession, formatCountdown, isEnded, metrics } = + useSessionTracker(); return ( -
+
{!isStarted ? ( { setIsStarted(true); startSession(); @@ -43,10 +45,28 @@ function App() { } /> - ) : ( + ) : !isEnded ? ( <> +

+ Remaining time: {formatCountdown()} +

- {isEnded ? "Beendet" : formatCountdown()} + + ) : ( + <> + Results of the session: + Missed Notes: {metrics.missedNotes} + + Successful Notes: {metrics.successfulNotes} + + )}
diff --git a/src/Components/Button/index.tsx b/src/Components/Button/index.tsx index 7f304aa..fdb3816 100644 --- a/src/Components/Button/index.tsx +++ b/src/Components/Button/index.tsx @@ -2,13 +2,17 @@ import { FC } from "react"; const Button: FC<{ onClick?: () => void; + bgFill?: boolean; + className?: string; children: React.ReactNode; -}> = ({ onClick, children }) => { +}> = ({ onClick, children, bgFill, className }) => { return ( diff --git a/src/Components/ListboxSelector/index.tsx b/src/Components/ListboxSelector/index.tsx index 8e83204..ccc45ca 100644 --- a/src/Components/ListboxSelector/index.tsx +++ b/src/Components/ListboxSelector/index.tsx @@ -14,7 +14,7 @@ function ListboxSelector({ return (
- + {buttonTitle} - + {options.map((option, index) => ( {selected ? ( - + ) : null} diff --git a/src/Components/Modal/index.tsx b/src/Components/Modal/index.tsx index 5c22d58..3b9e26d 100644 --- a/src/Components/Modal/index.tsx +++ b/src/Components/Modal/index.tsx @@ -44,7 +44,7 @@ function Modal({ leaveFrom="opacity-100 scale-100" leaveTo="opacity-0 scale-95" > - + { const { playedNote, initAudio, stopAudio } = useAudioProcessor(notes); - const [difficulty, setDifficulty] = useState(EDifficulty.easy); const [isNoteCorrect, setIsNoteCorrect] = useState(false); + const { addMissedNote, addSuccessfulNote } = useSessionTracker(); + const { metrics, changeDifficulty } = useSessionStore(); const [randomNote, setRandomNote] = useState({ frequency: 0, abcNote: "", note: "", - difficulty, + difficulty: metrics.difficulty, }); useEffect(() => { @@ -28,22 +31,23 @@ const NoteDisplay = ({ isStarted, setIsStarted }: Props) => { useEffect(() => { const timer = setTimeout(() => { - if (!playedNote || !randomNote) return; + setIsNoteCorrect(playedNote.note === randomNote.note); + if (playedNote.note === randomNote.note) { - setIsNoteCorrect(true); + addSuccessfulNote(); } else { - setIsNoteCorrect(false); + addMissedNote(); } }, 1500); return () => clearTimeout(timer); - }, [playedNote, randomNote]); + }, [playedNote.note, randomNote.note]); const notationRef = useRef(null); useEffect(() => { const changeNote = () => { - const random = NoteUtils.getRandomNote(difficulty); + const random = NoteUtils.getRandomNote(randomNote, metrics.difficulty); abcjs.renderAbc( notationRef.current!, NoteUtils.generateAbcNotation(random), @@ -62,12 +66,15 @@ const NoteDisplay = ({ isStarted, setIsStarted }: Props) => { } changeNote(); - const intervalId = setInterval(changeNote, 4000); + const intervalId = setInterval( + changeNote, + metrics.difficulty === EDifficulty.easy ? 5000 : 4000 + ); return () => { clearInterval(intervalId); }; - }, [isStarted, difficulty]); + }, [isStarted, metrics.difficulty]); const handleStop = () => { stopAudio(); @@ -80,12 +87,12 @@ const NoteDisplay = ({ isStarted, setIsStarted }: Props) => {
-
+

Performed

- + -

+

{playedNote.note ? playedNote.note : "No note played"}

@@ -93,8 +100,8 @@ const NoteDisplay = ({ isStarted, setIsStarted }: Props) => {

Difficulty

-

- {difficulty} +

+ {metrics.difficulty}

@@ -102,9 +109,9 @@ const NoteDisplay = ({ isStarted, setIsStarted }: Props) => {
setDifficulty(value)} + onChange={(value) => changeDifficulty(value)} buttonTitle="Change Difficulty" - value={difficulty} + value={metrics.difficulty} options={difficultyOptions} />
diff --git a/src/Hooks/useSessionTracker/index.ts b/src/Hooks/useSessionTracker/index.ts index c938622..e339398 100644 --- a/src/Hooks/useSessionTracker/index.ts +++ b/src/Hooks/useSessionTracker/index.ts @@ -1,6 +1,9 @@ -import { useState, useEffect } from "react"; +import { useEffect } from "react"; +import useSessionStore from "../../Stores/SessionStore"; +import { EDifficulty } from "../../types"; interface SessionMetrics { + difficulty: EDifficulty; successfulNotes: number; missedNotes: number; } @@ -14,41 +17,21 @@ const useSessionTracker = (): { addSuccessfulNote: () => void; addMissedNote: () => void; countdownTime: number; + changeDifficulty: (newDifficulty: EDifficulty) => void; formatCountdown: () => string; } => { - const [isStarted, setIsStarted] = useState(false); - const [isEnded, setIsEnded] = useState(false); - const [startTime, setStartTime] = useState(null); - const [endTime, setEndTime] = useState(null); - const [metrics, setMetrics] = useState({ - successfulNotes: 0, - missedNotes: 0, - }); - const [countdownTime, setCountdownTime] = useState(120); - - const startSession = (): void => { - setIsStarted(true); - setStartTime(Date.now()); - setIsEnded(false); - setCountdownTime(120); - }; - - const endSession = (): void => { - setIsStarted(false); - setEndTime(Date.now()); - setIsEnded(true); - }; - - const addSuccessfulNote = (): void => { - setMetrics((prev) => ({ - ...prev, - successfulNotes: prev.successfulNotes + 1, - })); - }; - - const addMissedNote = (): void => { - setMetrics((prev) => ({ ...prev, missedNotes: prev.missedNotes + 1 })); - }; + const { + countdownTime, + endSession, + isEnded, + isStarted, + metrics, + startSession, + addMissedNote, + setCountdownTime, + changeDifficulty, + addSuccessfulNote, + } = useSessionStore(); const formatCountdown = (): string => { const minutes = Math.floor(countdownTime / 60); @@ -57,19 +40,20 @@ const useSessionTracker = (): { }; useEffect(() => { - if (isStarted && !isEnded && countdownTime >= 0) { + if (isStarted && !isEnded) { const countdownTimer = setInterval(() => { - setCountdownTime((prevTime) => { - if (prevTime === 0) { - setIsEnded(true); - return 0; - } - return prevTime - 1; - }); + setCountdownTime(countdownTime - 1); + if (countdownTime <= 0) { + endSession(); + } }, 1000); - return (): void => clearInterval(countdownTimer); + return () => { + if (countdownTimer) { + clearInterval(countdownTimer); + } + }; } - }, [isStarted, isEnded, countdownTime]); + }, [isStarted, isEnded, countdownTime, endSession, setCountdownTime]); return { isStarted, @@ -79,6 +63,7 @@ const useSessionTracker = (): { metrics, addSuccessfulNote, addMissedNote, + changeDifficulty, countdownTime, formatCountdown, }; diff --git a/src/Stores/SessionStore/index.tsx b/src/Stores/SessionStore/index.tsx new file mode 100644 index 0000000..f60cb74 --- /dev/null +++ b/src/Stores/SessionStore/index.tsx @@ -0,0 +1,65 @@ +import { create } from "zustand"; +import { SessionStore } from "./types"; +import { EDifficulty } from "../../types"; + +const useSessionStore = create()((set) => ({ + isEnded: false, + isStarted: false, + metrics: { + difficulty: EDifficulty.easy, + successfulNotes: 0, + missedNotes: 0, + }, + countdownTime: 120, + startSession: (): void => { + set((state) => ({ + ...state, + isStarted: true, + isEnded: false, + countdownTime: 120, + metrics: { + difficulty: EDifficulty.easy, + successfulNotes: 0, + missedNotes: 0, + }, + })); + }, + endSession: (): void => { + set((state) => ({ + ...state, + isStarted: false, + isEnded: true, + })); + }, + changeDifficulty: (newDifficulty: EDifficulty): void => { + set((state) => ({ + ...state, + metrics: { + ...state.metrics, + difficulty: newDifficulty, + }, + })); + }, + addSuccessfulNote: (): void => { + set((state) => ({ + ...state, + metrics: { + ...state.metrics, + successfulNotes: state.metrics.successfulNotes + 1, + }, + })); + }, + addMissedNote: (): void => { + set((state) => ({ + ...state, + metrics: { + ...state.metrics, + missedNotes: state.metrics.missedNotes + 1, + }, + })); + }, + setCountdownTime: (newTime: number) => + set((state) => ({ ...state, countdownTime: newTime })), +})); + +export default useSessionStore; diff --git a/src/Stores/SessionStore/types.ts b/src/Stores/SessionStore/types.ts new file mode 100644 index 0000000..2b9e917 --- /dev/null +++ b/src/Stores/SessionStore/types.ts @@ -0,0 +1,20 @@ +import { EDifficulty } from "../../types"; + +export interface SessionStore { + isEnded: boolean; + isStarted: boolean; + metrics: SessionMetrics; + countdownTime: number; + setCountdownTime: (newTime: number) => void; + startSession: () => void; + endSession: () => void; + addSuccessfulNote: () => void; + changeDifficulty: (newDifficulty: EDifficulty) => void; + addMissedNote: () => void; +} + +export interface SessionMetrics { + difficulty: EDifficulty; + successfulNotes: number; + missedNotes: number; +} diff --git a/src/Utils/AudioUtils/index.ts b/src/Utils/AudioUtils/index.ts index f0e7137..0334928 100644 --- a/src/Utils/AudioUtils/index.ts +++ b/src/Utils/AudioUtils/index.ts @@ -1,3 +1,4 @@ +import useSessionStore from "../../Stores/SessionStore"; import { EDifficulty, INote } from "../../types"; export class AudioUtils { diff --git a/src/Utils/NoteUtils/index.ts b/src/Utils/NoteUtils/index.ts index 0879feb..eda86ea 100644 --- a/src/Utils/NoteUtils/index.ts +++ b/src/Utils/NoteUtils/index.ts @@ -204,14 +204,18 @@ export const notes: INote[] = [ class NoteUtils { /** * Get a random note from the notes array filtered by difficulty. + * @param lastNote The last note played. * @param difficulty The difficulty level to filter by. * @returns INote */ - public static getRandomNote(difficulty: string): INote { + public static getRandomNote(lastNote: INote, difficulty: EDifficulty): INote { const filteredNotes = notes.filter( (note) => note.difficulty === difficulty ); const randomIndex = Math.floor(Math.random() * filteredNotes.length); + if (lastNote && filteredNotes[randomIndex].note === lastNote.note) + return this.getRandomNote(lastNote, difficulty); + return filteredNotes[randomIndex]; } diff --git a/tailwind.config.js b/tailwind.config.js index 841310c..6c36039 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -5,7 +5,9 @@ export default { theme: { extend: { colors: { - primary: "#121212", + background: "#121212", + primary: "#FACC15", + muted: "#212121", }, }, }, From 1e0f27ab7118c717e09b59c9de961499f838a6ff Mon Sep 17 00:00:00 2001 From: xRxphael Date: Wed, 1 May 2024 16:56:40 +0200 Subject: [PATCH 3/3] Updated UI --- src/App.tsx | 71 ++++++++++++++---------- src/Components/Icons/IconDoorOpen.tsx | 26 +++++++++ src/Components/ListboxSelector/index.tsx | 2 +- src/Components/NoteDisplay/index.tsx | 49 ++++++++++------ tailwind.config.js | 1 + 5 files changed, 101 insertions(+), 48 deletions(-) create mode 100644 src/Components/Icons/IconDoorOpen.tsx diff --git a/src/App.tsx b/src/App.tsx index d11b71c..c498747 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,13 +7,12 @@ import useSessionTracker from "./Hooks/useSessionTracker"; function App() { const [isStarted, setIsStarted] = useState(false); - const { startSession, formatCountdown, isEnded, metrics } = - useSessionTracker(); + const { startSession, isEnded, metrics } = useSessionTracker(); return (
-
- {!isStarted ? ( + {!isStarted ? ( +
@@ -45,31 +44,45 @@ function App() { } /> - ) : !isEnded ? ( - <> -

- Remaining time: {formatCountdown()} -

- - - ) : ( - <> - Results of the session: - Missed Notes: {metrics.missedNotes} - - Successful Notes: {metrics.successfulNotes} - - - - )} -
+
+ ) : !isEnded ? ( + + ) : ( +
+ + + + + +
+ )}
); } diff --git a/src/Components/Icons/IconDoorOpen.tsx b/src/Components/Icons/IconDoorOpen.tsx new file mode 100644 index 0000000..2f2e3f2 --- /dev/null +++ b/src/Components/Icons/IconDoorOpen.tsx @@ -0,0 +1,26 @@ +import { SVGProps } from "react"; + +function IconDoorOpen(props: SVGProps) { + return ( + + + + + + + + ); +} + +export default IconDoorOpen; diff --git a/src/Components/ListboxSelector/index.tsx b/src/Components/ListboxSelector/index.tsx index ccc45ca..f1c4de4 100644 --- a/src/Components/ListboxSelector/index.tsx +++ b/src/Components/ListboxSelector/index.tsx @@ -35,7 +35,7 @@ function ListboxSelector({ key={index} className={({ active }) => `relative cursor-pointer select-none py-2 pl-10 pr-4 ${ - active ? "bg-slate-700 text-white" : "text-white" + active ? "bg-mutedSecondary text-white" : "text-white" }` } value={option.value} diff --git a/src/Components/NoteDisplay/index.tsx b/src/Components/NoteDisplay/index.tsx index 55eca07..e401e29 100644 --- a/src/Components/NoteDisplay/index.tsx +++ b/src/Components/NoteDisplay/index.tsx @@ -7,16 +7,16 @@ import NoteUtils, { notes } from "../../Utils/NoteUtils"; import { EDifficulty, INote } from "../../types"; import ListboxSelector from "../ListboxSelector"; import { Props, difficultyOptions } from "./types"; -import Button from "../Button"; import IconMusikNote from "../Icons/IconMusikNote"; import useSessionTracker from "../../Hooks/useSessionTracker"; -import useSessionStore from "../../Stores/SessionStore"; +import IconDoorOpen from "../Icons/IconDoorOpen"; const NoteDisplay = ({ isStarted, setIsStarted }: Props) => { const { playedNote, initAudio, stopAudio } = useAudioProcessor(notes); const [isNoteCorrect, setIsNoteCorrect] = useState(false); const { addMissedNote, addSuccessfulNote } = useSessionTracker(); - const { metrics, changeDifficulty } = useSessionStore(); + const { metrics, changeDifficulty, formatCountdown, endSession } = + useSessionTracker(); const [randomNote, setRandomNote] = useState({ frequency: 0, @@ -54,6 +54,7 @@ const NoteDisplay = ({ isStarted, setIsStarted }: Props) => { { responsive: "resize", staffwidth: 120, + selectionColor: "white", } ); @@ -78,16 +79,38 @@ const NoteDisplay = ({ isStarted, setIsStarted }: Props) => { const handleStop = () => { stopAudio(); + endSession(); setIsStarted(false); }; return (
-
- +
+ + +

+ Remaining time: {formatCountdown()} +

+
-
-
+ +
+ changeDifficulty(value)} + buttonTitle="Change Difficulty" + value={metrics.difficulty} + options={difficultyOptions} + /> +
+ +
+

Performed

@@ -105,19 +128,9 @@ const NoteDisplay = ({ isStarted, setIsStarted }: Props) => {
- -
- changeDifficulty(value)} - buttonTitle="Change Difficulty" - value={metrics.difficulty} - options={difficultyOptions} - /> -
-
+