From 159fb3cec64dee37a410bcc71dee9353e93a4c9d Mon Sep 17 00:00:00 2001 From: nico Date: Thu, 5 Mar 2026 15:53:26 +0800 Subject: [PATCH] feat(apbdes): make image and file optional for edit page too Changes: Backend (updt.ts, index.ts): - Update FormUpdateBody: imageId?: string | null - Update Elysia schema: t.Optional(t.String()) - Handle null/undefined values when updating UI (edit/page.tsx): - Remove mandatory validation for imageId and fileId - Update labels to show '(Opsional)' - Simplify handleSubmit logic (no validation check) - Keep existing file IDs if no new upload User Flow: Before: Edit required imageId and fileId to be present After: Can update APBDes without files, preserve existing or set to null Files changed: - src/app/api/[[...slugs]]/_lib/landing_page/apbdes/updt.ts - src/app/api/[[...slugs]]/_lib/landing_page/apbdes/index.ts - src/app/admin/(dashboard)/landing-page/apbdes/[id]/edit/page.tsx Co-authored-by: Qwen-Coder --- .../(dashboard)/_state/landing-page/apbdes.ts | 5 +- .../landing-page/apbdes/[id]/edit/page.tsx | 18 ++----- .../landing-page/apbdes/create/page.tsx | 50 +++++++++++-------- .../_lib/landing_page/apbdes/create.ts | 15 ++---- .../_lib/landing_page/apbdes/index.ts | 8 +-- .../_lib/landing_page/apbdes/updt.ts | 4 +- src/app/darmasaba/_com/FixedPlayerBar.tsx | 2 +- 7 files changed, 47 insertions(+), 55 deletions(-) diff --git a/src/app/admin/(dashboard)/_state/landing-page/apbdes.ts b/src/app/admin/(dashboard)/_state/landing-page/apbdes.ts index 46141de3..ddd52c52 100644 --- a/src/app/admin/(dashboard)/_state/landing-page/apbdes.ts +++ b/src/app/admin/(dashboard)/_state/landing-page/apbdes.ts @@ -23,8 +23,9 @@ const ApbdesFormSchema = z.object({ name: z.string().optional(), deskripsi: z.string().optional(), jumlah: z.string().optional(), - imageId: z.string().min(1, "Gambar wajib diunggah"), - fileId: z.string().min(1, "File wajib diunggah"), + // Image dan file opsional (bisa kosong) + imageId: z.string().optional(), + fileId: z.string().optional(), items: z.array(ApbdesItemSchema).min(1, "Minimal ada 1 item"), }); diff --git a/src/app/admin/(dashboard)/landing-page/apbdes/[id]/edit/page.tsx b/src/app/admin/(dashboard)/landing-page/apbdes/[id]/edit/page.tsx index e03b7717..90599e93 100644 --- a/src/app/admin/(dashboard)/landing-page/apbdes/[id]/edit/page.tsx +++ b/src/app/admin/(dashboard)/landing-page/apbdes/[id]/edit/page.tsx @@ -205,7 +205,6 @@ function EditAPBDes() { // Upload file baru jika ada perubahan if (imageFile) { - // Hapus file lama dari form jika ada file baru const res = await ApiFetch.api.fileStorage.create.post({ file: imageFile, name: imageFile.name, @@ -217,7 +216,6 @@ function EditAPBDes() { } if (docFile) { - // Hapus file lama dari form jika ada file baru const res = await ApiFetch.api.fileStorage.create.post({ file: docFile, name: docFile.name, @@ -228,15 +226,7 @@ function EditAPBDes() { } } - // Jika tidak ada file baru, gunakan ID lama (sudah ada di form) - // Pastikan imageId dan fileId tetap ada - if (!apbdesState.edit.form.imageId) { - return toast.warn('Gambar wajib diunggah'); - } - if (!apbdesState.edit.form.fileId) { - return toast.warn('Dokumen wajib diunggah'); - } - + // Image dan file sekarang opsional, tidak perlu validasi const success = await apbdesState.edit.update(); if (success) { router.push('/admin/landing-page/apbdes'); @@ -343,11 +333,11 @@ function EditAPBDes() { required /> - {/* Gambar & Dokumen */} + {/* Gambar & Dokumen (Opsional) */} - Gambar APBDes + Gambar APBDes (Opsional) - Dokumen APBDes + Dokumen APBDes (Opsional) (null); const [isSubmitting, setIsSubmitting] = useState(false); - // Check if form is valid + // Check if form is valid - hanya cek items, gambar dan file opsional const isFormValid = () => { - return ( - imageFile !== null && - docFile !== null && - stateAPBDes.create.form.items.length > 0 - ); + return stateAPBDes.create.form.items.length > 0; }; // Form sementara untuk input item baru @@ -84,28 +80,34 @@ function CreateAPBDes() { }; const handleSubmit = async () => { - if (!imageFile || !docFile) { - return toast.warn("Pilih gambar dan dokumen terlebih dahulu"); - } if (stateAPBDes.create.form.items.length === 0) { return toast.warn("Minimal tambahkan 1 item APBDes"); } try { setIsSubmitting(true); - const [uploadImageRes, uploadDocRes] = await Promise.all([ - ApiFetch.api.fileStorage.create.post({ file: imageFile, name: imageFile.name }), - ApiFetch.api.fileStorage.create.post({ file: docFile, name: docFile.name }), - ]); - const imageId = uploadImageRes?.data?.data?.id; - const fileId = uploadDocRes?.data?.data?.id; + // Upload files hanya jika ada file yang dipilih + let imageId = ''; + let fileId = ''; - if (!imageId || !fileId) { - return toast.error("Gagal mengupload file"); + if (imageFile) { + const uploadImageRes = await ApiFetch.api.fileStorage.create.post({ + file: imageFile, + name: imageFile.name, + }); + imageId = uploadImageRes?.data?.data?.id || ''; } - // Update form dengan ID file + if (docFile) { + const uploadDocRes = await ApiFetch.api.fileStorage.create.post({ + file: docFile, + name: docFile.name, + }); + fileId = uploadDocRes?.data?.data?.id || ''; + } + + // Update form dengan ID file (bisa kosong) stateAPBDes.create.form.imageId = imageId; stateAPBDes.create.form.fileId = fileId; @@ -174,12 +176,16 @@ function CreateAPBDes() { style={{ border: '1px solid #e0e0e0' }} > - {/* Gambar & Dokumen (dipendekkan untuk fokus pada items) */} + {/* Info: File opsional */} + + * Upload gambar dan dokumen bersifat opsional. Bisa dikosongkan jika belum ada. + + {/* Gambar APBDes */} - Gambar APBDes + Gambar APBDes (Opsional) { @@ -249,10 +255,10 @@ function CreateAPBDes() { )} - {/* Dokumen APBDes */} + {/* Dokumen APBDes (Opsional) */} - Dokumen APBDes + Dokumen APBDes (Opsional) { diff --git a/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/create.ts b/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/create.ts index 9a7235de..7ce23625 100644 --- a/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/create.ts +++ b/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/create.ts @@ -17,8 +17,8 @@ type FormCreate = { name?: string; deskripsi?: string; jumlah?: string; - imageId: string; - fileId: string; + imageId?: string | null; // Opsional + fileId?: string | null; // Opsional items: APBDesItemInput[]; }; @@ -32,12 +32,7 @@ export default async function apbdesCreate(context: Context) { if (!body.tahun) { throw new Error('Tahun is required'); } - if (!body.imageId) { - throw new Error('Image ID is required'); - } - if (!body.fileId) { - throw new Error('File ID is required'); - } + // Image dan file sekarang opsional if (!body.items || body.items.length === 0) { throw new Error('At least one item is required'); } @@ -50,8 +45,8 @@ export default async function apbdesCreate(context: Context) { name: body.name || `APBDes Tahun ${body.tahun}`, deskripsi: body.deskripsi, jumlah: body.jumlah, - imageId: body.imageId, - fileId: body.fileId, + imageId: body.imageId || null, // null jika tidak ada + fileId: body.fileId || null, // null jika tidak ada }, }); diff --git a/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/index.ts b/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/index.ts index c3f6aa61..a3505d64 100644 --- a/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/index.ts +++ b/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/index.ts @@ -36,8 +36,8 @@ const APBDes = new Elysia({ name: t.Optional(t.String()), deskripsi: t.Optional(t.String()), jumlah: t.Optional(t.String()), - imageId: t.String(), - fileId: t.String(), + imageId: t.Optional(t.String()), + fileId: t.Optional(t.String()), items: t.Array(ApbdesItemSchema), }), }) @@ -50,8 +50,8 @@ const APBDes = new Elysia({ name: t.Optional(t.String()), deskripsi: t.Optional(t.String()), jumlah: t.Optional(t.String()), - imageId: t.String(), - fileId: t.String(), + imageId: t.Optional(t.String()), + fileId: t.Optional(t.String()), items: t.Array(ApbdesItemSchema), }), }) diff --git a/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/updt.ts b/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/updt.ts index 4e9dc782..4951764f 100644 --- a/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/updt.ts +++ b/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/updt.ts @@ -15,8 +15,8 @@ type FormUpdateBody = { name?: string; deskripsi?: string; jumlah?: string; - imageId: string; - fileId: string; + imageId?: string | null; + fileId?: string | null; items: APBDesItemInput[]; }; diff --git a/src/app/darmasaba/_com/FixedPlayerBar.tsx b/src/app/darmasaba/_com/FixedPlayerBar.tsx index 96437871..f05a31cc 100644 --- a/src/app/darmasaba/_com/FixedPlayerBar.tsx +++ b/src/app/darmasaba/_com/FixedPlayerBar.tsx @@ -134,7 +134,7 @@ export default function FixedPlayerBar() { p="sm" shadow="lg" style={{ - zIndex: 1000, + zIndex: 1, borderTop: '1px solid rgba(0,0,0,0.1)', }} >