diff options
| author | Miqdad <ahmadmiqdad27@gmail.com> | 2025-11-06 15:27:18 +0700 |
|---|---|---|
| committer | Miqdad <ahmadmiqdad27@gmail.com> | 2025-11-06 15:27:18 +0700 |
| commit | 77a0a082f0a5e1977c85a651a078376eab0d6df1 (patch) | |
| tree | dc1fc01ab55aa2f56b18dcab012f3ae19cb714aa /app/page.tsx | |
| parent | 8a0e4716aa12ce335758c84f7fdcb4b47cd9c2db (diff) | |
<MIqdad> multiple image SJ
Diffstat (limited to 'app/page.tsx')
| -rw-r--r-- | app/page.tsx | 99 |
1 files changed, 66 insertions, 33 deletions
diff --git a/app/page.tsx b/app/page.tsx index ae0e4d8..35609a6 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -13,8 +13,10 @@ import { MenuItem, Select, FormHelperText, + IconButton, + Tooltip, } from "@mui/material"; -import { SaveAsOutlined } from "@mui/icons-material"; +import { SaveAsOutlined, Close as CloseIcon } from "@mui/icons-material"; import axios from "axios"; import odooApi from "./lib/api/odooApi"; import { useEffect, useState } from "react"; @@ -27,7 +29,7 @@ type Role = "driver" | "dispatch"; type ShipMethod = "" | "self_pickup" | "indoteknik_delivery" | "ekspedisi"; export default function Home() { - const [isLogin, setIsLogin] = useState<boolean>(false); // start false biar nggak nge-flash + const [isLogin, setIsLogin] = useState<boolean>(false); const [isDriver, setIsDriver] = useState<boolean>(false); const [isDispatch, setIsDispatch] = useState<boolean>(false); const [shippingMethod, setShippingMethod] = useState<ShipMethod>(""); @@ -42,12 +44,13 @@ export default function Home() { setImageSj, setImagePackage, setImageDispatch, + removeSjImage, } = useCameraStore(); const [isLoading, setIsLoading] = useState<boolean>(false); const router = useRouter(); - // Single effect: auth gate + set role + // Auth gate + role dari cookie useEffect(() => { const auth = getAuth(); if (!auth) { @@ -73,7 +76,6 @@ export default function Home() { return; } - // Dispatch: shipping method wajib if (isDispatch) setShipTouched(true); if (isDispatch && !shippingMethod) { alert("Shipping Method wajib dipilih."); @@ -81,17 +83,20 @@ export default function Home() { return; } - // Validasi foto sesuai role & shipping method + const sjArr: string[] = Array.isArray(imageSj) + ? imageSj + : imageSj + ? [imageSj as unknown as string] + : []; + if (isDispatch) { if (!imageDispatch) { alert("Foto Dispatch Wajib Diisi"); setIsLoading(false); return; } - // SJ opsional untuk self_pickup & ekspedisi } else { - // Driver: SJ & Penerima wajib - if (!imageSj || !imagePackage) { + if (sjArr.length < 1 || !imagePackage) { alert("Barcode, Foto SJ, dan Foto Penerima harus tersedia."); setIsLoading(false); return; @@ -99,10 +104,13 @@ export default function Home() { } try { - const newSjImage = imageSj ? imageSj.replace(/^.*?,/, "") : undefined; + const latestSj = sjArr.at(-1) || null; + const newSjImage = latestSj ? latestSj.replace(/^.*?,/, "") : undefined; + const newPackageImage = imagePackage ? imagePackage.replace(/^.*?,/, "") : undefined; + const newDispatchImage = imageDispatch && imageDispatch.startsWith("data:") ? imageDispatch.replace(/^.*?,/, "") @@ -114,14 +122,11 @@ export default function Home() { const submittedDispatch = !!newDispatchImage && !isDriver; const data: Record<string, string> = {}; - if (submittedSj) data.sj_document = newSjImage!; + if (submittedSj) data.sj_documentations = newSjImage; // plural sesuai API if (submittedPackage) data.paket_document = newPackageImage!; if (submittedDispatch) data.dispatch_document = newDispatchImage!; if (isDispatch && shippingMethod) data.shipping_method = shippingMethod; - - if (shippingMethod === "self_pickup") { - data.self_pu = "true"; - } + if (shippingMethod === "self_pickup") data.self_pu = "true"; const response = (await odooApi( "PUT", @@ -132,8 +137,11 @@ export default function Home() { if (response?.status?.code === 200) { alert("Berhasil Submit Data"); setBarcode(""); - // Bersihkan HANYA yang dikirim - if (submittedSj) setImageSj(""); + + if (submittedSj) { + const next = sjArr.slice(0, -1); + setImageSj(next); + } if (submittedPackage) setImagePackage(""); if (submittedDispatch) setImageDispatch(""); } else if (response?.status?.code === 404) { @@ -155,15 +163,19 @@ export default function Home() { }; // === UI helpers === + const sjArr: string[] = Array.isArray(imageSj) + ? imageSj + : imageSj + ? [imageSj as unknown as string] + : []; + // dispatch: SJ hanya utk self_pickup & ekspedisi const showSjForDispatch = isDispatch && (shippingMethod === "self_pickup" || shippingMethod === "ekspedisi"); - // dispatch: kamera dispatch tampil utk semua method (asal sudah dipilih) const showDispatchForDispatch = isDispatch && shippingMethod !== ""; - // preview SJ: sembunyikan kalau dispatch belum pilih method - const showSjPreview = !!imageSj && (!isDispatch || showSjForDispatch); - // preview Dispatch: sembunyikan kalau dispatch belum pilih method + + const showSjPreview = sjArr.length > 0 && (!isDispatch || showSjForDispatch); const showDispatchPreview = !!imageDispatch && (!isDispatch || showDispatchForDispatch); @@ -234,7 +246,7 @@ export default function Home() { <div className="h-4" /> - <div className="flex justify-between"> + <div className="flex justify-between gap-3"> {isDispatch ? ( <> {showSjForDispatch && <SjCamera />} @@ -251,21 +263,42 @@ export default function Home() { <div className="h-2" /> - {/* Preview SJ */} + {/* Preview SJ (multi) + Remove per item */} {showSjPreview && ( <> <label className="block mt-2 text-sm font-medium text-gray-700 text-center"> Gambar Foto Surat Jalan </label> - <div className="relative w-full h-[300px] border-2 border-gray-200 p-2 rounded-sm"> - <Image - src={imageSj!} - alt="Captured" - fill - unoptimized - className="p-2" - style={{ objectFit: "cover" }} - /> + <div className="grid grid-cols-2 sm:grid-cols-3 gap-3"> + {sjArr.map((src, i) => ( + <div + key={i} + className="relative w-full h-[180px] border-2 border-gray-200 rounded-sm" + > + <Image + src={src} + alt={`SJ ${i + 1}`} + fill + unoptimized + style={{ objectFit: "cover" }} + className="rounded-sm" + /> + <div className="absolute top-1 right-1"> + <Tooltip title="Remove"> + <IconButton + size="small" + onClick={() => removeSjImage(i)} + sx={{ + bgcolor: "rgba(255,255,255,0.85)", + "&:hover": { bgcolor: "rgba(255,255,255,1)" }, + }} + > + <CloseIcon fontSize="small" /> + </IconButton> + </Tooltip> + </div> + </div> + ))} </div> </> )} @@ -273,7 +306,7 @@ export default function Home() { {/* Preview Penerima (hanya non-dispatch) */} {!isDispatch && imagePackage && ( <> - <label className="block mt-2 text-sm font-medium text-gray-700 text-center"> + <label className="block mt-4 text-sm font-medium text-gray-700 text-center"> Gambar Foto Penerima </label> <div className="relative w-full h-[300px] border-2 border-gray-200 p-2 rounded-sm"> @@ -292,7 +325,7 @@ export default function Home() { {/* Preview Dispatch */} {showDispatchPreview && ( <> - <label className="block mt-2 text-sm font-medium text-gray-700 text-center"> + <label className="block mt-4 text-sm font-medium text-gray-700 text-center"> Gambar Foto Dispatch </label> <div className="relative w-full h-[300px] border-2 border-gray-200 p-2 rounded-sm"> |
