Imporve the UI 4

This commit is contained in:
Urtzi Alfaro
2026-01-02 22:03:25 +01:00
parent b91979b840
commit db12c57b0b
5 changed files with 164 additions and 119 deletions

View File

@@ -247,17 +247,21 @@ const EnterpriseDashboardPage: React.FC<EnterpriseDashboardPageProps> = ({ tenan
// Error boundary fallback
const ErrorFallback = ({ error, resetErrorBoundary }: { error: Error; resetErrorBoundary: () => void }) => (
<div className="p-6 text-center">
<AlertTriangle className="mx-auto h-12 w-12 text-red-500 mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2">Something went wrong</h3>
<p className="text-gray-500 mb-4">{error.message}</p>
<Button onClick={resetErrorBoundary}>Try again</Button>
<div className="px-4 sm:px-6 lg:px-8 py-6">
<Card className="border-[var(--color-error)] bg-[var(--color-error-50)]">
<CardContent className="p-6 text-center">
<AlertTriangle className="mx-auto h-12 w-12 text-[var(--color-error)] mb-4" />
<h3 className="text-lg font-medium text-[var(--text-primary)] mb-2">Something went wrong</h3>
<p className="text-[var(--text-secondary)] mb-4">{error.message}</p>
<Button onClick={resetErrorBoundary} variant="primary">Try again</Button>
</CardContent>
</Card>
</div>
);
if (isNetworkSummaryLoading || isChildrenPerformanceLoading || isDistributionLoading || isForecastLoading) {
return (
<div className="p-6 min-h-screen">
<div className="px-4 sm:px-6 lg:px-8 py-6 min-h-screen">
<div className="flex items-center justify-center h-96">
<LoadingSpinner text={t('enterprise.loading')} />
</div>
@@ -267,69 +271,67 @@ const EnterpriseDashboardPage: React.FC<EnterpriseDashboardPageProps> = ({ tenan
if (networkSummaryError || childrenPerformanceError || distributionError || forecastError) {
return (
<div className="p-6 min-h-screen">
<div className="bg-red-50 border border-red-200 rounded-lg p-6 text-center">
<AlertTriangle className="mx-auto h-12 w-12 text-red-500 mb-4" />
<h3 className="text-lg font-medium text-red-800 mb-2">Error Loading Dashboard</h3>
<p className="text-red-600">
{networkSummaryError?.message ||
childrenPerformanceError?.message ||
distributionError?.message ||
forecastError?.message}
</p>
</div>
<div className="px-4 sm:px-6 lg:px-8 py-6 min-h-screen">
<Card className="border-[var(--color-error)] bg-[var(--color-error-50)]">
<CardContent className="p-6 text-center">
<AlertTriangle className="mx-auto h-12 w-12 text-[var(--color-error)] mb-4" />
<h3 className="text-lg font-medium text-[var(--text-primary)] mb-2">Error Loading Dashboard</h3>
<p className="text-[var(--text-secondary)]">
{networkSummaryError?.message ||
childrenPerformanceError?.message ||
distributionError?.message ||
forecastError?.message}
</p>
</CardContent>
</Card>
</div>
);
}
return (
<ErrorBoundary FallbackComponent={ErrorFallback}>
<div className="px-4 sm:px-6 lg:px-8 py-6 min-h-screen bg-[var(--bg-secondary)]">
<div className="px-4 sm:px-6 lg:px-8 py-6 min-h-screen">
{/* Breadcrumb / Return to Network Banner */}
{enterpriseState.selectedOutletId && !enterpriseState.isNetworkView && (
<div
className="mb-6 rounded-lg p-4 border border-[var(--border-primary)]"
style={{
backgroundColor: 'var(--color-info-50)',
}}
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<Network className="w-5 h-5 text-[var(--color-info)]" />
<div className="flex items-center gap-2 text-sm">
<span className="font-medium text-[var(--color-info)]">Network Overview</span>
<ChevronRight className="w-4 h-4 text-[var(--color-info-300)]" />
<span className="text-[var(--text-primary)] font-semibold">{enterpriseState.selectedOutletName}</span>
<Card className="mb-6 border-2 border-[var(--color-info)] bg-[var(--color-info-50)]">
<CardContent className="p-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<Network className="w-5 h-5 text-[var(--color-info)]" />
<div className="flex items-center gap-2 text-sm">
<span className="font-medium text-[var(--color-info)]">Network Overview</span>
<ChevronRight className="w-4 h-4 text-[var(--color-info-300)]" />
<span className="text-[var(--text-primary)] font-semibold">{enterpriseState.selectedOutletName}</span>
</div>
</div>
<Button
onClick={handleReturnToNetwork}
variant="outline"
size="sm"
className="flex items-center gap-2"
>
<ArrowLeft className="w-4 h-4" />
Return to Network View
</Button>
</div>
<Button
onClick={handleReturnToNetwork}
variant="outline"
size="sm"
className="flex items-center gap-2"
>
<ArrowLeft className="w-4 h-4" />
Return to Network View
</Button>
</div>
{enterpriseState.networkMetrics && (
<div className="mt-3 pt-3 border-t grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 text-sm"
style={{ borderColor: 'var(--border-primary)' }}>
<div>
<span className="text-[var(--color-info)]">Network Average Sales:</span>
<span className="ml-2 font-semibold text-[var(--text-primary)]">{currencySymbol}{enterpriseState.networkMetrics.averageSales.toLocaleString()}</span>
{enterpriseState.networkMetrics && (
<div className="mt-3 pt-3 border-t border-[var(--border-primary)] grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 text-sm">
<div>
<span className="text-[var(--color-info)]">Network Average Sales:</span>
<span className="ml-2 font-semibold text-[var(--text-primary)]">{currencySymbol}{enterpriseState.networkMetrics.averageSales.toLocaleString()}</span>
</div>
<div>
<span className="text-[var(--color-info)]">Total Outlets:</span>
<span className="ml-2 font-semibold text-[var(--text-primary)]">{enterpriseState.networkMetrics.childCount}</span>
</div>
<div>
<span className="text-[var(--color-info)]">Network Total:</span>
<span className="ml-2 font-semibold text-[var(--text-primary)]">{currencySymbol}{enterpriseState.networkMetrics.totalSales.toLocaleString()}</span>
</div>
</div>
<div>
<span className="text-[var(--color-info)]">Total Outlets:</span>
<span className="ml-2 font-semibold text-[var(--text-primary)]">{enterpriseState.networkMetrics.childCount}</span>
</div>
<div>
<span className="text-[var(--color-info)]">Network Total:</span>
<span className="ml-2 font-semibold text-[var(--text-primary)]">{currencySymbol}{enterpriseState.networkMetrics.totalSales.toLocaleString()}</span>
</div>
</div>
)}
</div>
)}
</CardContent>
</Card>
)}
{/* Enhanced Header */}
@@ -423,22 +425,22 @@ const EnterpriseDashboardPage: React.FC<EnterpriseDashboardPageProps> = ({ tenan
</CardHeader>
<CardContent>
{forecastSummary && forecastSummary.aggregated_forecasts ? (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{/* Total Demand Card */}
<Card className="hover:shadow-lg transition-shadow duration-300">
<Card className="hover:shadow-xl hover:-translate-y-1 transition-all duration-300 border-[var(--border-primary)]">
<CardContent className="p-6">
<div className="flex items-center gap-3 mb-3">
<div
className="w-10 h-10 rounded-lg flex items-center justify-center shadow-md"
className="w-12 h-12 rounded-xl flex items-center justify-center"
style={{ backgroundColor: 'var(--color-info-100)' }}
>
<Package className="w-5 h-5" style={{ color: 'var(--color-info-600)' }} />
<Package className="w-6 h-6" style={{ color: 'var(--color-info)' }} />
</div>
<h3 className="font-semibold text-sm" style={{ color: 'var(--color-info-800)' }}>
<h3 className="font-semibold text-sm text-[var(--text-secondary)]">
{t('enterprise.total_demand')}
</h3>
</div>
<p className="text-3xl font-bold" style={{ color: 'var(--color-info-900)' }}>
<p className="text-3xl font-bold text-[var(--text-primary)]">
{Object.values(forecastSummary.aggregated_forecasts).reduce((total: number, day: any) =>
total + Object.values(day).reduce((dayTotal: number, product: any) =>
dayTotal + (product.predicted_demand || 0), 0), 0
@@ -448,40 +450,40 @@ const EnterpriseDashboardPage: React.FC<EnterpriseDashboardPageProps> = ({ tenan
</Card>
{/* Days Forecast Card */}
<Card className="hover:shadow-lg transition-shadow duration-300">
<Card className="hover:shadow-xl hover:-translate-y-1 transition-all duration-300 border-[var(--border-primary)]">
<CardContent className="p-6">
<div className="flex items-center gap-3 mb-3">
<div
className="w-10 h-10 rounded-lg flex items-center justify-center shadow-md"
className="w-12 h-12 rounded-xl flex items-center justify-center"
style={{ backgroundColor: 'var(--color-success-100)' }}
>
<Calendar className="w-5 h-5" style={{ color: 'var(--color-success-600)' }} />
<Calendar className="w-6 h-6" style={{ color: 'var(--color-success)' }} />
</div>
<h3 className="font-semibold text-sm" style={{ color: 'var(--color-success-800)' }}>
<h3 className="font-semibold text-sm text-[var(--text-secondary)]">
{t('enterprise.days_forecast')}
</h3>
</div>
<p className="text-3xl font-bold" style={{ color: 'var(--color-success-900)' }}>
<p className="text-3xl font-bold text-[var(--text-primary)]">
{forecastSummary.days_forecast || 7}
</p>
</CardContent>
</Card>
{/* Average Daily Demand Card */}
<Card className="hover:shadow-lg transition-shadow duration-300">
<Card className="hover:shadow-xl hover:-translate-y-1 transition-all duration-300 border-[var(--border-primary)]">
<CardContent className="p-6">
<div className="flex items-center gap-3 mb-3">
<div
className="w-10 h-10 rounded-lg flex items-center justify-center shadow-md"
className="w-12 h-12 rounded-xl flex items-center justify-center"
style={{ backgroundColor: 'var(--color-secondary-100)' }}
>
<Activity className="w-5 h-5" style={{ color: 'var(--color-secondary-600)' }} />
<Activity className="w-6 h-6" style={{ color: 'var(--color-secondary)' }} />
</div>
<h3 className="font-semibold text-sm" style={{ color: 'var(--color-secondary-800)' }}>
<h3 className="font-semibold text-sm text-[var(--text-secondary)]">
{t('enterprise.avg_daily_demand')}
</h3>
</div>
<p className="text-3xl font-bold" style={{ color: 'var(--color-secondary-900)' }}>
<p className="text-3xl font-bold text-[var(--text-primary)]">
{forecastSummary.aggregated_forecasts
? Math.round(Object.values(forecastSummary.aggregated_forecasts).reduce((total: number, day: any) =>
total + Object.values(day).reduce((dayTotal: number, product: any) =>
@@ -494,20 +496,20 @@ const EnterpriseDashboardPage: React.FC<EnterpriseDashboardPageProps> = ({ tenan
</Card>
{/* Last Updated Card */}
<Card className="hover:shadow-lg transition-shadow duration-300">
<Card className="hover:shadow-xl hover:-translate-y-1 transition-all duration-300 border-[var(--border-primary)]">
<CardContent className="p-6">
<div className="flex items-center gap-3 mb-3">
<div
className="w-10 h-10 rounded-lg flex items-center justify-center shadow-md"
className="w-12 h-12 rounded-xl flex items-center justify-center"
style={{ backgroundColor: 'var(--color-warning-100)' }}
>
<Clock className="w-5 h-5" style={{ color: 'var(--color-warning-600)' }} />
<Clock className="w-6 h-6" style={{ color: 'var(--color-warning)' }} />
</div>
<h3 className="font-semibold text-sm" style={{ color: 'var(--color-warning-800)' }}>
<h3 className="font-semibold text-sm text-[var(--text-secondary)]">
{t('enterprise.last_updated')}
</h3>
</div>
<p className="text-lg font-semibold" style={{ color: 'var(--color-warning-900)' }}>
<p className="text-lg font-semibold text-[var(--text-primary)]">
{forecastSummary.last_updated ?
new Date(forecastSummary.last_updated).toLocaleTimeString() :
'N/A'}