import { useEffect, useState } from 'react'; import { dailyReportsClient } from '../../api/clients'; import { DAILY_REPORTS, APP_ID } from '../../api/config'; import { Card } from '../reusable/Card'; import { Spinner } from '../reusable/Spinner'; import { EmptyState } from '../reusable/EmptyState'; import { Calendar, Clock, Map, User, ClipboardList, Camera, MapPin, Hash, CheckCircle, XCircle, Activity, ArrowLeft, Mail } from 'lucide-react'; import { Button } from '../buttons/Button'; export interface DailyLogDetailProps { instanceId: number | string; refreshKey?: number; onPunchOut?: () => void; onBack?: () => void; } export function DailyLogDetail({ instanceId, refreshKey, onPunchOut, onBack }: DailyLogDetailProps) { const [data, setData] = useState | null>(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { let live = true; async function run() { setLoading(true); setError(null); try { const r = await dailyReportsClient.detailView(DAILY_REPORTS.detailViews.DAILY_LOGS, instanceId); if (live) setData(r.data || {}); } catch (e) { if (live) setError((e as { message?: string })?.message ?? 'Failed to load'); } finally { if (live) setLoading(false); } } run(); return () => { live = false; }; }, [instanceId, refreshKey]); if (error) { return ( ); } if (loading) { return (
); } if (!data || Object.keys(data).length === 0) { return ( ); } const remainingData = { ...data }; const extract = (key: string, obj: any = data) => { if (obj && key in obj) { const val = obj[key]; return val; } return null; }; // State const stateName = extract('current_state_name', remainingData) as string || '-'; const isPunchedIn = stateName.toLowerCase().includes('punched in'); // Date and Time let dateRaw = extract('date', remainingData); let timeRaw = extract('time', remainingData); let formattedDate = '-'; if (dateRaw) { formattedDate = new Date(dateRaw as string).toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); } // Format punch in text const punchInTimeText = timeRaw ? `Punch-in ${timeRaw}` : 'Punch-in time unknown'; // Route Info const routeCode = extract('route_code', remainingData) || '-'; const subRoute = extract('sub_route', remainingData) || '-'; // Notes & Details const dayPlanNotes = extract('day_plan_notes', remainingData) || '-'; const eodNotes = extract('eod_notes_remarks', remainingData) || '-'; // KPIs const prodCalls = extract('total_productive_calls', remainingData) || 0; const nonProdCalls = extract('total_non_productive_calls', remainingData) || 0; const totalCalls = Number(prodCalls) + Number(nonProdCalls); const productivity = totalCalls > 0 ? Math.round((Number(prodCalls) / totalCalls) * 100) : 0; // SO Info const soKey = Object.keys(remainingData).find(k => k.endsWith('__user_id')) || 'sales_officer_name'; const soRaw = extract(soKey, remainingData); let soName = '-'; let soEmail = '-'; let soId = '-'; if (soRaw && typeof soRaw === 'object') { soName = (soRaw as any).name || '-'; soEmail = (soRaw as any).email || '-'; soId = (soRaw as any).user_id || (soRaw as any).id || (soRaw as any).uid || '-'; } const soInitials = soName.length > 2 ? soName.substring(0, 2).toUpperCase() : 'SO'; // Meta const createdAtKey = Object.keys(remainingData).find(k => k.endsWith('__created_at')); const createdAtRaw = createdAtKey ? extract(createdAtKey, remainingData) : null; let createdAt = '-'; if (createdAtRaw) { createdAt = new Date(createdAtRaw as string).toLocaleString('en-US'); } // Image const storeImage = extract('store_image', remainingData); const imageFiles = Array.isArray(storeImage) ? storeImage : []; return (
{/* Top Header Card */}
{onBack && ( )}
Day Plan
{formattedDate}
{punchInTimeText} Route {String(routeCode)} - {String(subRoute)}
{soInitials}
{String(soName)}
Sales Officer - ID {String(soId)}
{isPunchedIn && onPunchOut && ( )}
{/* KPI Row & Progress Bar (Only show if Punched Out) */} {!isPunchedIn && ( <>
Productive Calls
{String(prodCalls)}
Non Productive
{String(nonProdCalls)}
Total Calls
{totalCalls}
Productivity
{productivity}%
Productive vs Non Productive {String(prodCalls)} / {totalCalls}
{totalCalls > 0 && ( <>
)}
)}
{/* Split Content */}
{/* Left Column */}
{/* Timeline */}
Day Timeline
{/* Punched In */}
Punched In
{formattedDate} {timeRaw ? `- ${timeRaw}` : ''}
{/* Day Plan */}
Day Plan Recorded
{String(dayPlanNotes)}
{/* EOD Submitted */}
EOD Submitted
{!isPunchedIn && (
{createdAt}
)}
{/* Notes Row */}
Day Plan Notes
{String(dayPlanNotes)}
{!isPunchedIn && (
EOD Remarks
{String(eodNotes)}
)}
{/* Route Assignment */}
Route Assignment
Route Code
{String(routeCode)}
Sub Route
{String(subRoute)}
{/* Right Column */}
{/* Store Image */}
Store Image
{imageFiles.length > 0 ? imageFiles.map((file: any, idx: number) => { const previewUrl = `${dailyReportsClient.baseUrl}/app/${APP_ID}/view/files/${file.uuid}/preview`; return (
Store
); }) : (
No image uploaded
)}
Uploaded at punch in.
{/* SO Card */}
Sales Officer
Name
{String(soName)}
Email
{String(soEmail)}
User ID
{String(soId)}
{/* Meta Card */}
Meta
Instance #{instanceId}
State {stateName}
Performed At {createdAt}
); }