From 6539d7dd2dd5b12a2840b7fd34f375cb1352d5c8 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Thu, 20 Aug 2026 21:51:38 +0700 Subject: [PATCH] feat: add variant preview functionality with modal for image display in cutting and purchase management --- .../js/pages/admin/manage/cutting/create.tsx | 23 ++++++++--- .../js/pages/admin/manage/cutting/edit.tsx | 31 ++++++++++----- .../js/pages/admin/manage/purchase/create.tsx | 38 +++++++++++++------ .../js/pages/admin/manage/purchase/edit.tsx | 16 +++++++- 4 files changed, 81 insertions(+), 27 deletions(-) diff --git a/resources/js/pages/admin/manage/cutting/create.tsx b/resources/js/pages/admin/manage/cutting/create.tsx index 1bf0e33..8f8b250 100644 --- a/resources/js/pages/admin/manage/cutting/create.tsx +++ b/resources/js/pages/admin/manage/cutting/create.tsx @@ -101,6 +101,7 @@ export default function CuttingCreate({ rawMaterials }: Props) { const [cartOpen, setCartOpen] = useState(false); const [previewKey, setPreviewKey] = useState(null); + const [variantPreview, setVariantPreview] = useState<{ src: string; title?: string; description?: string } | null>(null); const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false); const [deleteMaterialIndex, setDeleteMaterialIndex] = useState(null); @@ -456,7 +457,7 @@ export default function CuttingCreate({ rawMaterials }: Props) {
{price.photo_conversion_url ?? price.photo_url ? ( - {price.variant} + {price.variant} setVariantPreview({ src: price.photo_url, title: price.variant, description: rm.name })} /> ) : (
N/A
)} @@ -511,7 +512,7 @@ export default function CuttingCreate({ rawMaterials }: Props) {
{price.photo_conversion_url ?? price.photo_url ? ( - {price.variant} + {price.variant} setVariantPreview({ src: price.photo_url, title: price.variant, description: selectedMaterial?.name })} /> ) : (
N/A
)} @@ -767,6 +768,18 @@ export default function CuttingCreate({ rawMaterials }: Props) { sources={materials.filter((m) => m.photo_url).map((m) => m.photo_url!)} /> + { + if (!open) { + setVariantPreview(null); + } + }} + src={variantPreview?.src ?? null} + title={variantPreview?.title} + description={variantPreview?.description} + /> + {comboDialogOpen && (
setComboDialogOpen(false)} /> )} @@ -815,7 +828,7 @@ export default function CuttingCreate({ rawMaterials }: Props) {
{photoUrl ? ( - {variantName} + {variantName} setVariantPreview({ src: price?.photo_url ?? null, title: variantName, description: item.materialName })} /> ) : (
N/A
)} @@ -853,8 +866,8 @@ export default function CuttingCreate({ rawMaterials }: Props) { return (
- {price.photo_conversion_url ?? price.photo_url ? ( - {price.variant} + {price.photo_conversion_url ?? price.photo_url ? ( + {price.variant} setVariantPreview({ src: price.photo_url, title: price.variant, description: comboMaterial.name })} /> ) : (
N/A
)} diff --git a/resources/js/pages/admin/manage/cutting/edit.tsx b/resources/js/pages/admin/manage/cutting/edit.tsx index d927ae4..2b9f337 100644 --- a/resources/js/pages/admin/manage/cutting/edit.tsx +++ b/resources/js/pages/admin/manage/cutting/edit.tsx @@ -104,6 +104,7 @@ export default function CuttingEdit({ cutting, rawMaterials }: Props) { const [cartOpen, setCartOpen] = useState(false); const [previewKey, setPreviewKey] = useState(null); + const [variantPreview, setVariantPreview] = useState<{ src: string; title?: string; description?: string } | null>(null); const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false); const [deleteMaterialIndex, setDeleteMaterialIndex] = useState(null); @@ -455,8 +456,8 @@ export default function CuttingEdit({ cutting, rawMaterials }: Props) { return (
- {price.photo_conversion_url ?? price.photo_url ? ( - {price.variant} + {price.photo_conversion_url ?? price.photo_url ? ( + {price.variant} setVariantPreview({ src: price.photo_url, title: price.variant, description: rm.name })} /> ) : (
N/A
)} @@ -502,7 +503,7 @@ export default function CuttingEdit({ cutting, rawMaterials }: Props) { Tidak ada varian ditemukan.
) : ( -
+
{selectedMaterialVariants.map((price) => { const isAdded = materials.some((m) => m.raw_material_price_id === price.id); const addedCount = materials.filter((m) => m.raw_material_price_id === price.id).length; @@ -510,8 +511,8 @@ export default function CuttingEdit({ cutting, rawMaterials }: Props) { return (
- {price.photo_conversion_url ?? price.photo_url ? ( - {price.variant} + {price.photo_conversion_url ?? price.photo_url ? ( + {price.variant} setVariantPreview({ src: price.photo_url, title: price.variant, description: selectedMaterial?.name })} /> ) : (
N/A
)} @@ -528,7 +529,7 @@ export default function CuttingEdit({ cutting, rawMaterials }: Props) { Tambah - @@ -767,6 +768,18 @@ export default function CuttingEdit({ cutting, rawMaterials }: Props) { sources={materials.filter((m) => m.photo_url).map((m) => m.photo_url!)} /> + { + if (!open) { + setVariantPreview(null); + } + }} + src={variantPreview?.src ?? null} + title={variantPreview?.title} + description={variantPreview?.description} + /> + {comboDialogOpen && (
setComboDialogOpen(false)} /> )} @@ -815,7 +828,7 @@ export default function CuttingEdit({ cutting, rawMaterials }: Props) {
{photoUrl ? ( - {variantName} + {variantName} setVariantPreview({ src: price?.photo_url ?? null, title: variantName, description: item.materialName })} /> ) : (
N/A
)} @@ -844,8 +857,8 @@ export default function CuttingEdit({ cutting, rawMaterials }: Props) { return (
- {price.photo_conversion_url ?? price.photo_url ? ( - {price.variant} + {price.photo_conversion_url ?? price.photo_url ? ( + {price.variant} setVariantPreview({ src: price.photo_url, title: price.variant, description: comboMaterial.name })} /> ) : (
N/A
)} diff --git a/resources/js/pages/admin/manage/purchase/create.tsx b/resources/js/pages/admin/manage/purchase/create.tsx index 5bccae5..62397e1 100644 --- a/resources/js/pages/admin/manage/purchase/create.tsx +++ b/resources/js/pages/admin/manage/purchase/create.tsx @@ -141,6 +141,7 @@ export default function PurchaseCreate({ suppliers, rawMaterials }: Props) { ); const [cartOpen, setCartOpen] = useState(false); const [previewKey, setPreviewKey] = useState(null); + const [variantPreview, setVariantPreview] = useState<{ src: string; title?: string; description?: string } | null>(null); const [cartRemoveKey, setCartRemoveKey] = useState(null); const draftData = useMemo( @@ -915,18 +916,19 @@ export default function PurchaseCreate({ suppliers, rawMaterials }: Props) { : 'flex flex-wrap items-center justify-between gap-2 rounded-lg border p-3' } > -
- {price.photo_conversion_url ?? price.photo_url ? ( - { - ) : ( +
+ {price.photo_conversion_url ?? price.photo_url ? ( + { setVariantPreview({ src: price.photo_url, title: price.variant, description: selectedMaterial?.name })} + /> + ) : (
N/A
@@ -1334,6 +1336,18 @@ export default function PurchaseCreate({ suppliers, rawMaterials }: Props) { title={cartItems.find((i) => i.key === previewKey)?.title} /> + { + if (!open) { + setVariantPreview(null); + } + }} + src={variantPreview?.src ?? null} + title={variantPreview?.title} + description={variantPreview?.description} + /> + { diff --git a/resources/js/pages/admin/manage/purchase/edit.tsx b/resources/js/pages/admin/manage/purchase/edit.tsx index b8cacc7..5d5b9e6 100644 --- a/resources/js/pages/admin/manage/purchase/edit.tsx +++ b/resources/js/pages/admin/manage/purchase/edit.tsx @@ -95,6 +95,7 @@ export default function PurchaseEdit({ ); const [cartOpen, setCartOpen] = useState(false); const [previewKey, setPreviewKey] = useState(null); + const [variantPreview, setVariantPreview] = useState<{ src: string; title?: string; description?: string } | null>(null); const [cartRemoveKey, setCartRemoveKey] = useState(null); const [fetchedVariants, setFetchedVariants] = useState>(new Map()); @@ -314,7 +315,8 @@ export default function PurchaseEdit({ {price.variant} setVariantPreview({ src: price.photo_url ?? null, title: price.variant, description: group.name })} /> ) : (
@@ -679,6 +681,18 @@ export default function PurchaseEdit({ title={cartItems.find((i) => i.key === previewKey)?.title} /> + { + if (!open) { + setVariantPreview(null); + } + }} + src={variantPreview?.src ?? null} + title={variantPreview?.title} + description={variantPreview?.description} + /> + {