227 lines
6.8 KiB
TypeScript
227 lines
6.8 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import { useEffect, useState } from "react";
|
||
|
|
import {
|
||
|
|
Dialog,
|
||
|
|
DialogContent,
|
||
|
|
DialogHeader,
|
||
|
|
DialogTitle,
|
||
|
|
DialogFooter,
|
||
|
|
DialogClose,
|
||
|
|
} from "@/components/ui/dialog";
|
||
|
|
import { Input } from "@/components/ui/input";
|
||
|
|
import { Label } from "@/components/ui/label";
|
||
|
|
import { UploadCloud, X, Check } from "lucide-react";
|
||
|
|
import { Button } from "@/components/ui/button";
|
||
|
|
import { cn } from "@/lib/utils";
|
||
|
|
import withReactContent from "sweetalert2-react-content";
|
||
|
|
import Swal from "sweetalert2";
|
||
|
|
import { useRouter } from "next/navigation";
|
||
|
|
|
||
|
|
interface EditBannerDialogProps {
|
||
|
|
open: boolean;
|
||
|
|
onOpenChange: (open: boolean) => void;
|
||
|
|
onSubmit?: (data: FormData) => void;
|
||
|
|
bannerData?: {
|
||
|
|
id: number;
|
||
|
|
title: string;
|
||
|
|
thumbnail_url?: string;
|
||
|
|
order: number;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
export function EditBannerDialog({
|
||
|
|
open,
|
||
|
|
onOpenChange,
|
||
|
|
bannerData,
|
||
|
|
onSubmit,
|
||
|
|
}: {
|
||
|
|
open: boolean;
|
||
|
|
onOpenChange: (value: boolean) => void;
|
||
|
|
bannerData: any;
|
||
|
|
onSubmit?: (data: FormData, id: number) => void;
|
||
|
|
}) {
|
||
|
|
const [title, setTitle] = useState("");
|
||
|
|
const [file, setFile] = useState<File | null>(null);
|
||
|
|
const [preview, setPreview] = useState<string | null>(null);
|
||
|
|
const [selectedOrder, setSelectedOrder] = useState<number | null>(1);
|
||
|
|
|
||
|
|
const router = useRouter();
|
||
|
|
const MySwal = withReactContent(Swal);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (bannerData) {
|
||
|
|
setTitle(bannerData.title || "");
|
||
|
|
setPreview(bannerData.thumbnail_url || null);
|
||
|
|
setSelectedOrder(bannerData.position ? Number(bannerData.position) : 1);
|
||
|
|
}
|
||
|
|
}, [bannerData]);
|
||
|
|
|
||
|
|
const handleFileChange = (e: any) => {
|
||
|
|
const selected = e.target.files[0];
|
||
|
|
if (selected) {
|
||
|
|
setFile(selected);
|
||
|
|
setPreview(URL.createObjectURL(selected));
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleRemoveFile = () => {
|
||
|
|
setFile(null);
|
||
|
|
setPreview(null);
|
||
|
|
};
|
||
|
|
|
||
|
|
const successSubmit = () => {
|
||
|
|
MySwal.fire({
|
||
|
|
title: "Berhasil diperbarui!",
|
||
|
|
icon: "success",
|
||
|
|
confirmButtonColor: "#3085d6",
|
||
|
|
confirmButtonText: "OK",
|
||
|
|
}).then((result) => {
|
||
|
|
if (result.isConfirmed) router.refresh();
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleSubmit = async () => {
|
||
|
|
if (!title || !selectedOrder || !bannerData?.id) return;
|
||
|
|
|
||
|
|
const formData = new FormData();
|
||
|
|
formData.append("title", title);
|
||
|
|
formData.append("position", selectedOrder.toString());
|
||
|
|
formData.append("description", "dummy description");
|
||
|
|
|
||
|
|
if (file) {
|
||
|
|
formData.append("file", file);
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
await onSubmit?.(formData, bannerData.id);
|
||
|
|
successSubmit();
|
||
|
|
onOpenChange(false);
|
||
|
|
} catch (error) {
|
||
|
|
console.error("Error submit:", error);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const orderOptions = [
|
||
|
|
{ id: 1, label: "Pertama" },
|
||
|
|
{ id: 2, label: "Kedua" },
|
||
|
|
{ id: 3, label: "Ketiga" },
|
||
|
|
{ id: 4, label: "Keempat" },
|
||
|
|
{ id: 5, label: "Kelima" },
|
||
|
|
];
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||
|
|
<DialogContent className="max-w-lg p-0 overflow-hidden">
|
||
|
|
{/* Header */}
|
||
|
|
<DialogHeader className="bg-[#1F6779] px-6 py-4">
|
||
|
|
<DialogTitle className="text-white text-lg">Edit Banner</DialogTitle>
|
||
|
|
</DialogHeader>
|
||
|
|
|
||
|
|
{/* Body */}
|
||
|
|
<div className="p-6 space-y-4">
|
||
|
|
{/* Judul Banner */}
|
||
|
|
<div>
|
||
|
|
<Label className="text-gray-700">
|
||
|
|
Judul Banner <span className="text-red-500">*</span>
|
||
|
|
</Label>
|
||
|
|
<Input
|
||
|
|
value={title}
|
||
|
|
onChange={(e) => setTitle(e.target.value)}
|
||
|
|
placeholder="Masukkan judul banner"
|
||
|
|
className="mt-1"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Upload File */}
|
||
|
|
<div>
|
||
|
|
<Label className="text-gray-700">Upload File (optional)</Label>
|
||
|
|
<label
|
||
|
|
htmlFor="uploadFileEdit"
|
||
|
|
className="mt-1 border-2 border-dashed border-gray-300 rounded-xl p-6 flex flex-col items-center justify-center text-gray-500 cursor-pointer hover:border-[#1F6779]/50 transition"
|
||
|
|
>
|
||
|
|
<UploadCloud className="w-10 h-10 text-[#1F6779] mb-2" />
|
||
|
|
<p className="text-sm font-medium">
|
||
|
|
Klik untuk upload atau drag & drop
|
||
|
|
</p>
|
||
|
|
<p className="text-xs text-gray-400 mt-1">PNG, JPG (max 2 MB)</p>
|
||
|
|
<input
|
||
|
|
id="uploadFileEdit"
|
||
|
|
type="file"
|
||
|
|
accept="image/png, image/jpeg"
|
||
|
|
className="hidden"
|
||
|
|
onChange={handleFileChange}
|
||
|
|
/>
|
||
|
|
</label>
|
||
|
|
|
||
|
|
{preview && (
|
||
|
|
<div className="mt-3 relative w-28 h-28 rounded-md overflow-hidden border">
|
||
|
|
<img
|
||
|
|
src={preview}
|
||
|
|
alt="Preview"
|
||
|
|
className="w-full h-full object-cover"
|
||
|
|
/>
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={handleRemoveFile}
|
||
|
|
className="absolute top-1 right-1 bg-red-600 text-white p-1 rounded-full"
|
||
|
|
>
|
||
|
|
<X className="w-4 h-4" />
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Urutan Banner */}
|
||
|
|
<div>
|
||
|
|
<Label className="text-gray-700">
|
||
|
|
Urutan Banner <span className="text-red-500">*</span>
|
||
|
|
</Label>
|
||
|
|
<div className="grid grid-cols-5 gap-2 mt-2">
|
||
|
|
{orderOptions.map((opt) => (
|
||
|
|
<button
|
||
|
|
key={opt.id}
|
||
|
|
type="button"
|
||
|
|
onClick={() => setSelectedOrder(opt.id)}
|
||
|
|
className={cn(
|
||
|
|
"border rounded-lg py-2 flex flex-col items-center justify-center text-sm font-medium transition",
|
||
|
|
selectedOrder === opt.id
|
||
|
|
? "bg-[#1F6779]/20 border-[#1F6779] text-[#1F6779]"
|
||
|
|
: "bg-white border-gray-300 text-gray-600 hover:border-[#1F6779]/50"
|
||
|
|
)}
|
||
|
|
>
|
||
|
|
{selectedOrder === opt.id && (
|
||
|
|
<Check className="w-4 h-4 text-[#1F6779] mb-1" />
|
||
|
|
)}
|
||
|
|
<span>{opt.id}</span>
|
||
|
|
<span className="text-xs font-normal text-gray-500">
|
||
|
|
{opt.label}
|
||
|
|
</span>
|
||
|
|
</button>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Footer */}
|
||
|
|
<DialogFooter className="bg-gray-100 px-6 py-4 flex justify-end gap-3">
|
||
|
|
<DialogClose asChild>
|
||
|
|
<Button
|
||
|
|
variant="outline"
|
||
|
|
className="bg-[#A9C5CC]/40 text-[#1F6779] border-none"
|
||
|
|
>
|
||
|
|
Batal
|
||
|
|
</Button>
|
||
|
|
</DialogClose>
|
||
|
|
<Button
|
||
|
|
className="bg-[#1F6779] text-white hover:bg-[#155864]"
|
||
|
|
onClick={handleSubmit}
|
||
|
|
>
|
||
|
|
Simpan
|
||
|
|
</Button>
|
||
|
|
</DialogFooter>
|
||
|
|
</DialogContent>
|
||
|
|
</Dialog>
|
||
|
|
);
|
||
|
|
}
|