Files
Lageplan/src/app/settings/page.tsx

193 lines
7.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useState, useEffect } from 'react'
import { useRouter } from 'next/navigation'
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { useToast } from '@/components/ui/use-toast'
import {
ArrowLeft, Building2, Trash2, AlertTriangle, Loader2, Shield, Users, FileText,
} from 'lucide-react'
export default function SettingsPage() {
const [tenant, setTenant] = useState<any>(null)
const [loading, setLoading] = useState(true)
const [showDeleteDialog, setShowDeleteDialog] = useState(false)
const [deleteConfirmText, setDeleteConfirmText] = useState('')
const [deleting, setDeleting] = useState(false)
const router = useRouter()
const { toast } = useToast()
useEffect(() => {
fetch('/api/tenant/info')
.then(r => r.json())
.then(data => { setTenant(data.tenant); setLoading(false) })
.catch(() => setLoading(false))
}, [])
const handleDelete = async () => {
if (!tenant || deleteConfirmText !== tenant.name) return
setDeleting(true)
try {
const res = await fetch('/api/tenant/delete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ confirmText: deleteConfirmText }),
})
const data = await res.json()
if (res.ok) {
toast({ title: 'Organisation gelöscht', description: 'Alle Daten wurden entfernt.' })
// Logout and redirect
await fetch('/api/auth/logout', { method: 'POST' })
router.push('/')
} else {
toast({ title: 'Fehler', description: data.error || 'Löschung fehlgeschlagen', variant: 'destructive' })
}
} catch {
toast({ title: 'Fehler', description: 'Verbindungsfehler', variant: 'destructive' })
} finally {
setDeleting(false)
}
}
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center bg-background">
<Loader2 className="w-6 h-6 animate-spin text-muted-foreground" />
</div>
)
}
return (
<div className="min-h-screen bg-background">
<div className="max-w-2xl mx-auto px-4 py-8">
<Link href="/app" className="text-sm text-muted-foreground hover:text-foreground inline-flex items-center gap-1 mb-6">
<ArrowLeft className="w-3.5 h-3.5" />
Zurück zur App
</Link>
<h1 className="text-2xl font-bold text-foreground mb-6 flex items-center gap-2">
<Building2 className="w-6 h-6" />
Organisation verwalten
</h1>
{tenant ? (
<div className="space-y-6">
{/* Tenant Info */}
<div className="bg-card rounded-lg border p-5">
<h2 className="text-lg font-semibold mb-3 flex items-center gap-2">
<Building2 className="w-4 h-4 text-muted-foreground" />
{tenant.name}
</h2>
<div className="grid grid-cols-2 gap-3 text-sm">
<div>
<span className="text-muted-foreground">Slug:</span>
<span className="ml-2 font-mono text-xs">{tenant.slug}</span>
</div>
<div>
<span className="text-muted-foreground">Plan:</span>
<span className="ml-2">{tenant.plan}</span>
</div>
<div>
<span className="text-muted-foreground">Status:</span>
<span className="ml-2">{tenant.subscriptionStatus}</span>
</div>
<div>
<span className="text-muted-foreground">Kontakt:</span>
<span className="ml-2">{tenant.contactEmail || ''}</span>
</div>
</div>
</div>
{/* Privacy Info */}
<div className="bg-card rounded-lg border p-5">
<h2 className="text-lg font-semibold mb-3 flex items-center gap-2">
<Shield className="w-4 h-4 text-muted-foreground" />
Datenschutz
</h2>
<div className="text-sm text-muted-foreground space-y-2">
<p className="flex items-center gap-2">
{tenant.privacyAccepted ? '✅' : '❌'} Datenschutzerklärung akzeptiert
{tenant.privacyAcceptedAt && <span className="text-xs">({new Date(tenant.privacyAcceptedAt).toLocaleDateString('de-CH')})</span>}
</p>
<p className="flex items-center gap-2">
{tenant.adminAccessAccepted ? '✅' : '❌'} Administrator-Zugriff akzeptiert
</p>
<Link href="/datenschutz" target="_blank" className="text-red-500 hover:text-red-400 text-xs underline">
Datenschutzerklärung lesen
</Link>
</div>
</div>
{/* Danger Zone */}
<div className="bg-red-50 dark:bg-red-950/20 rounded-lg border border-red-200 dark:border-red-800/50 p-5">
<h2 className="text-lg font-semibold text-red-700 dark:text-red-400 mb-2 flex items-center gap-2">
<AlertTriangle className="w-5 h-5" />
Gefahrenzone
</h2>
<p className="text-sm text-muted-foreground mb-4">
Löscht Ihre Organisation <strong>{tenant.name}</strong> unwiderruflich, inklusive aller
Benutzer, Projekte, Lagepläne, Journal-Einträge, Rapports und hochgeladenen Dateien.
</p>
{!showDeleteDialog ? (
<Button
variant="destructive"
size="sm"
onClick={() => setShowDeleteDialog(true)}
>
<Trash2 className="w-4 h-4 mr-1.5" />
Organisation löschen
</Button>
) : (
<div className="bg-white dark:bg-gray-900 rounded-lg border border-red-300 dark:border-red-800 p-4 space-y-3">
<p className="text-sm font-medium text-red-700 dark:text-red-400">
Geben Sie den Namen Ihrer Organisation zur Bestätigung ein:
</p>
<p className="text-xs font-mono bg-red-100 dark:bg-red-950 rounded px-2 py-1 text-red-800 dark:text-red-300 inline-block">
{tenant.name}
</p>
<Input
value={deleteConfirmText}
onChange={(e) => setDeleteConfirmText(e.target.value)}
placeholder={tenant.name}
className="max-w-xs"
autoFocus
/>
<div className="flex gap-2">
<Button
variant="outline"
size="sm"
onClick={() => { setShowDeleteDialog(false); setDeleteConfirmText('') }}
disabled={deleting}
>
Abbrechen
</Button>
<Button
variant="destructive"
size="sm"
disabled={deleting || deleteConfirmText !== tenant.name}
onClick={handleDelete}
>
{deleting ? (
<><Loader2 className="w-4 h-4 mr-1.5 animate-spin" /> Wird gelöscht...</>
) : (
<><Trash2 className="w-4 h-4 mr-1.5" /> Endgültig löschen</>
)}
</Button>
</div>
</div>
)}
</div>
</div>
) : (
<div className="bg-card rounded-lg border p-8 text-center">
<p className="text-muted-foreground">Keine Organisation zugeordnet.</p>
</div>
)}
</div>
</div>
)
}