Files
Leon SerfatyandClaude Fable 5 5a555c715e Build GDPR compliance system: data export, account deletion, consent
- Data export (Art. 15/20): GET /api/gdpr/export serves a full JSON export
  of the user's data (credentials/tokens excluded, exclusions declared)
- Right to erasure (Art. 17): self-service deletion with 30-day grace
  period (Settings -> Privacy & Data), cancellable; daily /api/cron/gdpr
  drain cancels Stripe billing, purges Spaces files, cascade-deletes the
  account, anonymizes consent rows, and writes audit evidence
- Migration 0011: account_deletion_requests (partial unique index = one
  pending per user) + FK-less consent_log (survives erasure)
- Consent: terms/privacy acceptance logged at signup (email + Google);
  cookie banner with analytics opt-out (umami.disabled), choices logged
  server-side for signed-in users via POST /api/gdpr/consent
- Admin deleteUser upgraded to the same full purge (was leaving Spaces
  files and Stripe subscriptions orphaned)
- /gdpr legal page now points at the self-service tools
- scripts/verify-gdpr.ts: end-to-end verification vs live dev DB (22/22)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 06:03:27 -04:00

75 lines
3.0 KiB
TypeScript

"use client"
import { usePathname } from "next/navigation"
import Link from "next/link"
import { Plus, CreditCard, Wrench, FileText, Receipt, CalendarDays } from "lucide-react"
import { NotificationsBell } from "@/components/dashboard/notifications-bell"
import { CommandTrigger } from "@/components/dashboard/command-palette"
const pageTitles: Record<string, string> = {
"/dashboard": "Dashboard",
"/properties": "Properties",
"/tenants": "Tenants",
"/rent": "Rent Tracker",
"/maintenance": "Maintenance",
"/leases": "Leases",
"/expenses": "Expenses",
"/settings/profile": "Settings",
"/settings/billing": "Billing",
"/settings/privacy": "Privacy & Data",
"/settings/demo": "Demo Data",
"/ai": "AI Assistant",
"/reports": "Reports",
"/rent/generate": "Generate Rent",
"/vendors": "Vendors",
"/inspections": "Inspections",
"/calendar": "Calendar",
}
const pageActions: Record<string, { label: string; href: string; icon?: React.ElementType }> = {
"/dashboard": { label: "Add Property", href: "/properties/new" },
"/properties": { label: "Add Property", href: "/properties/new" },
"/tenants": { label: "Add Tenant", href: "/tenants/new" },
"/rent/generate": { label: "Rent Tracker", href: "/rent", icon: CreditCard },
"/rent": { label: "Record Payment", href: "/rent/new", icon: CreditCard },
"/maintenance": { label: "New Request", href: "/maintenance/new", icon: Wrench },
"/leases": { label: "New Lease", href: "/leases/new", icon: FileText },
"/expenses": { label: "Add Expense", href: "/expenses/new", icon: Receipt },
}
export function Header() {
const pathname = usePathname()
const title = Object.entries(pageTitles).find(([path]) =>
path === "/dashboard" ? pathname === path : pathname.startsWith(path)
)?.[1] ?? "Property Management Network"
const action = Object.entries(pageActions).find(([path]) =>
path === "/dashboard" ? pathname === path : pathname.startsWith(path)
)?.[1]
const ActionIcon = action?.icon ?? Plus
return (
<header className="flex h-16 shrink-0 items-center justify-between border-b border-white/[0.06] bg-[#111118]/90 px-6 backdrop-blur-sm pl-16 md:pl-6">
<div>
<h1 className="text-sm font-semibold text-white leading-tight">{title}</h1>
</div>
<div className="flex items-center gap-2.5">
<CommandTrigger />
<NotificationsBell />
{action && (
<Link
href={action.href}
className="flex items-center gap-1.5 rounded-xl bg-indigo-600 px-3.5 py-2 text-xs font-semibold text-white transition-all hover:bg-indigo-500 hover:shadow-lg hover:shadow-indigo-500/25"
>
<ActionIcon className="h-3.5 w-3.5" />
<span className="hidden sm:inline">{action.label}</span>
</Link>
)}
</div>
</header>
)
}