CoompanionApp/front/privacy.tsx

169 lines
5.2 KiB
TypeScript

import React, { useEffect, useMemo, useState } from "react";
import { createRoot } from "react-dom/client";
import "./privacy.css";
type Locale = "en" | "fr";
type CopyBlock = {
title: string;
tagline: string;
backLabel: string;
effective: string;
summaryTitle: string;
summaryText: string;
sections: { title: string; items: string[] }[];
footer: string;
};
const copy: Record<Locale, CopyBlock> = {
en: {
title: "Privacy Policy",
tagline: "A tiny policy for a tabletop bank.",
backLabel: "Back to NegoCity",
effective: "Effective February 3, 2026",
summaryTitle: "Quick summary",
summaryText:
"We do not sell personal data. We do not run ads or analytics. We only use the game info needed to run a session.",
sections: [
{
title: "What we do not do",
items: [
"We do not sell, trade, or rent personal data.",
"We do not sell your soul (or anyone else's).",
"We do not run ads or third-party analytics.",
"We do not create user accounts.",
],
},
{
title: "What we do use to run the game",
items: [
"Session code, player names, balances, transactions, and chat messages you enter.",
"Optional device notification token, only if you enable push notifications.",
"Electricity.",
],
},
{
title: "Where data lives",
items: [
"Game data lives in memory while the session is active and disappears when it ends.",
"Some data can be stored locally on your device (such as the last session and autosave snapshots).",
"In your head, hopefully.",
],
},
],
footer: "This policy applies to the Negopoly Companion app and companion web experience.",
},
fr: {
title: "Politique de confidentialite",
tagline: "Une politique simple pour une banque de jeu de societe.",
backLabel: "Retour a NegoCity",
effective: "En vigueur le 3 fevrier 2026",
summaryTitle: "Resume rapide",
summaryText:
"Nous ne vendons pas de donnees personnelles. Nous n'utilisons ni publicites ni analytics. Nous utilisons uniquement les infos de jeu necessaires pour la session.",
sections: [
{
title: "Ce que nous ne faisons pas",
items: [
"Nous ne vendons, n'echangeons, ni ne louons vos donnees personnelles.",
"Nous ne vendons pas votre ame (ni celle de qui que ce soit).",
"Nous n'affichons pas de publicites et n'utilisons pas d'analytics tiers.",
"Nous ne creons pas de comptes utilisateurs.",
],
},
{
title: "Ce que nous utilisons pour faire tourner la partie",
items: [
"Code de session, noms des joueurs, soldes, transactions et messages de chat que vous saisissez.",
"Jeton de notification, uniquement si vous activez les notifications push.",
"De l'electricite.",
],
},
{
title: "Ou les donnees sont stockees",
items: [
"Les donnees de jeu restent en memoire pendant la session et disparaissent a la fin.",
"Certaines donnees peuvent etre stockees localement sur votre appareil (par exemple la derniere session et les sauvegardes automatiques).",
"Dans votre tete, esperons-le.",
],
},
],
footer: "Cette politique s'applique a l'application Negopoly Companion et a l'experience web associee.",
},
};
function getDefaultLocale(): Locale {
if (typeof navigator === "undefined") return "en";
return navigator.language?.toLowerCase().startsWith("fr") ? "fr" : "en";
}
function Privacy() {
const [locale, setLocale] = useState<Locale>(getDefaultLocale());
const content = useMemo(() => copy[locale], [locale]);
useEffect(() => {
document.documentElement.lang = locale;
}, [locale]);
return (
<div className="privacy">
<header className="hero reveal" style={{ "--delay": "0.05s" } as React.CSSProperties}>
<div className="hero__top">
<a className="back-link" href="/">
{content.backLabel}
</a>
<div className="lang-toggle" role="tablist" aria-label="Language">
<button
type="button"
className={locale === "en" ? "active" : ""}
onClick={() => setLocale("en")}
aria-pressed={locale === "en"}
>
English
</button>
<button
type="button"
className={locale === "fr" ? "active" : ""}
onClick={() => setLocale("fr")}
aria-pressed={locale === "fr"}
>
Francais
</button>
</div>
</div>
<h1>{content.title}</h1>
<p>{content.tagline}</p>
<div className="hero__meta">{content.effective}</div>
</header>
<section className="summary reveal" style={{ "--delay": "0.12s" } as React.CSSProperties}>
<div className="summary__label">{content.summaryTitle}</div>
<div className="summary__text">{content.summaryText}</div>
</section>
<section className="policy">
{content.sections.map((section, index) => (
<article
key={section.title}
className="policy__card reveal"
style={{ "--delay": `${0.18 + index * 0.08}s` } as React.CSSProperties}
>
<h2>{section.title}</h2>
<ul>
{section.items.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</article>
))}
</section>
<footer className="footer reveal" style={{ "--delay": "0.42s" } as React.CSSProperties}>
{content.footer}
</footer>
</div>
);
}
const root = createRoot(document.getElementById("root")!);
root.render(<Privacy />);