Files
webshop/shop/app/my-customers/page.tsx
2026-06-24 10:54:00 +02:00

167 lines
7.5 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.
export const dynamic = 'force-dynamic';
import { redirect } from 'next/navigation'
import Link from 'next/link'
import { getEndCustomers } from '@/lib/actions/end-customers'
import type { EndCustomer } from '@/lib/types'
import { ArrowLeft, Building2, Plus, Edit2, AlertTriangle } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Card, CardContent } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge';
import { createClient } from '@/lib/supabase/server';
export default async function MyCustomersPage() {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) redirect('/auth/login')
let customers: EndCustomer[] = []
let fetchError: string | null = null
try {
customers = await getEndCustomers()
} catch (err: any) {
console.error("Error loading end customers:", err)
fetchError = err.message || "Es gab ein Problem beim Laden Ihrer Endkunden."
}
// Anzahl Bestellungen pro Endkunde
const { data: orderCounts, error: orderError } = await supabase.from('orders').select('end_customer_id').not('end_customer_id', 'is', null);
if (orderError) {
console.error("Error loading order counts:", orderError)
}
const countMap: Record<string, number> = {}
;(orderCounts ?? []).forEach(o => {
if (o.end_customer_id) {
countMap[o.end_customer_id] = (countMap[o.end_customer_id] ?? 0) + 1
}
})
return (
<div className="min-h-screen bg-[#020617] text-white px-4 py-12">
<div className="max-w-5xl mx-auto space-y-8">
{/* Header */}
<div className="flex items-center justify-between gap-4 flex-wrap">
<div className="flex items-center gap-4">
<Link href="/">
<Button variant="ghost" size="sm" className="text-slate-400 hover:text-white">
<ArrowLeft className="w-4 h-4 mr-2" /> Startseite
</Button>
</Link>
<div>
<h1 className="text-3xl font-extrabold tracking-tight flex items-center gap-3">
<Building2 className="w-8 h-8 text-primary" />
Meine Kunden
</h1>
<p className="text-slate-400 text-sm mt-1">
Verwalten Sie Ihre Endkunden deren Daten werden für Bestellungen verwendet.
</p>
</div>
</div>
<Link href="/my-customers/new">
<Button className="gap-2">
<Plus className="w-4 h-4" /> Kunde hinzufügen
</Button>
</Link>
</div>
{fetchError && (
<div className="p-4 rounded-xl bg-red-500/10 border border-red-500/20 text-red-200 text-sm">
{fetchError}
</div>
)}
{/* Keine Kunden */}
{customers.length === 0 && (
<Card className="glass-dark border-white/10">
<CardContent className="flex flex-col items-center justify-center py-16 gap-4">
<Building2 className="w-12 h-12 text-slate-600" />
<p className="text-slate-400 text-lg">Noch keine Endkunden angelegt.</p>
<Link href="/my-customers/new">
<Button><Plus className="w-4 h-4 mr-2" /> Ersten Kunden anlegen</Button>
</Link>
</CardContent>
</Card>
)}
{/* Kundenliste */}
{customers.length > 0 && (
<div className="overflow-x-auto">
<table className="w-full">
<thead>
<tr className="border-b border-white/10 text-left">
<th className="pb-3 text-xs font-semibold text-slate-400 uppercase tracking-wider">Unternehmen</th>
<th className="pb-3 text-xs font-semibold text-slate-400 uppercase tracking-wider hidden sm:table-cell">Adresse</th>
<th className="pb-3 text-xs font-semibold text-slate-400 uppercase tracking-wider hidden md:table-cell">Bestellungen</th>
<th className="pb-3 text-xs font-semibold text-slate-400 uppercase tracking-wider">Status</th>
<th className="pb-3 text-xs font-semibold text-slate-400 uppercase tracking-wider text-right">Aktionen</th>
</tr>
</thead>
<tbody className="divide-y divide-white/5">
{customers.map(customer => (
<tr key={customer.id} className="hover:bg-white/3 transition-colors">
<td className="py-4 pr-4">
<p className="font-semibold text-white">{customer.company_name}</p>
{(customer.first_name || customer.last_name) && (
<p className="text-sm text-slate-400">
{[customer.first_name, customer.last_name].filter(Boolean).join(' ')}
</p>
)}
{customer.vat_id && (
<p className="text-xs text-slate-500">{customer.vat_id}</p>
)}
</td>
<td className="py-4 pr-4 hidden sm:table-cell">
<p className="text-sm text-slate-300">
{customer.street ?? ''}
</p>
<p className="text-sm text-slate-400">
{[customer.zip, customer.city].filter(Boolean).join(' ') || ''}
</p>
</td>
<td className="py-4 pr-4 hidden md:table-cell">
<Link href={`/my-orders?customer=${customer.id}`} className="group">
<span className="text-primary font-bold group-hover:underline">
{countMap[customer.id] ?? 0}
</span>
<span className="text-slate-500 text-xs ml-1">Bestellung(en)</span>
</Link>
</td>
<td className="py-4 pr-4">
{customer.is_anonymized ? (
<Badge className="bg-red-500/10 text-red-400 border-red-500/20 gap-1">
<AlertTriangle className="w-3 h-3" /> Anonymisiert
</Badge>
) : (
<Badge className="bg-green-500/10 text-green-400 border-green-500/20">Aktiv</Badge>
)}
</td>
<td className="py-4 text-right">
{!customer.is_anonymized && (
<Link href={`/my-customers/${customer.id}`}>
<Button variant="ghost" size="sm" className="text-slate-400 hover:text-white gap-1">
<Edit2 className="w-3.5 h-3.5" /> Bearbeiten
</Button>
</Link>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
{/* DSGVO-Hinweis */}
<div className="p-4 rounded-xl bg-amber-500/5 border border-amber-500/20 text-xs text-amber-300/80 space-y-1">
<p className="font-semibold flex items-center gap-2"><AlertTriangle className="w-3.5 h-3.5" /> DSGVO-Hinweis</p>
<p>
Die hier gespeicherten Kundendaten unterliegen der DSGVO. Auf Wunsch Ihrer Endkunden können Sie deren Daten
über die Bearbeitungsmaske anonymisieren (Recht auf Vergessenwerden). Bestehende Bestellungen bleiben aus
steuerrechtlichen Gründen unverändert.
</p>
</div>
</div>
</div>
)
}