Add POI feature and imporve the overall backend implementation
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
* - Trust-building (explain system reasoning)
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { RefreshCw, ExternalLink, Plus, Sparkles } from 'lucide-react';
|
||||
import { useTenant } from '../../stores/tenant.store';
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
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';
|
||||
@@ -36,11 +37,15 @@ import { ProductionTimelineCard } from '../../components/dashboard/ProductionTim
|
||||
import { InsightsGrid } from '../../components/dashboard/InsightsGrid';
|
||||
import { UnifiedAddWizard } from '../../components/domain/unified-wizard';
|
||||
import type { ItemType } from '../../components/domain/unified-wizard';
|
||||
import { useDemoTour, shouldStartTour, clearTourStartPending } from '../../features/demo-onboarding';
|
||||
import { DemoBanner } from '../../components/layout/DemoBanner/DemoBanner';
|
||||
|
||||
export function NewDashboardPage() {
|
||||
const navigate = useNavigate();
|
||||
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);
|
||||
@@ -79,6 +84,7 @@ export function NewDashboardPage() {
|
||||
|
||||
// Mutations
|
||||
const approvePO = useApprovePurchaseOrder();
|
||||
const rejectPO = useRejectPurchaseOrder();
|
||||
const startBatch = useStartProductionBatch();
|
||||
const pauseBatch = usePauseProductionBatch();
|
||||
|
||||
@@ -94,6 +100,17 @@ export function NewDashboardPage() {
|
||||
}
|
||||
};
|
||||
|
||||
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) => {
|
||||
// Navigate to appropriate detail page based on action type
|
||||
navigate(`/app/operations/procurement`);
|
||||
@@ -137,8 +154,43 @@ export function NewDashboardPage() {
|
||||
handleRefreshAll();
|
||||
};
|
||||
|
||||
// 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 (
|
||||
<div className="min-h-screen pb-20 md:pb-8" style={{ backgroundColor: 'var(--bg-secondary)' }}>
|
||||
{/* Demo Banner */}
|
||||
{isDemoMode && <DemoBanner />}
|
||||
|
||||
{/* Mobile-optimized container */}
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||
{/* Header */}
|
||||
@@ -183,30 +235,40 @@ export function NewDashboardPage() {
|
||||
{/* Main Dashboard Layout */}
|
||||
<div className="space-y-6">
|
||||
{/* SECTION 1: Bakery Health Status */}
|
||||
<HealthStatusCard healthStatus={healthStatus} loading={healthLoading} />
|
||||
<div data-tour="dashboard-stats">
|
||||
<HealthStatusCard healthStatus={healthStatus} loading={healthLoading} />
|
||||
</div>
|
||||
|
||||
{/* SECTION 2: What Needs Your Attention (Action Queue) */}
|
||||
<ActionQueueCard
|
||||
actionQueue={actionQueue}
|
||||
loading={actionQueueLoading}
|
||||
onApprove={handleApprove}
|
||||
onViewDetails={handleViewDetails}
|
||||
onModify={handleModify}
|
||||
/>
|
||||
<div data-tour="pending-po-approvals">
|
||||
<ActionQueueCard
|
||||
actionQueue={actionQueue}
|
||||
loading={actionQueueLoading}
|
||||
onApprove={handleApprove}
|
||||
onReject={handleReject}
|
||||
onViewDetails={handleViewDetails}
|
||||
onModify={handleModify}
|
||||
tenantId={tenantId}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* SECTION 3: What the System Did for You (Orchestration Summary) */}
|
||||
<OrchestrationSummaryCard
|
||||
summary={orchestrationSummary}
|
||||
loading={orchestrationLoading}
|
||||
/>
|
||||
<div data-tour="real-time-alerts">
|
||||
<OrchestrationSummaryCard
|
||||
summary={orchestrationSummary}
|
||||
loading={orchestrationLoading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* SECTION 4: Today's Production Timeline */}
|
||||
<ProductionTimelineCard
|
||||
timeline={productionTimeline}
|
||||
loading={timelineLoading}
|
||||
onStart={handleStartBatch}
|
||||
onPause={handlePauseBatch}
|
||||
/>
|
||||
<div data-tour="today-production">
|
||||
<ProductionTimelineCard
|
||||
timeline={productionTimeline}
|
||||
loading={timelineLoading}
|
||||
onStart={handleStartBatch}
|
||||
onPause={handlePauseBatch}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* SECTION 5: Quick Insights Grid */}
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user