feat: add search toggle for game setup and improve RGPD compliance
This commit is contained in:
@@ -68,6 +68,14 @@ export function AuthModal({ onClose, onSuccess }: { onClose: () => void; onSucce
|
||||
<button className="w-full min-h-11 px-5 rounded-xl text-sm font-semibold bg-[#7c3aed] text-white hover:bg-[#6d28d9] disabled:opacity-50 cursor-pointer mt-1" type="submit" disabled={loading}>
|
||||
{loading ? "Chargement..." : mode === "login" ? "Se connecter" : "Créer un compte"}
|
||||
</button>
|
||||
{mode === "register" && (
|
||||
<p className="text-xs text-[#555] text-center leading-relaxed">
|
||||
En créant un compte, vous acceptez notre{" "}
|
||||
<a href="/privacy" className="text-[#888] hover:text-[#f0f0f0] underline underline-offset-2 transition-colors">
|
||||
politique de confidentialité
|
||||
</a>.
|
||||
</p>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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 }) {
|
||||
<p className="text-[#888] text-sm sm:text-base leading-relaxed">
|
||||
Tu as <span className="text-[#f0f0f0] font-bold">2 minutes</span>{" "}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 !
|
||||
</p>
|
||||
<button
|
||||
onClick={toggleSearch}
|
||||
className={`w-full min-h-11 rounded-xl text-sm font-semibold border transition-colors cursor-pointer flex items-center justify-between px-4 ${searchAllowed ? "bg-[#7c3aed]/10 border-[#7c3aed] text-[#a78bfa]" : "bg-[#1a1a1a] border-[#2e2e2e] text-[#888]"}`}
|
||||
>
|
||||
<span>🔍 Recherche Ctrl+F</span>
|
||||
<span className={`text-xs font-bold px-2 py-0.5 rounded-full ${searchAllowed ? "bg-[#7c3aed]/30 text-[#a78bfa]" : "bg-[#242424] text-[#555]"}`}>
|
||||
{searchAllowed ? "Autorisée" : "Bloquée"}
|
||||
</span>
|
||||
</button>
|
||||
<button className={btnPrimary} onClick={game.start} disabled={game.loading}>
|
||||
{game.loading ? "Préparation..." : "Lancer le chrono !"}
|
||||
</button>
|
||||
|
||||
@@ -117,7 +117,7 @@ export function GameScreen({
|
||||
</div>
|
||||
<Breadcrumbs history={history} endRef={breadcrumbEndRef} />
|
||||
</div>
|
||||
<div className="flex gap-2 sm:gap-3 shrink-0 text-[10px] sm:text-xs font-bold text-[#888] tabular-nums">
|
||||
<div className="flex items-center gap-2 sm:gap-3 shrink-0 text-[10px] sm:text-xs font-bold text-[#888] tabular-nums">
|
||||
<span>{elapsed}</span>
|
||||
<span>{clicks} clics</span>
|
||||
<span className="hidden sm:inline">{myPlayer?.score ?? 0} pts</span>
|
||||
|
||||
@@ -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({
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={toggleSearch}
|
||||
className={`w-full min-h-11 rounded-xl text-sm font-semibold border transition-colors cursor-pointer flex items-center justify-between px-4 ${searchAllowed ? "bg-[#7c3aed]/10 border-[#7c3aed] text-[#a78bfa]" : "bg-[#1a1a1a] border-[#2e2e2e] text-[#888]"}`}
|
||||
>
|
||||
<span>🔍 Recherche Ctrl+F</span>
|
||||
<span className={`text-xs font-bold px-2 py-0.5 rounded-full ${searchAllowed ? "bg-[#7c3aed]/30 text-[#a78bfa]" : "bg-[#242424] text-[#555]"}`}>
|
||||
{searchAllowed ? "Autorisée" : "Bloquée"}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{room.round > 0 && <p className="text-xs text-[#888] text-center">Manche {room.round} terminée</p>}
|
||||
|
||||
{isHost ? (
|
||||
|
||||
@@ -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<HTMLDivElement>(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({
|
||||
<p className="text-[#888] text-sm sm:text-base leading-relaxed">
|
||||
Deux articles aléatoires seront choisis. Atteins l'article cible en cliquant uniquement sur les liens !
|
||||
</p>
|
||||
<button
|
||||
onClick={toggleSearch}
|
||||
className={`w-full min-h-11 rounded-xl text-sm font-semibold border transition-colors cursor-pointer flex items-center justify-between px-4 ${searchAllowed ? "bg-[#7c3aed]/10 border-[#7c3aed] text-[#a78bfa]" : "bg-[#1a1a1a] border-[#2e2e2e] text-[#888]"}`}
|
||||
>
|
||||
<span>🔍 Recherche Ctrl+F</span>
|
||||
<span className={`text-xs font-bold px-2 py-0.5 rounded-full ${searchAllowed ? "bg-[#7c3aed]/30 text-[#a78bfa]" : "bg-[#242424] text-[#555]"}`}>
|
||||
{searchAllowed ? "Autorisée" : "Bloquée"}
|
||||
</span>
|
||||
</button>
|
||||
<button className={btnPrimary} onClick={onStart} disabled={loading}>
|
||||
{loading ? "Préparation..." : "Lancer une partie"}
|
||||
</button>
|
||||
|
||||
+206
-49
@@ -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 (
|
||||
<div className="min-h-dvh bg-[#0f0f0f] text-[#f0f0f0]">
|
||||
<div className="max-w-2xl mx-auto px-4 py-12 sm:py-16">
|
||||
<a href="/" className="inline-flex items-center gap-2 text-sm text-[#888] hover:text-[#f0f0f0] mb-8 transition-colors">
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center gap-2 text-sm text-[#888] hover:text-[#f0f0f0] mb-8 transition-colors"
|
||||
>
|
||||
← Retour
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<h1 className="text-3xl sm:text-4xl font-black mb-2">Politique de confidentialité</h1>
|
||||
<p className="text-sm text-[#888] mb-10">Dernière mise à jour : avril 2025</p>
|
||||
<h1 className="text-3xl sm:text-4xl font-black mb-2">
|
||||
Politique de confidentialité
|
||||
</h1>
|
||||
<p className="text-sm text-[#888] mb-10">
|
||||
Dernière mise à jour : avril 2026
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col gap-8 text-sm sm:text-base leading-relaxed text-[#ccc]">
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">1. Présentation</h2>
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">
|
||||
1. Présentation
|
||||
</h2>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
Responsable du traitement :{" "}
|
||||
<span className="text-[#f0f0f0] font-semibold">DAVID Jessy</span>{" "}
|
||||
-{" "}
|
||||
<a
|
||||
href="mailto:contact@jessy-david.dev"
|
||||
className="text-[#7c3aed] hover:underline"
|
||||
>
|
||||
contact@jessy-david.dev
|
||||
</a>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">2. Données collectées</h2>
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">
|
||||
2. Données collectées
|
||||
</h2>
|
||||
<p>Lors de la création d'un compte, nous collectons :</p>
|
||||
<ul className="list-disc pl-5 flex flex-col gap-1.5 text-[#ccc]">
|
||||
<li><span className="text-[#f0f0f0] font-semibold">Pseudo</span> - affiché dans les parties et le classement.</li>
|
||||
<li><span className="text-[#f0f0f0] font-semibold">Adresse e-mail</span> - utilisée uniquement pour l'authentification. Elle n'est jamais affichée publiquement.</li>
|
||||
<li><span className="text-[#f0f0f0] font-semibold">Mot de passe</span> - stocké sous forme hachée (bcrypt). Nous n'avons jamais accès à votre mot de passe en clair.</li>
|
||||
<li>
|
||||
<span className="text-[#f0f0f0] font-semibold">Pseudo</span> -
|
||||
affiché dans les parties et le classement.
|
||||
</li>
|
||||
<li>
|
||||
<span className="text-[#f0f0f0] font-semibold">
|
||||
Adresse e-mail
|
||||
</span>{" "}
|
||||
- utilisée uniquement pour l'authentification. Elle
|
||||
n'est jamais affichée publiquement.
|
||||
</li>
|
||||
<li>
|
||||
<span className="text-[#f0f0f0] font-semibold">
|
||||
Mot de passe
|
||||
</span>{" "}
|
||||
- stocké sous forme hachée (bcrypt). Nous n'avons jamais
|
||||
accès à votre mot de passe en clair.
|
||||
</li>
|
||||
</ul>
|
||||
<p>Pour chaque partie jouée, nous enregistrons :</p>
|
||||
<ul className="list-disc pl-5 flex flex-col gap-1.5 text-[#ccc]">
|
||||
<li>Mode de jeu (solo / multijoueur)</li>
|
||||
<li>Mode de jeu (solo / multijoueur / blitz / défi du jour)</li>
|
||||
<li>Articles de départ et cible</li>
|
||||
<li>Chemin parcouru, nombre de clics, temps</li>
|
||||
<li>Résultat (victoire / abandon)</li>
|
||||
@@ -42,53 +81,171 @@ export default function PrivacyPage() {
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">3. Utilisation des données</h2>
|
||||
<p>Les données collectées servent exclusivement à :</p>
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">
|
||||
3. Finalités et bases légales
|
||||
</h2>
|
||||
<ul className="list-disc pl-5 flex flex-col gap-1.5">
|
||||
<li>Afficher votre historique de parties dans votre profil.</li>
|
||||
<li>Alimenter le classement global (pseudo + statistiques uniquement).</li>
|
||||
<li>Maintenir votre session de connexion.</li>
|
||||
</ul>
|
||||
<p>Aucune donnée n'est vendue, partagée ou utilisée à des fins commerciales ou publicitaires.</p>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">4. Stockage et sécurité</h2>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">5. Données de navigation</h2>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">6. Vos droits</h2>
|
||||
<p>Vous pouvez à tout moment :</p>
|
||||
<ul className="list-disc pl-5 flex flex-col gap-1.5">
|
||||
<li><span className="text-[#f0f0f0] font-semibold">Consulter</span> vos données via votre page de profil.</li>
|
||||
<li>
|
||||
<span className="text-[#f0f0f0] font-semibold">Supprimer</span> votre compte directement depuis votre profil,
|
||||
rubrique <span className="italic">Zone dangereuse</span>. Cette action supprime immédiatement et définitivement
|
||||
votre compte ainsi que l'intégralité de vos parties enregistrées.
|
||||
<span className="text-[#f0f0f0] font-semibold">
|
||||
Gestion du compte
|
||||
</span>{" "}
|
||||
- base légale : exécution du contrat (Art. 6.1.b RGPD).
|
||||
</li>
|
||||
<li>
|
||||
<span className="text-[#f0f0f0] font-semibold">
|
||||
Historique de parties et classement
|
||||
</span>{" "}
|
||||
- base légale : exécution du contrat (Art. 6.1.b RGPD).
|
||||
</li>
|
||||
<li>
|
||||
<span className="text-[#f0f0f0] font-semibold">
|
||||
Session de connexion
|
||||
</span>{" "}
|
||||
- base légale : intérêt légitime (Art. 6.1.f RGPD) - nécessaire
|
||||
au fonctionnement du service.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
Aucune donnée n'est vendue, partagée ou utilisée à des fins
|
||||
commerciales ou publicitaires.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">
|
||||
4. Durées de conservation
|
||||
</h2>
|
||||
<ul className="list-disc pl-5 flex flex-col gap-1.5">
|
||||
<li>
|
||||
Les données de compte (pseudo, email) sont conservées
|
||||
jusqu'à la suppression du compte.
|
||||
</li>
|
||||
<li>
|
||||
Les données de parties sont liées au compte et supprimées avec
|
||||
lui.
|
||||
</li>
|
||||
<li>
|
||||
Aucune archive n'est conservée après suppression du compte.
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">7. Contact</h2>
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">
|
||||
5. Stockage et sécurité
|
||||
</h2>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">
|
||||
6. Hébergement et transferts
|
||||
</h2>
|
||||
<p>
|
||||
WikiRush est hébergé par{" "}
|
||||
<span className="text-[#f0f0f0] font-semibold">
|
||||
QuantumCraft Studios
|
||||
</span>{" "}
|
||||
(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.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">
|
||||
7. Données de navigation
|
||||
</h2>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">
|
||||
8. Vos droits
|
||||
</h2>
|
||||
<p>Conformément au RGPD, vous disposez des droits suivants :</p>
|
||||
<ul className="list-disc pl-5 flex flex-col gap-1.5">
|
||||
<li>
|
||||
<span className="text-[#f0f0f0] font-semibold">Accès</span> -
|
||||
consulter vos données via votre page de profil.
|
||||
</li>
|
||||
<li>
|
||||
<span className="text-[#f0f0f0] font-semibold">
|
||||
Portabilité
|
||||
</span>{" "}
|
||||
- télécharger l'intégralité de vos données au format JSON
|
||||
depuis votre profil (bouton « Télécharger mes
|
||||
données »).
|
||||
</li>
|
||||
<li>
|
||||
<span className="text-[#f0f0f0] font-semibold">
|
||||
Rectification
|
||||
</span>{" "}
|
||||
- corriger des données inexactes en nous contactant.
|
||||
</li>
|
||||
<li>
|
||||
<span className="text-[#f0f0f0] font-semibold">
|
||||
Suppression
|
||||
</span>{" "}
|
||||
- supprimer votre compte depuis votre profil, rubrique{" "}
|
||||
<span className="italic">Zone dangereuse</span>. Cette action
|
||||
supprime immédiatement et définitivement votre compte ainsi que
|
||||
l'intégralité de vos données.
|
||||
</li>
|
||||
<li>
|
||||
<span className="text-[#f0f0f0] font-semibold">Opposition</span>{" "}
|
||||
- vous opposer à un traitement en nous contactant.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
Pour exercer ces droits :{" "}
|
||||
<a
|
||||
href="mailto:contact@jessy-david.dev"
|
||||
className="text-[#7c3aed] hover:underline"
|
||||
>
|
||||
contact@jessy-david.dev
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
Vous pouvez également introduire une réclamation auprès de la{" "}
|
||||
<a
|
||||
href="https://www.cnil.fr/fr/plaintes"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-[#7c3aed] hover:underline"
|
||||
>
|
||||
CNIL
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-lg sm:text-xl font-bold text-[#f0f0f0]">
|
||||
9. Contact
|
||||
</h2>
|
||||
<p>
|
||||
Pour toute question relative à vos données personnelles :{" "}
|
||||
<a
|
||||
href="mailto:contact@jessy-david.dev"
|
||||
className="text-[#7c3aed] hover:underline"
|
||||
>
|
||||
contact@jessy-david.dev
|
||||
</a>
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user