github-actions[bot]
chore: sync uc-deliveries Space
f6213fc
import { formatClock, kindLabel, toneForKind } from './formatters.mjs';
export function buildVehicleTimelineModel(preview) {
const axis = buildAxis(preview);
return {
axis,
lanes: (preview?.vehicles || []).map((vehicle) => ({
id: `vehicle-${vehicle.vehicleId}`,
label: vehicle.vehicleName,
mode: 'detailed',
badges: [
`${vehicle.stopCount} stops`,
`${vehicle.totalDemand}/${vehicle.totalDemand - vehicle.capacityOverage + vehicle.capacityOverage || vehicle.totalDemand}`,
],
items: vehicle.stops.map((stop) => ({
id: `vehicle-${vehicle.vehicleId}-stop-${stop.deliveryId}`,
startMinute: Math.floor(stop.serviceStartTime / 60),
endMinute: Math.ceil(stop.departureTime / 60),
label: stop.label,
meta: `${kindLabel(stop.kind)}${formatClock(stop.arrivalTime)} arrival`,
tone: toneForKind(stop.kind),
})),
})),
};
}
export function buildDeliveryTimelineModel(preview) {
const axis = buildAxis(preview);
return {
axis,
lanes: (preview?.deliveries || []).map((delivery) => {
const items = [
{
id: `delivery-window-${delivery.deliveryId}`,
startMinute: Math.floor(delivery.minStartTime / 60),
endMinute: Math.ceil(delivery.maxEndTime / 60),
label: 'Window',
meta: `${formatClock(delivery.minStartTime)} to ${formatClock(delivery.maxEndTime)}`,
tone: 'slate',
},
];
if (delivery.serviceStartTime != null && delivery.departureTime != null) {
items.push({
id: `delivery-service-${delivery.deliveryId}`,
startMinute: Math.floor(delivery.serviceStartTime / 60),
endMinute: Math.ceil(delivery.departureTime / 60),
label: delivery.assignedVehicleName || 'Assigned',
meta: `${delivery.label}${kindLabel(delivery.kind)}`,
tone: toneForKind(delivery.kind),
});
}
return {
id: `delivery-${delivery.deliveryId}`,
label: delivery.label,
mode: 'detailed',
badges: [kindLabel(delivery.kind), delivery.assignedVehicleName || 'Unassigned'],
items,
};
}),
};
}
function buildAxis(preview) {
let minMinute = 6 * 60;
let maxMinute = 21 * 60;
const previewData = preview || { deliveries: [], vehicles: [] };
for (const delivery of previewData.deliveries || []) {
minMinute = Math.min(minMinute, Math.floor((delivery.minStartTime || 0) / 60) - 30);
maxMinute = Math.max(maxMinute, Math.ceil((delivery.maxEndTime || 0) / 60) + 30);
}
for (const vehicle of previewData.vehicles || []) {
minMinute = Math.min(minMinute, Math.floor((vehicle.startTime || 0) / 60) - 15);
maxMinute = Math.max(maxMinute, Math.ceil((vehicle.endTime || 0) / 60) + 15);
}
minMinute = Math.max(0, minMinute);
maxMinute = Math.min(24 * 60, Math.max(minMinute + 120, maxMinute));
const ticks = [];
for (let minute = minMinute; minute <= maxMinute; minute += 60) {
ticks.push({ minute, label: formatClock(minute * 60) });
}
return {
startMinute: minMinute,
endMinute: maxMinute,
days: [{ dayIndex: 0, label: 'Day 1' }],
ticks,
initialViewport: { startMinute: minMinute, endMinute: maxMinute },
};
}