167 lines
6.0 KiB
TypeScript
167 lines
6.0 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import Link from "next/link";
|
|
import { useRouter } from "next/navigation";
|
|
import { createBrowserSupabaseClient } from "@/lib/supabase";
|
|
import type { User } from "@supabase/supabase-js";
|
|
|
|
interface Anfrage {
|
|
id: string;
|
|
created_at: string;
|
|
status: string;
|
|
name: string;
|
|
betreff: string;
|
|
nachricht: string | null;
|
|
email: string;
|
|
}
|
|
|
|
function formatDatum(iso: string) {
|
|
return new Date(iso).toLocaleDateString("de-DE", {
|
|
day: "2-digit",
|
|
month: "2-digit",
|
|
year: "numeric",
|
|
});
|
|
}
|
|
|
|
function StatusBadge({ status }: { status: string }) {
|
|
const styles: Record<string, string> = {
|
|
offen: "bg-amber-500/10 text-amber-400 border border-amber-500/20",
|
|
in_bearbeitung: "bg-blue-500/10 text-blue-400 border border-blue-500/20",
|
|
abgeschlossen: "bg-green-500/10 text-green-400 border border-green-500/20",
|
|
};
|
|
const labels: Record<string, string> = {
|
|
offen: "Offen",
|
|
in_bearbeitung: "In Bearbeitung",
|
|
abgeschlossen: "Abgeschlossen",
|
|
};
|
|
return (
|
|
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${styles[status] ?? styles.offen}`}>
|
|
{labels[status] ?? status}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
export default function KundenDashboardPage() {
|
|
const router = useRouter();
|
|
const [user, setUser] = useState<User | null>(null);
|
|
const [anfragen, setAnfragen] = useState<Anfrage[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
const supabase = createBrowserSupabaseClient();
|
|
|
|
async function init() {
|
|
const {
|
|
data: { session },
|
|
} = await supabase.auth.getSession();
|
|
if (!session) {
|
|
router.push("/kunden/login");
|
|
return;
|
|
}
|
|
setUser(session.user);
|
|
|
|
const res = await fetch("/api/kunden/anfragen", {
|
|
headers: { Authorization: `Bearer ${session.access_token}` },
|
|
});
|
|
if (res.ok) {
|
|
const json = await res.json();
|
|
setAnfragen(json.anfragen ?? []);
|
|
}
|
|
setLoading(false);
|
|
}
|
|
init();
|
|
}, [router]);
|
|
|
|
async function handleLogout() {
|
|
const supabase = createBrowserSupabaseClient();
|
|
await supabase.auth.signOut();
|
|
router.push("/kunden/login");
|
|
}
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="min-h-screen bg-[#111925] flex items-center justify-center">
|
|
<p className="text-slate-500">Wird geladen…</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-[#111925]">
|
|
<div className="max-w-4xl mx-auto px-4 py-10">
|
|
<div className="flex items-start justify-between gap-4 mb-8">
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-white tracking-tight">Mein Bereich</h1>
|
|
<p className="text-slate-500 text-sm mt-1">{user?.email}</p>
|
|
</div>
|
|
<button
|
|
onClick={handleLogout}
|
|
className="inline-flex items-center gap-1.5 text-sm border border-gray-700 rounded-lg px-3 py-1.5 text-slate-400 hover:text-white hover:border-gray-600 transition-colors"
|
|
>
|
|
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
|
|
</svg>
|
|
Abmelden
|
|
</button>
|
|
</div>
|
|
|
|
<hr className="border-gray-800 mb-8" />
|
|
|
|
<div>
|
|
<div className="flex items-center justify-between mb-5">
|
|
<h2 className="font-semibold text-white">Meine IT-Anfragen</h2>
|
|
<Link
|
|
href="/#contact"
|
|
className="text-sm text-orange-400 hover:text-orange-300 font-medium transition-colors"
|
|
>
|
|
+ Neue Anfrage
|
|
</Link>
|
|
</div>
|
|
|
|
{anfragen.length === 0 ? (
|
|
<div className="border border-dashed border-gray-700 py-12 text-center rounded-xl">
|
|
<svg className="w-8 h-8 text-slate-600 mx-auto mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
</svg>
|
|
<p className="text-slate-500 mb-1">Noch keine Anfragen vorhanden</p>
|
|
<p className="text-sm text-slate-600 mb-4">
|
|
Kontaktieren Sie uns über das Kontaktformular auf der Startseite.
|
|
</p>
|
|
<Link
|
|
href="/#contact"
|
|
className="inline-flex items-center justify-center bg-orange-500 hover:bg-orange-600 text-white rounded-xl font-semibold px-5 py-2 text-sm transition-colors"
|
|
>
|
|
Zum Kontaktformular
|
|
</Link>
|
|
</div>
|
|
) : (
|
|
<div className="space-y-4">
|
|
{anfragen.map((anfrage) => (
|
|
<div key={anfrage.id} className="bg-[#18212f] border border-gray-800 rounded-xl overflow-hidden">
|
|
<div className="flex items-center justify-between gap-3 px-5 py-4 border-b border-gray-800">
|
|
<div className="flex items-center gap-3">
|
|
<StatusBadge status={anfrage.status} />
|
|
<span className="text-xs text-slate-500">{formatDatum(anfrage.created_at)}</span>
|
|
</div>
|
|
<span className="text-xs text-slate-600 font-mono hidden sm:block">
|
|
#{anfrage.id.slice(0, 8)}
|
|
</span>
|
|
</div>
|
|
|
|
<div className="px-5 py-4">
|
|
<p className="font-semibold text-white text-sm mb-1">{anfrage.betreff}</p>
|
|
{anfrage.nachricht && (
|
|
<p className="text-sm text-slate-400 line-clamp-2">{anfrage.nachricht}</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|