specs / 037-Changes-Court-Quick-Edit-Photos

037 - Court Quick-Edit Panels + Photo Manager (Admin Site)

  • Tanggal: 2026-08-15
  • Chat/topik: Admin merasa edit foto/harga/specs Court terlalu ribet karena satu form besar; minta menu khusus per bagian, dan form upload foto asli untuk Court Images (bukan paste URL).

Ringkasan perubahan

Form Court (CourtForm.tsx) di admin site sebelumnya satu form monolitik: Name, Type, Base Price, Status, Bundled Room, Description, Main Image URL, Gallery (paste URL), Specs, Perks, dan Advanced Pricing — semua disimpan lewat satu server action saveCourt yang menimpa seluruh record (termasuk hapus-buat-ulang semua price override).

Sekarang dipecah:

  • Court Info (CourtForm.tsx, tetap di ikon Edit) — hanya Name, Type, Status, Bundled VIP Room.
  • Court Photos (CourtPhotosPanel.tsx, ikon baru) — upload foto asli ke Firebase Storage (bukan paste URL): grid thumbnail main + gallery, tiap foto bisa "Jadikan Utama" / "Ganti" / "Hapus", drag reorder gallery, multi-file upload, auto-save per aksi (tanpa tombol Save).
  • Court Pricing (CourtPricingPanel.tsx, ikon baru) — Base Price/Hour, Special Day Price, Time Group override.
  • Court Specs & Description (CourtSpecsPanel.tsx, ikon baru) — Description, Specs (label/value), Perks.

Tabel Court (CourtsClient.tsx) dapat 3 ikon aksi cepat baru (Foto/Harga/Specs) di samping Edit dan Delete yang sudah ada, masing-masing membuka SlidePanel khusus tanpa membuka form edit penuh.

Impact bisnis

  • Staf admin bisa update foto/harga/specs court jauh lebih cepat (2 klik: ikon → aksi) tanpa menavigasi form besar yang tidak relevan.
  • Foto Court kini benar-benar diunggah (bukan tergantung link eksternal admin paste manual) — mengurangi risiko link mati/salah format dan mempercepat proses onboarding foto court baru.
  • Court baru dibuat dengan basePricePerHour = 0 sampai admin mengisi harga lewat panel Pricing — perlu diperhatikan agar tidak lupa mengisi harga sebelum court tampil ke member (court dengan harga 0 tetap tampil apa adanya di list, tidak ada guard tambahan di sesi ini).

Epic / User stories

  • Epic: Court content management ergonomics.
  • US1: Sebagai admin, saya ingin menambah/mengganti/menghapus foto court langsung dari galeri upload, tanpa perlu hosting foto di tempat lain dan paste URL.
  • US2: Sebagai admin, saya ingin mengubah harga atau specs satu court tanpa membuka form edit penuh yang berisi field tidak relevan.

User terdampak

Admin/staf backoffice pengelola Court (mpc-admin). Tidak ada perubahan yang terlihat member (kontrak data ke member app tetap sama).

Aplikasi terdampak

  • mpc-be: TIDAK — endpoint court read-only, bentuk field imageUrl/gallery/specs/perks tidak berubah.
  • mpc-admin: PERLU (dikerjakan sesi ini) — lihat di atas.
  • mpc-android / mpc-ios / mpc-web: TIDAK — mengonsumsi field yang sudah ada tanpa perubahan kontrak; hanya cara admin mengisinya yang berubah.
  • mpc-be-pos / mpc-pos / mpc-owner / mpc-crm / ksr-sync: TIDAK — di luar domain Court showcase admin.

Perubahan schema

Tidak ada. Semua field (Court.imageUrl, Court.gallery, Court.specs, Court.perks, ItemPriceOverride) sudah ada dari migration 019-court-showcase-content. Tidak perlu file migration baru.

Perubahan kode

  • mpc-admin (mpc-admin-site):
    • src/lib/firebaseAdmin.ts (baru) — init firebase-admin singleton (Storage bucket) dari env FIREBASE_CLIENT_EMAIL / FIREBASE_PRIVATE_KEY / FIREBASE_STORAGE_BUCKET.
    • src/actions/uploads.ts (baru) — uploadCourtImage(courtId, formData) (validasi image/* + maks 5MB, upload ke courts/{courtId}/{uuid}.{ext}, makePublic()); deleteStorageImage(url) (best-effort cleanup blob saat foto diganti/dihapus).
    • src/actions/courts.tssaveCourt dipangkas ke identity fields saja (create baru default basePricePerHour=0); tambah updateCourtPhotos, updateCourtSpecs, updateCourtPricing (masing-masing granular, tidak menyentuh field lain).
    • src/components/ui/SlidePanel.tsx — prop opsional width?: "md" | "lg" untuk panel lebih lebar (dipakai panel Foto).
    • src/app/(dashboard)/services/courts/CourtForm.tsx — dipangkas: Name, Type, Status, Bundled VIP Room saja.
    • src/app/(dashboard)/services/courts/CourtPhotosPanel.tsx (baru), CourtPricingPanel.tsx (baru), CourtSpecsPanel.tsx (baru).
    • src/app/(dashboard)/services/courts/CourtsClient.tsx — 3 ikon aksi cepat baru (Foto/Harga/Specs) + state + SlidePanel masing-masing.
    • next.config.tsexperimental.serverActions.bodySizeLimit dinaikkan ke "10mb".
    • .env — tambah placeholder FIREBASE_CLIENT_EMAIL, FIREBASE_PRIVATE_KEY, FIREBASE_STORAGE_BUCKET (nilai asli perlu diisi manual oleh user dari Firebase Console — agent tidak bisa generate service account key).
    • Dependency baru: firebase-admin.
    • Changelog: mpc-dev/docs/changes/admin.md v0.11.

Catatan setup lanjutan (perlu aksi manual user)

Fitur upload foto tidak akan berfungsi sampai user mengisi env berikut di .env (dan environment deploy production bila relevan):

  1. Buka Firebase Console → project mpclub-a3b1e → Project Settings → Service Accounts → Generate new private key (unduh JSON).
  2. Pastikan Storage sudah diaktifkan untuk project ini (Firebase Console → Storage → Get Started jika belum).
  3. Isi di .env: FIREBASE_CLIENT_EMAIL (dari JSON client_email), FIREBASE_PRIVATE_KEY (dari JSON private_key, jaga literal \n), FIREBASE_STORAGE_BUCKET (nama bucket, cek di Console → Storage, biasanya mpclub-a3b1e.firebasestorage.app atau mpclub-a3b1e.appspot.com).