Initial commit - ERP System
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
// /opt/erp-system/app/search/page.tsx
|
||||
'use client';
|
||||
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { useEffect, useState, Suspense } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Search, Ticket, Users } from 'lucide-react';
|
||||
import { getStatusBadge } from '../components/AppShell';
|
||||
|
||||
function SearchResults() {
|
||||
const searchParams = useSearchParams();
|
||||
const q = searchParams.get('q');
|
||||
|
||||
const [results, setResults] = useState({ tickets: [], customers: [] });
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (q) {
|
||||
setLoading(true);
|
||||
fetch(`/api/search?q=${encodeURIComponent(q)}`)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
setResults(data);
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
}, [q]);
|
||||
|
||||
if (!q) return <div className="text-slate-500 font-medium">Bitte gib einen Suchbegriff ein.</div>;
|
||||
|
||||
return (
|
||||
<div className="max-w-5xl mx-auto space-y-6">
|
||||
<h1 className="text-2xl font-bold text-slate-900 flex items-center gap-2">
|
||||
<Search className="w-6 h-6 text-indigo-600" /> Suchergebnisse für "{q}"
|
||||
</h1>
|
||||
|
||||
{loading ? (
|
||||
<div className="text-slate-500 font-medium animate-pulse">Suche läuft...</div>
|
||||
) : (
|
||||
<div className="space-y-8">
|
||||
|
||||
<div className="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
|
||||
<div className="p-4 border-b border-slate-200 bg-slate-50 flex items-center gap-2 font-semibold text-slate-800">
|
||||
<Users className="w-5 h-5 text-slate-500" /> Kunden ({results.customers?.length || 0})
|
||||
</div>
|
||||
<div className="divide-y divide-slate-100">
|
||||
{results.customers?.length > 0 ? results.customers.map((c: any) => (
|
||||
<Link key={c.id} href={`/customers/${c.id}`} className="block p-4 hover:bg-slate-50 transition">
|
||||
<p className="font-semibold text-indigo-600">{c.companyName || `${c.firstName} ${c.lastName}`}</p>
|
||||
<p className="text-sm text-slate-500">{c.email}</p>
|
||||
</Link>
|
||||
)) : (
|
||||
<div className="p-4 text-sm text-slate-500">Keine Kunden gefunden.</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
|
||||
<div className="p-4 border-b border-slate-200 bg-slate-50 flex items-center gap-2 font-semibold text-slate-800">
|
||||
<Ticket className="w-5 h-5 text-slate-500" /> Tickets ({results.tickets?.length || 0})
|
||||
</div>
|
||||
<div className="divide-y divide-slate-100">
|
||||
{results.tickets?.length > 0 ? results.tickets.map((t: any) => (
|
||||
<Link key={t.id} href={`/tickets/${t.id}`} className="block p-4 hover:bg-slate-50 transition flex justify-between items-start">
|
||||
<div>
|
||||
<p className="font-semibold text-indigo-600">#{t.id} - {t.title}</p>
|
||||
<p className="text-sm text-slate-500 mt-1 line-clamp-1">{t.description}</p>
|
||||
<p className="text-xs text-slate-400 mt-1">
|
||||
Kunde: {t.customer.companyName || `${t.customer.firstName} ${t.customer.lastName}`}
|
||||
</p>
|
||||
</div>
|
||||
<div className="ml-4 shrink-0">
|
||||
{getStatusBadge(t.status)}
|
||||
</div>
|
||||
</Link>
|
||||
)) : (
|
||||
<div className="p-4 text-sm text-slate-500">Keine Tickets gefunden.</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function SearchPage() {
|
||||
return (
|
||||
<Suspense fallback={<div className="text-slate-500">Lade Suche...</div>}>
|
||||
<SearchResults />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user