feat: integritet zatvaranja taska i putnog naloga
Dodaje status 'spreman_za_zavrsetak' i backend provjeru koja blokira zatvaranje taska kada je povezani putni nalog otvoren, uz 409 odgovor i opcionalni auto-close flow.\n\nPri zatvaranju putnog naloga taskovi u statusu 'servis' automatski prelaze u 'spreman_za_zavrsetak'. Frontend modal sada podržava potvrdu i retry s auto_close_work_order=true.\n\nUključeni su i ciljani testovi za novi behavior, te ažuriran prikaz statusa u dashboardu.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -33,7 +33,7 @@ import { showToast } from '../../stores/toastStore';
|
||||
import { $accessToken, $authReady, $user, hydrateAuthFromStorage, validateToken } from '../../stores/authStore';
|
||||
import { cacheCraneSerial, cacheCraneSerialsFromVehicles } from '../../stores/craneSerialStore';
|
||||
import { formatEntityCode } from '../../lib/displayIds';
|
||||
import { $tasks, fetchTasks, isTaskActive, updateTask } from '../../stores/taskStore';
|
||||
import { $tasks, fetchTasks, getStatusLabel, isTaskActive, updateTask } from '../../stores/taskStore';
|
||||
import AnimatedDataTable from '../ui/AnimatedDataTable';
|
||||
import AnimatedPage from '../ui/AnimatedPage';
|
||||
|
||||
@@ -66,6 +66,15 @@ function formatDate(value) {
|
||||
return parsed.toLocaleDateString('hr-HR');
|
||||
}
|
||||
|
||||
function formatTaskCraneLabel(task, cranes) {
|
||||
const crane = cranes.find((item) => String(item.id) === String(task?.vehicle || ''));
|
||||
const serial = String(crane?.crane_serial_number || '').trim();
|
||||
const model = [crane?.make, crane?.model].filter(Boolean).join(' ').trim();
|
||||
const registration = String(task?.vehicle_registration || crane?.registration_number || '').trim();
|
||||
const primary = serial ? `SN ${serial}` : (registration || '-');
|
||||
return model ? `${primary} / ${model}` : primary;
|
||||
}
|
||||
|
||||
function formatCost(value) {
|
||||
const numeric = Number(value);
|
||||
if (Number.isNaN(numeric)) return '-';
|
||||
@@ -663,14 +672,17 @@ export default function FleetDashboardShell({ initialSection = 'dashboard', page
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<span className={isTaskActive(task) ? 'text-emerald-700' : 'text-red-700'}>
|
||||
{task.status || '-'}
|
||||
{getStatusLabel(task.status || '-')}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3">{formatDateTime(task.created_at)}</td>
|
||||
<td
|
||||
className="px-4 py-3"
|
||||
title={formatDateTime(task.created_at) !== '-' ? formatDateTime(task.created_at) : undefined}
|
||||
>
|
||||
<span className="cursor-help">{formatDate(task.created_at)}</span>
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
{task.vehicle_registration
|
||||
|| cranes.find((item) => String(item.id) === String(task.vehicle))?.registration_number
|
||||
|| '-'}
|
||||
{formatTaskCraneLabel(task, cranes)}
|
||||
</td>
|
||||
<td className="px-4 py-3">{task.work_order_label || '-'}</td>
|
||||
<td className="px-4 py-3">{task.assigned_to_name || '-'}</td>
|
||||
@@ -1138,6 +1150,12 @@ export default function FleetDashboardShell({ initialSection = 'dashboard', page
|
||||
setSelectedTask(updatedTask);
|
||||
return updatedTask;
|
||||
}}
|
||||
onUpdateTask={async (task, changes) => {
|
||||
const updatedTask = await updateTask(task.id, changes);
|
||||
setSelectedTask(updatedTask);
|
||||
await fetchFleetDashboardData({ silent: true });
|
||||
return updatedTask;
|
||||
}}
|
||||
onCreateServiceRecord={(task) => {
|
||||
const taskCrane = cranes.find((item) => String(item.id) === String(task?.vehicle));
|
||||
setSelectedTask(null);
|
||||
|
||||
Reference in New Issue
Block a user