import { useMemo, useRef } from 'react'; import { Transition } from '@headlessui/react'; import { Head, Form, Link, router, useForm, usePage } from '@inertiajs/react'; import { useTranslation } from 'react-i18next'; import { CalendarClock, CheckCircle2, MailWarning, ReceiptText } from 'lucide-react'; import ProfileController from '@/actions/App/Http/Controllers/Settings/ProfileController'; import PasswordController from '@/actions/App/Http/Controllers/Settings/PasswordController'; import InputError from '@/components/input-error'; import AppLayout from '@/layouts/app-layout'; import { type BreadcrumbItem, type SharedData } from '@/types'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Badge } from '@/components/ui/badge'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { Separator } from '@/components/ui/separator'; import { send as resendVerificationRoute } from '@/routes/verification'; type ProfilePageProps = { userData: { id: number; name: string; email: string; username?: string | null; preferredLocale?: string | null; emailVerifiedAt: string | null; mustVerifyEmail: boolean; }; tenant: { id: number; name: string; subscriptionStatus: string | null; subscriptionExpiresAt: string | null; activePackage: { name: string; price: number | null; expiresAt: string | null; remainingEvents: number | null; } | null; } | null; purchases: Array<{ id: number; packageName: string; price: number | null; purchasedAt: string | null; type: string | null; provider: string | null; }>; dataExport: { exports: Array<{ id: number; status: string; size: number | null; created_at: string | null; expires_at: string | null; download_url: string | null; error_message: string | null; }>; hasPending: boolean; nextRequestAt?: string | null; }; }; const breadcrumbs: BreadcrumbItem[] = [ { title: 'Profil', href: '/profile', }, ]; export default function ProfileIndex() { const { userData, tenant, purchases, supportedLocales, locale, dataExport } = usePage().props; const { t } = useTranslation('profile'); const dateFormatter = useMemo(() => new Intl.DateTimeFormat(locale ?? 'de-DE', { day: '2-digit', month: 'long', year: 'numeric', }), [locale]); const currencyFormatter = useMemo(() => new Intl.NumberFormat(locale ?? 'de-DE', { style: 'currency', currency: 'EUR', maximumFractionDigits: 2, }), [locale]); const byteFormatter = useMemo(() => new Intl.NumberFormat(locale ?? 'de-DE', { maximumFractionDigits: 1, }), [locale]); const dataExportInfo = dataExport ?? { exports: [], hasPending: false, nextRequestAt: null }; const nextRequestDeadline = dataExportInfo.nextRequestAt ? new Date(dataExportInfo.nextRequestAt) : null; const canRequestExport = !dataExportInfo.hasPending && (!nextRequestDeadline || nextRequestDeadline <= new Date()); const handleExportRequest = () => { router.post('/profile/data-exports'); }; const deleteForm = useForm({ confirmation: '' }); const handleDeleteSubmit = (event: React.FormEvent) => { event.preventDefault(); deleteForm.delete('/profile/account'); }; const formatExportStatus = (status: string) => t(`export.status.${status}`, status); const formatBytes = (input: number | null) => { if (!input) { return '—'; } const units = ['B', 'KB', 'MB', 'GB']; let value = input; let unitIndex = 0; while (value >= 1024 && unitIndex < units.length - 1) { value /= 1024; unitIndex += 1; } return `${byteFormatter.format(value)} ${units[unitIndex]}`; }; const registrationDate = useMemo(() => { if (!userData.emailVerifiedAt) { return null; } try { return dateFormatter.format(new Date(userData.emailVerifiedAt)); } catch { return null; } }, [userData.emailVerifiedAt, dateFormatter]); const formatDate = (value: string | null) => (value ? dateFormatter.format(new Date(value)) : '—'); const formatPrice = (price: number | null) => (price === null ? '—' : currencyFormatter.format(price)); const localeOptions = (supportedLocales ?? ['de', 'en']).map((value) => ({ label: value.toUpperCase(), value, })); return (
Hallo, {userData.name || userData.email}

Hier verwaltest du deine Zugangsdaten, sprichst mit uns in deiner Lieblingssprache und behältst alle Buchungen im Blick.

{userData.emailVerifiedAt ? : } {userData.emailVerifiedAt ? 'E-Mail bestätigt' : 'Bestätigung ausstehend'} {registrationDate && (

Aktiv seit {registrationDate}

)}
{!userData.emailVerifiedAt && userData.mustVerifyEmail && (
E-Mail-Bestätigung ausstehend Bestätige deine E-Mail-Adresse, damit wir dich über Uploads, Rechnungen und Event-Updates informieren können.
Bestätigungslink erneut senden
)}
Abonnements & Pakete

Hier findest du die wichtigsten Daten zu deinem aktuellen Paket und deinen letzten Buchungen.

{tenant?.activePackage ? ( Läuft bis {formatDate(tenant.activePackage.expiresAt)} ) : ( Kein aktives Paket )}
{tenant?.activePackage ? (

{tenant.activePackage.name}

{tenant.activePackage.remainingEvents ?? 0} Events inklusive

Status {tenant.subscriptionStatus ?? 'aktiv'}
Verlängerung {formatDate(tenant.subscriptionExpiresAt)}
Preis {formatPrice(tenant.activePackage.price)}
) : ( Du hast aktuell kein aktives Paket. Wähle ein Paket, um ohne Unterbrechung neue Events zu planen. )}
Letzte Buchungen
{purchases.length === 0 ? (
Noch keine Buchungen vorhanden. Schaue im Dashboard vorbei, um passende Pakete zu finden.
) : ( Paket Typ Anbieter Datum Preis {purchases.map((purchase) => ( {purchase.packageName} {purchase.type ?? '—'} {purchase.provider ?? 'Checkout'} {formatDate(purchase.purchasedAt)} {formatPrice(purchase.price)} ))}
)}
{t('export.title')}

{t('export.description')}

{dataExportInfo.exports.length === 0 ? (

{t('export.empty')}

) : ( {t('export.table.status')} {t('export.table.created')} {t('export.table.expires')} {t('export.table.size')} {t('export.table.action')} {dataExportInfo.exports.map((item) => ( {formatExportStatus(item.status)} {formatDate(item.created_at)} {formatDate(item.expires_at)} {formatBytes(item.size)} {item.download_url && item.status === 'ready' ? ( {t('export.download')} ) : item.status === 'failed' && item.error_message ? ( {t('export.failed_reason', { reason: item.error_message })} ) : ( )} ))}
)} {dataExportInfo.hasPending && ( {t('export.pending_alert_title')} {t('export.pending_alert_body')} )} {!canRequestExport && nextRequestDeadline && (

{t('export.cooldown', { date: nextRequestDeadline.toLocaleDateString(locale ?? 'de-DE'), })}

)}
{t('delete.title')}

{t('delete.description')}

{t('delete.warning_title')} {t('delete.warning_body')}
deleteForm.setData('confirmation', event.target.value.toUpperCase())} placeholder={t('delete.confirmation_placeholder')} />

{t('delete.confirmation_hint')}

); } function AccountForm({ userData, localeOptions }: { userData: ProfilePageProps['userData']; localeOptions: Array<{ label: string; value: string }> }) { return ( <> Profilinformationen

Aktualisiere deine Kontaktdaten und die Standardsprache für E-Mails und Oberfläche.

{({ processing, recentlySuccessful, errors }) => ( <>

Gespeichert

)}
); } function PasswordForm() { const passwordInputRef = useRef(null); const currentPasswordInputRef = useRef(null); return ( <> Sicherheit & Passwort

Vergebe ein starkes Passwort, um dein Konto bestmöglich zu schützen.

{ if (errors.password) { passwordInputRef.current?.focus(); } if (errors.current_password) { currentPasswordInputRef.current?.focus(); } }} className="space-y-6" > {({ errors, processing, recentlySuccessful }) => ( <>

Aktualisiert

)}
); }