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) - [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** - [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). - 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, Event as EventIcon,
People as PeopleIcon, People as PeopleIcon,
Place as PlaceIcon, Place as PlaceIcon,
Inventory as InventoryIcon,
Person as PersonIcon,
CalendarMonth as CalendarIcon, CalendarMonth as CalendarIcon,
Print as PrintIcon, Print as PrintIcon,
Extension as ModulesIcon, Extension as ModulesIcon,
@@ -84,15 +82,10 @@ export default function Sidebar({ onClose }: { onClose?: () => void }) {
const menuStructure: MenuItem[] = [ const menuStructure: MenuItem[] = [
{ {
id: 'core', id: 'dashboard',
label: 'Zentral', label: 'Zentral Dashboard',
icon: <DashboardIcon />, icon: <DashboardIcon />,
children: [ path: '/',
{ 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' },
],
}, },
{ {
id: 'warehouse', 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() { 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 ( return (
<Box> <Box sx={{ p: 3 }}>
<Typography variant="h4" gutterBottom> <Box sx={{ mb: 4 }}>
Dashboard <Typography variant="h3" gutterBottom sx={{ fontWeight: 'bold', color: 'primary.main' }}>
Zentral Dashboard
</Typography> </Typography>
<Typography variant="h6" color="text.secondary">
Overview of your active modules and system status
</Typography>
</Box>
<Grid container spacing={3}> <Grid container spacing={3}>
{/* System Status / Welcome Card */}
<Grid size={12}> <Grid size={12}>
<Paper sx={{ p: 2 }}> <Paper
<Typography variant="h6">Welcome to Zentral</Typography> sx={{
<Typography variant="body1"> p: 3,
Select a module from the menu to get started. 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>
<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> </Paper>
</Grid> </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> </Grid>
</Box> </Box>
); );