fix: prikaži sve povezane dizalice i SN u tablici putnih naloga

Kada putni nalog dijele taskovi više dizalica, stupci DIZALICA i SN
u tablici Putni nalozi dizalica prikazuju sve uključene dizalice
odvojene s ' • ' umjesto samo one za koju je WO kreiran.

- Dodana workOrderSharedCranes mapa (workOrderId -> {vehicleId -> crane})
  izgrađena iz task.work_order + task.vehicle veza
- Render stupaca DIZALICA i SN koristi mapu ako postoje shared cranes,
  inače fallback na craneInfo s originalnog WO-a

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
mariomitte
2026-08-01 08:27:54 +02:00
parent 79145c58e4
commit 2a9cac0c81

View File

@@ -442,6 +442,20 @@ export default function FleetDashboardShell({ initialSection = 'dashboard', page
() => scopedWorkOrders.slice((currentPage - 1) * pageSize, currentPage * pageSize), () => scopedWorkOrders.slice((currentPage - 1) * pageSize, currentPage * pageSize),
[scopedWorkOrders, currentPage] [scopedWorkOrders, currentPage]
); );
// Map: workOrderId → array of unique crane objects (own + cross-crane task links)
const workOrderSharedCranes = useMemo(() => {
const craneById = new Map(cranes.map((c) => [String(c.id), c]));
const map = new Map();
tasks.forEach((task) => {
if (!task.work_order || !task.vehicle) return;
const woId = String(task.work_order);
if (!map.has(woId)) map.set(woId, new Map());
const craneObj = craneById.get(String(task.vehicle));
if (craneObj) map.get(woId).set(String(task.vehicle), craneObj);
});
return map;
}, [tasks, cranes]);
const serviceRecordWorkOrders = useMemo(() => { const serviceRecordWorkOrders = useMemo(() => {
// Show ALL open work orders so a task can be linked to any work order regardless of crane. // Show ALL open work orders so a task can be linked to any work order regardless of crane.
// Cross-crane sharing is intentional: a servicer may use one travel order for multiple cranes. // Cross-crane sharing is intentional: a servicer may use one travel order for multiple cranes.
@@ -973,10 +987,30 @@ export default function FleetDashboardShell({ initialSection = 'dashboard', page
<td <td
className="px-4 py-3" className="px-4 py-3"
> >
{[workOrder.craneInfo?.make, workOrder.craneInfo?.model].filter(Boolean).join(' ') || workOrder.craneLabel || workOrder.craneInfo?.registration_number || `#${workOrder.crane || workOrder.vehicle}`} {(() => {
const sharedCranes = workOrderSharedCranes.get(String(workOrder.id));
if (sharedCranes && sharedCranes.size > 0) {
return [...sharedCranes.values()].map((c) => (
[c.make, c.model].filter(Boolean).join(' ') || c.registration_number || `#${c.id}`
)).join(' • ');
}
return [workOrder.craneInfo?.make, workOrder.craneInfo?.model].filter(Boolean).join(' ')
|| workOrder.craneLabel
|| workOrder.craneInfo?.registration_number
|| `#${workOrder.crane || workOrder.vehicle}`;
})()}
</td> </td>
<td className="px-4 py-3 font-mono text-xs text-text-muted"> <td className="px-4 py-3 font-mono text-xs text-text-muted">
{workOrder.craneInfo?.crane_serial_number || '-'} {(() => {
const sharedCranes = workOrderSharedCranes.get(String(workOrder.id));
if (sharedCranes && sharedCranes.size > 0) {
const sns = [...sharedCranes.values()]
.map((c) => c.crane_serial_number)
.filter(Boolean);
return sns.length > 0 ? sns.join(' • ') : '-';
}
return workOrder.craneInfo?.crane_serial_number || '-';
})()}
</td> </td>
<td className="px-4 py-3"> <td className="px-4 py-3">
{formatDate(workOrder.date)} {formatDate(workOrder.date)}