import React, { useCallback, useRef, useState } from 'react';
import {
View,
Text,
FlatList,
TouchableOpacity,
StyleSheet,
ActivityIndicator,
} from 'react-native';
import { useFocusEffect } from '@react-navigation/native';
import { obtenirClasse, effectuerTirage, reTirer } from '../storage';
import { couleurs } from '../theme';
function formaterDate(iso) {
const d = new Date(iso);
const pad = (n) => String(n).padStart(2, '0');
return `${pad(d.getDate())}/${pad(d.getMonth() + 1)}/${d.getFullYear()} ${pad(
d.getHours()
)}:${pad(d.getMinutes())}`;
}
export default function DetailClasseScreen({ route, navigation }) {
const { classeId } = route.params;
const [classe, setClasse] = useState(null);
const [enCours, setEnCours] = useState(false);
// Ref en plus du state : le state ne se répercute qu'au prochain rendu,
// ce qui laisse une fenêtre où un second tap très rapide (avant que le
// bouton soit visuellement désactivé) pourrait lancer un 2e tirage pendant
// que le premier écrit encore dans le stockage. La ref, elle, est lue et
// mise à jour de façon synchrone, donc elle bloque le double-tap immédiatement.
const enCoursRef = useRef(false);
const recharger = useCallback(async () => {
const c = await obtenirClasse(classeId);
setClasse(c);
if (c) navigation.setOptions({ title: c.nom });
}, [classeId]);
useFocusEffect(
useCallback(() => {
recharger();
}, [recharger])
);
const tirer = async () => {
if (enCoursRef.current) return;
enCoursRef.current = true;
setEnCours(true);
try {
const c = await effectuerTirage(classeId);
setClasse(c);
} finally {
enCoursRef.current = false;
setEnCours(false);
}
};
const reTirerAction = async () => {
if (enCoursRef.current) return;
enCoursRef.current = true;
setEnCours(true);
try {
const c = await reTirer(classeId);
setClasse(c);
} finally {
enCoursRef.current = false;
setEnCours(false);
}
};
if (!classe) {
return (
);
}
const dernierTirage = classe.tirages[0];
return (
{classe.nombreEleves} élèves · pondération max ×{classe.ponderationMax}
🎲 Tirer un élève au sort
{dernierTirage && (
<>
n°{dernierTirage.numeroEleve}
🔁 Re-tirer (annule et retire)
>
)}
Historique des tirages
item.id}
contentContainerStyle={{ paddingBottom: 24 }}
ListEmptyComponent={
Aucun tirage pour le moment.
}
renderItem={({ item, index }) => (
{item.numeroEleve}
{formaterDate(item.dateTirage)}
{index === 0 && dernier}
)}
/>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: couleurs.fond, padding: 16 },
centre: { justifyContent: 'center', alignItems: 'center' },
sousTitre: { color: couleurs.texteSecondaire, marginBottom: 14, fontSize: 14 },
cardTirage: {
backgroundColor: couleurs.carte,
borderRadius: 14,
padding: 20,
alignItems: 'center',
marginBottom: 22,
shadowColor: '#000',
shadowOpacity: 0.06,
shadowRadius: 4,
shadowOffset: { width: 0, height: 1 },
elevation: 1,
},
bouton: {
backgroundColor: couleurs.primaire,
borderRadius: 10,
paddingVertical: 14,
paddingHorizontal: 20,
alignItems: 'center',
width: '100%',
},
boutonDesactive: { opacity: 0.6 },
boutonTexte: { color: 'white', fontSize: 16, fontWeight: '600' },
numeroTire: {
fontSize: 52,
fontWeight: '800',
color: couleurs.primaire,
marginVertical: 14,
},
boutonSecondaire: {
borderRadius: 10,
paddingVertical: 12,
paddingHorizontal: 20,
alignItems: 'center',
width: '100%',
backgroundColor: couleurs.fond,
borderWidth: 1,
borderColor: couleurs.bordure,
},
boutonSecondaireTexte: { color: couleurs.texte, fontSize: 15, fontWeight: '600' },
titreHistorique: { fontSize: 16, fontWeight: '700', marginBottom: 10, color: couleurs.texte },
texteVide: { color: couleurs.texteSecondaire },
ligneHistorique: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: 10,
borderBottomWidth: 1,
borderBottomColor: couleurs.bordure,
},
badge: {
backgroundColor: couleurs.primaire,
borderRadius: 14,
width: 28,
height: 28,
justifyContent: 'center',
alignItems: 'center',
marginRight: 12,
},
badgeTexte: { color: 'white', fontWeight: '700', fontSize: 13 },
dateHistorique: { color: couleurs.texteSecondaire, flex: 1 },
etiquetteRecent: {
fontSize: 11,
color: couleurs.succes,
fontWeight: '700',
textTransform: 'uppercase',
},
});