You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
5.4 KiB
TypeScript
144 lines
5.4 KiB
TypeScript
import { For, Show, createMemo, createSignal } from 'solid-js'
|
|
|
|
import Box from '@suid/material/Box'
|
|
import Button from '@suid/material/Button'
|
|
import Card from '@suid/material/Card'
|
|
import CardContent from '@suid/material/CardContent'
|
|
import Divider from '@suid/material/Divider'
|
|
import Stack from '@suid/material/Stack'
|
|
import Switch from '@suid/material/Switch'
|
|
import TextField from '@suid/material/TextField'
|
|
import Typography from '@suid/material/Typography'
|
|
|
|
import { useAuth } from '../hooks/useAuth'
|
|
import { loadGameHistory } from '../services/session'
|
|
|
|
function readInputValue(event: Event): string {
|
|
return (event.target as HTMLInputElement).value
|
|
}
|
|
|
|
export default function ProfileRoute() {
|
|
const { isAuthenticated, signInDemo, signOut } = useAuth()
|
|
const [name, setName] = createSignal(localStorage.getItem('kf.playerName') ?? '')
|
|
const [showHints, setShowHints] = createSignal(true)
|
|
|
|
const gameHistory = createMemo(() => loadGameHistory())
|
|
const stats = createMemo(() => {
|
|
const history = gameHistory()
|
|
const gamesPlayed = history.length
|
|
const totalScore = history.reduce((acc, item) => acc + item.finalScore, 0)
|
|
const averageScore = gamesPlayed > 0 ? Math.round((totalScore / gamesPlayed) * 10) / 10 : 0
|
|
const bestScore = history.reduce((best, item) => Math.max(best, item.finalScore), 0)
|
|
return { gamesPlayed, averageScore, bestScore }
|
|
})
|
|
|
|
const save = () => {
|
|
localStorage.setItem('kf.playerName', name().trim())
|
|
}
|
|
|
|
return (
|
|
<Box>
|
|
<Show
|
|
when={isAuthenticated()}
|
|
fallback={
|
|
<Card variant="outlined" sx={{ bgcolor: '#111827', borderColor: '#1f2937' }}>
|
|
<CardContent>
|
|
<Stack spacing={2}>
|
|
<Typography variant="h4" sx={{ fontWeight: 800 }}>
|
|
Profil
|
|
</Typography>
|
|
<Typography sx={{ opacity: 0.8 }}>Connexion requise pour accéder au profil joueur.</Typography>
|
|
<Button variant="contained" onClick={signInDemo}>
|
|
Se connecter (mode démo)
|
|
</Button>
|
|
</Stack>
|
|
</CardContent>
|
|
</Card>
|
|
}
|
|
>
|
|
<Stack spacing={2}>
|
|
<Card variant="outlined" sx={{ bgcolor: '#111827', borderColor: '#1f2937' }}>
|
|
<CardContent>
|
|
<Stack spacing={1}>
|
|
<Typography variant="h5" sx={{ fontWeight: 800 }}>
|
|
Statistiques joueur
|
|
</Typography>
|
|
<Typography>Parties jouées : {stats().gamesPlayed}</Typography>
|
|
<Typography>Score moyen : {stats().averageScore}</Typography>
|
|
<Typography>Meilleur score : {stats().bestScore}</Typography>
|
|
</Stack>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card variant="outlined" sx={{ bgcolor: '#111827', borderColor: '#1f2937' }}>
|
|
<CardContent>
|
|
<Stack spacing={1}>
|
|
<Typography variant="h5" sx={{ fontWeight: 800 }}>
|
|
Historique des parties
|
|
</Typography>
|
|
<Show
|
|
when={gameHistory().length > 0}
|
|
fallback={<Typography sx={{ opacity: 0.8 }}>Aucune partie enregistrée.</Typography>}
|
|
>
|
|
<For each={gameHistory().slice(0, 5)}>
|
|
{(item) => (
|
|
<Stack spacing={0.5}>
|
|
<Typography>
|
|
Score {item.finalScore} • Réussite {item.successRate}% • Durée {Math.floor(item.durationSec / 60)}m
|
|
</Typography>
|
|
<Divider />
|
|
</Stack>
|
|
)}
|
|
</For>
|
|
</Show>
|
|
</Stack>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card variant="outlined" sx={{ bgcolor: '#111827', borderColor: '#1f2937' }}>
|
|
<CardContent>
|
|
<Stack spacing={2}>
|
|
<Typography variant="h5" sx={{ fontWeight: 800 }}>
|
|
Paramètres
|
|
</Typography>
|
|
|
|
<TextField
|
|
label="Nom de joueur"
|
|
value={name()}
|
|
onInput={(e) => setName(readInputValue(e))}
|
|
fullWidth
|
|
InputLabelProps={{ style: { color: '#cbd5e1' } }}
|
|
InputProps={{ style: { color: '#e5e7eb' } }}
|
|
/>
|
|
|
|
<Stack direction="row" spacing={1} alignItems="center">
|
|
<Switch checked={showHints()} onChange={() => setShowHints((v) => !v)} />
|
|
<Typography>Afficher les indices pendant une partie</Typography>
|
|
</Stack>
|
|
|
|
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
|
|
<Button variant="contained" onClick={save}>
|
|
Enregistrer
|
|
</Button>
|
|
<Button
|
|
variant="outlined"
|
|
onClick={() => {
|
|
localStorage.removeItem('kf.playerName')
|
|
setName('')
|
|
}}
|
|
>
|
|
Effacer le pseudo
|
|
</Button>
|
|
<Button variant="outlined" color="error" onClick={signOut}>
|
|
Se déconnecter
|
|
</Button>
|
|
</Stack>
|
|
</Stack>
|
|
</CardContent>
|
|
</Card>
|
|
</Stack>
|
|
</Show>
|
|
</Box>
|
|
)
|
|
}
|