Score wip

This commit is contained in:
2025-02-15 18:33:31 +01:00
parent 78ee06ceaa
commit 4fc0fbf1ed
7 changed files with 228 additions and 17 deletions
+11 -3
View File
@@ -1,7 +1,15 @@
.container {
margin: auto;
padding: 1rem;
letter-spacing: 0.12rem;
display: grid;
grid-template-columns: repeat(2, 1fr);
column-gap: 1rem;
}
.code {
padding: 1rem;
}
.score {
text-align: right;
}
.pending, .space {
+47 -3
View File
@@ -8,14 +8,18 @@ function Code() {
// TODO: Create a function that combines a sequence of spaces into tabs.
const [code, setCode] = useState<string>('');
const [loaded, setLoaded] = useState<boolean>(false);
const [startedTyping, setStartedTyping] = useState<boolean>(false);
const [characters, setCharacters] = useState<Array<boolean | 'space'>>([]);
const [timer, setTimer] = useState<number>(0);
const [score, setScore] = useState<number>(0);
const [accuracy, setAccuracy] = useState<number>(0);
useEffect(() => {
(async function () {
setCode('');
const response = await fetch(
`${import.meta.env.VITE_API_URL}/generate?lang=typescript`,
`${import.meta.env.VITE_API_URL}/generate?lang=lisp`,
);
if (!response.ok || !response.body) return;
@@ -38,14 +42,36 @@ function Code() {
})();
}, []);
useEffect(() => {
let interval = null;
if (!startedTyping) {
if (interval) clearInterval(interval);
return;
}
interval = setInterval(() => {
setTimer(prev => prev + 1);
}, 1000);
return () => clearInterval(interval);
}, [startedTyping]);
useEffect(() => {
function handleKeyPress(event: KeyboardEvent) {
event.preventDefault();
if (!loaded) return;
if (characters.length === code.length) return;
if (characters.length === code.length) {
setStartedTyping(false);
return;
}
if (KEYS_TO_DISABLE.includes(event.key)) return;
if (!startedTyping) setStartedTyping(true);
const char = code[characters.length];
if (/^\n$/.test(char)) {
@@ -71,6 +97,17 @@ function Code() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [loaded, characters]);
useEffect(() => {
const typed = characters.filter(char => char !== 'space').length;
const correctlyTyped = characters.filter(char => char && char !== 'space').length;
const incorrectlyTyped = characters.filter(char => !char).length;
if (timer > 0) {
setScore((typed / 5 - incorrectlyTyped) / (timer / 60));
setAccuracy(correctlyTyped / typed * 100);
}
}, [timer, characters]);
function renderCharacterClassName(index: number) {
const typed = characters[index];
@@ -115,7 +152,14 @@ function Code() {
return (
<div className='container'>
{code.split('').map((char, index) => renderCharacter(char, index))}
<div className='code'>
{code.split('').map((char, index) => renderCharacter(char, index))}
</div>
<div className='score'>
<p>Time: {timer}</p>
<p>WPM: {Math.round(score)}</p>
<p>Accuracy: {Math.round(accuracy)}%</p>
</div>
</div>
);
}
+17
View File
@@ -0,0 +1,17 @@
import { useState } from "react";
function Score() {
const [timer] = useState<number>(0);
const [score] = useState<number>(0);
const [accuracy] = useState<number>(0);
return (
<div className='score'>
<p>Time: {timer}</p>
<p>WPM: {Math.round(score)}</p>
<p>Accuracy: {Math.round(accuracy)}%</p>
</div>
)
}
export default Score;
+58
View File
@@ -0,0 +1,58 @@
import { createContext, useContext, useState } from "react";
export type CodeContextValues = {
startedTyping: boolean;
characters: Array<boolean | 'space'>;
score: number;
accuracy: number;
setStartedTyping: React.Dispatch<React.SetStateAction<boolean>>;
setCharacters: React.Dispatch<React.SetStateAction<Array<boolean | 'space'>>>;
setScore: React.Dispatch<React.SetStateAction<number>>;
setAccuracy: React.Dispatch<React.SetStateAction<number>>;
}
const CodeContext = createContext<CodeContextValues>({
startedTyping: false,
characters: [],
score: 0,
accuracy: 0,
setStartedTyping: () => { },
setCharacters: () => { },
setScore: () => { },
setAccuracy: () => { },
});
export function useCodeContext() {
return useContext(CodeContext);
}
type CodeContextProviderProps = {
children: React.ReactNode,
}
function CodeContextProvider({ children }: CodeContextProviderProps) {
const [startedTyping, setStartedTyping] = useState<boolean>(false);
const [characters, setCharacters] = useState<Array<boolean | 'space'>>([]);
const [score, setScore] = useState<number>(0);
const [accuracy, setAccuracy] = useState<number>(0);
return (
<CodeContext.Provider value={{
startedTyping,
characters,
score,
accuracy,
setStartedTyping,
setCharacters,
setScore,
setAccuracy,
}}>
{children}
</CodeContext.Provider>
)
}
export default CodeContextProvider;