// ================================================================ // frontend/src/pages/app/NewDashboardPage.tsx // ================================================================ /** * JTBD-Aligned Dashboard Page * * Complete redesign based on Jobs To Be Done methodology. * Focused on answering: "What requires my attention right now?" * * Key principles: * - Automation-first (show what system did) * - Action-oriented (prioritize tasks) * - Progressive disclosure (show 20% that matters 80%) * - Mobile-first (one-handed operation) * - Trust-building (explain system reasoning) */ import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { RefreshCw, ExternalLink, Plus, Sparkles } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { useTenant } from '../../stores/tenant.store'; import { useBakeryHealthStatus, useOrchestrationSummary, useActionQueue, useProductionTimeline, useInsights, useApprovePurchaseOrder, useStartProductionBatch, usePauseProductionBatch, } from '../../api/hooks/newDashboard'; import { useRejectPurchaseOrder } from '../../api/hooks/purchase-orders'; import { HealthStatusCard } from '../../components/dashboard/HealthStatusCard'; import { ActionQueueCard } from '../../components/dashboard/ActionQueueCard'; import { OrchestrationSummaryCard } from '../../components/dashboard/OrchestrationSummaryCard'; import { ProductionTimelineCard } from '../../components/dashboard/ProductionTimelineCard'; import { InsightsGrid } from '../../components/dashboard/InsightsGrid'; import { PurchaseOrderDetailsModal } from '../../components/dashboard/PurchaseOrderDetailsModal'; import { UnifiedAddWizard } from '../../components/domain/unified-wizard'; import type { ItemType } from '../../components/domain/unified-wizard'; import { useDemoTour, shouldStartTour, clearTourStartPending } from '../../features/demo-onboarding'; export function NewDashboardPage() { const navigate = useNavigate(); const { t } = useTranslation(['dashboard', 'common']); const { currentTenant } = useTenant(); const tenantId = currentTenant?.id || ''; const { startTour } = useDemoTour(); const isDemoMode = localStorage.getItem('demo_mode') === 'true'; // Unified Add Wizard state const [isAddWizardOpen, setIsAddWizardOpen] = useState(false); const [addWizardError, setAddWizardError] = useState(null); // PO Details Modal state const [selectedPOId, setSelectedPOId] = useState(null); const [isPOModalOpen, setIsPOModalOpen] = useState(false); // Data fetching const { data: healthStatus, isLoading: healthLoading, refetch: refetchHealth, } = useBakeryHealthStatus(tenantId); const { data: orchestrationSummary, isLoading: orchestrationLoading, refetch: refetchOrchestration, } = useOrchestrationSummary(tenantId); const { data: actionQueue, isLoading: actionQueueLoading, refetch: refetchActionQueue, } = useActionQueue(tenantId); const { data: productionTimeline, isLoading: timelineLoading, refetch: refetchTimeline, } = useProductionTimeline(tenantId); const { data: insights, isLoading: insightsLoading, refetch: refetchInsights, } = useInsights(tenantId); // Mutations const approvePO = useApprovePurchaseOrder(); const rejectPO = useRejectPurchaseOrder(); const startBatch = useStartProductionBatch(); const pauseBatch = usePauseProductionBatch(); // Handlers const handleApprove = async (actionId: string) => { try { await approvePO.mutateAsync({ tenantId, poId: actionId }); // Refetch to update UI refetchActionQueue(); refetchHealth(); } catch (error) { console.error('Error approving PO:', error); } }; const handleReject = async (actionId: string, reason: string) => { try { await rejectPO.mutateAsync({ tenantId, poId: actionId, reason }); // Refetch to update UI refetchActionQueue(); refetchHealth(); } catch (error) { console.error('Error rejecting PO:', error); } }; const handleViewDetails = (actionId: string) => { // Open modal to show PO details setSelectedPOId(actionId); setIsPOModalOpen(true); }; const handleModify = (actionId: string) => { // Navigate to procurement page for modification navigate(`/app/operations/procurement`); }; const handleStartBatch = async (batchId: string) => { try { await startBatch.mutateAsync({ tenantId, batchId }); refetchTimeline(); refetchHealth(); } catch (error) { console.error('Error starting batch:', error); } }; const handlePauseBatch = async (batchId: string) => { try { await pauseBatch.mutateAsync({ tenantId, batchId }); refetchTimeline(); refetchHealth(); } catch (error) { console.error('Error pausing batch:', error); } }; const handleRefreshAll = () => { refetchHealth(); refetchOrchestration(); refetchActionQueue(); refetchTimeline(); refetchInsights(); }; const handleAddWizardComplete = (itemType: ItemType, data?: any) => { console.log('Item created:', itemType, data); // Refetch relevant data based on what was added handleRefreshAll(); }; // Keyboard shortcut for Quick Add (Cmd/Ctrl + K) useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { // Check for Cmd+K (Mac) or Ctrl+K (Windows/Linux) if ((event.metaKey || event.ctrlKey) && event.key === 'k') { event.preventDefault(); setIsAddWizardOpen(true); } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, []); // Demo tour auto-start logic useEffect(() => { console.log('[Dashboard] Demo mode:', isDemoMode); console.log('[Dashboard] Should start tour:', shouldStartTour()); console.log('[Dashboard] SessionStorage demo_tour_should_start:', sessionStorage.getItem('demo_tour_should_start')); console.log('[Dashboard] SessionStorage demo_tour_start_step:', sessionStorage.getItem('demo_tour_start_step')); // Check if there's a tour intent from redirection (higher priority) const shouldStartFromRedirect = sessionStorage.getItem('demo_tour_should_start') === 'true'; const redirectStartStep = parseInt(sessionStorage.getItem('demo_tour_start_step') || '0', 10); if (isDemoMode && (shouldStartTour() || shouldStartFromRedirect)) { console.log('[Dashboard] Starting tour in 1.5s...'); const timer = setTimeout(() => { console.log('[Dashboard] Executing startTour()'); if (shouldStartFromRedirect) { // Start tour from the specific step that was intended startTour(redirectStartStep); // Clear the redirect intent sessionStorage.removeItem('demo_tour_should_start'); sessionStorage.removeItem('demo_tour_start_step'); } else { // Start tour normally (from beginning or resume) startTour(); clearTourStartPending(); } }, 1500); return () => clearTimeout(timer); } }, [isDemoMode, startTour]); return (
{/* Mobile-optimized container */}
{/* Header */}

{t('dashboard:title')}

{t('dashboard:subtitle')}

{/* Action Buttons */}
{/* Unified Add Button with Keyboard Shortcut */}
{/* Main Dashboard Layout */}
{/* SECTION 1: Bakery Health Status */}
{/* SECTION 2: What Needs Your Attention (Action Queue) */}
{/* SECTION 3: What the System Did for You (Orchestration Summary) */}
{/* SECTION 4: Today's Production Timeline */}
{/* SECTION 5: Quick Insights Grid */}

{t('dashboard:sections.key_metrics')}

{/* SECTION 6: Quick Action Links */}

{t('dashboard:sections.quick_actions')}

{/* Mobile-friendly bottom padding */}
{/* Unified Add Wizard */} setIsAddWizardOpen(false)} onComplete={handleAddWizardComplete} /> {/* Purchase Order Details Modal */} {selectedPOId && ( { setIsPOModalOpen(false); setSelectedPOId(null); }} onApprove={handleApprove} onModify={handleModify} /> )}
); } export default NewDashboardPage;