diff --git a/apps/web/src/components/views/AdminView.stories.tsx b/apps/web/src/components/views/AdminView.stories.tsx index 782c546f8..71bc000e4 100644 --- a/apps/web/src/components/views/AdminView.stories.tsx +++ b/apps/web/src/components/views/AdminView.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { AdminView } from './AdminView'; +import { AdminView, AdminViewSkeleton } from './admin-view'; /** * AdminView - Vue principale d'administration @@ -8,42 +8,45 @@ import { AdminView } from './AdminView'; * pour basculer entre les différentes vues admin. */ const meta: Meta = { - title: 'Components/Features/Views/AdminView', - component: AdminView, - parameters: { - layout: 'fullscreen', - docs: { - description: { - component: 'Vue conteneur admin avec navigation sidebar vers sous-vues.', - }, - }, + title: 'Components/Features/Views/AdminView', + component: AdminView, + parameters: { + layout: 'fullscreen', + docs: { + description: { + component: + 'Vue conteneur admin avec navigation sidebar vers sous-vues.', + }, }, - tags: ['autodocs'], - argTypes: { - currentSubView: { - control: 'select', - options: ['dashboard', 'users', 'moderation', 'audit', 'settings'], - description: 'Sous-vue à afficher par défaut', - }, + }, + tags: ['autodocs'], + argTypes: { + currentSubView: { + control: 'select', + options: ['dashboard', 'users', 'moderation', 'audit', 'settings'], + description: 'Sous-vue à afficher par défaut', }, - decorators: [ - (Story) => ( -
- -
- ), - ], + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], }; export default meta; type Story = StoryObj; -/** - * Vue dashboard par défaut. - */ export const Default: Story = { - name: 'Par défaut (Dashboard)', - args: { - currentSubView: 'dashboard', - }, + name: 'Par défaut (Dashboard)', + args: { + currentSubView: 'dashboard', + }, +}; + +export const Loading: Story = { + render: () => , + name: 'Chargement', }; diff --git a/apps/web/src/components/views/AdminView.tsx b/apps/web/src/components/views/AdminView.tsx index 28e37673b..9bb994b95 100644 --- a/apps/web/src/components/views/AdminView.tsx +++ b/apps/web/src/components/views/AdminView.tsx @@ -1,96 +1 @@ -import React, { useState } from 'react'; -import { AdminDashboardView } from '../admin/AdminDashboardView'; -import { AdminUsersView } from '../admin/AdminUsersView'; -import { AdminModerationView } from '../admin/AdminModerationView'; -import { AdminAuditLogsView } from '../admin/AdminAuditLogsView'; -import { AdminSettingsView } from '../admin/AdminSettingsView'; -import { LayoutDashboard, Users, ShieldAlert, Settings, History } from 'lucide-react'; - -interface AdminViewProps { - currentSubView?: string; // 'dashboard' | 'users' | 'moderation' | 'audit' | 'settings' -} - -export const AdminView: React.FC = ({ - currentSubView = 'dashboard', -}) => { - // Local state for internal navigation if not driven by props, but props is better for deep linking simulation - const [activeTab, setActiveTab] = useState(currentSubView); - - const renderContent = () => { - switch (activeTab) { - case 'users': - return ; - case 'moderation': - return ; - case 'audit': - return ; - case 'settings': - return ; - case 'dashboard': - default: - return ; - } - }; - - return ( -
- {/* Admin Sidebar */} -
-
- -
-

Admin Area

-

Restricted Access

-
-
- -
- {[ - { - id: 'dashboard', - label: 'Dashboard', - icon: , - }, - { - id: 'users', - label: 'Users', - icon: , - }, - { - id: 'moderation', - label: 'Moderation', - icon: , - }, - { - id: 'audit', - label: 'Audit Logs', - icon: , - }, - { - id: 'settings', - label: 'Settings', - icon: , - }, - ].map((item) => ( - - ))} -
-
- - {/* Content Area */} -
- {renderContent()} -
-
- ); -}; +export { AdminView } from './admin-view'; diff --git a/apps/web/src/components/views/admin-view/AdminView.tsx b/apps/web/src/components/views/admin-view/AdminView.tsx new file mode 100644 index 000000000..54027790c --- /dev/null +++ b/apps/web/src/components/views/admin-view/AdminView.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { AdminViewSidebar } from './AdminViewSidebar'; +import { AdminViewContent } from './AdminViewContent'; +import { useAdminView } from './useAdminView'; +import type { AdminViewProps, AdminSubViewId } from './types'; + +const DEFAULT_SUB_VIEW: AdminSubViewId = 'dashboard'; + +export function AdminView({ + currentSubView = DEFAULT_SUB_VIEW, +}: AdminViewProps = {}) { + const { activeTab, setActiveTab, tabs } = useAdminView(currentSubView); + + return ( +
+ +
+ +
+
+ ); +} diff --git a/apps/web/src/components/views/admin-view/AdminViewContent.tsx b/apps/web/src/components/views/admin-view/AdminViewContent.tsx new file mode 100644 index 000000000..75f3ddc2b --- /dev/null +++ b/apps/web/src/components/views/admin-view/AdminViewContent.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { AdminDashboardView } from '@/components/admin/AdminDashboardView'; +import { AdminUsersView } from '@/components/admin/AdminUsersView'; +import { AdminModerationView } from '@/components/admin/AdminModerationView'; +import { AdminAuditLogsView } from '@/components/admin/AdminAuditLogsView'; +import { AdminSettingsView } from '@/components/admin/AdminSettingsView'; +import type { AdminSubViewId } from './types'; + +interface AdminViewContentProps { + activeTab: AdminSubViewId; +} + +export function AdminViewContent({ activeTab }: AdminViewContentProps) { + switch (activeTab) { + case 'users': + return ; + case 'moderation': + return ; + case 'audit': + return ; + case 'settings': + return ; + case 'dashboard': + default: + return ; + } +} diff --git a/apps/web/src/components/views/admin-view/AdminViewSidebar.tsx b/apps/web/src/components/views/admin-view/AdminViewSidebar.tsx new file mode 100644 index 000000000..efd42f279 --- /dev/null +++ b/apps/web/src/components/views/admin-view/AdminViewSidebar.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { ShieldAlert } from 'lucide-react'; +import type { AdminSubViewId, AdminTabConfig } from './types'; + +interface AdminViewSidebarProps { + tabs: AdminTabConfig[]; + activeTab: AdminSubViewId; + onTabChange: (id: AdminSubViewId) => void; +} + +export function AdminViewSidebar({ + tabs, + activeTab, + onTabChange, +}: AdminViewSidebarProps) { + return ( +
+
+ +
+

Admin Area

+

Restricted Access

+
+
+ +
+ {tabs.map((item) => ( + + ))} +
+
+ ); +} diff --git a/apps/web/src/components/views/admin-view/AdminViewSkeleton.tsx b/apps/web/src/components/views/admin-view/AdminViewSkeleton.tsx new file mode 100644 index 000000000..7e1a2aa3a --- /dev/null +++ b/apps/web/src/components/views/admin-view/AdminViewSkeleton.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Skeleton } from '@/components/ui/skeleton'; + +export function AdminViewSkeleton() { + return ( +
+
+ +
+ {[1, 2, 3, 4, 5].map((i) => ( + + ))} +
+
+
+ + + +
+
+ ); +} diff --git a/apps/web/src/components/views/admin-view/index.ts b/apps/web/src/components/views/admin-view/index.ts new file mode 100644 index 000000000..3eee6ab61 --- /dev/null +++ b/apps/web/src/components/views/admin-view/index.ts @@ -0,0 +1,4 @@ +export { AdminView } from './AdminView'; +export { AdminViewSkeleton } from './AdminViewSkeleton'; +export { useAdminView } from './useAdminView'; +export type { AdminViewProps, AdminSubViewId, AdminTabConfig } from './types'; diff --git a/apps/web/src/components/views/admin-view/types.ts b/apps/web/src/components/views/admin-view/types.ts new file mode 100644 index 000000000..4c575c94e --- /dev/null +++ b/apps/web/src/components/views/admin-view/types.ts @@ -0,0 +1,18 @@ +import type { ReactNode } from 'react'; + +export type AdminSubViewId = + | 'dashboard' + | 'users' + | 'moderation' + | 'audit' + | 'settings'; + +export interface AdminViewProps { + currentSubView?: AdminSubViewId; +} + +export interface AdminTabConfig { + id: AdminSubViewId; + label: string; + icon: ReactNode; +} diff --git a/apps/web/src/components/views/admin-view/useAdminView.tsx b/apps/web/src/components/views/admin-view/useAdminView.tsx new file mode 100644 index 000000000..ee08f07e5 --- /dev/null +++ b/apps/web/src/components/views/admin-view/useAdminView.tsx @@ -0,0 +1,31 @@ +import { useState, useEffect } from 'react'; +import { + LayoutDashboard, + Users, + ShieldAlert, + Settings, + History, +} from 'lucide-react'; +import type { AdminSubViewId, AdminTabConfig } from './types'; + +const ADMIN_TABS: AdminTabConfig[] = [ + { id: 'dashboard', label: 'Dashboard', icon: }, + { id: 'users', label: 'Users', icon: }, + { id: 'moderation', label: 'Moderation', icon: }, + { id: 'audit', label: 'Audit Logs', icon: }, + { id: 'settings', label: 'Settings', icon: }, +]; + +export function useAdminView(initialSubView: AdminSubViewId = 'dashboard') { + const [activeTab, setActiveTab] = useState(initialSubView); + + useEffect(() => { + setActiveTab(initialSubView); + }, [initialSubView]); + + return { + activeTab, + setActiveTab, + tabs: ADMIN_TABS, + }; +}