Added 404, 500 & Dashboard Page
This commit is contained in:
@@ -12,10 +12,14 @@ export default async function DashboardPage() {
|
|||||||
return (
|
return (
|
||||||
<DashboardLayout user={user}>
|
<DashboardLayout user={user}>
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
<h1 className="text-3xl font-bold text-gray-900 dark:text-white mb-6">
|
<h1 className="text-3xl font-semibold text-cblack mb-1">
|
||||||
Tableau de bord
|
Content de vous revoir <span className="text-dyellow">{user.name || user.email}</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
<p className="text-sm text-cgray mb-6">
|
||||||
|
Bienvenue sur votre tableau de bord.
|
||||||
|
</p>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
|
||||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
||||||
|
|||||||
75
app/error.tsx
Normal file
75
app/error.tsx
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import Image from 'next/image';
|
||||||
|
|
||||||
|
interface ErrorProps {
|
||||||
|
error: Error & { digest?: string };
|
||||||
|
reset: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Error({ error, reset }: ErrorProps) {
|
||||||
|
useEffect(() => {
|
||||||
|
// Log l'erreur dans la console/terminal
|
||||||
|
console.error('Erreur serveur:', error);
|
||||||
|
}, [error]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen flex items-center justify-center bg-cwhite">
|
||||||
|
<div className="text-center px-4">
|
||||||
|
{/* Logo */}
|
||||||
|
<div className="flex justify-center mb-8">
|
||||||
|
<Image
|
||||||
|
src="/logo.svg"
|
||||||
|
alt="MAD Logo"
|
||||||
|
width={120}
|
||||||
|
height={120}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 500 Content */}
|
||||||
|
<div className="max-w-md mx-auto">
|
||||||
|
<h1 className="text-9xl font-bold text-lorange mb-4">500</h1>
|
||||||
|
<h2 className="text-3xl font-semibold text-gray-900 mb-4">
|
||||||
|
Erreur serveur
|
||||||
|
</h2>
|
||||||
|
<p className="text-gray-600 mb-2">
|
||||||
|
Une erreur inattendue s'est produite sur le serveur.
|
||||||
|
</p>
|
||||||
|
{error.message && (
|
||||||
|
<p className="text-sm text-gray-500 mb-8 font-mono bg-gray-100 p-3 rounded-lg">
|
||||||
|
{error.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
{!error.message && (
|
||||||
|
<p className="text-gray-600 mb-8">
|
||||||
|
Veuillez réessayer dans quelques instants.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Action Buttons */}
|
||||||
|
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||||
|
<button
|
||||||
|
onClick={reset}
|
||||||
|
className="inline-flex items-center justify-center px-6 py-3 border border-transparent rounded-lg text-sm font-medium text-white bg-lorange hover:bg-dorange focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-lorange transition-colors"
|
||||||
|
>
|
||||||
|
Réessayer
|
||||||
|
</button>
|
||||||
|
<Link
|
||||||
|
href="/dashboard"
|
||||||
|
className="inline-flex items-center justify-center px-6 py-3 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-lorange transition-colors"
|
||||||
|
>
|
||||||
|
Retour au tableau de bord
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<div className="mt-12 text-center text-xs text-gray-500">
|
||||||
|
© 2025 MAD - <a href="https://legouix.dev" target="_blank" className="text-lblue hover:text-dblue">Propulsé par LGX</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
52
app/not-found.tsx
Normal file
52
app/not-found.tsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import Link from 'next/link';
|
||||||
|
import Image from 'next/image';
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen flex items-center justify-center bg-cwhite">
|
||||||
|
<div className="text-center px-4">
|
||||||
|
{/* Logo */}
|
||||||
|
<div className="flex justify-center mb-8">
|
||||||
|
<Image
|
||||||
|
src="/logo.svg"
|
||||||
|
alt="MAD Logo"
|
||||||
|
width={120}
|
||||||
|
height={120}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 404 Content */}
|
||||||
|
<div className="max-w-md mx-auto">
|
||||||
|
<h1 className="text-9xl font-bold text-lblue mb-4">404</h1>
|
||||||
|
<h2 className="text-3xl font-semibold text-gray-900 mb-4">
|
||||||
|
Page non trouvée
|
||||||
|
</h2>
|
||||||
|
<p className="text-gray-600 mb-8">
|
||||||
|
Désolé, la page que vous recherchez n'existe pas ou a été déplacée.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Action Buttons */}
|
||||||
|
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||||
|
<Link
|
||||||
|
href="/dashboard"
|
||||||
|
className="inline-flex items-center justify-center px-6 py-3 border border-transparent rounded-lg text-sm font-medium text-white bg-lblue hover:bg-dblue focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-lblue transition-colors"
|
||||||
|
>
|
||||||
|
Retour au tableau de bord
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href="/login"
|
||||||
|
className="inline-flex items-center justify-center px-6 py-3 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-lblue transition-colors"
|
||||||
|
>
|
||||||
|
Page de connexion
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<div className="mt-12 text-center text-xs text-gray-500">
|
||||||
|
© 2025 MAD - <a href="https://legouix.dev" target="_blank" className="text-lblue hover:text-dblue">Propulsé par LGX</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter, usePathname } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -14,10 +16,84 @@ interface DashboardLayoutProps {
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface NavItem {
|
||||||
|
label: string;
|
||||||
|
href: string;
|
||||||
|
icon: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
export default function DashboardLayout({ user, children }: DashboardLayoutProps) {
|
export default function DashboardLayout({ user, children }: DashboardLayoutProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const pathname = usePathname();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const navItems: NavItem[] = [
|
||||||
|
{
|
||||||
|
label: 'Tableau de Board',
|
||||||
|
href: '/dashboard',
|
||||||
|
icon: (
|
||||||
|
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 20 20">
|
||||||
|
<path d="M2 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1H3a1 1 0 01-1-1V4zM8 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1H9a1 1 0 01-1-1V4zM15 3a1 1 0 00-1 1v12a1 1 0 001 1h2a1 1 0 001-1V4a1 1 0 00-1-1h-2z" />
|
||||||
|
</svg>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Calendrier',
|
||||||
|
href: '/dashboard/calendrier',
|
||||||
|
icon: (
|
||||||
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||||
|
</svg>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Chauffeurs',
|
||||||
|
href: '/dashboard/chauffeurs',
|
||||||
|
icon: (
|
||||||
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 17a2 2 0 11-4 0 2 2 0 014 0zM19 17a2 2 0 11-4 0 2 2 0 014 0z" />
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16V6a1 1 0 00-1-1H4a1 1 0 00-1 1v10a1 1 0 001 1h1m8-1a1 1 0 01-1 1H9m4-1V8a1 1 0 011-1h2.586a1 1 0 01.707.293l3.414 3.414a1 1 0 01.293.707V16a1 1 0 01-1 1h-1m-6-1a1 1 0 001 1h1M5 17a2 2 0 104 0m-4 0a2 2 0 114 0m6 0a2 2 0 104 0m-4 0a2 2 0 114 0" />
|
||||||
|
</svg>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Adhérents',
|
||||||
|
href: '/dashboard/adherents',
|
||||||
|
icon: (
|
||||||
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||||
|
</svg>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Univers Pro',
|
||||||
|
href: '/dashboard/univers-pro',
|
||||||
|
icon: (
|
||||||
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 13.255A23.931 23.931 0 0112 15c-3.183 0-6.22-.62-9-1.745M16 6V4a2 2 0 00-2-2h-4a2 2 0 00-2 2v2m4 6h.01M5 20h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||||
|
</svg>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Messagerie',
|
||||||
|
href: '/dashboard/messagerie',
|
||||||
|
icon: (
|
||||||
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
|
||||||
|
</svg>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Factures',
|
||||||
|
href: '/dashboard/factures',
|
||||||
|
icon: (
|
||||||
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} 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>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
@@ -32,34 +108,90 @@ export default function DashboardLayout({ user, children }: DashboardLayoutProps
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
|
<div className="min-h-screen bg-cwhite flex">
|
||||||
<nav className="bg-white dark:bg-gray-800 shadow">
|
{/* Sidebar */}
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<aside className="w-64 bg-white flex flex-col h-screen sticky top-0 border-r border-gray-200">
|
||||||
<div className="flex justify-between h-16">
|
{/* Logo Section */}
|
||||||
<div className="flex items-center">
|
<div className="py-5 m-auto">
|
||||||
<h1 className="text-xl font-bold text-gray-900 dark:text-white">
|
<div className="flex items-center gap-3">
|
||||||
Platform SaaS
|
<Image
|
||||||
</h1>
|
src="/logo.svg"
|
||||||
|
alt="MAD Logo"
|
||||||
|
width={32}
|
||||||
|
height={32}
|
||||||
|
/>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="font-semibold text-gray-900">Association MAD</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-4">
|
</div>
|
||||||
<span className="text-sm text-gray-700 dark:text-gray-300">
|
</div>
|
||||||
{user.name || user.email}
|
|
||||||
</span>
|
{/* Navigation */}
|
||||||
<button
|
<nav className="flex-1 p-4 border-t border-gray-200">
|
||||||
onClick={handleLogout}
|
<ul className="space-y-1">
|
||||||
disabled={loading}
|
{navItems.map((item) => {
|
||||||
className="px-4 py-2 text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 rounded-md disabled:opacity-50"
|
const isActive = pathname === item.href;
|
||||||
|
return (
|
||||||
|
<li key={item.href}>
|
||||||
|
<Link
|
||||||
|
href={item.href}
|
||||||
|
className={`flex items-center gap-3 px-4 py-3 rounded-lg transition-colors ${
|
||||||
|
isActive
|
||||||
|
? 'bg-lblue text-white'
|
||||||
|
: 'text-gray-700 hover:bg-lblue/10'
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{loading ? 'Déconnexion...' : 'Déconnexion'}
|
<span className={isActive ? 'text-white' : 'text-lblue'}>
|
||||||
|
{item.icon}
|
||||||
|
</span>
|
||||||
|
<span className={`text-sm font-medium ${isActive ? '' : ''}`}>
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<div className="p-6 border-t border-gray-200">
|
||||||
|
<p className="text-xs text-gray-500 text-center">
|
||||||
|
© 2025 MAD - <a href="https://legouix.dev" target="_blank" className="text-lblue hover:text-dblue">Propulsé par LGX</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
{/* Main Content Area */}
|
||||||
|
<div className="flex-1 flex flex-col">
|
||||||
|
{/* Top Navbar */}
|
||||||
|
<header className="bg-white border-b border-gray-200 px-6 py-4">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<h1 className="text-xl font-semibold text-gray-900"></h1>
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
{/* Notification Icon */}
|
||||||
|
<button className="relative w-10 h-10 rounded-full bg-[#6B46C1] flex items-center justify-center hover:bg-[#5B21B6] transition-colors">
|
||||||
|
<svg className="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||||
|
</svg>
|
||||||
|
<span className="absolute -top-0.5 -right-0.5 w-3 h-3 bg-red-500 rounded-full border-2 border-white"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Profile Avatar */}
|
||||||
|
<button className="w-10 h-10 rounded-full bg-[#6B46C1] flex items-center justify-center hover:bg-[#5B21B6] transition-colors">
|
||||||
|
<svg className="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 20 20">
|
||||||
|
<path fillRule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clipRule="evenodd" />
|
||||||
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</header>
|
||||||
</nav>
|
|
||||||
|
|
||||||
<main className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
|
{/* Page Content */}
|
||||||
|
<main className="flex-1 overflow-auto">
|
||||||
{children}
|
{children}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user