diff --git a/frontend/src/app/(dashboard)/admin/categories/page.tsx b/frontend/src/app/(dashboard)/admin/categories/page.tsx index 8c29daf..a71b5ab 100644 --- a/frontend/src/app/(dashboard)/admin/categories/page.tsx +++ b/frontend/src/app/(dashboard)/admin/categories/page.tsx @@ -1,6 +1,9 @@ "use client"; -import { useEffect, useState } from "react"; +import { Edit, Plus, Trash2 } from "lucide-react"; +import Image from "next/image"; +import { useCallback, useEffect, useState } from "react"; +import { Button } from "@/components/ui/button"; import { Skeleton } from "@/components/ui/skeleton"; import { Table, @@ -12,24 +15,57 @@ import { } from "@/components/ui/table"; import { CategoryService } from "@/services/category.service"; import type { Category } from "@/types/content"; +import { CategoryDialog } from "./category-dialog"; export default function AdminCategoriesPage() { const [categories, setCategories] = useState([]); const [loading, setLoading] = useState(true); + const [dialogOpen, setDialogOpen] = useState(false); + const [selectedCategory, setSelectedCategory] = useState( + null, + ); - useEffect(() => { + const fetchCategories = useCallback(() => { + setLoading(true); CategoryService.getAll() .then(setCategories) .catch((err) => console.error(err)) .finally(() => setLoading(false)); }, []); + useEffect(() => { + fetchCategories(); + }, [fetchCategories]); + + const handleDelete = async (id: string) => { + if (!confirm("Êtes-vous sûr de vouloir supprimer cette catégorie ?")) return; + try { + await CategoryService.remove(id); + setCategories(categories.filter((c) => c.id !== id)); + } catch (error) { + console.error(error); + } + }; + + const handleEdit = (category: Category) => { + setSelectedCategory(category); + setDialogOpen(true); + }; + + const handleCreate = () => { + setSelectedCategory(null); + setDialogOpen(true); + }; + return (

Catégories ({categories.length})

+
@@ -38,6 +74,7 @@ export default function AdminCategoriesPage() { NomSlugDescription + @@ -54,11 +91,14 @@ export default function AdminCategoriesPage() { + + + )) ) : categories.length === 0 ? ( - + Aucune catégorie trouvée. @@ -66,18 +106,55 @@ export default function AdminCategoriesPage() { categories.map((category) => ( - {category.name} +
+ {category.iconUrl && ( +
+ +
+ )} + {category.name} +
{category.slug} {category.description || "Aucune description"} + +
+ + +
+
)) )}
+
); } diff --git a/frontend/src/app/(dashboard)/admin/contents/page.tsx b/frontend/src/app/(dashboard)/admin/contents/page.tsx index 94b97af..e614d1c 100644 --- a/frontend/src/app/(dashboard)/admin/contents/page.tsx +++ b/frontend/src/app/(dashboard)/admin/contents/page.tsx @@ -2,8 +2,15 @@ import { format } from "date-fns"; import { fr } from "date-fns/locale"; -import { Download, Eye, Image as ImageIcon, Trash2, Video } from "lucide-react"; -import { useEffect, useState } from "react"; +import { + Download, + Edit, + Eye, + Image as ImageIcon, + Trash2, + Video, +} from "lucide-react"; +import { useCallback, useEffect, useState } from "react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Skeleton } from "@/components/ui/skeleton"; @@ -17,13 +24,17 @@ import { } from "@/components/ui/table"; import { ContentService } from "@/services/content.service"; import type { Content } from "@/types/content"; +import { ContentEditDialog } from "./content-edit-dialog"; export default function AdminContentsPage() { const [contents, setContents] = useState([]); const [loading, setLoading] = useState(true); const [totalCount, setTotalCount] = useState(0); + const [selectedContent, setSelectedContent] = useState(null); + const [dialogOpen, setDialogOpen] = useState(false); - useEffect(() => { + const fetchContents = useCallback(() => { + setLoading(true); ContentService.getExplore({ limit: 20 }) .then((res) => { setContents(res.data); @@ -33,6 +44,10 @@ export default function AdminContentsPage() { .finally(() => setLoading(false)); }, []); + useEffect(() => { + fetchContents(); + }, [fetchContents]); + const handleDelete = async (id: string) => { if (!confirm("Êtes-vous sûr de vouloir supprimer ce contenu ?")) return; @@ -45,6 +60,11 @@ export default function AdminContentsPage() { } }; + const handleEdit = (content: Content) => { + setSelectedContent(content); + setDialogOpen(true); + }; + return (
@@ -61,7 +81,7 @@ export default function AdminContentsPage() { Auteur Stats Date - + @@ -84,11 +104,14 @@ export default function AdminContentsPage() { + + + )) ) : contents.length === 0 ? ( - + Aucun contenu trouvé. @@ -132,14 +155,23 @@ export default function AdminContentsPage() { {format(new Date(content.createdAt), "dd/MM/yyyy", { locale: fr })} - +
+ + +
)) @@ -147,6 +179,12 @@ export default function AdminContentsPage() {
+
); } diff --git a/frontend/src/app/(dashboard)/admin/users/page.tsx b/frontend/src/app/(dashboard)/admin/users/page.tsx index 1fdee58..d6dba69 100644 --- a/frontend/src/app/(dashboard)/admin/users/page.tsx +++ b/frontend/src/app/(dashboard)/admin/users/page.tsx @@ -2,8 +2,8 @@ import { format } from "date-fns"; import { fr } from "date-fns/locale"; -import { Trash2 } from "lucide-react"; -import { useEffect, useState } from "react"; +import { Edit, Trash2 } from "lucide-react"; +import { useCallback, useEffect, useState } from "react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Skeleton } from "@/components/ui/skeleton"; @@ -17,13 +17,17 @@ import { } from "@/components/ui/table"; import { UserService } from "@/services/user.service"; import type { User } from "@/types/user"; +import { UserEditDialog } from "./user-edit-dialog"; export default function AdminUsersPage() { const [users, setUsers] = useState([]); const [loading, setLoading] = useState(true); const [totalCount, setTotalCount] = useState(0); + const [selectedUser, setSelectedUser] = useState(null); + const [dialogOpen, setDialogOpen] = useState(false); - useEffect(() => { + const fetchUsers = useCallback(() => { + setLoading(true); UserService.getUsersAdmin() .then((res) => { setUsers(res.data); @@ -35,6 +39,10 @@ export default function AdminUsersPage() { .finally(() => setLoading(false)); }, []); + useEffect(() => { + fetchUsers(); + }, [fetchUsers]); + const handleDelete = async (uuid: string) => { if ( !confirm( @@ -52,6 +60,11 @@ export default function AdminUsersPage() { } }; + const handleEdit = (user: User) => { + setSelectedUser(user); + setDialogOpen(true); + }; + return (
@@ -68,7 +81,7 @@ export default function AdminUsersPage() { Rôle Status Date d'inscription - + @@ -91,11 +104,14 @@ export default function AdminUsersPage() { + + + )) ) : users.length === 0 ? ( - + Aucun utilisateur trouvé. @@ -113,7 +129,15 @@ export default function AdminUsersPage() { - + {user.status} @@ -121,14 +145,19 @@ export default function AdminUsersPage() { {format(new Date(user.createdAt), "PPP", { locale: fr })} - +
+ + +
)) @@ -136,6 +165,12 @@ export default function AdminUsersPage() {
+
); }