Add ability to delete all leaderboard

This commit is contained in:
2024-02-19 08:46:05 +01:00
parent 9426b8499c
commit ffa6468b70
5 changed files with 161 additions and 22 deletions
+72
View File
@@ -0,0 +1,72 @@
const Difficulty = (props: any) => {
return (
<svg
xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 512 512'
{...props}
>
<path
fill='none'
stroke='currentColor'
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth='32'
d='M48 256h416'
/>
<rect
x='384'
y='128'
width='32'
height='256'
rx='16'
ry='16'
fill='none'
stroke='currentColor'
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth='32'
/>
<rect
x='96'
y='128'
width='32'
height='256'
rx='16'
ry='16'
fill='none'
stroke='currentColor'
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth='32'
/>
<rect
x='32'
y='192'
width='16'
height='128'
rx='8'
ry='8'
fill='none'
stroke='currentColor'
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth='32'
/>
<rect
x='464'
y='192'
width='16'
height='128'
rx='8'
ry='8'
fill='none'
stroke='currentColor'
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth='32'
/>
</svg>
);
};
export default Difficulty;
+20
View File
@@ -0,0 +1,20 @@
const Size = (props: any) => {
return (
<svg
xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 512 512'
{...props}
>
<path
fill='none'
stroke='currentColor'
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth='32'
d='M304 96h112v112M405.77 106.2L111.98 400.02M208 416H96V304'
/>
</svg>
);
};
export default Size;
+48 -15
View File
@@ -3,7 +3,7 @@
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------ React -------------------------------------------------------- // ------------------------------------------------------ React --------------------------------------------------------
import { useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
// ----------------------------------------------- Context & Stockage -------------------------------------------------- // ----------------------------------------------- Context & Stockage --------------------------------------------------
@@ -12,8 +12,9 @@ import { useRecoilState } from 'recoil';
import { gameStateAtom } from '../../contexts/gameState'; import { gameStateAtom } from '../../contexts/gameState';
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------ Types -------------------------------------------------------- // -------------------------------------------------- Utils & Types ----------------------------------------------------
import { LeaderBoardItem } from '../../types/game'; import { Difficulty, LeaderBoardItem } from '../../types/game';
import { getDifficultyLabel } from '../../utils/generics';
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------- Assets -------------------------------------------------------- // ----------------------------------------------------- Assets --------------------------------------------------------
@@ -22,6 +23,8 @@ import Replay from '../../assets/replay';
import Settings from '../../assets/settings'; import Settings from '../../assets/settings';
import TimerIcon from '../../assets/timer'; import TimerIcon from '../../assets/timer';
import Trash from '../../assets/trash'; import Trash from '../../assets/trash';
import DifficultyIcon from '../../assets/difficulty';
import Size from '../../assets/size';
import './styles.scss'; import './styles.scss';
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
@@ -37,18 +40,30 @@ const LeaderBoard = () => {
const [gameState, setGameState] = useRecoilState(gameStateAtom); const [gameState, setGameState] = useRecoilState(gameStateAtom);
const [data, setData] = useState<LeaderBoardItem[]>([]); const [data, setData] = useState<LeaderBoardItem[]>([]);
const [, updateLeaderboard] = useState({});
const forceUpdate = useCallback(() => updateLeaderboard({}), []);
const getData = async () => {
const storeData = await store.getItem<LeaderBoardItem[]>(`${gameState.difficulty}:${gameState.gridSize}`);
setData(storeData || []);
};
useEffect(() => { useEffect(() => {
const getData = async () => {
const storeData = await store.getItem<LeaderBoardItem[]>(`${gameState.difficulty}:${gameState.gridSize}`);
setData(storeData || []);
};
if (data.length === 0) { if (data.length === 0) {
getData(); getData();
} }
}, [data.length]); }, [data.length]);
const clearAllLeaderboards = async () => {
const keys = await store.keys();
for (let i = 0; i < keys.length; i++) {
await store.removeItem(keys[i]);
}
getData();
};
return ( return (
<> <>
<h1 className='title'>Time Leaderboard</h1> <h1 className='title'>Time Leaderboard</h1>
@@ -60,6 +75,14 @@ const LeaderBoard = () => {
<CalendarIcon /> <CalendarIcon />
Date Date
</p> </p>
<p>
<DifficultyIcon style={{ rotate: '-45deg' }} />
Difficulté
</p>
<p>
<Size />
Taille
</p>
<p> <p>
<TimerIcon /> <TimerIcon />
Time Time
@@ -75,6 +98,8 @@ const LeaderBoard = () => {
> >
<span>{index + 1}</span> <span>{index + 1}</span>
<span>{item.date}</span> <span>{item.date}</span>
<span>{getDifficultyLabel(gameState.difficulty as Difficulty)}</span>
<span>{gameState.gridSize}</span>
<span>{item.time}</span> <span>{item.time}</span>
</div> </div>
); );
@@ -91,11 +116,19 @@ const LeaderBoard = () => {
Paramètres Paramètres
</button> </button>
<button
className='controlButton replay'
onClick={() => setGameState((prev) => ({ ...prev, status: 'idle', endType: '', placedFlags: 0, bombs: 0, gameTime: '' }))}
>
<Replay />
Rejouer
</button>
<button <button
className='controlButton clear' className='controlButton clear'
onClick={() => { onClick={async () => {
setGameState((prev) => ({ ...prev, status: 'settings', endType: '', placedFlags: 0, bombs: 0, gameTime: '' })); await store.setItem(`${gameState.difficulty}:${gameState.gridSize}`, []);
store.setItem(`${gameState.difficulty}:${gameState.gridSize}`, []); await getData();
}} }}
> >
<Trash /> <Trash />
@@ -103,11 +136,11 @@ const LeaderBoard = () => {
</button> </button>
<button <button
className='controlButton replay' className='controlButton clearAll'
onClick={() => setGameState((prev) => ({ ...prev, status: 'idle', endType: '', placedFlags: 0, bombs: 0, gameTime: '' }))} onClick={clearAllLeaderboards}
> >
<Replay /> <Replay />
Rejouer Tout supprimer
</button> </button>
</div> </div>
</> </>
+14 -7
View File
@@ -9,14 +9,14 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 95svw; width: 95svw;
max-width: 500px; max-width: 600px;
border-radius: 5px; border-radius: 5px;
background-color: #fff; background-color: #fff;
overflow: hidden; overflow: hidden;
& > .header { & > .header {
display: grid; display: grid;
grid-template-columns: 1em repeat(2, 1fr); grid-template-columns: 1em 1fr 1fr 0.7fr 1fr;
gap: 30px; gap: 30px;
padding: 15px 20px; padding: 15px 20px;
background-color: #333; background-color: #333;
@@ -47,7 +47,9 @@
& > .score { & > .score {
display: grid; display: grid;
grid-template-columns: 1em repeat(2, 1fr); grid-template-columns: 1em 1fr 1fr 0.7fr 1fr;
align-items: center;
justify-content: center;
gap: 30px; gap: 30px;
padding: 10px 20px; padding: 10px 20px;
background-color: #e1e1e1; background-color: #e1e1e1;
@@ -59,7 +61,7 @@
} }
&:last-child { &:last-child {
justify-self: end; text-align: right;
font-weight: 600; font-weight: 600;
} }
} }
@@ -73,7 +75,8 @@
.controls { .controls {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 1fr);
gap: 10px; gap: 10px;
width: 100%; width: 100%;
@@ -100,12 +103,16 @@
background-color: #f39440; background-color: #f39440;
} }
&.replay {
background-color: #f39440;
}
&.clear { &.clear {
background-color: #ca5940; background-color: #ca5940;
} }
&.replay { &.clearAll {
background-color: #f39440; background-color: hsl(0, 57%, 52%);
} }
& > svg { & > svg {
+7
View File
@@ -44,3 +44,10 @@ export const saveToLocalStorage = async (time: string, difficulty: Difficulty, g
await store.setItem(`${difficulty}:${gridSize}`, leaderboard); await store.setItem(`${difficulty}:${gridSize}`, leaderboard);
}; };
export const getDifficultyLabel = (difficulty: Difficulty): string => {
if (difficulty == 'beginner') return 'Débutant';
if (difficulty == 'intermediate') return 'Intermédiaire';
if (difficulty == 'expert') return 'Expert';
return difficulty;
};