diff --git a/app/admin/dashboard/page-advanced.tsx b/app/admin/dashboard/page-advanced.tsx
index 2b7688a..f4b259b 100644
--- a/app/admin/dashboard/page-advanced.tsx
+++ b/app/admin/dashboard/page-advanced.tsx
@@ -416,11 +416,6 @@ export default function AdminDashboardAdvanced() {
-
diff --git a/app/admin/dashboard/page-backup.tsx b/app/admin/dashboard/page-backup.tsx
index d8ef4f1..b86fc64 100644
--- a/app/admin/dashboard/page-backup.tsx
+++ b/app/admin/dashboard/page-backup.tsx
@@ -203,11 +203,6 @@ export default function AdminDashboard() {
-
diff --git a/app/admin/dashboard/page.tsx b/app/admin/dashboard/page.tsx
index 2b7688a..f4b259b 100644
--- a/app/admin/dashboard/page.tsx
+++ b/app/admin/dashboard/page.tsx
@@ -416,11 +416,6 @@ export default function AdminDashboardAdvanced() {
-
diff --git a/app/admin/marketing-data/page.tsx b/app/admin/marketing-data/page.tsx
index 2bf2bfd..3627512 100644
--- a/app/admin/marketing-data/page.tsx
+++ b/app/admin/marketing-data/page.tsx
@@ -159,7 +159,6 @@ export default function MarketingPage() {
'Code Postal',
'Genre',
'Âge',
- 'Vérifié',
'A joué',
'A gagné',
'Nombre de tickets',
@@ -173,7 +172,6 @@ export default function MarketingPage() {
user.postal_code || '',
user.gender || '',
user.age || '',
- user.is_verified ? 'Oui' : 'Non',
user.has_played ? 'Oui' : 'Non',
user.has_won ? 'Oui' : 'Non',
user.ticket_count || 0,
@@ -388,19 +386,7 @@ export default function MarketingPage() {
{/* Filtres additionnels */}
-
-
-
- setFilters({ ...filters, verified: e.target.checked })}
- className="w-4 h-4"
- />
- Emails vérifiés uniquement
-
-
-
+
Ville
Statut du compte
-
-
- Email vérifié
-
-
- {user.isVerified ? (
- Vérifié ✓
- ) : (
- Non vérifié
- )}
-
-
Membre depuis
diff --git a/app/admin/tirages/page.tsx b/app/admin/tirages/page.tsx
index a9e4990..1b775e8 100644
--- a/app/admin/tirages/page.tsx
+++ b/app/admin/tirages/page.tsx
@@ -505,9 +505,6 @@ ${report.draw.notifiedAt ? `📧 Gagnant notifié le: ${new Date(report.draw.not
Lots Gagnés
-
- Statut
-
@@ -537,19 +534,6 @@ ${report.draw.notifiedAt ? `📧 Gagnant notifié le: ${new Date(report.draw.not
{participant.prizes_won}
-
- {participant.is_verified ? (
-
-
- Vérifié
-
- ) : (
-
-
- Non vérifié
-
- )}
-
))}
diff --git a/app/admin/utilisateurs/[id]/page.tsx b/app/admin/utilisateurs/[id]/page.tsx
index 60f4082..5c99bde 100644
--- a/app/admin/utilisateurs/[id]/page.tsx
+++ b/app/admin/utilisateurs/[id]/page.tsx
@@ -200,23 +200,13 @@ export default function UserDetailsPage() {
Statut du compte
-
Vérification email
+
Statut
- {user.isVerified ? (
- <>
-
- Vérifié
- >
- ) : (
- <>
-
- Non vérifié
- >
- )}
+ {user.isActive !== false ? 'Actif' : 'Inactif'}
@@ -245,14 +235,6 @@ export default function UserDetailsPage() {
>
Modifier l'utilisateur
- {user.role === 'CLIENT' && (
- router.push(`/admin/tickets?userId=${user.id}`)}
- className="w-full px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors"
- >
- Voir les tickets
-
- )}
diff --git a/app/contact/page.tsx b/app/contact/page.tsx
index 0398f1b..e1aa722 100644
--- a/app/contact/page.tsx
+++ b/app/contact/page.tsx
@@ -214,11 +214,16 @@ export default function ContactPage() {
📍
@@ -265,6 +270,44 @@ export default function ContactPage() {
+
+ {/* Google Maps */}
+
diff --git a/app/employe/profil/page.tsx b/app/employe/profil/page.tsx
index bd82d45..85477a6 100644
--- a/app/employe/profil/page.tsx
+++ b/app/employe/profil/page.tsx
@@ -182,18 +182,6 @@ export default function EmployeProfilePage() {
Statut du compte
-
-
- Email vérifié
-
-
- {user.isVerified ? (
- Vérifié ✓
- ) : (
- Non vérifié
- )}
-
-
Membre depuis
diff --git a/app/not-found.tsx b/app/not-found.tsx
new file mode 100644
index 0000000..4e7daaa
--- /dev/null
+++ b/app/not-found.tsx
@@ -0,0 +1,59 @@
+"use client";
+
+import Link from "next/link";
+import { useRouter } from "next/navigation";
+
+export default function NotFound() {
+ const router = useRouter();
+
+ return (
+
+
+ {/* Logo and 404 */}
+
+
+
+
+
+ 404
+
+
+
+ {/* Text content */}
+
+ Oups ! Page introuvable
+
+
+ Il semble que cette page se soit évaporée comme la vapeur d'une bonne tasse de thé...
+
+
+ {/* Action buttons */}
+
+
router.back()}
+ className="inline-flex items-center justify-center gap-2 border-2 border-[#d4a574] text-[#d4a574] hover:bg-[#d4a574] hover:text-white font-bold px-8 py-3 rounded-lg transition-all duration-300"
+ >
+
+
+
+ Retour
+
+
+
+
+
+ Accueil
+
+
+
+
+
+ );
+}
diff --git a/app/profil/page.tsx b/app/profil/page.tsx
index 89bf73d..b1284eb 100644
--- a/app/profil/page.tsx
+++ b/app/profil/page.tsx
@@ -13,15 +13,18 @@ import toast from "react-hot-toast";
import { useRouter } from "next/navigation";
import { ROUTES } from "@/utils/constants";
import { formatDate } from "@/utils/helpers";
+import { Modal } from "@/components/ui/Modal";
export const dynamic = 'force-dynamic';
export default function ProfilePage() {
- const { user, isAuthenticated, refreshUser } = useAuth();
+ const { user, isAuthenticated, refreshUser, logout } = useAuth();
const router = useRouter();
const [isEditing, setIsEditing] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [isReady, setIsReady] = useState(false);
+ const [showDeleteModal, setShowDeleteModal] = useState(false);
+ const [isDeleting, setIsDeleting] = useState(false);
const {
register,
@@ -72,6 +75,21 @@ export default function ProfilePage() {
setIsEditing(false);
};
+ const handleDeleteAccount = async () => {
+ setIsDeleting(true);
+ try {
+ await userService.archiveAccount();
+ toast.success("Votre compte a été supprimé avec succès");
+ logout();
+ router.push(ROUTES.HOME);
+ } catch (error: any) {
+ toast.error(error.message || "Erreur lors de la suppression du compte");
+ } finally {
+ setIsDeleting(false);
+ setShowDeleteModal(false);
+ }
+ };
+
const getRoleBadgeVariant = (role: string) => {
switch (role) {
case "admin":
@@ -145,13 +163,19 @@ export default function ProfilePage() {
-
+
setIsEditing(true)}
className="bg-gradient-to-r from-[#d4a574] to-[#c4956a] hover:from-[#e5b685] hover:to-[#d4a574] text-white font-bold px-6 py-3 rounded-lg transition-all shadow-lg hover:scale-105 duration-300"
>
Modifier mes informations
+ setShowDeleteModal(true)}
+ className="bg-red-500 hover:bg-red-600 text-white font-bold px-6 py-3 rounded-lg transition-all shadow-lg hover:scale-105 duration-300"
+ >
+ Supprimer mon compte
+
) : (
@@ -217,18 +241,6 @@ export default function ProfilePage() {
Statut du compte
-
-
- Email vérifié
-
-
- {user.isVerified ? (
- Vérifié ✓
- ) : (
- Non vérifié
- )}
-
-
Membre depuis
@@ -280,9 +292,45 @@ export default function ProfilePage() {
)}
+
+
+ {/* Delete Confirmation Modal */}
+ setShowDeleteModal(false)}
+ title="Confirmer la suppression"
+ >
+
+
+ Êtes-vous sûr de vouloir supprimer votre compte ?
+
+
+ Votre compte sera supprimé et vous ne pourrez plus vous connecter. Vos données seront conservées et un administrateur pourra réactiver votre compte si nécessaire.
+
+
+ setShowDeleteModal(false)}
+ disabled={isDeleting}
+ className="flex-1 border-2 border-gray-300 hover:bg-gray-100 text-gray-700 font-bold px-6 py-3 rounded-lg transition-all"
+ >
+ Annuler
+
+
+ {isDeleting ? "Suppression..." : "Supprimer"}
+
+
+
);
}
diff --git a/components/admin/UserManagement.tsx b/components/admin/UserManagement.tsx
index 2a23564..6e41331 100644
--- a/components/admin/UserManagement.tsx
+++ b/components/admin/UserManagement.tsx
@@ -1,6 +1,6 @@
'use client';
-import { useState, useEffect, useCallback } from 'react';
+import { useState, useEffect, useCallback, useMemo } from 'react';
import { useRouter } from 'next/navigation';
import { adminService } from '@/services/admin.service';
import { User, CreateEmployeeData, UpdateUserData, PaginatedResponse } from '@/types';
@@ -13,6 +13,20 @@ export default function UserManagement() {
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [filterRole, setFilterRole] = useState('');
+ const [filterStatus, setFilterStatus] = useState('');
+ const [searchQuery, setSearchQuery] = useState('');
+
+ // Filtrage côté client par nom/email
+ const filteredUsers = useMemo(() => {
+ if (!searchQuery.trim()) return users;
+ const query = searchQuery.toLowerCase().trim();
+ return users.filter(user =>
+ user.firstName?.toLowerCase().includes(query) ||
+ user.lastName?.toLowerCase().includes(query) ||
+ user.email?.toLowerCase().includes(query) ||
+ `${user.firstName} ${user.lastName}`.toLowerCase().includes(query)
+ );
+ }, [users, searchQuery]);
// Modals
const [isCreateEmployeeModalOpen, setIsCreateEmployeeModalOpen] = useState(false);
@@ -33,10 +47,14 @@ export default function UserManagement() {
try {
setLoading(true);
setError(null);
+ const filters: any = {};
+ if (filterRole) filters.role = filterRole;
+ if (filterStatus) filters.isActive = filterStatus === 'active';
+
const response: PaginatedResponse = await adminService.getAllUsers(
page,
- 20,
- filterRole ? { role: filterRole } : undefined
+ 100, // Charger plus pour le filtrage côté client
+ Object.keys(filters).length > 0 ? filters : undefined
);
setUsers(response.data || []);
setTotalPages(response.totalPages || 1);
@@ -46,7 +64,7 @@ export default function UserManagement() {
} finally {
setLoading(false);
}
- }, [page, filterRole]);
+ }, [page, filterRole, filterStatus]);
useEffect(() => {
loadUsers();
@@ -68,7 +86,6 @@ export default function UserManagement() {
setEditingUser(user);
setUserFormData({
role: user.role,
- isVerified: user.isVerified,
firstName: user.firstName,
lastName: user.lastName,
});
@@ -89,14 +106,15 @@ export default function UserManagement() {
}
};
- const handleDeleteUser = async (userId: string) => {
- if (!confirm('Êtes-vous sûr de vouloir supprimer cet utilisateur ?')) return;
+ const handleToggleUserStatus = async (user: User) => {
+ const action = user.isActive ? 'désactiver' : 'réactiver';
+ if (!confirm(`Êtes-vous sûr de vouloir ${action} cet utilisateur ?`)) return;
try {
- await adminService.deleteUser(userId);
+ await adminService.updateUser(user.id, { isActive: !user.isActive });
loadUsers();
} catch (err: any) {
- alert(err.message || 'Erreur lors de la suppression');
+ alert(err.message || `Erreur lors de la ${action}ation`);
}
};
@@ -136,7 +154,16 @@ export default function UserManagement() {
)}
{/* Filtres */}
-
+
+
+ setSearchQuery(e.target.value)}
+ className="w-full border rounded px-3 py-2"
+ />
+
{
@@ -150,6 +177,18 @@ export default function UserManagement() {
Employés
Administrateurs
+
{
+ setFilterStatus(e.target.value);
+ setPage(1);
+ }}
+ className="border rounded px-3 py-2"
+ >
+ Tous les statuts
+ Actifs
+ Inactifs (archivés)
+
{/* Table des utilisateurs */}
@@ -178,14 +217,14 @@ export default function UserManagement() {
- {users.length === 0 ? (
+ {filteredUsers.length === 0 ? (
- Aucun utilisateur trouvé
+ {searchQuery ? 'Aucun résultat pour cette recherche' : 'Aucun utilisateur trouvé'}
) : (
- users.map((user) => (
+ filteredUsers.map((user) => (
@@ -201,31 +240,19 @@ export default function UserManagement() {
-
- {user.isVerified ? 'Vérifié' : 'Non vérifié'}
+
+ {user.isActive !== false ? 'Actif' : 'Inactif'}
{new Date(user.createdAt).toLocaleDateString('fr-FR')}
-
+
router.push(`/admin/utilisateurs/${user.id}`)}
- className="text-green-600 hover:text-green-900"
- >
- Détails
-
- handleEditUser(user)}
className="text-blue-600 hover:text-blue-900"
>
- Modifier
-
- handleDeleteUser(user.id)}
- className="text-red-600 hover:text-red-900"
- >
- Supprimer
+ Détails
@@ -340,18 +367,6 @@ export default function UserManagement() {
Administrateur
-
- setUserFormData({ ...userFormData, isVerified: e.target.checked })}
- className="rounded"
- />
-
- Email vérifié
-
-
> => {
const params = new URLSearchParams({
page: page.toString(),
limit: limit.toString(),
...(filters?.role && { role: filters.role }),
+ ...(filters?.search && { search: filters.search }),
+ ...(filters?.isActive !== undefined && { isActive: filters.isActive.toString() }),
});
const response = await api.get(
`${API_ENDPOINTS.USERS}?${params}`
@@ -161,6 +165,7 @@ export const adminService = {
postalCode: user.postal_code || user.postalCode,
role: user.role,
isVerified: user.is_verified !== undefined ? user.is_verified : user.isVerified,
+ isActive: user.is_active !== undefined ? user.is_active : (user.isActive !== undefined ? user.isActive : true),
createdAt: user.created_at || user.createdAt,
ticketsCount: user.tickets_count || user.ticketsCount || 0,
}));
diff --git a/services/user.service.ts b/services/user.service.ts
index 25dc533..4772345 100644
--- a/services/user.service.ts
+++ b/services/user.service.ts
@@ -35,4 +35,14 @@ export const userService = {
changePassword: async (data: ChangePasswordData): Promise => {
await api.post(API_ENDPOINTS.USER.CHANGE_PASSWORD, data);
},
+
+ // Archive account (désactive le compte au lieu de le supprimer)
+ archiveAccount: async (): Promise => {
+ await api.put(API_ENDPOINTS.USER.UPDATE_PROFILE, { isActive: false });
+ },
+
+ // Delete account (kept for backwards compatibility)
+ deleteAccount: async (): Promise => {
+ await api.delete(API_ENDPOINTS.USER.DELETE_ACCOUNT);
+ },
};
diff --git a/types/index.ts b/types/index.ts
index b1004a6..cd105b8 100644
--- a/types/index.ts
+++ b/types/index.ts
@@ -12,6 +12,7 @@ export interface User {
dateOfBirth?: string;
role: 'CLIENT' | 'EMPLOYEE' | 'ADMIN';
isVerified: boolean;
+ isActive: boolean;
createdAt: string;
updatedAt?: string;
// Ticket statistics (populated in getUserById)
@@ -171,6 +172,7 @@ export interface CreateEmployeeData {
export interface UpdateUserData {
role?: 'CLIENT' | 'EMPLOYEE' | 'ADMIN';
isVerified?: boolean;
+ isActive?: boolean;
firstName?: string;
lastName?: string;
}
diff --git a/utils/constants.ts b/utils/constants.ts
index 8184072..5384b98 100644
--- a/utils/constants.ts
+++ b/utils/constants.ts
@@ -36,6 +36,7 @@ export const API_ENDPOINTS = {
PROFILE: '/users/profile',
UPDATE_PROFILE: '/users/profile',
CHANGE_PASSWORD: '/users/change-password',
+ DELETE_ACCOUNT: '/users/account',
},
NEWSLETTER: {
SUBSCRIBE: '/newsletter/subscribe',