clientlist selectie & dashboardpage

This commit is contained in:
colinislit
2025-11-19 23:19:56 +01:00
parent f5a30dbae5
commit 4b71c4a615
3 changed files with 104 additions and 102 deletions

View File

@@ -2,25 +2,99 @@
* Client Dashboard - Level 2 (Client Dossier) * Client Dashboard - Level 2 (Client Dossier)
* *
* Overzicht van client voortgang, recente activiteit en belangrijke metrics. * Overzicht van client voortgang, recente activiteit en belangrijke metrics.
* Dit is de hoofd-dashboard pagina die opent wanneer je een client selecteert.
*/ */
export default function ClientDashboardPage({ params }: { params: Promise<{ id: string }> }) { import { notFound } from 'next/navigation';
return ( import { ChevronLeft } from 'lucide-react';
<div> import Link from 'next/link';
<h1 className="text-2xl font-bold text-slate-900 mb-6"> import { getClient } from '../../actions';
Dashboard import { transformClient } from '@/lib/types/client';
</h1> import { ClientTabs } from '../components/client-tabs';
<div className="bg-slate-100 border-2 border-dashed border-slate-300 rounded-lg p-12 text-center"> interface ClientDashboardPageProps {
<p className="text-slate-600 text-lg mb-2"> params: Promise<{ id: string }>;
Client Dashboard searchParams: Promise<{ tab?: string }>;
</p> }
<p className="text-slate-500 text-sm">
Overzicht, recente activiteit, snelle acties export default async function ClientDashboardPage({
</p> params,
<p className="text-xs text-slate-400 mt-4"> searchParams,
Placeholder - Not designed yet }: ClientDashboardPageProps) {
</p> const { id } = await params;
const { tab } = await searchParams;
// Fetch client data
let client;
try {
client = await getClient(id);
} catch (error) {
notFound();
}
if (!client) {
notFound();
}
const clientWithAge = transformClient(client);
return (
<div className="min-h-full bg-slate-50">
{/* Header */}
<div className="bg-white border-b border-slate-200">
<div className="px-4 sm:px-6 lg:px-8 py-6">
{/* Breadcrumb */}
<Link
href="/epd/clients"
className="inline-flex items-center gap-2 text-sm text-slate-600 hover:text-slate-900 mb-4 transition-colors"
>
<ChevronLeft className="h-4 w-4" />
<span>Terug naar cliënten</span>
</Link>
{/* Client Info */}
<div className="flex items-start justify-between">
<div className="flex items-center gap-4">
{/* Avatar */}
<div className="h-16 w-16 rounded-full bg-gradient-to-br from-teal-500 to-teal-600 flex items-center justify-center shadow-md">
<span className="text-white font-semibold text-xl">
{client.first_name[0]}
{client.last_name[0]}
</span>
</div>
{/* Name & Info */}
<div>
<h1 className="text-2xl font-bold text-slate-900">
{clientWithAge.full_name}
</h1>
<div className="flex items-center gap-4 mt-1 text-sm text-slate-600">
<span>{clientWithAge.age} jaar</span>
<span></span>
<span>
Geboren:{' '}
{new Date(client.birth_date).toLocaleDateString('nl-NL')}
</span>
</div>
</div>
</div>
{/* Actions */}
<div className="flex items-center gap-2">
<Link
href={`/epd/clients/${client.id}/edit`}
className="inline-flex items-center gap-2 px-4 py-2 border border-slate-300 text-slate-700 font-medium rounded-lg hover:bg-slate-50 transition-colors"
>
Bewerken
</Link>
</div>
</div>
</div>
</div>
{/* Tab Content */}
<div className="px-4 sm:px-6 lg:px-8 py-6">
<ClientTabs clientId={client.id} activeTab={tab} />
</div> </div>
</div> </div>
); );

View File

@@ -1,94 +1,18 @@
import { notFound } from 'next/navigation'; import { redirect } from 'next/navigation';
import { ChevronLeft } from 'lucide-react';
import Link from 'next/link';
import { getClient } from '../actions';
import { transformClient } from '@/lib/types/client';
import { ClientTabs } from './components/client-tabs';
interface ClientDetailPageProps { interface ClientDetailPageProps {
params: Promise<{ id: string }>; params: Promise<{ id: string }>;
searchParams: Promise<{ tab?: string }>;
} }
/**
* Redirect route: /epd/clients/[id] -> /epd/clients/[id]/dashboard
*
* Wanneer een gebruiker direct naar /epd/clients/[id] navigeert,
* wordt deze automatisch doorgestuurd naar het dashboard.
*/
export default async function ClientDetailPage({ export default async function ClientDetailPage({
params, params,
searchParams,
}: ClientDetailPageProps) { }: ClientDetailPageProps) {
const { id } = await params; const { id } = await params;
const { tab } = await searchParams; redirect(`/epd/clients/${id}/dashboard`);
// Fetch client data
let client;
try {
client = await getClient(id);
} catch (error) {
notFound();
}
if (!client) {
notFound();
}
const clientWithAge = transformClient(client);
return (
<div className="min-h-full bg-slate-50">
{/* Header */}
<div className="bg-white border-b border-slate-200">
<div className="px-4 sm:px-6 lg:px-8 py-6">
{/* Breadcrumb */}
<Link
href="/epd/clients"
className="inline-flex items-center gap-2 text-sm text-slate-600 hover:text-slate-900 mb-4 transition-colors"
>
<ChevronLeft className="h-4 w-4" />
<span>Terug naar cliënten</span>
</Link>
{/* Client Info */}
<div className="flex items-start justify-between">
<div className="flex items-center gap-4">
{/* Avatar */}
<div className="h-16 w-16 rounded-full bg-gradient-to-br from-teal-500 to-teal-600 flex items-center justify-center shadow-md">
<span className="text-white font-semibold text-xl">
{client.first_name[0]}
{client.last_name[0]}
</span>
</div>
{/* Name & Info */}
<div>
<h1 className="text-2xl font-bold text-slate-900">
{clientWithAge.full_name}
</h1>
<div className="flex items-center gap-4 mt-1 text-sm text-slate-600">
<span>{clientWithAge.age} jaar</span>
<span></span>
<span>
Geboren:{' '}
{new Date(client.birth_date).toLocaleDateString('nl-NL')}
</span>
</div>
</div>
</div>
{/* Actions */}
<div className="flex items-center gap-2">
<Link
href={`/epd/clients/${client.id}/edit`}
className="inline-flex items-center gap-2 px-4 py-2 border border-slate-300 text-slate-700 font-medium rounded-lg hover:bg-slate-50 transition-colors"
>
Bewerken
</Link>
</div>
</div>
</div>
</div>
{/* Tab Content */}
<div className="px-4 sm:px-6 lg:px-8 py-6">
<ClientTabs clientId={client.id} activeTab={tab} />
</div>
</div>
);
} }

View File

@@ -124,7 +124,8 @@ export function ClientList({ initialClients }: ClientListProps) {
{filteredClients.map((client) => ( {filteredClients.map((client) => (
<tr <tr
key={client.id} key={client.id}
className="hover:bg-slate-50 transition-colors" onClick={() => router.push(`/epd/clients/${client.id}`)}
className="hover:bg-slate-50 transition-colors cursor-pointer"
> >
<td className="px-6 py-4 whitespace-nowrap"> <td className="px-6 py-4 whitespace-nowrap">
<div className="flex items-center"> <div className="flex items-center">
@@ -153,7 +154,10 @@ export function ClientList({ initialClients }: ClientListProps) {
{new Date(client.created_at).toLocaleDateString('nl-NL')} {new Date(client.created_at).toLocaleDateString('nl-NL')}
</td> </td>
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> <td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<div className="flex items-center justify-end gap-2"> <div
className="flex items-center justify-end gap-2"
onClick={(e) => e.stopPropagation()}
>
<Link <Link
href={`/epd/clients/${client.id}`} href={`/epd/clients/${client.id}`}
className="text-teal-600 hover:text-teal-900 p-1 rounded hover:bg-teal-50 transition-colors" className="text-teal-600 hover:text-teal-900 p-1 rounded hover:bg-teal-50 transition-colors"