clientlist selectie & dashboardpage
This commit is contained in:
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user