jaecoo-kelapagading/components/dialog/promo-edit-dialog.tsx

182 lines
4.9 KiB
TypeScript
Raw Normal View History

2026-01-28 18:19:14 +00:00
"use client";
import { useEffect, useState } from "react";
import Image from "next/image";
import Cookies from "js-cookie";
import Swal from "sweetalert2";
import withReactContent from "sweetalert2-react-content";
import { getPromotionById, updatePromotion } from "@/service/promotion";
import { Button } from "@/components/ui/button";
import { loading, success, error } from "@/config/swal";
type PromoEditDialogProps = {
promoId: number | null;
open: boolean;
onOpenChange: (open: boolean) => void;
onSuccess?: () => void;
};
export default function PromoEditDialog({
promoId,
open,
onOpenChange,
onSuccess,
}: PromoEditDialogProps) {
const [loadingData, setLoadingData] = useState(false);
// 🔹 FORM STATE
const [title, setTitle] = useState("");
const [thumbnailUrl, setThumbnailUrl] = useState<string | null>(null);
const [thumbnailFile, setThumbnailFile] = useState<File | null>(null);
const MySwal = withReactContent(Swal);
/* =========================
* Fetch promo detail
========================= */
useEffect(() => {
if (!promoId || !open) return;
async function fetchPromo() {
try {
setLoadingData(true);
const res = await getPromotionById(promoId);
const data = res?.data?.data;
setTitle(data?.title || "");
setThumbnailUrl(data?.thumbnail_url || null);
} catch (e) {
console.error("FETCH PROMO ERROR:", e);
} finally {
setLoadingData(false);
}
}
fetchPromo();
}, [promoId, open]);
if (!open) return null;
/* =========================
* Handlers
========================= */
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
setThumbnailFile(file);
setThumbnailUrl(URL.createObjectURL(file));
};
const handleSubmit = async () => {
if (!promoId) return;
const formData = new FormData();
formData.append("title", title);
if (thumbnailFile) {
formData.append("file", thumbnailFile);
}
loading();
const res = await updatePromotion(formData, promoId);
if (res?.error) {
error(res.message || "Gagal update promo");
return;
}
success("Promo berhasil diperbarui");
onOpenChange(false);
onSuccess?.();
};
/* =========================
* Render
========================= */
return (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
onClick={() => onOpenChange(false)}
>
<div
className="bg-white rounded-2xl shadow-xl max-w-lg w-full overflow-hidden"
onClick={(e) => e.stopPropagation()}
>
{/* HEADER */}
<div className="bg-gradient-to-br from-[#1F6779] to-[#0F6C75] text-white px-6 py-5 relative">
<button
onClick={() => onOpenChange(false)}
className="absolute top-4 right-4 text-xl"
>
</button>
<h2 className="text-lg font-semibold">Edit Promo</h2>
</div>
{/* BODY */}
<div className="p-6 space-y-5">
{loadingData ? (
<p>Memuat data...</p>
) : (
<>
{/* TITLE */}
<div>
<label className="block text-sm font-medium text-gray-600 mb-1">
Judul Promo
</label>
<input
value={title}
onChange={(e) => setTitle(e.target.value)}
className="w-full border rounded-lg px-3 py-2 focus:ring-2 focus:ring-[#0F6C75]"
placeholder="Judul promo"
/>
</div>
{/* THUMBNAIL */}
<div>
<label className="block text-sm font-medium text-gray-600 mb-2">
Thumbnail
</label>
{thumbnailUrl && (
<div className="w-32 h-32 mb-3 rounded-lg overflow-hidden border">
<img
src={thumbnailUrl}
alt="Thumbnail"
className="w-32 h-32 object-cover rounded-lg border"
/>
</div>
)}
<input
type="file"
accept="image/*"
onChange={handleFileChange}
className="bg-[#0F6C75] text-white rounded-full px-2 w-[230px]"
/>
</div>
</>
)}
</div>
{/* FOOTER */}
<div className="flex justify-end gap-3 px-6 py-4 border-t bg-[#F2F7FA]">
<Button variant="secondary" onClick={() => onOpenChange(false)}>
Batal
</Button>
<Button
className="bg-[#1F6779] hover:bg-[#0F6C75] text-white"
onClick={handleSubmit}
disabled={loadingData}
>
Simpan Perubahan
</Button>
</div>
</div>
</div>
);
}