diff --git a/frontend/src/components/ui/StatusCard/StatusCard.tsx b/frontend/src/components/ui/StatusCard/StatusCard.tsx index 5769e3d2..bcbae11e 100644 --- a/frontend/src/components/ui/StatusCard/StatusCard.tsx +++ b/frontend/src/components/ui/StatusCard/StatusCard.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { LucideIcon } from 'lucide-react'; import { Card } from '../Card'; -import { Button } from '../Button'; import { ProgressBar } from '../ProgressBar'; import { statusColors } from '../../../styles/colors'; import { TextOverflowPrevention, overflowClasses, getScreenSize, safeText } from '../../../utils/textUtils'; @@ -121,12 +120,12 @@ export const StatusCard: React.FC = ({ return ( = ({ }} onClick={onClick} > -
+
{/* Header with status indicator */} -
-
+
+
{StatusIcon && ( )}
{truncationEngine.title(title)}
{subtitle && (
{truncationEngine.subtitle(subtitle)} @@ -175,13 +174,13 @@ export const StatusCard: React.FC = ({ )}
= ({
-
+
- {safeText(primaryValue?.toString(), '0', isMobile ? 12 : 18)} + {safeText(primaryValue?.toString(), '0', isMobile ? 10 : 18)}
{primaryValueLabel && (
{truncationEngine.primaryValueLabel(primaryValueLabel)} @@ -228,9 +227,9 @@ export const StatusCard: React.FC = ({ {/* Secondary info - Mobile optimized */} {secondaryInfo && ( -
+
{truncationEngine.secondaryLabel(secondaryInfo.label)} @@ -246,7 +245,7 @@ export const StatusCard: React.FC = ({ {/* Progress indicator */} {progress && ( -
+
= ({ {/* Metadata - Improved mobile layout with overflow prevention */} {metadata.length > 0 && ( -
- {metadata.slice(0, isMobile ? 3 : 4).map((item, index) => ( +
+ {metadata.slice(0, isMobile ? 2 : 4).map((item, index) => (
{truncationEngine.metadataItem(item)}
))} - {metadata.length > (isMobile ? 3 : 4) && ( -
- +{metadata.length - (isMobile ? 3 : 4)} más... + {metadata.length > (isMobile ? 2 : 4) && ( +
+ +{metadata.length - (isMobile ? 2 : 4)} más...
)}
@@ -285,9 +284,9 @@ export const StatusCard: React.FC = ({ {/* Simplified Action System - Mobile optimized */} {actions.length > 0 && ( -
+
{/* All actions in a clean horizontal layout */} -
+
{/* Primary action as a subtle text button */} {primaryActions.length > 0 && ( @@ -300,8 +299,8 @@ export const StatusCard: React.FC = ({ }} disabled={primaryActions[0].disabled} className={` - flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-lg - transition-all duration-200 hover:scale-105 active:scale-95 flex-shrink-0 max-w-[140px] sm:max-w-[160px] + flex items-center gap-1.5 sm:gap-2 px-2 py-1.5 sm:px-3 sm:py-2 text-xs sm:text-sm font-medium rounded-lg + transition-all duration-200 hover:scale-105 active:scale-95 flex-shrink-0 max-w-[120px] sm:max-w-[160px] ${primaryActions[0].disabled ? 'opacity-50 cursor-not-allowed' : primaryActions[0].destructive @@ -311,7 +310,7 @@ export const StatusCard: React.FC = ({ `} title={primaryActions[0].label} > - {primaryActions[0].icon && React.createElement(primaryActions[0].icon, { className: "w-4 h-4 flex-shrink-0" })} + {primaryActions[0].icon && React.createElement(primaryActions[0].icon, { className: "w-3.5 h-3.5 sm:w-4 sm:h-4 flex-shrink-0" })} {truncationEngine.actionLabel(primaryActions[0].label)} @@ -319,7 +318,7 @@ export const StatusCard: React.FC = ({ )} {/* Action icons for secondary actions */} -
+
{secondaryActions.map((action, index) => ( ))} @@ -360,7 +359,7 @@ export const StatusCard: React.FC = ({ disabled={action.disabled} title={action.label} className={` - p-2 rounded-lg transition-all duration-200 hover:scale-110 active:scale-95 hover:shadow-sm + p-1.5 sm:p-2 rounded-lg transition-all duration-200 hover:scale-110 active:scale-95 hover:shadow-sm ${action.disabled ? 'opacity-50 cursor-not-allowed' : action.destructive @@ -369,7 +368,7 @@ export const StatusCard: React.FC = ({ } `} > - {action.icon && React.createElement(action.icon, { className: "w-4 h-4" })} + {action.icon && React.createElement(action.icon, { className: "w-3.5 h-3.5 sm:w-4 sm:h-4" })} ))}
diff --git a/frontend/src/locales/en/dashboard.json b/frontend/src/locales/en/dashboard.json index 2a7b1495..0d9329f3 100644 --- a/frontend/src/locales/en/dashboard.json +++ b/frontend/src/locales/en/dashboard.json @@ -102,7 +102,12 @@ "quality_checks": "Quality Checks", "manage_quality": "Manage quality control processes", "quality_management": "Quality Management", - "event_message": "Message" + "event_message": "Message", + "batches_today": "batches today", + "batches_late": "late", + "late_to_start": "Late to Start", + "running": "Currently Running", + "pending_today": "Pending Today" }, "po_approvals": { "title": "What purchase orders need approval?", diff --git a/frontend/src/locales/es/dashboard.json b/frontend/src/locales/es/dashboard.json index 0fc23dda..d0ffcdf5 100644 --- a/frontend/src/locales/es/dashboard.json +++ b/frontend/src/locales/es/dashboard.json @@ -102,7 +102,12 @@ "quality_checks": "Controles de Calidad", "manage_quality": "Gestionar procesos de control de calidad", "quality_management": "Gestión de Calidad", - "event_message": "Mensaje" + "event_message": "Mensaje", + "batches_today": "lotes hoy", + "batches_late": "atrasado", + "late_to_start": "Atrasados para Empezar", + "running": "En Ejecución", + "pending_today": "Pendientes Hoy" }, "po_approvals": { "title": "¿Qué órdenes debo aprobar?", diff --git a/frontend/src/locales/eu/dashboard.json b/frontend/src/locales/eu/dashboard.json index b4206dbb..da067058 100644 --- a/frontend/src/locales/eu/dashboard.json +++ b/frontend/src/locales/eu/dashboard.json @@ -69,9 +69,43 @@ "items_needed": "elementu behar dira" }, "production": { - "title": "Zer ekoiztu behar da gaur?", + "title": "Ekoizpen Egoera", "empty": "Ez dago ekoizpen programaturik gaur", - "batches_pending": "sortak zain" + "batches_pending": "sortak zain", + "equipment_status": "Ekipamenduaren Egoera", + "temperature": "Tenperatura", + "utilization": "Erabilera", + "next_maintenance": "Hurrengo Mantentze-Lanak", + "last_maintenance": "Azken Mantentze-Lanak", + "view_details": "Xehetasunak Ikusi", + "status_critical": "Kritikoa", + "status_warning": "Abisua", + "status_normal": "Normala", + "no_equipment": "Ez dago ekipamendurik erabilgarri", + "efficiency_metrics": "Ekoizpen Eraginkortasunaren Metrikak", + "on_time_start_rate": "Denboraren Arabera Hasieraren Tasa", + "batches_started_on_time": "Denboraren arabera hasitako sortak", + "efficiency_rate": "Eraginkortasun Tasa", + "overall_efficiency": "Ekoizpen eraginkortasun orokorra", + "active_alerts": "Alerta Aktiboak", + "issues_require_attention": "Arreta behar duten arazoak", + "ai_prevented": "ADk Saihestutako Arazoak", + "problems_prevented": "ADk saihestutako arazoak", + "quick_actions": "Ekintza Azkarrak", + "create_batch": "Sortu Ekoizpen Sorta", + "create_batch_description": "Sortu ekoizpen sorta berria sarearentzat", + "maintenance": "Ekipamenduen Mantentze-Lanak", + "schedule_maintenance": "Programatu mantentze-lanak ekoizpen ekipamendurako", + "manage_equipment": "Kudeatu Ekipamendua", + "quality_checks": "Kalitate Egiaztapenak", + "manage_quality": "Kudeatu kalitate kontrol prozesuak", + "quality_management": "Kalitate Kudeaketa", + "event_message": "Mezua", + "batches_today": "lote gaur", + "batches_late": "atzeratuta", + "late_to_start": "Hasteko Atzeratua", + "running": "Martxan", + "pending_today": "Gaur Zain" }, "po_approvals": { "title": "Zein erosketa agindu onartu behar ditut?", diff --git a/frontend/src/pages/app/EnterpriseDashboardPage.tsx b/frontend/src/pages/app/EnterpriseDashboardPage.tsx index 7968586f..014ae693 100644 --- a/frontend/src/pages/app/EnterpriseDashboardPage.tsx +++ b/frontend/src/pages/app/EnterpriseDashboardPage.tsx @@ -247,17 +247,21 @@ const EnterpriseDashboardPage: React.FC = ({ tenan // Error boundary fallback const ErrorFallback = ({ error, resetErrorBoundary }: { error: Error; resetErrorBoundary: () => void }) => ( -
- -

Something went wrong

-

{error.message}

- +
+ + + +

Something went wrong

+

{error.message}

+ +
+
); if (isNetworkSummaryLoading || isChildrenPerformanceLoading || isDistributionLoading || isForecastLoading) { return ( -
+
@@ -267,69 +271,67 @@ const EnterpriseDashboardPage: React.FC = ({ tenan if (networkSummaryError || childrenPerformanceError || distributionError || forecastError) { return ( -
-
- -

Error Loading Dashboard

-

- {networkSummaryError?.message || - childrenPerformanceError?.message || - distributionError?.message || - forecastError?.message} -

-
+
+ + + +

Error Loading Dashboard

+

+ {networkSummaryError?.message || + childrenPerformanceError?.message || + distributionError?.message || + forecastError?.message} +

+
+
); } return ( -
+
{/* Breadcrumb / Return to Network Banner */} {enterpriseState.selectedOutletId && !enterpriseState.isNetworkView && ( -
-
-
- -
- Network Overview - - {enterpriseState.selectedOutletName} + + +
+
+ +
+ Network Overview + + {enterpriseState.selectedOutletName} +
+
- -
- {enterpriseState.networkMetrics && ( -
-
- Network Average Sales: - {currencySymbol}{enterpriseState.networkMetrics.averageSales.toLocaleString()} + {enterpriseState.networkMetrics && ( +
+
+ Network Average Sales: + {currencySymbol}{enterpriseState.networkMetrics.averageSales.toLocaleString()} +
+
+ Total Outlets: + {enterpriseState.networkMetrics.childCount} +
+
+ Network Total: + {currencySymbol}{enterpriseState.networkMetrics.totalSales.toLocaleString()} +
-
- Total Outlets: - {enterpriseState.networkMetrics.childCount} -
-
- Network Total: - {currencySymbol}{enterpriseState.networkMetrics.totalSales.toLocaleString()} -
-
- )} -
+ )} + + )} {/* Enhanced Header */} @@ -423,22 +425,22 @@ const EnterpriseDashboardPage: React.FC = ({ tenan {forecastSummary && forecastSummary.aggregated_forecasts ? ( -
+
{/* Total Demand Card */} - +
- +
-

+

{t('enterprise.total_demand')}

-

+

{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 = ({ tenan {/* Days Forecast Card */} - +

- +
-

+

{t('enterprise.days_forecast')}

-

+

{forecastSummary.days_forecast || 7}

{/* Average Daily Demand Card */} - +
- +
-

+

{t('enterprise.avg_daily_demand')}

-

+

{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 = ({ tenan {/* Last Updated Card */} - +

- +
-

+

{t('enterprise.last_updated')}

-

+

{forecastSummary.last_updated ? new Date(forecastSummary.last_updated).toLocaleTimeString() : 'N/A'}