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.

121 lines
3.9 KiB
TypeScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { createMemo, createSignal, onCleanup, onMount } 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 TextField from '@suid/material/TextField'
import Typography from '@suid/material/Typography'
import AttemptIndicator from '../ui/AttemptIndicator'
import ScoreDisplay from '../ui/ScoreDisplay'
import Timer from '../ui/Timer'
import { useTimer } from '../hooks/useTimer'
export default function GameRoute() {
// Placeholder game state until backend exists.
const [question] = createSignal({ theme: 'Général', text: 'Quel est le plus petit nombre premier ?' })
const [answer, setAnswer] = createSignal('')
const [attempts, setAttempts] = createSignal(0)
const [hintUsed, setHintUsed] = createSignal(false)
const [score, setScore] = createSignal(0)
const [message, setMessage] = createSignal<string | null>(null)
const durationMs = 30 * 60 * 1000
const { remainingMs, isExpired, start } = useTimer(durationMs)
onMount(() => start())
onCleanup(() => {
// no-op; hook cleans itself
})
const attemptsLeft = createMemo(() => Math.max(0, 3 - attempts()))
const submit = () => {
if (isExpired()) {
setMessage('Session terminée (timeout).')
return
}
const normalized = answer().trim().toLowerCase()
const correct = normalized === '2' || normalized === 'deux'
setAttempts((a) => a + 1)
if (correct) {
const delta = hintUsed() ? 1 : 2
setScore((s) => s + delta)
setMessage(`Bonne réponse (+${delta}).`)
} else {
setMessage('Mauvaise réponse.')
}
setAnswer('')
}
const useHint = () => {
if (hintUsed()) return
setHintUsed(true)
setMessage('Indice: cest le seul nombre premier pair.')
}
return (
<Box>
<Stack spacing={2}>
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2} alignItems="center">
<Box sx={{ flexGrow: 1 }}>
<Typography variant="h4" sx={{ fontWeight: 800 }}>
Partie
</Typography>
<Typography sx={{ opacity: 0.8 }}>Thème : {question().theme}</Typography>
</Box>
<Timer remainingMs={remainingMs()} />
<ScoreDisplay score={score()} />
</Stack>
<Card variant="outlined" sx={{ bgcolor: '#111827', borderColor: '#1f2937' }}>
<CardContent>
<Stack spacing={2}>
<Typography variant="h6" sx={{ fontWeight: 700 }}>
{question().text}
</Typography>
<TextField
label="Ta réponse"
value={answer()}
onInput={(e) => setAnswer(e.currentTarget.value)}
fullWidth
InputLabelProps={{ style: { color: '#cbd5e1' } }}
InputProps={{ style: { color: '#e5e7eb' } }}
onKeyDown={(e) => {
if (e.key === 'Enter') submit()
}}
/>
<AttemptIndicator attemptsUsed={attempts()} attemptsMax={3} />
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
<Button variant="contained" disabled={attemptsLeft() === 0} onClick={submit}>
Envoyer
</Button>
<Button variant="outlined" disabled={hintUsed()} onClick={useHint}>
Indice (score réduit)
</Button>
</Stack>
<Divider />
{message() && <Typography sx={{ opacity: 0.9 }}>{message()}</Typography>}
{attemptsLeft() === 0 && <Typography color="warning.main">Plus d'essais.</Typography>}
{isExpired() && <Typography color="error.main">Temps écoulé.</Typography>}
</Stack>
</CardContent>
</Card>
</Stack>
</Box>
)
}