refactor: reorganize feature modules with consistent naming conventions and flattened structure
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Admin Server Actions
|
||||
*
|
||||
* Exported separately from admin/index.js to avoid bundling
|
||||
* server-side code (which includes database imports) into client components.
|
||||
*
|
||||
* Usage: import { getDashboardStats } from '@zen/core/features/admin/actions';
|
||||
*/
|
||||
|
||||
export { getDashboardStats } from './actions/statsActions.js';
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Admin Stats Actions
|
||||
*
|
||||
* @deprecated Utiliser collectAllDashboardData() de serverRegistry à la place.
|
||||
* Ce fichier est conservé pour la rétrocompatibilité avec les projets qui
|
||||
* appellent getDashboardStats() directement depuis leur page admin.
|
||||
*/
|
||||
|
||||
'use server';
|
||||
|
||||
import { query } from '@zen/core/database';
|
||||
import { fail } from '@zen/core/shared/logger';
|
||||
|
||||
/**
|
||||
* @deprecated Utiliser collectAllDashboardData() de serverRegistry à la place.
|
||||
* @returns {Promise<{ success: boolean, stats?: { totalUsers: number }, error?: string }>}
|
||||
*/
|
||||
export async function getDashboardStats() {
|
||||
try {
|
||||
const result = await query(`SELECT COUNT(*) as count FROM zen_auth_users`);
|
||||
const totalUsers = parseInt(result.rows[0].count) || 0;
|
||||
return { success: true, stats: { totalUsers } };
|
||||
} catch (error) {
|
||||
fail(`Error getting dashboard stats: ${error.message}`);
|
||||
return { success: false, error: error.message || 'Failed to get dashboard statistics' };
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import DashboardPage from './pages/DashboardPage.js';
|
||||
import UsersPage from './pages/UsersPage.js';
|
||||
import UserEditPage from './pages/UserEditPage.js';
|
||||
import ProfilePage from './pages/ProfilePage.js';
|
||||
import RolesPage from './pages/RolesPage.js';
|
||||
import RoleEditPage from './pages/RoleEditPage.js';
|
||||
|
||||
export default function AdminPagesClient({ params, user, dashboardStats = null }) {
|
||||
const parts = params?.admin || [];
|
||||
const page = parts[0] || 'dashboard';
|
||||
|
||||
if (page === 'users' && parts[1] === 'edit' && parts[2]) {
|
||||
return <UserEditPage userId={parts[2]} user={user} />;
|
||||
}
|
||||
|
||||
if (page === 'roles' && parts[1] === 'edit' && parts[2]) {
|
||||
return <RoleEditPage roleId={parts[2]} user={user} />;
|
||||
}
|
||||
|
||||
if (page === 'roles' && parts[1] === 'new') {
|
||||
return <RoleEditPage roleId="new" user={user} />;
|
||||
}
|
||||
|
||||
const corePages = {
|
||||
dashboard: () => <DashboardPage user={user} stats={dashboardStats} />,
|
||||
users: () => <UsersPage user={user} />,
|
||||
profile: () => <ProfilePage user={user} />,
|
||||
roles: () => <RolesPage user={user} />,
|
||||
};
|
||||
|
||||
const CorePageComponent = corePages[page];
|
||||
return CorePageComponent ? <CorePageComponent /> : <DashboardPage user={user} stats={dashboardStats} />;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
'use client';
|
||||
|
||||
/**
|
||||
* Dashboard Client Registry — API générique
|
||||
*
|
||||
* Les features s'enregistrent ici via registerClientWidget().
|
||||
* Ce fichier ne doit jamais importer une feature directement.
|
||||
* Les features dépendent de ce fichier, pas l'inverse.
|
||||
*/
|
||||
|
||||
const widgets = [];
|
||||
|
||||
/**
|
||||
* Enregistre un composant React pour le tableau de bord.
|
||||
* Appelé en side effect par chaque feature (ex: auth/dashboard.widget.js).
|
||||
* @param {string} id - Identifiant unique de la feature (doit correspondre à l'id serveur)
|
||||
* @param {React.ComponentType} Component - Composant avec props { data, loading }
|
||||
* @param {number} order - Ordre d'affichage (croissant). Utiliser des intervalles de 10.
|
||||
*/
|
||||
export function registerClientWidget(id, Component, order) {
|
||||
widgets.push({ id, Component, order });
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne tous les widgets enregistrés, triés par order croissant.
|
||||
* @returns {Array<{ id: string, Component: React.ComponentType, order: number }>}
|
||||
*/
|
||||
export function getClientWidgets() {
|
||||
return [...widgets].sort((a, b) => a.order - b.order);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* Dashboard Server Registry — API générique
|
||||
*
|
||||
* Les features s'enregistrent ici via registerServerWidget().
|
||||
* Ce fichier ne doit jamais importer une feature directement.
|
||||
* Les features dépendent de ce fichier, pas l'inverse.
|
||||
*/
|
||||
|
||||
const widgets = new Map(); // id → fetcher
|
||||
|
||||
/**
|
||||
* Enregistre une fonction de fetch pour le tableau de bord.
|
||||
* Appelé en side effect par chaque feature (ex: auth/dashboard.server.js).
|
||||
* @param {string} id - Identifiant unique de la feature
|
||||
* @param {() => Promise<any>} fetcher - Fonction async retournant des données sérialisables
|
||||
*/
|
||||
export function registerServerWidget(id, fetcher) {
|
||||
widgets.set(id, fetcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exécute tous les fetchers enregistrés en parallèle.
|
||||
* Un fetcher qui échoue n'empêche pas les autres (Promise.allSettled).
|
||||
* @returns {Promise<Record<string, any>>} Map featureId → données
|
||||
*/
|
||||
export async function collectAllDashboardData() {
|
||||
const results = await Promise.allSettled(
|
||||
Array.from(widgets.entries()).map(([id, fetcher]) =>
|
||||
fetcher().then(data => ({ id, data }))
|
||||
)
|
||||
);
|
||||
|
||||
return results.reduce((acc, result) => {
|
||||
if (result.status === 'fulfilled') {
|
||||
acc[result.value.id] = result.value.data;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Dashboard Server Registry — Point d'entrée
|
||||
*
|
||||
* Ré-exporte l'API du registre pur et déclenche le câblage des features
|
||||
* via un import side-effect de features/dashboard.server.js.
|
||||
*
|
||||
* Ne jamais importer une feature directement ici.
|
||||
* Pour ajouter une feature : éditer src/features/dashboard.server.js.
|
||||
*/
|
||||
|
||||
export { collectAllDashboardData } from './registry.js';
|
||||
|
||||
// Side effect : initialise le registre, enregistre les widgets core, puis les features
|
||||
import './registry.js';
|
||||
import './widgets/index.server.js';
|
||||
import '../../dashboard.server.js';
|
||||
@@ -1,10 +0,0 @@
|
||||
'use client';
|
||||
|
||||
/**
|
||||
* Widgets core — Câblage client
|
||||
*
|
||||
* Ce fichier est le SEUL à modifier pour ajouter un widget core côté client.
|
||||
* Les widgets core sont auto-enregistrés au démarrage de l'admin, sans module externe.
|
||||
*/
|
||||
|
||||
import './users.widget.js';
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* Widgets core — Câblage serveur
|
||||
*
|
||||
* Ce fichier est le SEUL à modifier pour ajouter un widget core côté serveur.
|
||||
* Les widgets core sont auto-enregistrés au démarrage de l'admin, sans module externe.
|
||||
*/
|
||||
|
||||
import './users.server.js';
|
||||
@@ -1,53 +0,0 @@
|
||||
/**
|
||||
* Admin Navigation Builder (Server-Only)
|
||||
*
|
||||
* IMPORTANT: Navigation data must be serializable (no functions/components).
|
||||
* Icons are passed as string names and resolved on the client.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Build complete navigation sections
|
||||
* @param {string} pathname - Current pathname
|
||||
* @returns {Array} Navigation sections (serializable, icons as strings)
|
||||
*/
|
||||
export function buildNavigationSections(pathname) {
|
||||
const coreNavigation = [
|
||||
{
|
||||
id: 'Dashboard',
|
||||
title: 'Tableau de bord',
|
||||
icon: 'DashboardSquare03Icon',
|
||||
items: [
|
||||
{
|
||||
name: 'Tableau de bord',
|
||||
href: '/admin/dashboard',
|
||||
icon: 'DashboardSquare03Icon',
|
||||
current: pathname === '/admin/dashboard'
|
||||
},
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const systemNavigation = [
|
||||
{
|
||||
id: 'users',
|
||||
title: 'Utilisateurs',
|
||||
icon: 'UserMultiple02Icon',
|
||||
items: [
|
||||
{
|
||||
name: 'Utilisateurs',
|
||||
href: '/admin/users',
|
||||
icon: 'UserMultiple02Icon',
|
||||
current: pathname.startsWith('/admin/users')
|
||||
},
|
||||
{
|
||||
name: 'Rôles',
|
||||
href: '/admin/roles',
|
||||
icon: 'Crown03Icon',
|
||||
current: pathname.startsWith('/admin/roles')
|
||||
},
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
return [...coreNavigation, ...systemNavigation];
|
||||
}
|
||||
Reference in New Issue
Block a user