test: add dashboard redesign tests (refs #201)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 3m22s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 3m22s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @ai-summary Pure function to compute per-vehicle health status from maintenance and document data
|
||||
*/
|
||||
|
||||
import { MaintenanceSchedule } from '../../maintenance/types/maintenance.types';
|
||||
import { DocumentRecord } from '../../documents/types/documents.types';
|
||||
import { VehicleHealth, AttentionItem } from '../types';
|
||||
|
||||
/**
|
||||
* Compute health status and attention items for a single vehicle.
|
||||
* Pure function -- no React dependencies, easily unit-testable.
|
||||
*/
|
||||
export function computeVehicleHealth(
|
||||
schedules: MaintenanceSchedule[],
|
||||
documents: DocumentRecord[],
|
||||
): { health: VehicleHealth; attentionItems: AttentionItem[] } {
|
||||
const now = new Date();
|
||||
const items: AttentionItem[] = [];
|
||||
|
||||
// Maintenance schedule attention items
|
||||
for (const schedule of schedules) {
|
||||
if (!schedule.nextDueDate || !schedule.isActive) continue;
|
||||
const dueDate = new Date(schedule.nextDueDate);
|
||||
const daysUntil = Math.floor((dueDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
||||
const label = schedule.subtypes.length > 0
|
||||
? schedule.subtypes[0]
|
||||
: schedule.category.replace(/_/g, ' ');
|
||||
|
||||
if (daysUntil < 0) {
|
||||
items.push({ label, urgency: 'overdue', daysUntilDue: daysUntil, source: 'maintenance' });
|
||||
} else if (daysUntil <= 14) {
|
||||
items.push({ label, urgency: 'due-soon', daysUntilDue: daysUntil, source: 'maintenance' });
|
||||
} else if (daysUntil <= 30) {
|
||||
items.push({ label, urgency: 'upcoming', daysUntilDue: daysUntil, source: 'maintenance' });
|
||||
}
|
||||
}
|
||||
|
||||
// Document expiry attention items (insurance, registration)
|
||||
for (const doc of documents) {
|
||||
if (!doc.expirationDate) continue;
|
||||
const expiryDate = new Date(doc.expirationDate);
|
||||
const daysUntil = Math.floor((expiryDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
||||
const label = doc.documentType === 'insurance' ? 'Insurance' : 'Registration';
|
||||
|
||||
if (daysUntil < 0) {
|
||||
items.push({ label, urgency: 'overdue', daysUntilDue: daysUntil, source: 'document' });
|
||||
} else if (daysUntil <= 14) {
|
||||
items.push({ label, urgency: 'due-soon', daysUntilDue: daysUntil, source: 'document' });
|
||||
} else if (daysUntil <= 30) {
|
||||
items.push({ label, urgency: 'upcoming', daysUntilDue: daysUntil, source: 'document' });
|
||||
}
|
||||
}
|
||||
|
||||
// Sort: overdue first (most overdue at top), then due-soon by proximity, then upcoming
|
||||
const urgencyOrder = { overdue: 0, 'due-soon': 1, upcoming: 2 };
|
||||
items.sort((a, b) => {
|
||||
const urgencyDiff = urgencyOrder[a.urgency] - urgencyOrder[b.urgency];
|
||||
if (urgencyDiff !== 0) return urgencyDiff;
|
||||
return a.daysUntilDue - b.daysUntilDue;
|
||||
});
|
||||
|
||||
// Determine health color
|
||||
const hasOverdue = items.some(i => i.urgency === 'overdue');
|
||||
const hasDueSoon = items.some(i => i.urgency === 'due-soon');
|
||||
|
||||
let health: VehicleHealth = 'green';
|
||||
if (hasOverdue) health = 'red';
|
||||
else if (hasDueSoon) health = 'yellow';
|
||||
|
||||
return { health, attentionItems: items.slice(0, 3) };
|
||||
}
|
||||
Reference in New Issue
Block a user