feat: implement dynamic dashboard displaying active modules and clean up sidebar menu.

This commit is contained in:
2025-12-04 02:23:20 +01:00
parent 500a3197e2
commit e70b30cab8
4 changed files with 225 additions and 20 deletions

View File

@@ -22,3 +22,5 @@ File riassuntivo dello stato di sviluppo di Zentral.
- [Menu Refactoring](./devlog/menu-refactoring.md) - Riorganizzazione menu e moduli (Dashboard, Clienti, Articoli, Risorse)
- [2025-12-03 Implementazione Modulo Personale](./devlog/2025-12-03_implementazione_modulo_personale.md) - **In Corso**
- Implementazione entità, API e Frontend per gestione Personale (Dipendenti, Contratti, Assenze, Pagamenti).
- [2025-12-04 Zentral Dashboard and Menu Cleanup](./devlog/2025-12-04-023000_zentral_dashboard.md) - **Completato**
- Pulizia menu Zentral (rimozione voci ridondanti) e creazione nuova Dashboard principale con riepilogo moduli attivi.

View File

@@ -0,0 +1,25 @@
# Zentral Dashboard and Menu Cleanup
## Stato Attuale
Completato.
## Lavoro Svolto
1. **Pulizia Menu Zentral**:
- Verificato che le voci "Clienti", "Articoli" e "Risorse" nel menu "Zentral" erano ridondanti o non funzionanti.
- "Articoli" è gestito dal modulo Warehouse (`/warehouse/articles`).
- "Clienti" e "Risorse" erano link non funzionanti (`/clienti`, `/risorse` non definiti nelle rotte).
- Rimossi questi elementi dal menu laterale (`Sidebar.tsx`).
- Appiattito il menu "Zentral" in un'unica voce di primo livello "Zentral Dashboard" che punta direttamente alla home page.
2. **Nuova Zentral Dashboard**:
- Aggiornato `src/frontend/src/pages/Dashboard.tsx` per diventare la nuova homepage "Zentral Dashboard".
- La dashboard ora mostra:
- Un messaggio di benvenuto con il conteggio dei moduli attivi.
- Una griglia di card per ogni modulo attivo, con icona, nome, descrizione e pulsante per aprire l'applicazione.
- Gestione dello stato di caricamento e caso di nessun modulo attivo.
- La dashboard utilizza `useModules` per recuperare dinamicamente i moduli attivi.
- Integrata con il sistema di Tab (`openTab`) per aprire le applicazioni.
## Prossimi Passi Suggeriti
- Implementare endpoint di backend per recuperare statistiche globali reali (es. numero ordini aperti, valore magazzino, ecc.) da mostrare nella dashboard principale.
- Aggiungere widget personalizzabili nella dashboard.

View File

