✨ Add ability to delete all leaderboard
This commit is contained in:
@@ -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;
|
||||||
@@ -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;
|
||||||
@@ -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[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
const [, updateLeaderboard] = useState({});
|
||||||
|
const forceUpdate = useCallback(() => updateLeaderboard({}), []);
|
||||||
|
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
const storeData = await store.getItem<LeaderBoardItem[]>(`${gameState.difficulty}:${gameState.gridSize}`);
|
const storeData = await store.getItem<LeaderBoardItem[]>(`${gameState.difficulty}:${gameState.gridSize}`);
|
||||||
|
|
||||||
setData(storeData || []);
|
setData(storeData || []);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
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>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user