import { useEffect, useMemo, useState } from 'preact/hooks'; import ModalShell from '../ui/ModalShell'; import { formatWorkOrderDisplayCode } from '../../lib/displayIds'; import { getStatusLabel } from '../../stores/taskStore'; import { getTaskCraneDisplay, getTaskCraneOwner } from '../../lib/taskCraneDisplay'; import { updateVehicle, $vehicles } from '../../stores/fleetDashboardStore'; const STATUS_OPTIONS = ['aktivan', 'servis', 'spreman_za_zavrsetak', 'zavrsen', 'neaktivan']; function todayIso() { return new Date().toISOString().slice(0, 10); } function formatDate(value) { if (!value) return '-'; const parsed = new Date(value); if (Number.isNaN(parsed.getTime())) return value; return parsed.toLocaleDateString('hr-HR'); } function formatDateTime(value) { if (!value) return '-'; const parsed = new Date(value); if (Number.isNaN(parsed.getTime())) return '-'; return parsed.toLocaleString('hr-HR'); } function formatCost(value) { const numeric = Number(value); if (Number.isNaN(numeric)) return '-'; return `${numeric.toFixed(2)} EUR`; } export default function TaskServiceRecordsModal({ open, task, records = [], workOrders = [], onClose, onOpenServiceRecord, onAssignWorkOrder, onUpdateTask, onCreateServiceRecord, onSetServiceContext, }) { const [showWorkOrderEditor, setShowWorkOrderEditor] = useState(false); const [selectedWorkOrderId, setSelectedWorkOrderId] = useState(''); const [assigningWorkOrder, setAssigningWorkOrder] = useState(false); const [assignError, setAssignError] = useState(''); const [showTaskEditor, setShowTaskEditor] = useState(false); const [updatingTask, setUpdatingTask] = useState(false); const [taskError, setTaskError] = useState(''); const [taskForm, setTaskForm] = useState({ title: '', description: '', status: 'aktivan', scheduled_date: '', }); const [craneDataModalOpen, setCraneDataModalOpen] = useState(false); const [craneDataForm, setCraneDataForm] = useState({ superstructure_working_hours: '', chassis_working_hours: '', current_mileage: '' }); const [savingCraneData, setSavingCraneData] = useState(false); const [craneDataError, setCraneDataError] = useState(''); useEffect(() => { if (!open || typeof window === 'undefined') return; window.scrollTo({ top: 0, behavior: 'smooth' }); }, [open]); useEffect(() => { if (!task) return; setSelectedWorkOrderId(task.work_order ? String(task.work_order) : ''); setShowWorkOrderEditor(!task.work_order); setAssignError(''); setAssigningWorkOrder(false); setShowTaskEditor(false); setTaskError(''); setUpdatingTask(false); setTaskForm({ title: String(task.title || ''), description: String(task.description || ''), status: String(task.status || 'aktivan'), scheduled_date: String(task.scheduled_date || ''), }); setCraneDataModalOpen(false); setCraneDataError(''); setSavingCraneData(false); }, [task?.id, task?.work_order]); const openCraneDataModal = () => { const craneVehicleId = task?.vehicle; if (!craneVehicleId) return; const craneVehicle = ($vehicles?.get?.() || []).find((v) => String(v.id) === String(craneVehicleId)) || null; setCraneDataForm({ superstructure_working_hours: String(craneVehicle?.superstructure_working_hours ?? ''), chassis_working_hours: String(craneVehicle?.chassis_working_hours ?? ''), current_mileage: String(craneVehicle?.current_mileage ?? ''), }); setCraneDataError(''); setCraneDataModalOpen(true); }; const handleSaveCraneData = async () => { const craneVehicleId = task?.vehicle; if (!craneVehicleId) { setCraneDataError('Dizalica nije pronađena.'); return; } const superstructure = craneDataForm.superstructure_working_hours === '' ? undefined : Number(craneDataForm.superstructure_working_hours); const chassis = craneDataForm.chassis_working_hours === '' ? undefined : Number(craneDataForm.chassis_working_hours); const mileage = craneDataForm.current_mileage === '' ? undefined : Number(craneDataForm.current_mileage); if (superstructure !== undefined && (Number.isNaN(superstructure) || superstructure < 0)) { setCraneDataError('Radni sati superstrukture moraju biti pozitivan broj.'); return; } if (chassis !== undefined && (Number.isNaN(chassis) || chassis < 0)) { setCraneDataError('Radni sati podvozja moraju biti pozitivan broj.'); return; } if (mileage !== undefined && (Number.isNaN(mileage) || mileage < 0)) { setCraneDataError('Kilometraža mora biti pozitivan broj.'); return; } const payload = {}; if (superstructure !== undefined) payload.superstructure_working_hours = superstructure; if (chassis !== undefined) payload.chassis_working_hours = chassis; if (mileage !== undefined) payload.current_mileage = mileage; if (Object.keys(payload).length === 0) { setCraneDataError('Nije unesena niti jedna vrijednost za ažuriranje.'); return; } setSavingCraneData(true); setCraneDataError(''); try { await updateVehicle(craneVehicleId, payload); setCraneDataModalOpen(false); } catch (err) { setCraneDataError(err?.message || 'Ažuriranje podataka dizalice nije uspjelo.'); } finally { setSavingCraneData(false); } }; const currentWorkOrder = useMemo( () => workOrders.find((item) => String(item.id) === String(task?.work_order || selectedWorkOrderId)) || null, [workOrders, task?.work_order, selectedWorkOrderId] ); const sortedWorkOrders = useMemo(() => { const today = todayIso(); return [...workOrders].sort((a, b) => { const aToday = String(a.date || '').slice(0, 10) === today ? 1 : 0; const bToday = String(b.date || '').slice(0, 10) === today ? 1 : 0; if (bToday !== aToday) return bToday - aToday; return String(b.date || '').localeCompare(String(a.date || '')); }); }, [workOrders]); const effectiveWorkOrderId = task?.work_order ? String(task.work_order) : String(selectedWorkOrderId || ''); const handleWorkOrderChange = async (event) => { const nextValue = String(event.currentTarget.value || ''); setSelectedWorkOrderId(nextValue); setAssignError(''); setAssigningWorkOrder(true); try { await onAssignWorkOrder?.(task, nextValue || null); setShowWorkOrderEditor(false); } catch (error) { setAssignError(error?.message || 'Neuspješno spremanje putnog naloga za radni zadatak.'); } finally { setAssigningWorkOrder(false); } }; const handleTaskUpdate = async (event) => { event.preventDefault(); const title = String(taskForm.title || '').trim(); const status = String(taskForm.status || 'aktivan'); const description = String(taskForm.description || '').trim(); if (!title) { setTaskError('Naslov zadatka je obavezan.'); return; } if ((status === 'zavrsen' || status === 'neaktivan') && !effectiveWorkOrderId) { setTaskError('Putni nalog je obavezan prije zatvaranja zadatka.'); return; } setTaskError(''); setUpdatingTask(true); try { await onUpdateTask?.(task, { title, description, status, scheduled_date: taskForm.scheduled_date || null, }); setShowTaskEditor(false); } catch (error) { const conflictCode = error?.details?.code; if (error?.status === 409 && conflictCode === 'OPEN_WORK_ORDER_BLOCKING_TASK_CLOSE') { const confirmText = error?.details?.message || error?.message || 'Povezani putni nalog je još otvoren. Želite li ga automatski zatvoriti?'; const approved = typeof window !== 'undefined' ? window.confirm(confirmText) : false; if (approved) { try { await onUpdateTask?.(task, { title, description, status, scheduled_date: taskForm.scheduled_date || null, auto_close_work_order: true, }); setShowTaskEditor(false); return; } catch (retryError) { setTaskError(retryError?.message || 'Neuspješno automatsko zatvaranje putnog naloga i završetak zadatka.'); return; } } setTaskError(confirmText); return; } setTaskError(error?.message || 'Neuspješno spremanje izmjena radnog zadatka.'); } finally { setUpdatingTask(false); } }; if (!open || !task) return null; return ( <>

Radni zadatak detalji

Radni zadatak: {task.title || '-'} • Status: {getStatusLabel(task.status || '-')} • Zapisa: {records.length}

{task?.vehicle && ( )}

Podaci radnog zadatka

{!showTaskEditor ? ( ) : null}
{!showTaskEditor ? (
Naslov
{task.title || '-'}
Status
{getStatusLabel(task.status || '-')}
Dodijeljeno
{task.assigned_to_name || '-'}
Vlasnik
{getTaskCraneOwner(task)}
Dizalica
{getTaskCraneDisplay(task)} {task?.vehicle && ( )}
Putni nalog
{task.work_order_label || '-'}
Planirani datum
{task.scheduled_date ? formatDate(task.scheduled_date) : '-'}
Vrijeme izrade
{formatDateTime(task.created_at)}
Opis
{task.description || '-'}
) : (