@@ -17,8 +17,6 @@ import {
Event as EventIcon,
People as PeopleIcon,
Place as PlaceIcon,
Inventory as InventoryIcon,
Person as PersonIcon,
CalendarMonth as CalendarIcon,
Print as PrintIcon,
Extension as ModulesIcon,
@@ -84,15 +82,10 @@ export default function Sidebar({ onClose }: { onClose?: () => void }) {
const menuStructure: MenuItem[] = [
{
id: 'core',
label: 'Zentral',
id: 'dashboard',
label: 'Zentral Dashboard',
icon: <DashboardIcon />,
children: [
{ id: 'dashboard', label: t('menu.dashboard'), icon: <DashboardIcon />, path: '/' },
{ id: 'clients', label: t('menu.clients'), icon: <PeopleIcon />, path: '/clienti' },
{ id: 'articles', label: t('menu.articles'), icon: <InventoryIcon />, path: '/articoli' },
{ id: 'resources', label: t('menu.resources'), icon: <PersonIcon />, path: '/risorse' },
],
path: '/',
},
{
id: 'warehouse',

View File

@@ -1,20 +1,205 @@
import { Box, Typography, Grid, Paper } from '@mui/material';
import {
Box,
Typography,
Grid,
Paper,
Card,
CardContent,
CardActions,
Button,
Chip,
useTheme,
alpha
} from '@mui/material';
import {
Dashboard as DashboardIcon,
Event as EventIcon,
People as PeopleIcon,
ShoppingCart as ShoppingCartIcon,
Sell as SellIcon,
Factory as ProductionIcon,
Settings as SettingsIcon,
ArrowForward as ArrowForwardIcon,
Storage as StorageIcon
} from '@mui/icons-material';
import { useModules } from '../contexts/ModuleContext';
import { useLanguage } from '../contexts/LanguageContext';
import { useTabs } from '../contexts/TabContext';
export default function Dashboard() {
const { activeModules, isLoading } = useModules();
const { t } = useLanguage();
const { openTab } = useTabs();
const theme = useTheme();
const getModuleIcon = (code: string) => {
switch (code) {
case 'warehouse': return <StorageIcon fontSize="large" />;
case 'purchases': return <ShoppingCartIcon fontSize="large" />;
case 'sales': return <SellIcon fontSize="large" />;
case 'production': return <ProductionIcon fontSize="large" />;
case 'events': return <EventIcon fontSize="large" />;
case 'hr': return <PeopleIcon fontSize="large" />;
default: return <DashboardIcon fontSize="large" />;
}
};
const getModulePath = (code: string) => {
switch (code) {
case 'warehouse': return '/warehouse';
case 'purchases': return '/purchases/orders'; // Default to orders for now
case 'sales': return '/sales/orders';
case 'production': return '/production';
case 'events': return '/events/list';
case 'hr': return '/hr/dipendenti';
default: return '/';
}
};
const handleModuleClick = (module: any) => {
const path = getModulePath(module.code);
openTab(path, module.name);
};
if (isLoading) {
return <Box sx={{ p: 3 }}>Loading...</Box>;
}
return (
<Box>
<Typography variant="h4" gutterBottom>
Dashboard
</Typography>
<Box sx={{ p: 3 }}>
<Box sx={{ mb: 4 }}>
<Typography variant="h3" gutterBottom sx={{ fontWeight: 'bold', color: 'primary.main' }}>
Zentral Dashboard
</Typography>
<Typography variant="h6" color="text.secondary">
Overview of your active modules and system status
</Typography>
</Box>
<Grid container spacing={3}>
{/* System Status / Welcome Card */}
<Grid size={12}>
<Paper sx={{ p: 2 }}>
<Typography variant="h6">Welcome to Zentral</Typography>
<Typography variant="body1">
Select a module from the menu to get started.
</Typography>
<Paper
sx={{
p: 3,
background: `linear-gradient(45deg, ${theme.palette.primary.main} 30%, ${theme.palette.primary.dark} 90%)`,
color: 'white',
borderRadius: 2,
boxShadow: 3
}}
>
<Grid container alignItems="center" spacing={2}>
<Grid size={{ xs: 12, md: 8 }}>
<Typography variant="h4" gutterBottom>
Welcome back!
</Typography>
<Typography variant="body1">
You have {activeModules.length} active modules running.
Select a module below to start working or manage your subscriptions in the Admin panel.
</Typography>
</Grid>
<Grid size={{ xs: 12, md: 4 }} sx={{ textAlign: 'right' }}>
<Button
variant="contained"
color="secondary"
startIcon={<SettingsIcon />}
onClick={() => openTab('/modules', t('menu.modules'))}
sx={{ bgcolor: 'white', color: 'primary.main', '&:hover': { bgcolor: 'grey.100' } }}
>
Manage Modules
</Button>
</Grid>
</Grid>
</Paper>
</Grid>
{/* Active Modules Grid */}
<Grid size={12}>
<Typography variant="h5" sx={{ mb: 2, mt: 2, fontWeight: 'medium' }}>
Active Applications
</Typography>
</Grid>
{activeModules.map((module) => (
<Grid size={{ xs: 12, sm: 6, md: 4, lg: 3 }} key={module.code}>
<Card
sx={{
height: '100%',
display: 'flex',
flexDirection: 'column',
transition: 'transform 0.2s, box-shadow 0.2s',
'&:hover': {
transform: 'translateY(-4px)',
boxShadow: 6,
cursor: 'pointer'
}
}}
onClick={() => handleModuleClick(module)}
>
<CardContent sx={{ flexGrow: 1 }}>
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
<Box
sx={{
p: 1.5,
borderRadius: 2,
bgcolor: alpha(theme.palette.primary.main, 0.1),
color: 'primary.main',
mr: 2
}}
>
{getModuleIcon(module.code)}
</Box>
<Box>
<Typography variant="h6" component="div">
{module.name}
</Typography>
<Chip
label="Active"
size="small"
color="success"
variant="outlined"
sx={{ height: 20, fontSize: '0.7rem' }}
/>
</Box>
</Box>
<Typography variant="body2" color="text.secondary">
{module.description || `Manage your ${module.name.toLowerCase()} efficiently.`}
</Typography>
</CardContent>
<CardActions sx={{ p: 2, pt: 0 }}>
<Button
size="small"
endIcon={<ArrowForwardIcon />}
onClick={(e) => {
e.stopPropagation();
handleModuleClick(module);
}}
>
Open App
</Button>
</CardActions>
</Card>
</Grid>
))}
{activeModules.length === 0 && (
<Grid size={12}>
<Paper sx={{ p: 4, textAlign: 'center', bgcolor: 'background.default', borderStyle: 'dashed' }}>
<Typography variant="h6" color="text.secondary" gutterBottom>
No active modules found
</Typography>
<Button
variant="contained"
startIcon={<SettingsIcon />}
onClick={() => openTab('/modules', t('menu.modules'))}
sx={{ mt: 2 }}
>
Go to Store
</Button>
</Paper>
</Grid>
)}
</Grid>
</Box>
);