const { useState, useEffect } = React; const niveauxParMatiere = { maths: 0, chimie: 13, physique:5, geographie:1,biologie:15,geographie:8,zoologie:6,svt:12,Economie:3, Chimie :3,Anglais:10,BaccSvt:17,Vitamine:4,geologie:9,sciences_sociales:21, sport:7}; const classes = ["9eme", "NSIV","NS3","Sciences","NSI","Linguistique","Sport"]; const matieres = {"9eme": ["biologie","physique","sciences_sociales"], "NSIV": ["chimie","svt","Economie","BaccSvt","Vitamine"], "NS3":["chimie"],"Sciences":["geographie","zoologie","botanique","geologie"],"NSI":["Chimie"],"Linguistique":["Anglais"],"Sport":["sport"]}; const getUserProgress = () => {return JSON.parse(localStorage.getItem("userProgress") || "{}");}; function HorizontalMenu() { return (
); } const Loader = () => (

Chargement du quiz...

); function sauvegarderProgression(userId, classe, matiere, niveau) { fetch("api/saveProgress.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ userId, classe, matiere, niveau }) }) .then(res => res.json()) .then(data => { if (data.success) { console.log("✅ Progression enregistrée"); } else { console.error("⚠️ Erreur de sauvegarde :", data.message); } }) .catch(console.error); } function CookieBanner() { const [showBanner, setShowBanner] = React.useState(false); React.useEffect(() => { const consent = window.cookieUtils.get("cookieConsent"); if (!consent) setShowBanner(true); }, []); function acceptCookies() { window.cookieUtils.set("cookieConsent", "accepted", 365); setShowBanner(false); } function refuseCookies() { window.cookieUtils.set("cookieConsent", "refused", 365); setShowBanner(false); } if (!showBanner) return null; return React.createElement( "div", { style: { position: "fixed", bottom: "0", left: "0", width: "100%", backgroundColor: "#1e1e1e", color: "white", padding: "1rem", zIndex: 1000, display: "flex", flexDirection: "column", alignItems: "center", gap: "0.5rem", boxShadow: "0 -2px 10px rgba(0,0,0,0.3)", fontSize: "1rem" } }, React.createElement("div", { style: { maxWidth: "90%", textAlign: "center" } }, "Nous utilisons des cookies pour améliorer votre expérience. et pour diffuser des publicités. Acceptez-vous ?"), React.createElement("div", { style: { display: "flex", gap: "1rem", flexWrap: "wrap", justifyContent: "center" } }, React.createElement("button", { onClick: acceptCookies, style: { backgroundColor: "#4caf50", color: "white", border: "none", borderRadius: "5px", padding: "0.5rem 1.2rem", cursor: "pointer" } }, "Accepter"), React.createElement("button", { onClick: refuseCookies, style: { backgroundColor: "#f44336", color: "white", border: "none", borderRadius: "5px", padding: "0.5rem 1.2rem", cursor: "pointer" } }, "Refuser") ) ); } const MonetagRewardAd = ({ onRewarded }) => { React.useEffect(() => {const script = document.createElement('script'); script.src = 'https://groleegni.net/401/8727837'; script.async = true; try { (document.body || document.documentElement).appendChild(script); } catch (e) { console.error("Erreur lors de l'ajout du script Monetag :", e); } // Simulation durée pub puis récompense (ajuste si API dispo) const timer = setTimeout(() => { onRewarded(); }, 5000); return () => { clearTimeout(timer); if (script.parentNode) { script.parentNode.removeChild(script); } }; }, [onRewarded]); return (
en cours...
); }; const ShareButton = ({ url = window.location.href, text = "Essaie ce super quiz !" }) => { const [message, setMessage] = React.useState(""); const share = async () => { if (navigator.share) { try { await navigator.share({ title: "Quiz éducatif", text, url }); setMessage("✅ Partagé avec succès !"); } catch (err) { setMessage("❌ Échec du partage."); } } else { try { await navigator.clipboard.writeText(url); setMessage("✅ Lien copié dans le presse-papiers !"); } catch (e) { setMessage("❌ Impossible de copier le lien."); } } setTimeout(() => setMessage(""), 3000); }; return (
{message &&

{message}

}
); }; const AdsterraBanner = () => { React.useEffect(() => { const script = document.createElement('script'); script.src = '//pl25317511.profitableratecpm.com/3a/47/d3/3a47d34d1ef582ce3780ed350b61f84d.js'; script.async = true; try { (document.body || document.documentElement).appendChild(script); } catch (e) { console.error("Erreur lors de l'ajout du script Monetag :", e); } }, []); return (
{/* Ici iframe ou script Adsterra */} Bannière Adsterra
); }; const OnClickARewardedVideo = ({ onRewarded, onCancel }) => { const [canCancel, setCanCancel] = React.useState(false); React.useEffect(() => { // Injecter le script OnClickA const script = document.createElement("script"); script.src = "https://js.onclckmn.com/static/onclicka.js"; script.async = true; script.setAttribute("data-admpid", "276511"); document.body.appendChild(script); // Autoriser annulation après 15 sec const cancelTimer = setTimeout(() => { setCanCancel(true); }, 15000); const finishTimer = setTimeout(() => { onRewarded(); }, 15000); // Nettoyer au démontage return () => { clearTimeout(cancelTimer); clearTimeout(finishTimer); document.body.removeChild(script); }; }, []); return (
en cours...

🎬 en cours...

{canCancel && }
); }; function Contact() { const [showPolicy, setShowPolicy] = useState(false); return (

📞 Contactez-Nous

Entreprise : teragroup Inc.

Email :teragroup@htschoolhaiti.com

Téléphone : +509 3809 4731

Adresse : Port-au-Prince, Haïti

{showPolicy && (
{}} />
)}
); } function About() { const [principes, setPrincipes] = useState(null); useEffect(() => { fetch("/principes_jeu.json") .then(res => res.json()) .then(data => setPrincipes(data)); }, []); if (!principes) return <> ; return (

{principes.title}

Dernière mise à jour : {principes.lastUpdate}

{principes.sections.map((section, i) => (

{section.heading}

    {section.content.map((item, j) => (
  • {item}
  • ))}
))}
); } const Updat_bagde = async ()=>{ const ph=JSON.parse(localStorage.getItem("quizUser")); const c=JSON.parse(localStorage.getItem("badges")); if (c && ph) { const xhr = new XMLHttpRequest(); xhr.open("POST", "api/updateUserProgress.php", true); xhr.setRequestHeader("Content-Type", "application/json");xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { console.log("Réponse du serveur :", xhr.responseText); } }; xhr.send(JSON.stringify({or:c.or, phone:ph.phone, agent:c.argent,bronze:c.bronze, diamant:c.diamant})); } } const User_if = async ({pseudo, phone, password})=>{ const xhr = new XMLHttpRequest(); xhr.open("POST", "api/registerUser.php", true); xhr.setRequestHeader("Content-Type", "application/json"); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { console.log("Réponse du serveur :", xhr.responseText); } }; xhr.send(JSON.stringify({username:pseudo, phone:phone ,pass:password })); } const Udat_user = async ({phone,password})=>{ const reponse = await fetch("api/user_htjggfs.php",{ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({phone: phone, pass:password}) }); if(reponse.ok==true &&reponse.status==200){ const inf = await reponse.json(); return inf; }else{ return false; } } const Quiz = ({ questions, onFinish }) => { const [shuffledQuestions, setShuffledQuestions] = React.useState([]); const [index, setIndex] = React.useState(0); const [score, setScore] = React.useState(0); const [selected, setSelected] = React.useState(null); const [showFeedback, setShowFeedback] = React.useState(false); const [timeLeft, setTimeLeft] = React.useState(30); const [animate, setAnimate] = React.useState(true); const [fillInputs, setFillInputs] = React.useState([]); const [assocAnswers, setAssocAnswers] = React.useState({}); const current = questions[index]; const correctSound = React.useRef(null); const wrongSound = React.useRef(null); const beepSound = new Audio("image/sispens.mp3"); React.useEffect(() => { correctSound.current = new Audio("image/bon.mp3"); wrongSound.current = new Audio("image/erreur.wav"); }, []); const shuffleArray = (arr) => arr.map(a => ({ sort: Math.random(), value: a })) .sort((a, b) => a.sort - b.sort) .map(a => a.value); React.useEffect(() => { const shuffled = shuffleArray(questions).map(q => { const type = q.type || "choice"; if (type === "choice" || !q.type) { const rep = q.reponse || q.choices || q.options; const shuffledRep = shuffleArray(rep); return { ...q, type: "choice", reponse: shuffledRep, answer: typeof q.answer === "string" ? shuffledRep.indexOf(q.answer) : q.answer }; } return q; }); setShuffledQuestions(shuffled); }, [questions]); const question = shuffledQuestions[index]; React.useEffect(() => { if (!question || selected !== null || question.type === "association") return; const timer = setInterval(() => { setTimeLeft((prev) => { if (prev <= 8 && prev > 1) beepSound.play().catch(() => {}); if (prev === 1) { clearInterval(timer); handleAnswer(null); return 0; } return prev - 1; }); }, 1000); return () => clearInterval(timer); }, [index, selected, question]); const handleAnswer = (i) => { if (selected !== null) return; const isCorrect = i !== null && i === question.answer; setSelected(i); setShowFeedback(true); if (isCorrect) { correctSound.current?.play(); setScore(s => s + 1); } else { wrongSound.current?.play(); } setTimeout(() => nextQuestion(isCorrect), 5000); }; const handleFillSubmit = () => { const isCorrect = JSON.stringify(fillInputs.map(t => t.trim().toLowerCase())) === JSON.stringify(question.answers.map(t => t.trim().toLowerCase())); setSelected(true); setShowFeedback(true); if (isCorrect) { correctSound.current?.play(); setScore(s => s + 1); } else { wrongSound.current?.play(); } setTimeout(() => nextQuestion(isCorrect), 8000); }; const RenderFeedback = () => { if (!showFeedback) return null; const type = question.type || "choice"; const feedback = question.feedback || ""; switch (type) { case "choice": return

💡 {feedback || "Cette réponse était informative."}

; case "fill": return (

📝 Réponse attendue : {question.answers.join(" / ")}

{feedback && typeof feedback === "string" &&

💬 {feedback}

}
); case "association": return (

✔️ Bonnes correspondances :

); default: return

💬 {typeof feedback === "string" ? feedback : "Aucune explication fournie."}

; } }; const handleAssociationSubmit = () => { const correct = question.pairs.every(p => assocAnswers[p.label] === question.answers[p.label]); setSelected(true); setShowFeedback(true); if (correct) { correctSound.current?.play(); setScore(s => s + 1); } else { wrongSound.current?.play(); } setTimeout(() => nextQuestion(correct), 15000); }; const nextQuestion = (wasCorrect) => { const finalScore = score + (wasCorrect ? 1 : 0); if (index + 1 < shuffledQuestions.length) { setAnimate(false); setTimeout(() => { setIndex(i => i + 1); setSelected(null); setShowFeedback(false); setTimeLeft(30); setFillInputs([]); setAssocAnswers({}); setAnimate(true); }, 50); } else { onFinish(finalScore, shuffledQuestions.length); } }; if (!question) return
Chargement…
; return (
{timeLeft}s

🧠 Score actuel : {score} / {questions.length}

Question {index + 1} / {shuffledQuestions.length}

{question.type === "choice" && (
{question.reponse.map((opt, i) => { let btnClass = "option-btn"; if (selected !== null) { if (i === question.answer) btnClass += " correct"; else if (i === selected) btnClass += " wrong"; } return (
)} {question.type === "fill" && (

{question.answers.map((_, i) => ( { const newInputs = [...fillInputs]; newInputs[i] = e.target.value; setFillInputs(newInputs); }} placeholder={`Réponse ${i + 1}`} /> ))}

)} {question.type === "association" && (
{question.pairs.map((pair) => (
{pair.label}. {pair.text}
))}
)} {RenderFeedback() }

); } const App = () => { const [currentTab, setCurrentTab] = useState("quiz"); const [classe, setClasse] = useState(null); const [matiere, setMatiere] = useState(null); const [showExtraNiveaux, setShowExtraNiveaux] = useState(false); const [niveauActif, setNiveauActif] = useState(null); const [questions, setQuestions] = useState(null); const [loading, setLoading] = useState(false); const [showDashboard, setshowDashboard] = useState(false); const [onComplete, setonComplete] = useState(false); const [userData, setUserData] = useState(() => JSON.parse(localStorage.getItem("userData")) || {}); const [modal, setModal] = useState(null); const [isReplay, setIsReplay] = useState(false); const [userProfile, setUserProfile] = React.useState(null); const [showOnClickA, setShowOnClickA] = useState(false); const [showMonetag, setShowMonetag] = useState(false); const [pendingNiveau, setPendingNiveau] = useState(null); // niveau à lancer après pub const [replayAfterAd, setReplayAfterAd] = useState(false); const [showMiniQuiz, setShowMiniQuiz] = useState(true); React.useEffect(() => { const saved = localStorage.getItem("userProfile"); if (saved) { setUserProfile(JSON.parse(saved)); }}, []); const handleSelectClasse = (c) => { setClasse(c); setMatiere(null); setNiveauActif(null); }; const handleSelectMatiere = (m) => { setMatiere(m); setNiveauActif(null); }; const handleStartNiveau = (n) => { const key = `${classe}_${matiere}_niveau${n}`; const niveauData = userData[key] || { completed: false, attempts: 0 }; if (niveauData.completed) { // niveau déjà fait => proposer rejouer avec pub ou points return setModal({ title: "Rejouer ce niveau ?", content: "Ce niveau est terminé. Pour rejouer, choisissez une option :", actions: [ { label: "🎥 Regarder pub OnClickA", onClick: () => { setPendingNiveau(key); setReplayAfterAd(true); setShowOnClickA(true); setModal(null); } }, { label: "🎥 Regarder pub Monetag", onClick: () => { setPendingNiveau(key); setReplayAfterAd(true); setShowMonetag(true); setModal(null); } }, { label: "💰 Dépenser 20 points", onClick: () => spendPoints(key) }, { label: "Annuler", onClick: () => setModal(null) } ] }); } // Niveau jamais fait => lancement normal (optionnel pub Monetag avant) setPendingNiveau(key); setReplayAfterAd(false); setShowMonetag(true); // ou setShowOnClickA(true); }; const allowReplay = (key) => { setModal(null); startNiveau(key, true); }; const spendPoints = (key) => { const points = parseInt(localStorage.getItem("totalPoints") || "0"); if (points >= 20) { localStorage.setItem("totalPoints", points - 30); allowReplay(key); } else { setModal({ title: "Pas assez de points", content: "Vous avez besoin de 30 points pour rejouer ce niveau.", actions: [{ label: "Fermer", onClick: () => setModal(null) }] });}}; let lastNiveau=null; const startNiveau = (key, replay) => { if(!localStorage.getItem("lastNiveauKey")){ localStorage.setItem("lastNiveauKey", JSON.stringify({})) } lastNiveau=JSON.parse(localStorage.getItem("lastNiveauKey")); const info=(key.split("_")); if(info[1]=="chimie" && info[0]=="NSIV"){ lastNiveau.chimieNSIV=key }else if(info[1]=="biologie" && info[0]=="9eme"){ lastNiveau.bio9eme=key; } localStorage.setItem("lastNiveauKey",JSON.stringify(lastNiveau)); setIsReplay(replay); setLoading(true); fetch(`json/${key}.json`) .then(res => res.json()) .then(data => { setQuestions(data.questions); setNiveauActif(key); }) .catch(() => { setModal({ title: "Erreur", content: "Impossible de charger les questions.", actions: [{ label: "Fermer", onClick: () => setModal(null) }] }); }) .finally(() => setLoading(false)); }; if(! localStorage.getItem("badges")){ localStorage.setItem("badges",JSON.stringify({argent:0, or:0,bronze:0, diamant:0}));} const handleFinish = (score, total) => { const key = niveauActif; // exemple: "NSIV_Chimie_niveau3" const prevData = userData[key] || { attempts: 0, completed: false }; const newData = { ...userData, [key]: { completed: true, attempts: prevData.attempts + 1 } }; setUserData(newData); localStorage.setItem("userData", JSON.stringify(newData)); // 🔍 Extraire classe, matière, niveau depuis la clé const [classe, matiere, niveauStr] = key.split("_"); const niveau = parseInt(niveauStr.replace("niveau", "")); // 🔒 ID utilisateur (localStorage ou global context) const User =localStorage.getItem("quizUser") || null ; if(User){ const user = JSON.parse(localStorage.getItem("quizUser")); if (user?.id) { fetch("api/saveProgressUser.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ userId: user.id, classe, matiere, niveau }) }) .then(res => res.json()) .then(data => { if (!data.success) console.error("Erreur MySQL:", data.message); }) .catch(console.error); } } // 🏅 Attribution de badge if (!isReplay && prevData.attempts === 0) { const cbadges = JSON.parse(localStorage.getItem("badges")); let earnBagdes = null; let badge = null; let gbadge = 0; const pourcentage = (score / total) * 100; if (pourcentage === 100) { badge = "💎 Diamant"; gbadge = parseInt(cbadges.diamant || 0); cbadges.diamant = gbadge + 1; earnBagdes = 1; } else if (pourcentage >= 80 && pourcentage > 70) { badge = "🥇 Or"; gbadge = parseInt(cbadges.or || 0); cbadges.or = gbadge + 1; earnBagdes = 1; } else if (pourcentage >= 60 && pourcentage > 50) { badge = "🥈 Argent"; gbadge = parseInt(cbadges.argent || 0); cbadges.argent = gbadge + 1; earnBagdes = 1; } else if (pourcentage >= 50 && pourcentage < 60) { badge = "🥉 Bronze"; gbadge = parseInt(cbadges.bronze || 0); cbadges.bronze = gbadge + 1; earnBagdes = 1; } if (badge) { localStorage.setItem("badges", JSON.stringify(cbadges)); Updat_bagde(); setModal({ title: "🎉 Félicitations !", content: `Vous avez obtenu ${earnBagdes} badges ${badge}`, actions: [{ label: "Fermer", onClick: () => setModal(null) }] }); } } // ➕ Mise à jour des points const points = parseInt(localStorage.getItem("totalPoints") || "0") + score; localStorage.setItem("totalPoints", points); // Nettoyage final setQuestions(null); setNiveauActif(); setIsReplay(false); }; const niveaux = matiere ? [...Array(niveauxParMatiere[matiere]).keys()].map(i => { const key = `${classe}_${matiere}_niveau${i + 1}`; const done = userData[key]?.completed; const attempts = userData[key]?.attempts || 0; const previousKey = `${classe}_${matiere}_niveau${i}`; const previousDone = i === 0 || userData[previousKey]?.completed; let label = `Niveau ${i + 1}`; let locked = !previousDone; return ( ); }) : null const Header = () => (

HT School Haiti

); const QuestionsNiveau = ({ matiere, niveau, onNextLevel }) => { const [questions, setQuestions] = useState([]); const [currentIndex, setCurrentIndex] = useState(0); const [selectedAnswer, setSelectedAnswer] = useState(null); const [isCorrect, setIsCorrect] = useState(null); const [flashClass, setFlashClass] = useState(""); const goodSound = React.useRef(null); const badSound = React.useRef(null); const shuffleArray = (arr) => arr .map((a) => ({ sort: Math.random(), value: a })) .sort((a, b) => a.sort - b.sort) .map((a) => a.value); useEffect(() => { const fileName = `/capitale/${matiere}_${niveau}.json`; fetch(fileName) .then((res) => res.json()) .then((data) => { const mixed = shuffleArray(data).map(q => ({ ...q, reponse: shuffleArray(q.reponse) })); setQuestions(mixed); }) .catch((err) => console.error(err)); }, [matiere, niveau]); if (questions.length === 0) { return ; } const currentQuestion = questions[currentIndex]; const handleChoice = (choice) => { const correct = choice === currentQuestion.answer; setSelectedAnswer(choice); setIsCorrect(correct); if (correct) { goodSound.current.play(); setFlashClass("flash-green"); } else { badSound.current.play(); setFlashClass("flash-red"); } setTimeout(() => setFlashClass(""), 500); setTimeout(() => { if (currentIndex < questions.length - 1) { setSelectedAnswer(null); setIsCorrect(null); setCurrentIndex((prev) => prev + 1); } }, 2000); }; const isLastQuestion = currentIndex === questions.length - 1 && selectedAnswer; return (
); }; const Accueil = ({ onExploreAll, showMiniQuiz }) => (

🎓 Bienvenue sur notre plateforme de quiz éducatifs !

{showMiniQuiz && { setNiveauActif(2); }} />}
); const IntroductionQuiz = ({ classe, matiere }) => { const textes = { // math: `Bienvenue au quiz de Mathématiques pour la classe de ${classe}. Ce quiz vous aidera à consolider vos acquis en arithmétique, géométrie et algèbre.`, chimie: `Bienvenue au quiz de Chimie – classe de ${classe}. Vous allez tester vos connaissances sur les molécules, réactions chimiques, et plus encore.`, biologie: `Bienvenue au quiz de Biologie pour ${classe}. Préparez-vous à répondre à des questions sur le corps humain, les cellules, et les écosystèmes.`, zoologie: `Bienvenue au quiz de Biologie pour ${classe}. Préparez-vous à répondre à des questions sur les batraciens, les mammifères,les reptiles etc .`, svt: `Bienvenue dans le quiz de svt – ${classe}. préparer vous à répondre à des questions sur la structure cellulaire,la microbiologie, embryologie, la reproduction et la génétique.`, geographie: `Bienvenue au quiz de Géographie pour la classe de ${classe}. Vous allez explorer les continents, les pays, les capitales et la géographie locale.`, }; const texte = textes[matiere] || `Bienvenue dans le quiz de ${matiere} – ${classe}.`; return (

📘 Introduction

{texte}

🧠 Chaque niveau comporte entre 7 et 10 questions. Vous devez obtenir 80% pour débloquer le niveau suivant.

Bonne chance ! 🚀

); }; const MatiereBanner = ({ matiere, onClick }) => (
e.currentTarget.style.transform = "scale(1.05)"} onMouseLeave={e => e.currentTarget.style.transform = "scale(1)"} >

{matiere}

); const ClasseBanner = ({ classe, onClick }) => (

{classe}

); return (

HTSchool

{/* === CONTENU PRINCIPAL === */}
{currentTab === "duel" && } {currentTab === "about" && } {currentTab === "contact" && } {!classe && !matiere && !niveauActif && !showDashboard && currentTab === "quiz" && ( <> { setClasse(null); setMatiere(null); setNiveauActif(null); setShowMiniQuiz(false); setshowDashboard(false); setCurrentTab("quiz"); }} showMiniQuiz={showMiniQuiz} /> )} {currentTab === "quiz" && (showDashboard ? ( ) : ( <> {!classe && ( <>

 Nos quiz sont adaptés à votre niveau d’études, ce qui vous permet de mieux réviser et de vous concentrer sur les notions essentielles. Dans cette partie vous gagner des points convertible en gourdes pour chaque niveau terminé.

🎓 Sélectionne ta classe

{classes.map((c) => ( handleSelectClasse(c)} /> ))}
)} {classe && !matiere && ( <>

📘 Matières

{(matieres[classe] || []).map((m) => ( handleSelectMatiere(m)} /> ))}
)} {classe && matiere && !niveauActif && ( <>

📚 {matiere} – {classe}

{niveaux.slice(0, 3)}
{niveaux.slice(3)}
{niveaux.length > 3 && ( )}
)} {/* === PUBS RÉCOMPENSÉES === */} {showOnClickA && ( { setShowOnClickA(false); if (pendingNiveau) startNiveau(pendingNiveau, replayAfterAd); setPendingNiveau(null); }} onCancel={() => { setShowOnClickA(false); setPendingNiveau(null); setModal({ title: "Pub annulée", content: "Vous devez regarder la vidéo complète pour débloquer ce niveau.", actions: [ { label: "OK", onClick: () => setModal(null) }, ], }); }} /> )} {showMonetag && ( { setShowMonetag(false); if (pendingNiveau) startNiveau(pendingNiveau, replayAfterAd); setPendingNiveau(null); }} /> )} {/* === QUIZ === */} {questions && niveauActif && ( )} ))} {modal && (

{modal.title}

{modal.content}

{modal.actions.map((a, i) => ( ))}
)}
<>

