diff --git a/src/components/MissingDataView.tsx b/src/components/MissingDataView.tsx index 2ca8e32..7b9595e 100644 --- a/src/components/MissingDataView.tsx +++ b/src/components/MissingDataView.tsx @@ -96,6 +96,7 @@ export function MissingDataView({ data, headers, onSaveRow, onCaptureState }: Mi { col: COLUMNS.CLASSIFICATION, label: 'Classification', width: 130 }, ...(launchDateCol >= 0 ? [{ col: launchDateCol, label: launchHeader, width: 130 }] : []), ...(readyToOrderCol >= 0 ? [{ col: readyToOrderCol, label: readyHeader, width: 130 }] : []), + ...((activeTab === 'launchInconsistent' || activeTab === 'upcomingLaunch') ? [{ col: -1, label: 'Days Until Launch', width: 120 }] : []), ]; const columnUniqueValues = useMemo(() => { @@ -124,7 +125,10 @@ export function MissingDataView({ data, headers, onSaveRow, onCaptureState }: Mi }; const filteredData = useMemo(() => { - let result = data.map((row, index) => ({ row, index })); + let result = data.map((row, index) => ({ row, index, status: 'ok' as string, daysUntil: 0 })); + + const today = new Date(); + today.setHours(0, 0, 0, 0); if (activeTab === 'missingLaunch') { result = result.filter(r => { @@ -133,6 +137,60 @@ export function MissingDataView({ data, headers, onSaveRow, onCaptureState }: Mi }); } + if (activeTab === 'launchInconsistent' || activeTab === 'upcomingLaunch') { + result = result.map(r => { + const launchVal = launchDateCol >= 0 ? r.row[launchDateCol] : undefined; + const readyVal = readyToOrderCol >= 0 ? r.row[readyToOrderCol] : undefined; + const launchDate = formatDateValue(launchVal); + const readyDate = formatDateValue(readyVal); + let daysUntil = 0; + let status = 'ok'; + + if (launchDate && /^\d{4}-\d{2}-\d{2}$/.test(launchDate)) { + const launchD = new Date(launchDate); + const diffTime = launchD.getTime() - today.getTime(); + daysUntil = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); + + if (activeTab === 'launchInconsistent') { + if (readyDate && /^\d{4}-\d{2}-\d{2}$/.test(readyDate)) { + const readyD = new Date(readyDate); + if (readyD > launchD) { + status = 'error_ready_after_launch'; + } else { + status = 'ok'; + } + } else { + status = 'ok'; + } + } else if (activeTab === 'upcomingLaunch') { + if (daysUntil <= 0) { + status = 'past'; + } else if (daysUntil <= 120) { + status = 'critical'; + } else if (daysUntil <= 180) { + status = 'warning'; + } else { + status = 'ok'; + } + } + } else { + status = 'missing_launch'; + } + + return { ...r, status, daysUntil }; + }); + + if (activeTab === 'launchInconsistent') { + result = result.filter(r => + r.status === 'error_ready_after_launch' || (r.status === 'ok' && r.daysUntil > 0 && isEmptyOrEpoch(launchDateCol >= 0 ? r.row[readyToOrderCol] : undefined)) + ); + } + + if (activeTab === 'upcomingLaunch') { + result = result.filter(r => r.status === 'warning' || r.status === 'critical' || r.status === 'past'); + } + } + if (search) { const s = search.toLowerCase(); result = result.filter(r => @@ -228,6 +286,8 @@ export function MissingDataView({ data, headers, onSaveRow, onCaptureState }: Mi const tabs: { id: TabType; label: string }[] = [ { id: 'missingLaunch', label: 'Missing Launch Date' }, + { id: 'launchInconsistent', label: 'Launch Date Inconsistencies' }, + { id: 'upcomingLaunch', label: 'Upcoming Launch Date' }, ]; const editingRow = editing ? data[editing.rowIndex] : null; @@ -363,8 +423,14 @@ export function MissingDataView({ data, headers, onSaveRow, onCaptureState }: Mi
- {paginatedData.map(({ row, index }) => ( -