refactor: reorganize feature modules with consistent naming conventions and flattened structure

This commit is contained in:
2026-04-22 14:12:15 -04:00
parent 256df9102c
commit 61388f04a6
41 changed files with 0 additions and 824 deletions
-10
View File
@@ -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);
}
-39
View File
@@ -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';
-53
View File
@@ -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];
}