Vous pouvez cliquer ici pour regaerger des publicités afin de nous soutenir. Publicité

); }; function UserForm({ onSubmit }) { const [pseudo, setPseudo] = useState(""); const [phone, setPhone] = useState(""); const [isLogin, setIsLogin] = useState(true); const [isyou, setIsyou] = useState(null); const [password, setPassword] = useState(""); const [showForm, setShowForm] = useState(true); useEffect(() => { const savedUser =localStorage.getItem("quizUser"); if (savedUser) { setShowForm(false); onSubmit?.(JSON.parse(savedUser)); // Utilisateur déjà enregistré } }, []); const handleSubmit = (e) => { e.preventDefault(); if (!pseudo || !phone || !password) { alert("Tous les champs sont requis."); return; } localStorage.setItem("quizUser", JSON.stringify({pseudo, phone})); onSubmit?.({pseudo, phone}); if(!isLogin){ User_if({pseudo, phone, password }); } setShowForm(false); }; const handleSubmitcon = (e) => { e.preventDefault(); if (!phone || !password) { alert("Tous les champs sont requis."); return null; } if(isLogin){ Udat_user({phone,password}).then((data)=>{ if(data!=0 && data !=1 ){ localStorage.setItem("quizUser", JSON.stringify({pseudo})); onSubmit?.({phone}); setShowForm(false); }else{ setIsyou("mot passe ou Téléphone incorrect"); setShowForm(true); } }) } }; if (!showForm) return null; if(!isLogin){ return (

📝 Créer un compte joueur

setPseudo(e.target.value)} placeholder="Pseudo" />
setPhone(e.target.value)} />
setPassword(e.target.value)} />

{isLogin ? "Pas encore de compte ?" : "Déjà inscrit ?"}{" "}

); } else if (isLogin){ return (

📝 Connexion

setPhone(e.target.value)} placeholder="Téléphone" focus="focus" />
setPassword(e.target.value)} placeholder="mot de passe"/>

