Een dating-app op basis van brieven, niet van gezichten!
Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.
import { useState } from "react";
import { INK, RED, BLUE, PAPER, SKY, MUTE, FONT_MONO, FONT_SERIF } from "../../theme";
import { FAREWELL_MAX, GENERAL_CONTACT } from "../../constants";
import ExportDialog from "./ExportDialog";
import PrivacyDialog from "../privacy/PrivacyDialog";
/*
* Jouw gegevens (AVG), onderaan Mijn profiel: inzage (onExport() → Promise<export>, getoond in
* ExportDialog) en vergetelheid (onDelete(password, farewell) → Promise; daarna is de sessie weg
* en toont App het inlogscherm). Verwijderen vraagt eerst het wachtwoord, inline — geen
* browser-confirm, want er is echt iets in te vullen.
*
* In datzelfde formulier staat de brief aan de beheerder. Dat is de enige plek waar hij thuishoort:
* wie weggaat heeft meestal een reden, en die reden is precies wat je nooit te horen krijgt als het
* vertrek één knop is. Hij is niet verplicht, hij houdt niets tegen, en hij blijft staan zonder wie
* hem schreef — dus antwoorden kan niet, en dat staat er ook bij.
*/
const FAREWELL_START = { text: "", open: false };
export default function DataSection({ email, onExport, onDelete }) {
const [exp, setExp] = useState({ busy: false, data: null, error: null });
const [del, setDel] = useState({ open: false, password: "", busy: false, error: null });
const [farewell, setFarewell] = useState(FAREWELL_START);
const [privacyOpen, setPrivacyOpen] = useState(false);
const exportData = async () => {
setExp({ busy: true, data: null, error: null });
try {
setExp({ busy: false, data: await onExport(), error: null });
} catch (e) {
setExp({ busy: false, data: null, error: e.message });
}
};
const deleteAccount = async (e) => {
e.preventDefault();
if (!del.password) return;
setDel((d) => ({ ...d, busy: true, error: null }));
try {
await onDelete(del.password, farewell.text);
// gelukt: de sessie is gewist, App wisselt naar het inlogscherm — hier valt niets meer te tonen
} catch (err) {
setDel((d) => ({ ...d, busy: false, error: err.message }));
}
};
const closeDelete = () => {
setDel({ open: false, password: "", busy: false, error: null });
setFarewell(FAREWELL_START);
};
const outline = (color) => ({ background: "#fff", color, border: `2px solid ${color}`, padding: "8px 14px", fontSize: 13, fontWeight: 600 });
return (
<div style={{ marginTop: 36, paddingTop: 16, borderTop: `1px solid ${SKY}` }}>
<h3 style={{ margin: "0 0 4px", fontSize: 16 }}>Jouw gegevens</h3>
<p style={{ fontSize: 13, color: MUTE, margin: "0 0 12px", lineHeight: 1.5 }}>
Je kunt altijd opvragen wat we van je bewaren (je profiel, brieven, favorieten, blokkades en sessies) en
je account met alles erin laten wissen — zoals de AVG voorschrijft. Wat we bewaren en waarom staat in de{" "}
<button onClick={() => setPrivacyOpen(true)} style={{ background: "none", border: "none", color: BLUE, fontWeight: 700, fontSize: 13, padding: 0, textDecoration: "underline" }}>
privacyverklaring
</button>.
</p>
{privacyOpen && <PrivacyDialog onClose={() => setPrivacyOpen(false)} />}
<div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
<button onClick={exportData} disabled={exp.busy} style={{ ...outline(INK), opacity: exp.busy ? 0.6 : 1 }}>
{exp.busy ? "Ophalen…" : "⤓ Mijn gegevens opvragen"}
</button>
{!del.open && (
<button onClick={() => setDel({ open: true, password: "", busy: false, error: null })} style={outline(RED)}>
Account verwijderen
</button>
)}
</div>
{exp.error && (
<p role="alert" style={{ fontFamily: FONT_MONO, fontSize: 12, color: RED, margin: "8px 0 0" }}>fout: {exp.error}</p>
)}
{exp.data && <ExportDialog data={exp.data} onClose={() => setExp((s) => ({ ...s, data: null }))} />}
{del.open && (
<form onSubmit={deleteAccount} style={{ marginTop: 14, padding: "12px 14px", border: `2px solid ${RED}`, background: "#fff" }}>
<p style={{ fontSize: 14, fontWeight: 700, margin: "0 0 4px", color: RED }}>Je account definitief verwijderen?</p>
<p style={{ fontSize: 13, color: MUTE, margin: "0 0 10px", lineHeight: 1.5 }}>
Dit wist je account, je profiel en álle brieven — ook wat je aan anderen schreef; bij hen verdwijnt de
correspondentie eveneens. Dit kan niet ongedaan worden gemaakt. Bevestig met je wachtwoord.
</p>
{/*
* De brief aan de beheerder. Ingeklapt, want hij mag het vertrek niet in de weg zitten:
* wie weg wil moet weg kunnen zonder eerst een tekstvak te zien dat om uitleg vraagt.
*/}
{!farewell.open ? (
<button
type="button"
onClick={() => setFarewell({ text: "", open: true })}
style={{ background: "none", border: "none", color: BLUE, fontWeight: 700, fontSize: 13, padding: 0, textDecoration: "underline", marginBottom: 12 }}
>
een brief aan de beheerder achterlaten
</button>
) : (
<div style={{ marginBottom: 14 }}>
<label htmlFor="afscheidsbrief" style={{ display: "block", fontSize: 13, fontWeight: 600, marginBottom: 4 }}>
Brief aan de beheerder <span style={{ fontWeight: 400, color: MUTE }}>(niet verplicht)</span>
</label>
<textarea
id="afscheidsbrief"
value={farewell.text}
onChange={(e) => setFarewell({ open: true, text: e.target.value.slice(0, FAREWELL_MAX) })}
rows={6}
autoFocus
placeholder="Wat je hier gevonden hebt, of wat er mis was. Allebei mag."
style={{
width: "100%", padding: 12, fontSize: 14.5, fontFamily: FONT_SERIF, lineHeight: 1.6,
border: `2px solid ${INK}`, background: PAPER, resize: "vertical",
}}
/>
<p style={{ fontFamily: FONT_MONO, fontSize: 11, color: MUTE, margin: "6px 0 0" }}>
nog {FAREWELL_MAX - farewell.text.length} tekens
</p>
<p style={{ fontSize: 13, color: MUTE, margin: "8px 0 0", lineHeight: 1.5 }}>
Deze brief blijft bewaard als je account weg is — maar zonder jou erbij: geen naam, geen e-mailadres,
geen verwijzing naar je account. Alleen de tekst en de dag. Er komt dus geen antwoord; wil je dat wel,
mail dan {GENERAL_CONTACT}.
</p>
</div>
)}
<label style={{ display: "block", fontSize: 13, fontWeight: 600 }}>
Wachtwoord van {email}
<input
type="password"
value={del.password}
onChange={(e) => setDel((d) => ({ ...d, password: e.target.value }))}
autoComplete="current-password"
autoFocus
style={{ display: "block", width: "100%", marginTop: 4, padding: 10, border: `2px solid ${INK}`, fontSize: 15 }}
/>
</label>
{del.error && (
<p role="alert" style={{ fontFamily: FONT_MONO, fontSize: 12, color: RED, margin: "8px 0 0" }}>fout: {del.error}</p>
)}
<div style={{ display: "flex", gap: 10, alignItems: "center", marginTop: 12 }}>
<button
type="submit"
disabled={!del.password || del.busy}
style={{
background: RED, color: "#fff", border: "none", padding: "10px 16px", fontSize: 14, fontWeight: 700,
opacity: !del.password || del.busy ? 0.5 : 1,
}}
>
{del.busy ? "Verwijderen…" : "Ja, wis mijn account"}
</button>
<button
type="button"
onClick={closeDelete}
disabled={del.busy}
style={{ background: "none", border: "none", color: MUTE, fontSize: 13, fontWeight: 600, textDecoration: "underline" }}
>
annuleer
</button>
</div>
</form>
)}
</div>
);
}