update:bugs dialog
This commit is contained in:
parent
e1f99bd4c4
commit
9bc0b301cb
|
|
@ -115,7 +115,7 @@ export function DialogDetailGaleri({ open, onClose, data }: any) {
|
||||||
const res = await commentGalery(id, message || undefined);
|
const res = await commentGalery(id, message || undefined);
|
||||||
|
|
||||||
if (res?.error) {
|
if (res?.error) {
|
||||||
error(res.message || "Gagal komentar promotion");
|
error(res.message || "Gagal komentar galeri");
|
||||||
close();
|
close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -161,11 +161,24 @@ export function DialogDetailGaleri({ open, onClose, data }: any) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Dialog open={open} onOpenChange={onClose}>
|
<div
|
||||||
<DialogContent className=" rounded-2xl p-0 overflow-hidden">
|
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
|
||||||
{/* Header */}
|
onClick={onClose}
|
||||||
<div className="bg-[#1F6779] text-white px-6 py-4">
|
>
|
||||||
<DialogTitle className="text-white">Detail Galeri</DialogTitle>
|
<div
|
||||||
|
className="bg-white rounded-2xl shadow-2xl max-w-xl 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={onClose}
|
||||||
|
className="absolute top-4 right-4 text-white/80 hover:text-white text-xl"
|
||||||
|
>
|
||||||
|
✕
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<h2 className="text-lg font-semibold">Detail Galeri</h2>
|
||||||
<div className="flex items-center gap-2 mt-3">
|
<div className="flex items-center gap-2 mt-3">
|
||||||
<span
|
<span
|
||||||
className={`text-xs font-medium px-3 py-1 rounded-full ${
|
className={`text-xs font-medium px-3 py-1 rounded-full ${
|
||||||
|
|
@ -199,7 +212,7 @@ export function DialogDetailGaleri({ open, onClose, data }: any) {
|
||||||
|
|
||||||
<div className=" py-3">
|
<div className=" py-3">
|
||||||
{/* Images List */}
|
{/* Images List */}
|
||||||
<div className="mx-2">
|
<div className="mx-4">
|
||||||
<h2 className="text-2xl font-semibold text-black">
|
<h2 className="text-2xl font-semibold text-black">
|
||||||
{data.title}
|
{data.title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
@ -240,7 +253,7 @@ export function DialogDetailGaleri({ open, onClose, data }: any) {
|
||||||
{/* Deskripsi */}
|
{/* Deskripsi */}
|
||||||
|
|
||||||
{/* Tanggal Upload */}
|
{/* Tanggal Upload */}
|
||||||
<div className="mx-2">
|
<div className="mx-4">
|
||||||
<p className="font-medium text-sm text-gray-700">
|
<p className="font-medium text-sm text-gray-700">
|
||||||
Tanggal Upload
|
Tanggal Upload
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -250,7 +263,7 @@ export function DialogDetailGaleri({ open, onClose, data }: any) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Timeline */}
|
{/* Timeline */}
|
||||||
<div className="mx-2">
|
<div className="mx-4">
|
||||||
<h4 className="text-sm font-semibold text-gray-700 mb-3">
|
<h4 className="text-sm font-semibold text-gray-700 mb-3">
|
||||||
Status Timeline
|
Status Timeline
|
||||||
</h4>
|
</h4>
|
||||||
|
|
@ -374,17 +387,8 @@ export function DialogDetailGaleri({ open, onClose, data }: any) {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{/* <DialogFooter className="px-6 pb-6">
|
</div>
|
||||||
<button
|
|
||||||
onClick={onClose}
|
|
||||||
className="bg-gray-300 text-gray-700 px-6 py-2 rounded-lg"
|
|
||||||
>
|
|
||||||
Tutup
|
|
||||||
</button>
|
|
||||||
</DialogFooter> */}
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
{openApproverHistory && (
|
{openApproverHistory && (
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 z-[60] flex items-center justify-center bg-black/50 p-4"
|
className="fixed inset-0 z-[60] flex items-center justify-center bg-black/50 p-4"
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import { error, loading, success } from "@/config/swal";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
import promo from "../landing-page/promo";
|
import promo from "../landing-page/promo";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
type PromoDetailDialogProps = {
|
type PromoDetailDialogProps = {
|
||||||
promoId: number | null;
|
promoId: number | null;
|
||||||
|
|
@ -220,16 +221,24 @@ export default function PromoDetailDialog({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
<div
|
||||||
<DialogContent className="p-0 max-w-lg overflow-hidden">
|
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-2xl max-w-xl w-full overflow-hidden"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
{/* HEADER */}
|
{/* HEADER */}
|
||||||
<div className="bg-gradient-to-r from-[#0f6c75] to-[#145f66] text-white px-6 py-5 relative">
|
<div className="bg-gradient-to-br from-[#1F6779] to-[#0F6C75] text-white px-6 py-5 relative">
|
||||||
<DialogHeader>
|
<button
|
||||||
<DialogTitle className="text-white text-xl font-semibold">
|
onClick={() => onOpenChange(false)}
|
||||||
Detail Promoaa
|
className="absolute top-4 right-4 text-white/80 hover:text-white text-xl"
|
||||||
</DialogTitle>
|
>
|
||||||
</DialogHeader>
|
✕
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<h2 className="text-lg font-semibold">Detail Promo</h2>
|
||||||
<div className="flex items-center gap-2 mt-3">
|
<div className="flex items-center gap-2 mt-3">
|
||||||
<span
|
<span
|
||||||
className={`text-xs font-medium px-3 py-1 rounded-full ${
|
className={`text-xs font-medium px-3 py-1 rounded-full ${
|
||||||
|
|
@ -279,8 +288,15 @@ export default function PromoDetailDialog({
|
||||||
|
|
||||||
<div className="space-y-4 text-sm">
|
<div className="space-y-4 text-sm">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-gray-600">Ukuran File</p>
|
<div className="w-24 h-24 rounded-lg overflow-hidden border">
|
||||||
<p className="font-medium">{promo.fileSize}</p>
|
<Image
|
||||||
|
src={promo.thumbnail_url}
|
||||||
|
alt="Profile"
|
||||||
|
width={96}
|
||||||
|
height={96}
|
||||||
|
className="object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -418,104 +434,6 @@ export default function PromoDetailDialog({
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{openApproverHistory && (
|
|
||||||
<div
|
|
||||||
className=" flex items-center justify-center bg-black/50 p-4"
|
|
||||||
onClick={() => setOpenApproverHistory(false)}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="bg-white rounded-2xl shadow-2xl max-w-3xl 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={() => setOpenApproverHistory(false)}
|
|
||||||
className="absolute top-4 right-4 text-white/80 hover:text-white text-xl"
|
|
||||||
>
|
|
||||||
✕
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<h2 className="text-lg font-semibold">Approver History</h2>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-2 mt-3">
|
|
||||||
<span className="bg-yellow-100 text-yellow-800 text-xs font-medium px-3 py-1 rounded-full">
|
|
||||||
Menunggu
|
|
||||||
</span>
|
|
||||||
<span className="bg-white text-[#0F6C75] text-xs font-medium px-3 py-1 rounded-full">
|
|
||||||
Banner
|
|
||||||
</span>
|
|
||||||
<span className="bg-white/20 text-white text-xs px-2 py-[2px] rounded-full">
|
|
||||||
1
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* BODY */}
|
|
||||||
<div className="p-6 grid grid-cols-[1fr_auto_1fr] gap-6 items-start">
|
|
||||||
{/* LEFT TIMELINE */}
|
|
||||||
<div className="relative space-y-6">
|
|
||||||
{/* Upload */}
|
|
||||||
<div className="flex flex-col items-center">
|
|
||||||
<span className="bg-[#C7DDE4] text-[#0F6C75] text-xs px-4 py-1 rounded-full">
|
|
||||||
Upload
|
|
||||||
</span>
|
|
||||||
<div className="w-px h-6 bg-gray-300" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Diterima */}
|
|
||||||
<div className="relative bg-[#1F6779] text-white rounded-xl p-4">
|
|
||||||
<h4 className="font-semibold text-sm mb-2">Diterima</h4>
|
|
||||||
<span className="inline-block bg-[#E3EFF4] text-[#0F6C75] text-xs px-3 py-1 rounded-full">
|
|
||||||
Direview oleh: approver-jaecoo1
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-px h-6 bg-gray-300 mx-auto" />
|
|
||||||
|
|
||||||
{/* Pending */}
|
|
||||||
<div className="relative bg-[#B36A00] text-white rounded-xl p-4">
|
|
||||||
<h4 className="font-semibold text-sm mb-2">Pending</h4>
|
|
||||||
<span className="inline-block bg-[#FFF6CC] text-[#7A4A00] text-xs px-3 py-1 rounded-full">
|
|
||||||
Direview oleh: approver-jaecoo1
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* ARROW */}
|
|
||||||
<div className="flex flex-col gap-20 text-gray-500 font-bold">
|
|
||||||
<span>></span>
|
|
||||||
<span>></span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* RIGHT NOTES */}
|
|
||||||
<div className="space-y-14">
|
|
||||||
<div>
|
|
||||||
<div className="bg-[#C7DDE4] text-sm px-4 py-2 rounded-lg">
|
|
||||||
Catatan:
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div className="bg-[#FFF9C4] text-sm px-4 py-2 rounded-lg">
|
|
||||||
Catatan:
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* FOOTER */}
|
|
||||||
<div className="border-t bg-[#F2F7FA] text-center py-3">
|
|
||||||
<button
|
|
||||||
onClick={() => setOpenApproverHistory(false)}
|
|
||||||
className="text-[#0F6C75] font-medium hover:underline"
|
|
||||||
>
|
|
||||||
Tutup
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{/* FOOTER
|
{/* FOOTER
|
||||||
<div className="bg-[#E3EFF4] text-center py-3">
|
<div className="bg-[#E3EFF4] text-center py-3">
|
||||||
<button
|
<button
|
||||||
|
|
@ -525,8 +443,8 @@ export default function PromoDetailDialog({
|
||||||
Tutup
|
Tutup
|
||||||
</button>
|
</button>
|
||||||
</div> */}
|
</div> */}
|
||||||
</DialogContent>
|
</div>
|
||||||
</Dialog>
|
</div>
|
||||||
{openApproverHistory && (
|
{openApproverHistory && (
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 z-[60] flex items-center justify-center bg-black/50 p-4"
|
className="fixed inset-0 z-[60] flex items-center justify-center bg-black/50 p-4"
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,10 @@ export default function AddProductForm() {
|
||||||
>([{ id: 1, name: "", file: null }]);
|
>([{ id: 1, name: "", file: null }]);
|
||||||
|
|
||||||
const [selectedColor, setSelectedColor] = useState<string | null>(null);
|
const [selectedColor, setSelectedColor] = useState<string | null>(null);
|
||||||
const [specs, setSpecs] = useState([{ id: 1 }]);
|
const [specs, setSpecs] = useState<
|
||||||
|
{ id: number; title: string; file: File | null }[]
|
||||||
|
>([{ id: 1, title: "", file: null }]);
|
||||||
|
|
||||||
const [file, setFile] = useState<File | null>(null);
|
const [file, setFile] = useState<File | null>(null);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const MySwal = withReactContent(Swal);
|
const MySwal = withReactContent(Swal);
|
||||||
|
|
@ -40,9 +43,9 @@ export default function AddProductForm() {
|
||||||
if (selected) setFile(selected);
|
if (selected) setFile(selected);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddSpec = () => {
|
// const handleAddSpec = () => {
|
||||||
setSpecs((prev) => [...prev, { id: prev.length + 1 }]);
|
// setSpecs((prev) => [...prev, { id: prev.length + 1 }]);
|
||||||
};
|
// };
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
|
|
@ -52,6 +55,22 @@ export default function AddProductForm() {
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleSpecTitleChange = (index: number, value: string) => {
|
||||||
|
const updated = [...specs];
|
||||||
|
updated[index].title = value;
|
||||||
|
setSpecs(updated);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSpecFileChange = (
|
||||||
|
index: number,
|
||||||
|
e: React.ChangeEvent<HTMLInputElement>,
|
||||||
|
) => {
|
||||||
|
const file = e.target.files?.[0] || null;
|
||||||
|
const updated = [...specs];
|
||||||
|
updated[index].file = file;
|
||||||
|
setSpecs(updated);
|
||||||
|
};
|
||||||
|
|
||||||
const onSubmit = async (data: z.infer<typeof formSchema>) => {
|
const onSubmit = async (data: z.infer<typeof formSchema>) => {
|
||||||
try {
|
try {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
@ -80,6 +99,19 @@ export default function AddProductForm() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 🔥 specifications JSON
|
||||||
|
const specificationsPayload = specs.map((s) => ({
|
||||||
|
title: s.title,
|
||||||
|
}));
|
||||||
|
formData.append("specifications", JSON.stringify(specificationsPayload));
|
||||||
|
|
||||||
|
// 🔥 imagespecification_url (files)
|
||||||
|
specs.forEach((s) => {
|
||||||
|
if (s.file) {
|
||||||
|
formData.append("imagespecification_url", s.file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
await createProduct(formData);
|
await createProduct(formData);
|
||||||
successSubmit("/admin/product");
|
successSubmit("/admin/product");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -311,36 +343,49 @@ export default function AddProductForm() {
|
||||||
Judul Spesifikasi {index + 1}
|
Judul Spesifikasi {index + 1}
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Contoh: Mesin Turbo 1.6L, Interior Premium, Safety Features"
|
placeholder="Contoh: Mesin Turbo 1.6L"
|
||||||
className="mt-1"
|
className="mt-1"
|
||||||
|
value={spec.title}
|
||||||
|
onChange={(e) => handleSpecTitleChange(index, e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Label className="text-sm font-semibold mt-4 block">
|
<Label className="text-sm font-semibold mt-4 block">
|
||||||
Foto Spesifikasi {index + 1}
|
Foto Spesifikasi {index + 1}
|
||||||
</Label>
|
</Label>
|
||||||
<div className="border-2 border-dashed rounded-lg flex flex-col items-center justify-center py-10 cursor-pointer hover:bg-gray-50 transition mt-1">
|
|
||||||
|
<label
|
||||||
|
htmlFor={`spec-file-${index}`}
|
||||||
|
className="border-2 border-dashed rounded-lg flex flex-col items-center justify-center py-10 cursor-pointer hover:bg-gray-50 transition mt-1"
|
||||||
|
>
|
||||||
<Upload className="w-8 h-8 text-gray-400 mb-2" />
|
<Upload className="w-8 h-8 text-gray-400 mb-2" />
|
||||||
<p className="text-sm text-gray-500 text-center">
|
<p className="text-sm text-gray-500 text-center">
|
||||||
Klik untuk upload gambar spesifikasi
|
Klik untuk upload gambar spesifikasi
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-gray-400">PNG, JPG (max 5 MB)</p>
|
<p className="text-xs text-gray-400">PNG, JPG (max 5 MB)</p>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
|
id={`spec-file-${index}`}
|
||||||
type="file"
|
type="file"
|
||||||
accept="image/png,image/jpeg"
|
accept="image/png,image/jpeg"
|
||||||
className="hidden"
|
className="hidden"
|
||||||
|
onChange={(e) => handleSpecFileChange(index, e)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</label>
|
||||||
|
|
||||||
|
{spec.file && (
|
||||||
|
<p className="text-xs text-teal-700 mt-2">{spec.file.name}</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<button
|
{/* <button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleAddSpec}
|
onClick={handleAddSpec}
|
||||||
className="w-full bg-teal-800 hover:bg-teal-900 text-white py-3 rounded-lg mt-6 flex items-center justify-center gap-2"
|
className="w-full bg-teal-800 hover:bg-teal-900 text-white py-3 rounded-lg mt-6 flex items-center justify-center gap-2"
|
||||||
>
|
>
|
||||||
<Plus className="w-4 h-4" />
|
<Plus className="w-4 h-4" />
|
||||||
Tambahkan Spesifikasi Baru
|
Tambahkan Spesifikasi Baru
|
||||||
</button>
|
</button> */}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,7 @@ export default function ArticleTable() {
|
||||||
setViewBanner(item);
|
setViewBanner(item);
|
||||||
setOpenViewDialog(true);
|
setOpenViewDialog(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const [previewImage, setPreviewImage] = useState<string | null>(null);
|
const [previewImage, setPreviewImage] = useState<string | null>(null);
|
||||||
|
|
||||||
const handleOpenApproverHistory = () => {
|
const handleOpenApproverHistory = () => {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,14 @@
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
images: {
|
images: {
|
||||||
domains: ["mikulnews.com", "dev.mikulnews.com", "jaecoocihampelasbdg.com"],
|
domains: [
|
||||||
|
"mikulnews.com",
|
||||||
|
"dev.mikulnews.com",
|
||||||
|
"jaecoocihampelasbdg.com",
|
||||||
|
"jaecookelapagading.com",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
eslint: {
|
eslint: {
|
||||||
ignoreDuringBuilds: true,
|
ignoreDuringBuilds: true,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue