182 lines
4.9 KiB
TypeScript
182 lines
4.9 KiB
TypeScript
"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>
|
|
);
|
|
}
|