didi-website-erp-crm/website/src/app/(dashboard)/dashboard/profile/page.tsx

202 lines
6.5 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { useSession } from "next-auth/react";
import { updateCustomer } from "@/lib/api";
export default function ProfilePage() {
const { data: session } = useSession();
const userName = session?.user?.name || "";
const userEmail = session?.user?.email || "";
const [customer, setCustomer] = useState<Record<string, unknown> | null>(null);
const [customerName, setCustomerName] = useState("");
const [saving, setSaving] = useState(false);
const [saved, setSaved] = useState(false);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/customer/me")
.then((res) => (res.ok ? res.json() : null))
.then((res) => {
if (res?.data) {
setCustomer(res.data);
setCustomerName(String(res.data.name || ""));
}
})
.catch(() => {})
.finally(() => setLoading(false));
}, []);
async function handleSave(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setSaving(true);
setSaved(false);
const form = new FormData(e.currentTarget);
try {
await updateCustomer(customerName, {
customer_name: form.get("company") as string,
tax_id: form.get("tax_id") as string,
});
setSaved(true);
} catch {
alert("Eroare la salvare");
} finally {
setSaving(false);
}
}
if (loading) {
return (
<div>
<h1 className="text-2xl font-bold text-gray-900">Profil</h1>
<p className="mt-4 text-gray-500">Se incarca...</p>
</div>
);
}
return (
<div>
<h1 className="text-2xl font-bold text-gray-900">Profil</h1>
<p className="mt-1 text-sm text-gray-500">Gestioneaza datele tale personale.</p>
<form onSubmit={handleSave} className="mt-6 max-w-lg space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700">Nume</label>
<input
type="text"
defaultValue={userName}
disabled
className="mt-1 block w-full rounded-lg border border-gray-200 bg-gray-50 px-4 py-2.5 text-sm text-gray-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Email</label>
<input
type="email"
defaultValue={userEmail}
disabled
className="mt-1 block w-full rounded-lg border border-gray-200 bg-gray-50 px-4 py-2.5 text-sm text-gray-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Companie</label>
<input
name="company"
type="text"
defaultValue={String(customer?.customer_name || "")}
className="mt-1 block w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">CUI</label>
<input
name="tax_id"
type="text"
defaultValue={String(customer?.tax_id || "")}
className="mt-1 block w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm"
/>
</div>
<div className="flex items-center gap-3">
<button
type="submit"
disabled={saving}
className="rounded-lg bg-teal-600 px-6 py-2.5 text-sm font-semibold text-white hover:bg-teal-700 disabled:opacity-50"
>
{saving ? "Se salveaza..." : "Salveaza"}
</button>
{saved && <span className="text-sm text-green-600">Salvat!</span>}
</div>
</form>
{/* GDPR section */}
<GdprActions />
</div>
);
}
function GdprActions() {
const [busy, setBusy] = useState<string | null>(null);
const [msg, setMsg] = useState<string | null>(null);
function exportData() {
setBusy("export");
setMsg(null);
// Open download in new tab — server returns Content-Disposition: attachment
window.open("/api/gdpr/export", "_blank");
setTimeout(() => {
setBusy(null);
setMsg("Datele tale au fost descarcate ca fisier JSON.");
}, 1500);
}
async function requestDelete() {
const ok = confirm(
"Esti SIGUR ca vrei sa stergi contul?\n\n" +
"- Analizele si rapoartele tale vor fi anonimizate\n" +
"- Facturile fiscale raman in arhiva 10 ani (cerinta legala RO)\n" +
"- Datele personale vor fi sterse in 30 zile\n" +
"- Actiunea este IREVERSIBILA dupa 30 zile\n\n" +
"Continui?"
);
if (!ok) return;
setBusy("delete");
setMsg(null);
try {
const res = await fetch("/api/gdpr/delete", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ confirm: true, reason: "Solicitare self-service din dashboard" }),
});
const data = await res.json();
if (res.ok) {
setMsg(data.message || "Cererea a fost inregistrata.");
} else {
setMsg(`Eroare: ${data.error}`);
}
} catch (e) {
setMsg(`Eroare: ${e instanceof Error ? e.message : "necunoscuta"}`);
} finally {
setBusy(null);
}
}
return (
<div className="mt-10 border-t pt-8">
<h2 className="text-lg font-semibold text-gray-900">Protectia datelor (GDPR)</h2>
<p className="mt-2 text-sm text-gray-500">
Exercita-ti drepturile conform Regulamentului (UE) 2016/679 (GDPR).
</p>
<div className="mt-4 grid gap-3 sm:grid-cols-2">
<button
disabled={!!busy}
onClick={exportData}
className="rounded-lg border p-4 text-left text-sm hover:bg-gray-50 disabled:opacity-50"
>
<div className="font-semibold text-gray-900">Exporta datele mele</div>
<div className="mt-1 text-xs text-gray-500">
Art. 20 GDPR portabilitate. Descarca toate datele tale (profil, facturi, plati, analize) in format JSON.
</div>
</button>
<button
disabled={!!busy}
onClick={requestDelete}
className="rounded-lg border border-red-200 p-4 text-left text-sm hover:bg-red-50 disabled:opacity-50"
>
<div className="font-semibold text-red-700">Solicita stergerea contului</div>
<div className="mt-1 text-xs text-red-600">
Art. 17 GDPR dreptul la stergere. Cererea va fi procesata in 30 zile.
</div>
</button>
</div>
{msg && (
<p className={`mt-4 text-sm ${msg.startsWith("Eroare") ? "text-red-600" : "text-green-700"}`}>
{msg}
</p>
)}
</div>
);
}