diff --git a/app/components/AuthModal.tsx b/app/components/AuthModal.tsx index c941215..1f9f425 100644 --- a/app/components/AuthModal.tsx +++ b/app/components/AuthModal.tsx @@ -68,6 +68,14 @@ export function AuthModal({ onClose, onSuccess }: { onClose: () => void; onSucce + {mode === "register" && ( +

+ En créant un compte, vous acceptez notre{" "} + + politique de confidentialité + . +

+ )} diff --git a/app/components/BlitzScreen.tsx b/app/components/BlitzScreen.tsx index f018d37..d20c289 100644 --- a/app/components/BlitzScreen.tsx +++ b/app/components/BlitzScreen.tsx @@ -3,6 +3,7 @@ import { useBlitzGame } from "../../lib/useBlitzGame"; import { ArticleView } from "./ArticleView"; import { ShareBar } from "./ShareBar"; +import { useSearchAllowed } from "../../lib/useSearchAllowed"; function fmtLeft(s: number): string { const m = Math.floor(s / 60); @@ -12,6 +13,8 @@ function fmtLeft(s: number): string { export function BlitzScreen({ onBack }: { onBack: () => void }) { const game = useBlitzGame(); + const { allowed: searchAllowed, toggle: toggleSearch } = useSearchAllowed(); + const btnPrimary = "w-full min-h-11 rounded-xl text-sm font-semibold bg-[#7c3aed] text-white hover:bg-[#6d28d9] disabled:opacity-50 cursor-pointer transition-colors"; const btnGhost = "w-full min-h-11 rounded-xl text-sm font-semibold bg-[#242424] border border-[#2e2e2e] text-[#f0f0f0] hover:bg-[#1a1a1a] cursor-pointer transition-colors"; @@ -28,6 +31,15 @@ export function BlitzScreen({ onBack }: { onBack: () => void }) {

Tu as 2 minutes{" "}pour naviguer de l'article de départ jusqu'à l'article cible en cliquant sur les liens Wikipedia. Plus tu es rapide, mieux c'est !

+ diff --git a/app/components/GameScreen.tsx b/app/components/GameScreen.tsx index 68e96d1..e34dfb0 100644 --- a/app/components/GameScreen.tsx +++ b/app/components/GameScreen.tsx @@ -117,7 +117,7 @@ export function GameScreen({ -
+
{elapsed} {clicks} clics {myPlayer?.score ?? 0} pts diff --git a/app/components/LobbyScreen.tsx b/app/components/LobbyScreen.tsx index 28113bf..70b784a 100644 --- a/app/components/LobbyScreen.tsx +++ b/app/components/LobbyScreen.tsx @@ -1,6 +1,7 @@ "use client"; import { useState } from "react"; +import { useSearchAllowed } from "../../lib/useSearchAllowed"; import type { Room } from "../api/rooms/route"; type LobbyScreenProps = { @@ -19,6 +20,7 @@ export function LobbyScreen({ }: LobbyScreenProps) { const isHost = room.players.find((p) => p.id === playerId)?.isHost ?? false; const [copied, setCopied] = useState(false); + const { allowed: searchAllowed, toggle: toggleSearch } = useSearchAllowed(); function copyCode() { navigator.clipboard.writeText(room.code).then(() => { @@ -74,6 +76,16 @@ export function LobbyScreen({
+ + {room.round > 0 &&

Manche {room.round} terminée

} {isHost ? ( diff --git a/app/components/SoloScreen.tsx b/app/components/SoloScreen.tsx index c2ce350..2f7fb55 100644 --- a/app/components/SoloScreen.tsx +++ b/app/components/SoloScreen.tsx @@ -4,6 +4,7 @@ import { useEffect, useRef } from "react"; import { ArticleView } from "./ArticleView"; import { Breadcrumbs } from "./Breadcrumbs"; import { ShareBar } from "./ShareBar"; +import { useSearchAllowed } from "../../lib/useSearchAllowed"; import type { Puzzle } from "../../lib/types"; type SoloPhase = "setup" | "playing" | "won"; @@ -32,8 +33,10 @@ export function SoloScreen({ elapsedDisplay, canGoBack, onStart, onNavigate, onBack, onQuit, onNewGame, onRetry, }: SoloScreenProps) { const breadcrumbEndRef = useRef(null); + const { allowed: searchAllowed, toggle: toggleSearch } = useSearchAllowed(); useEffect(() => { + breadcrumbEndRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "end" }); }, [history]); @@ -49,6 +52,15 @@ export function SoloScreen({

Deux articles aléatoires seront choisis. Atteins l'article cible en cliquant uniquement sur les liens !

+ diff --git a/app/privacy/page.tsx b/app/privacy/page.tsx index ceea493..5b96034 100644 --- a/app/privacy/page.tsx +++ b/app/privacy/page.tsx @@ -1,3 +1,5 @@ +import Link from "next/link"; + export const metadata = { title: "Politique de confidentialité - WikiRush", }; @@ -6,34 +8,71 @@ export default function PrivacyPage() { return (
- + ← Retour - + -

Politique de confidentialité

-

Dernière mise à jour : avril 2025

+

+ Politique de confidentialité +

+

+ Dernière mise à jour : avril 2026 +

-
-

1. Présentation

+

+ 1. Présentation +

- WikiRush est un jeu de navigation Wikipedia jouable en solo et en multijoueur. - Cette politique explique quelles données sont collectées, pourquoi, et comment elles sont protégées. + WikiRush est un jeu de navigation Wikipedia jouable en solo et en + multijoueur. Cette politique explique quelles données sont + collectées, pourquoi, et comment elles sont protégées. +

+

+ Responsable du traitement :{" "} + DAVID Jessy{" "} + -{" "} + + contact@jessy-david.dev +

-

2. Données collectées

+

+ 2. Données collectées +

Lors de la création d'un compte, nous collectons :

    -
  • Pseudo - affiché dans les parties et le classement.
  • -
  • Adresse e-mail - utilisée uniquement pour l'authentification. Elle n'est jamais affichée publiquement.
  • -
  • Mot de passe - stocké sous forme hachée (bcrypt). Nous n'avons jamais accès à votre mot de passe en clair.
  • +
  • + Pseudo - + affiché dans les parties et le classement. +
  • +
  • + + Adresse e-mail + {" "} + - utilisée uniquement pour l'authentification. Elle + n'est jamais affichée publiquement. +
  • +
  • + + Mot de passe + {" "} + - stocké sous forme hachée (bcrypt). Nous n'avons jamais + accès à votre mot de passe en clair. +

Pour chaque partie jouée, nous enregistrons :

    -
  • Mode de jeu (solo / multijoueur)
  • +
  • Mode de jeu (solo / multijoueur / blitz / défi du jour)
  • Articles de départ et cible
  • Chemin parcouru, nombre de clics, temps
  • Résultat (victoire / abandon)
  • @@ -42,53 +81,171 @@ export default function PrivacyPage() {
-

3. Utilisation des données

-

Les données collectées servent exclusivement à :

+

+ 3. Finalités et bases légales +

    -
  • Afficher votre historique de parties dans votre profil.
  • -
  • Alimenter le classement global (pseudo + statistiques uniquement).
  • -
  • Maintenir votre session de connexion.
  • -
-

Aucune donnée n'est vendue, partagée ou utilisée à des fins commerciales ou publicitaires.

-
- -
-

4. Stockage et sécurité

-

- Les données sont stockées dans une base SQLite hébergée localement sur le serveur de l'application. - Les mots de passe sont hachés avec bcrypt avant tout stockage. - Les sessions sont gérées via JWT (JSON Web Token) et ne contiennent pas d'informations sensibles. -

-
- -
-

5. Données de navigation

-

- WikiRush n'utilise pas de cookies tiers, de trackers analytiques (Google Analytics, etc.) ni de réseaux publicitaires. - La session de connexion est stockée dans un cookie HTTP sécurisé et httpOnly, nécessaire au fonctionnement de l'authentification. -

-
- -
-

6. Vos droits

-

Vous pouvez à tout moment :

-
    -
  • Consulter vos données via votre page de profil.
  • - Supprimer votre compte directement depuis votre profil, - rubrique Zone dangereuse. Cette action supprime immédiatement et définitivement - votre compte ainsi que l'intégralité de vos parties enregistrées. + + Gestion du compte + {" "} + - base légale : exécution du contrat (Art. 6.1.b RGPD). +
  • +
  • + + Historique de parties et classement + {" "} + - base légale : exécution du contrat (Art. 6.1.b RGPD). +
  • +
  • + + Session de connexion + {" "} + - base légale : intérêt légitime (Art. 6.1.f RGPD) - nécessaire + au fonctionnement du service. +
  • +
+

+ Aucune donnée n'est vendue, partagée ou utilisée à des fins + commerciales ou publicitaires. +

+
+ +
+

+ 4. Durées de conservation +

+
    +
  • + Les données de compte (pseudo, email) sont conservées + jusqu'à la suppression du compte. +
  • +
  • + Les données de parties sont liées au compte et supprimées avec + lui. +
  • +
  • + Aucune archive n'est conservée après suppression du compte.
-

7. Contact

+

+ 5. Stockage et sécurité +

- Pour toute question relative à vos données personnelles, contactez-nous via la page GitHub du projet. + Les données sont stockées dans une base SQLite hébergée sur le + serveur de l'application. Les mots de passe sont hachés avec + bcrypt avant tout stockage. Les sessions sont gérées via JWT (JSON + Web Token) et ne contiennent pas d'informations sensibles.

+
+

+ 6. Hébergement et transferts +

+

+ WikiRush est hébergé par{" "} + + QuantumCraft Studios + {" "} + (58 Rue de Monceau, 75008 Paris). L'infrastructure de + déploiement peut faire appel à des prestataires établis hors UE. + Dans ce cas, les transferts sont encadrés par des clauses + contractuelles types (SCC) conformes au RGPD. +

+
+ +
+

+ 7. Données de navigation +

+

+ WikiRush n'utilise pas de cookies tiers, de trackers + analytiques (Google Analytics, etc.) ni de réseaux publicitaires. + La session de connexion est stockée dans un cookie HTTP sécurisé + et httpOnly, nécessaire au fonctionnement de + l'authentification. +

+
+ +
+

+ 8. Vos droits +

+

Conformément au RGPD, vous disposez des droits suivants :

+
    +
  • + Accès - + consulter vos données via votre page de profil. +
  • +
  • + + Portabilité + {" "} + - télécharger l'intégralité de vos données au format JSON + depuis votre profil (bouton « Télécharger mes + données »). +
  • +
  • + + Rectification + {" "} + - corriger des données inexactes en nous contactant. +
  • +
  • + + Suppression + {" "} + - supprimer votre compte depuis votre profil, rubrique{" "} + Zone dangereuse. Cette action + supprime immédiatement et définitivement votre compte ainsi que + l'intégralité de vos données. +
  • +
  • + Opposition{" "} + - vous opposer à un traitement en nous contactant. +
  • +
+

+ Pour exercer ces droits :{" "} + + contact@jessy-david.dev + +

+

+ Vous pouvez également introduire une réclamation auprès de la{" "} + + CNIL + + . +

+
+ +
+

+ 9. Contact +

+

+ Pour toute question relative à vos données personnelles :{" "} + + contact@jessy-david.dev + +

+
diff --git a/lib/useSearchAllowed.ts b/lib/useSearchAllowed.ts new file mode 100644 index 0000000..11bccfe --- /dev/null +++ b/lib/useSearchAllowed.ts @@ -0,0 +1,35 @@ +"use client"; + +import { useEffect, useState } from "react"; + +const KEY = "wikirush_search_allowed"; + +export function useSearchAllowed() { + const [allowed, setAllowed] = useState(() => { + if (typeof window === "undefined") return false; + return localStorage.getItem(KEY) === "true"; + }); + + function toggle() { + setAllowed((prev) => { + const next = !prev; + localStorage.setItem(KEY, String(next)); + return next; + }); + } + + useEffect(() => { + function handleKeyDown(e: KeyboardEvent) { + if ((e.ctrlKey || e.metaKey) && e.key === "f") { + if (!allowed) { + e.preventDefault(); + e.stopPropagation(); + } + } + } + window.addEventListener("keydown", handleKeyDown, { capture: true }); + return () => window.removeEventListener("keydown", handleKeyDown, { capture: true }); + }, [allowed]); + + return { allowed, toggle }; +}