{isLogin ? "Pas encore de compte ?" : "Déjà inscrit ?"}{" "}

{isyou !=null ? isyou : ""}

); } } const Dashboard = ({ userData, classe, matiere,setModal }) => { const [badges, setBadges] = React.useState(0); const [points, setPoints] = React.useState(0); const [user, setUser] = useState(() => { const saved = localStorage.getItem("quizUser"); return saved ? JSON.parse(saved) : null;}); const [loadingWithdrawal, setLoadingWithdrawal] = useState(false); const b = JSON.parse(localStorage.getItem("badges") || "0"); const pts = parseInt(localStorage.getItem("totalPoints") || "0"); React.useEffect(() => { const c = parseInt(b.argent)+parseInt(b.bronze) +parseInt(b.or)+parseInt(b.diamant); if (typeof c === "number" && !isNaN(c)) { setBadges(c); }else{ setBadges(0) } setPoints(pts) }, []); const gourdesbagdes = parseInt(b.diamant)*5 + parseInt(b.or) + parseInt(b.argent)/4 + parseInt(b.bronze)/8+ pts/32; function getGourdes() { if (typeof gourdesbagdes === "number" && !isNaN(gourdesbagdes)) { Updat_bagde(); return Math.round(gourdesbagdes * 100) / 100; }else{return 0} } async function sendWithdrawalRequest(c, setModal) { try { setLoadingWithdrawal(true); const response = await fetch("api/requestWithdrawal.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(c) }); const data = await response.json(); setLoadingWithdrawal(false); if (data.success) { setModal({ title: "✅ Demande envoyée", content: data.message || "Votre demande de retrait a été soumise avec succès.", actions: [{ label: "OK", onClick: () => setModal(null) }] }); } else { setModal({ title: "❌ Échec", content: data.message || "Une erreur est survenue lors de la soumission.", actions: [{ label: "Fermer", onClick: () => setModal(null) }] }); } } catch (error) { console.error("Erreur lors de la requête :", error); setModal({ title: "❌ Erreur réseau", content: "Impossible de contacter le serveur. Veuillez réessayer plus tard.", actions: [{ label: "Fermer", onClick: () => setModal(null) }] }); } } const handleRequestWithdrawal = () => { const username = localStorage.getItem("username"); if (!username || gourdesbagdes < 2500) { setModal({ title: "❗ Retrait impossible", content: "Vous devez avoir au moins 2500 Gdes pour demander un retrait.", actions: [{ label: "OK", onClick: () => setModal(null) }] }); return; }else{ setLoadingWithdrawal(true); const requestData = { username, amount: Math.floor(gourdesbagdes*0.8), phone: localStorage.getItem("phone") || "non renseigné" }; sendWithdrawalRequest(requestData, setModal); } }; const ProgressionParMatiere = () => { return (

📈 Progression par matière ({classe})

{(matieres[classe] || []).map((matiere) => { const total = niveauxParMatiere[matiere] || 0; if (total === 0) return null; let completed = 0; const lastData = JSON.parse(localStorage.getItem("lastNiveauKey")) || {}; // Ajout de la progression finale uniquement si existante dans lastNiveauKey if (classe === "NSIV" && matiere === "chimie" && lastData.chimieNSIV) { completed = parseInt(lastData.chimieNSIV.slice(-1)) || 0; } else if (classe === "9eme" && matiere === "biologie" && lastData.bio9eme) { completed = parseInt(lastData.bio9eme.slice(-1)) || 0; } else { for (let i = 1; i <= total; i++) { const key = `${classe}_${matiere}_niveau${i}`; if (userData[key]?.completed) completed++; } } const pourcentage = total > 0 ? (completed / total) * 100 : 0; return (
{matiere} : {completed}/{total} niveaux complétés
); })}
); }; if (!user) { return ( { localStorage.setItem("quizUser", JSON.stringify(data)); setUser(data); }} /> ); } return (

🎓 Tableau de bord

Total de points : {points}

Badges spéciaux obtenus : {badges}

Mes badges spéciaux

  • 💎
    {b.diamant}
  • 🥇
    {b.or}
  • 🥈
    {b.argent}
  • 🥉
    {b.bronze}

Portefeuille

{getGourdes()} GOURDES {gourdesbagdes>2500 ? ( ):( )}
); }; function PrivacyPolicy() { const [accepted, setAccepted] = useState(false); useEffect(() => { const hasAccepted = localStorage.getItem("privacyAccepted") === "true"; if (hasAccepted) { setAccepted(true); //onAccept?.(); // Sécurité au cas où onAccept est undefined } }, []); const handleAccept = () => { localStorage.setItem("privacyAccepted", "true"); setAccepted(true); onAccept?.(); }; return (

📜 Politique de Confidentialité

Dernière mise à jour : 04/06/2025

Votre confidentialité est importante pour nous. Cette application collecte :

  • Nom d’utilisateur (pseudo)
  • Numéro de téléphone
  • Progression dans les quiz
  • Récompenses, badges et scores
  • Historique

Les données sont utilisées uniquement pour suivre vos progrès et attribuer vos récompenses. Aucune donnée n’est vendue ou partagée à des tiers.

En jouant à notre jeux, automatiquement, vous acceptez cette politique.

Nous nous reservons le droit de modifier cette politique.

); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(React.createElement(App)); const cookieRoot = ReactDOM.createRoot(document.getElementById("cookie-root")); cookieRoot.render(React.createElement(CookieBanner)); const QUESTIONS = [ { question: "Capitale du Canada ?", reponse: ["Ottawa", "Toronto", "Vancouver"], answer: "Ottawa" }, { question: "2 + 2 ?", reponse: ["3", "4", "5"], answer: "4" }, { question: "Couleur du drapeau France ?", reponse: ["Bleu-Blanc-Rouge", "Vert-Blanc-Rouge"], answer: "Bleu-Blanc-Rouge" } ]; const DuelApp = () => { const firebaseConfig = { apiKey: "AIzaSyD-ndZ-rwgLuRvUa2_AuMGLeaWtyQfv9PY", authDomain: "htschool-9f6bd.firebaseapp.com", projectId: "htschool-9f6bd", storageBucket: "htschool-9f6bd.firebasestorage.app", messagingSenderId: "227755708079", appId: "1:227755708079:web:de581aeb1fff5d17e7ce5a", measurementId: "G-CGQKKMYQ69" }; firebase.initializeApp(firebaseConfig); const db = firebase.database(); const [player, setPlayer] = useState("player1"); const [roomId, setRoomId] = useState(""); const [joined, setJoined] = useState(false); const [questions, setQuestions] = useState(QUESTIONS); const handleCreate = () => { const newId = generateRoomId(); setRoomId(newId); setJoined(true); }; const handleJoin = () => { if (roomId.trim() !== "") { setJoined(true); } else { alert("Veuillez entrer un Room ID !"); } }; if (!joined) { return (

⚔️ Démarrer un duel

{player === "player1" && ( )} {player === "player2" && (
setRoomId(e.target.value.toUpperCase())} />
)}
); } return ; }; const DuelRealtime = ({ player, roomId, questions }) => { const [state, setState] = useState(null); const [selected, setSelected] = useState(null); const [timer, setTimer] = useState(10); const roomRef = db.ref("duels/" + roomId); useEffect(() => { if (player === "player1") { roomRef.once("value", snap => { if (!snap.exists()) { roomRef.set({ questions: questions, currentIndex: 0, player1: { score: 0 }, player2: { score: 0 } }); } }); } const unsub = roomRef.on("value", snap => { setState(snap.val()); }); return () => roomRef.off("value", unsub); }, [roomId]); useEffect(() => { if (!state) return; if (state.currentIndex >= state.questions.length) return; setTimer(10); const interval = setInterval(() => { setTimer(t => { if (t <= 1) { clearInterval(interval); handleNext(); return 0; } return t - 1; }); }, 1000); return () => clearInterval(interval); }, [state && state.currentIndex]); // ✅ Supprimer la room après le quiz useEffect(() => { if (state && state.currentIndex >= state.questions.length) { setTimeout(() => { roomRef.remove() .then(() => console.log("Room supprimée")) .catch(err => console.error("Erreur suppression:", err)); }, 5000); } }, [state]); const handleChoice = (choice) => { if (selected) return; setSelected(choice); const q = state.questions[state.currentIndex]; const isCorrect = choice === q.answer; const btn = document.getElementById(`choice-${q.reponse.indexOf(choice)}`); if (btn) { btn.classList.add(isCorrect ? "fade" : "shake"); } if (isCorrect) { roomRef.child(`${player}/score`).transaction(score => (score || 0) + 1); } setTimeout(() => handleNext(), 1000); }; const handleNext = () => { if (state.currentIndex < state.questions.length - 1) { roomRef.child("currentIndex").transaction(index => index + 1); setSelected(null); } }; if (!state) return

Connexion à la room {roomId}...

; if (state.currentIndex >= state.questions.length) { return (

🏆 Duel terminé !

Room ID : {roomId}

🎉 Joueur 1 : {state.player1.score} pts

🎉 Joueur 2 : {state.player2.score} pts

Gagnant : {state.player1.score === state.player2.score ? "Égalité" : (state.player1.score > state.player2.score ? "Joueur 1" : "Joueur 2")}

La room sera supprimée automatiquement.

); } const q = state.questions[state.currentIndex]; const copyRoomId = () => { navigator.clipboard.writeText(roomId).then(() => alert("Room ID copié !")); }; return (

⚔️ Room {roomId}

Joueur : {player.toUpperCase()}

⏱️ Temps restant : {timer}s

Score : {state[player].score}

Adversaire : {state[player === "player1" ? "player2" : "player1"].score} pts

{q.question}

{q.reponse.map((c, i) => ( ))}
); };