feat: WorkOrderPhoto izolacija, upload modal i SN stupac u tablici putnih naloga
Some checks failed
ERP CI/CD Pipeline / test (push) Has been cancelled
ERP CI/CD Pipeline / Deploy (server git pull + compose) (push) Has been cancelled

- Dodan WorkOrderPhoto model (FK na WorkOrder, odvojen od VehicleServicePhoto)
- Migracija 0022_workorderphoto
- WorkOrderViewSet.images action refaktoriran: GET/POST koristi WorkOrderPhoto
- WorkOrderPhotoSerializer dodan u serializers.py
- WorkOrderPhotoInline dodan u admin.py
- Novi WorkOrderPhotoUpload.jsx modal s podrskom za onBack prop i z-[60]
- WorkOrderDetailModal: gumb Dodaj fotografije u editMode, photoUploadOpen state,
  ispravljen onSuccess callback (map na URL stringove), reset pri zatvaranju
- FleetDashboardShell: stupac SN u tablici putnih naloga (craneInfo.crane_serial_number)
- fleetDashboardStore: uklonjen dupli toast iz uploadWorkOrderPhoto
- Dodan test test_work_order_images_endpoint.py

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
mariomitte
2026-07-16 06:33:08 +02:00
parent 1ab2bfb3c3
commit 8e4b3f8aea
11 changed files with 539 additions and 58 deletions

View File

@@ -1,6 +1,7 @@
import { useEffect, useMemo, useState } from 'preact/hooks';
import { useStore } from '@nanostores/preact';
import WorkOrderImageCarousel from './WorkOrderImageCarousel';
import WorkOrderPhotoUpload from '../fleet/WorkOrderPhotoUpload';
import ModalShell from '../ui/ModalShell';
import {
createWorkOrderInvoice,
@@ -55,6 +56,7 @@ export default function WorkOrderDetailModal({ open, workOrder, onClose, onSubmi
});
const [invoices, setInvoices] = useState([]);
const [invoiceModalOpen, setInvoiceModalOpen] = useState(false);
const [photoUploadOpen, setPhotoUploadOpen] = useState(false);
const [invoiceSaving, setInvoiceSaving] = useState(false);
const [invoiceForm, setInvoiceForm] = useState({
naziv_racuna: '',
@@ -133,6 +135,7 @@ export default function WorkOrderDetailModal({ open, workOrder, onClose, onSubmi
});
setInvoices([]);
setInvoiceModalOpen(false);
setPhotoUploadOpen(false);
setInvoiceSaving(false);
setInvoiceForm({
naziv_racuna: '',
@@ -811,14 +814,23 @@ export default function WorkOrderDetailModal({ open, workOrder, onClose, onSubmi
Izmijeni
</button>
) : (
<button
type="button"
onClick={submit}
disabled={submitting}
className="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white hover:bg-indigo-700 disabled:opacity-60"
>
{submitting ? 'Spremam...' : 'Spremi izmjene'}
</button>
<>
<button
type="button"
onClick={() => setPhotoUploadOpen(true)}
className="rounded-lg border border-border-hairline px-4 py-2 text-sm font-medium text-text-main hover:bg-canvas-deep"
>
📷 Dodaj fotografije
</button>
<button
type="button"
onClick={submit}
disabled={submitting}
className="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white hover:bg-indigo-700 disabled:opacity-60"
>
{submitting ? 'Spremam...' : 'Spremi izmjene'}
</button>
</>
)}
</div>
</form>
@@ -1110,6 +1122,20 @@ export default function WorkOrderDetailModal({ open, workOrder, onClose, onSubmi
</div>
</ModalShell>
)}
<WorkOrderPhotoUpload
open={photoUploadOpen}
workOrderId={workOrder?.id}
onClose={() => setPhotoUploadOpen(false)}
onBack={() => setPhotoUploadOpen(false)}
onSuccess={() => {
setPhotoUploadOpen(false);
if (workOrder?.id) {
fetchWorkOrderImages(workOrder.id, { w: 1280, q: 75, fmt: 'webp' })
.then((files) => setImageFiles(files.map((item) => item.optimized_url || item.original_url).filter(Boolean)))
.catch(() => {});
}
}}
/>
</>
);
}