web-campaignpool/components/form/campaign-form.tsx

477 lines
16 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Label } from "@/components/ui/label";
import { Calendar } from "@/components/ui/calendar";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { CalendarIcon, Plus, Trash2 } from "lucide-react";
import { format } from "date-fns";
import { id } from "date-fns/locale";
import { Progress } from "../ui/progress";
import DialogMediaOnline from "../dialog/media-online";
import DialogMediaSosial from "../dialog/media-sosial";
export default function FormCampaign() {
const [startDate, setStartDate] = useState<Date | undefined>(undefined);
const [endDate, setEndDate] = useState<Date | undefined>(undefined);
const [goal, setGoal] = useState("Publikasi");
const [available, setAvailable] = useState("Yes");
const [isUploadOpen, setIsUploadOpen] = useState(false);
const [media, setMedia] = useState("Media Online");
const [isDialogOpen, setIsDialogOpen] = useState(false);
// contoh data pilihan media online (bisa diganti sesuai kebutuhan)
const mediaOnlineList = [
"Tribrata News Mabes",
"Tribrata News Polda Aceh",
"Tribrata News Polda Jawa Timur",
"Tribrata News Polda Jawa Tengah",
"Tribrata News Polda Jawa Barat",
];
const [selectedMediaOnline, setSelectedMediaOnline] = useState<string[]>([]);
const toggleMediaOnline = (item: string) => {
setSelectedMediaOnline((prev) =>
prev.includes(item) ? prev.filter((m) => m !== item) : [...prev, item]
);
};
const [files, setFiles] = useState<
{ file: File; progress: number; uploaded: boolean }[]
>([]);
const [url, setUrl] = useState("");
// ✅ Upload dari file input
const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
const selectedFiles = e.target.files;
if (!selectedFiles) return;
const newFiles = Array.from(selectedFiles).map((f) => ({
file: f,
progress: 0,
uploaded: false,
}));
setFiles((prev) => [...prev, ...newFiles]);
simulateUpload(newFiles);
};
// ✅ Simulasi upload progress
const simulateUpload = (
fileList: { file: File; progress: number; uploaded: boolean }[]
) => {
fileList.forEach((fileObj) => {
let progress = 0;
const interval = setInterval(() => {
progress += 10;
setFiles((prev) =>
prev.map((f) =>
f.file === fileObj.file
? { ...f, progress, uploaded: progress >= 100 }
: f
)
);
if (progress >= 100) clearInterval(interval);
}, 300);
});
};
// ✅ Upload dari URL
const handleUploadFromUrl = () => {
if (!url.trim()) return;
const fakeFile = {
file: new File([], url.split("/").pop() || "file_from_url.jpg"),
progress: 100,
uploaded: true,
};
setFiles((prev) => [...prev, fakeFile]);
setUrl("");
};
// ✅ Hapus file
const removeFile = (index: number) => {
setFiles((prev) => prev.filter((_, i) => i !== index));
};
return (
<div className="bg-white rounded-2xl shadow-sm p-6 space-y-8">
{/* Langkah 1 */}
<section className="border-b pb-6">
<h2 className="font-semibold mb-4">Langkah 1</h2>
<p className="text-sm font-medium mb-2">Pilih Durasi</p>
<div className="flex flex-wrap gap-4">
<div>
<Label className="text-sm">Dari Tanggal</Label>
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
className="w-[200px] justify-start text-left font-normal"
>
<CalendarIcon className="mr-2 h-4 w-4" />
{startDate
? format(startDate, "dd MMMM yyyy", { locale: id })
: "Pilih tanggal"}
</Button>
</PopoverTrigger>
<PopoverContent className="p-0" align="start">
<Calendar
mode="single"
selected={startDate}
onSelect={setStartDate}
locale={id}
/>
</PopoverContent>
</Popover>
</div>
<div>
<Label className="text-sm">Sampai Tanggal</Label>
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
className="w-[200px] justify-start text-left font-normal"
>
<CalendarIcon className="mr-2 h-4 w-4" />
{endDate
? format(endDate, "dd MMMM yyyy", { locale: id })
: "Pilih tanggal"}
</Button>
</PopoverTrigger>
<PopoverContent className="p-0" align="start">
<Calendar
mode="single"
selected={endDate}
onSelect={setEndDate}
locale={id}
/>
</PopoverContent>
</Popover>
</div>
</div>
</section>
<section className="border-b pb-6">
<h2 className="font-semibold mb-4">Langkah 2</h2>
<p className="text-sm font-medium mb-2">Pilih Media</p>
<RadioGroup
value={media}
onValueChange={setMedia}
className="flex flex-wrap gap-4"
>
{[
"Media Online",
"Media Sosial",
"Videotron",
"Radio Polri",
"TV Polri",
"Majalah Digital",
].map((m) => (
<div key={m} className="flex items-center space-x-2">
<RadioGroupItem value={m} id={m} />
<Label htmlFor={m}>{m}</Label>
</div>
))}
</RadioGroup>
{/* Tombol muncul sesuai media terpilih */}
{media === "Media Online" && (
<Button
variant="outline"
size="sm"
className="mt-4"
onClick={() => setIsDialogOpen(true)}
>
<Plus className="h-4 w-4 mr-2" />
Tambahkan Media Online
</Button>
)}
{media === "Media Sosial" && (
<Button
variant="outline"
size="sm"
className="mt-4"
onClick={() => setIsDialogOpen(true)}
>
<Plus className="h-4 w-4 mr-2" />
Tambahkan Media Sosial
</Button>
)}
{media === "Videotron" && (
<Button
variant="outline"
size="sm"
className="mt-4"
onClick={() => setIsDialogOpen(true)}
>
<Plus className="h-4 w-4 mr-2" />
Tambahkan Videotron
</Button>
)}
{/* 🧩 Komponen DialogMediaOnline dipanggil di sini */}
{media === "Media Online" && (
<DialogMediaOnline
isOpen={isDialogOpen}
onClose={() => setIsDialogOpen(false)}
/>
)}
{media === "Media Sosial" && (
<DialogMediaSosial
isOpen={isDialogOpen}
onClose={() => setIsDialogOpen(false)}
/>
)}
{media === "Videotron" && (
<DialogMediaSosial
isOpen={isDialogOpen}
onClose={() => setIsDialogOpen(false)}
/>
)}
{media === "Radio Polri" && (
<div className="mt-4 space-y-3">
{[
"Pagi pukul 06:00 07:00",
"Siang pukul 12:00 13:00",
"Sore pukul 16:00 17:00",
"Malam pukul 20:00 21:00",
].map((time) => (
<div key={time} className="flex items-center space-x-2">
<input
type="checkbox"
id={time}
value={time}
className="w-4 h-4 border border-purple-600 text-purple-600 focus:ring-2 focus:ring-purple-500 rounded"
/>
<Label htmlFor={time} className="text-sm">
{time}
</Label>
</div>
))}
</div>
)}
{media === "TV Polri" && (
<div className="mt-4 space-y-3">
{[
"Pagi pukul 06:00 07:00",
"Siang pukul 12:00 13:00",
"Sore pukul 16:00 17:00",
"Malam pukul 20:00 21:00",
].map((time) => (
<div key={time} className="flex items-center space-x-2">
<input
type="checkbox"
id={time}
value={time}
className="w-4 h-4 border border-purple-600 text-purple-600 focus:ring-2 focus:ring-purple-500 rounded"
/>
<Label htmlFor={time} className="text-sm">
{time}
</Label>
</div>
))}
</div>
)}
</section>
{/* Langkah 3 */}
<section className="border-b pb-6">
<h2 className="font-semibold mb-4">Langkah 3</h2>
<p className="text-sm font-medium mb-2">Tujuan</p>
<RadioGroup value={goal} onValueChange={setGoal} className="flex gap-4">
{["Publikasi", "Sosialisasi"].map((g) => (
<div key={g} className="flex items-center space-x-2">
<RadioGroupItem value={g} id={g} />
<Label htmlFor={g}>{g}</Label>
</div>
))}
</RadioGroup>
</section>
{/* Langkah 4 */}
<section>
<h2 className="font-semibold mb-4">Langkah 4</h2>
<p className="text-sm font-medium mb-2">Materi Promote Tersedia</p>
<RadioGroup
value={available}
onValueChange={setAvailable}
className="flex gap-4 mb-4"
>
{["Yes", "Tidak"].map((a) => (
<div key={a} className="flex items-center space-x-2">
<RadioGroupItem value={a} id={a} />
<Label htmlFor={a}>{a}</Label>
</div>
))}
</RadioGroup>
{available === "Yes" ? (
// ✅ Jika user pilih "Yes" → tampil upload file
<div className="space-y-2">
<Label className="text-sm font-medium">Upload File</Label>
<div className="flex items-center gap-2">
<Button
variant="outline"
size="sm"
onClick={() => setIsUploadOpen(true)}
>
<Plus className="h-4 w-4 mr-2" />
Upload File
</Button>
</div>
</div>
) : (
// ✅ Jika user pilih "Tidak" → tampil textarea deskripsi
<div className="space-y-2">
<Label className="text-sm font-medium">Deskripsi Promote</Label>
<textarea
placeholder="Tulis deskripsi promote..."
className="w-full min-h-[100px] p-3 border rounded-md text-sm resize-none focus:outline-none focus:ring-2 focus:ring-primary"
/>
</div>
)}
</section>
<div className="pt-6">
<Button className="w-[120px]" size="lg">
Submit
</Button>
</div>
{/* Modal Upload */}
<Dialog open={isUploadOpen} onOpenChange={setIsUploadOpen}>
<DialogContent className="max-w-lg w-[90vw] sm:w-full">
<DialogHeader>
<DialogTitle>Unggah Berkas</DialogTitle>
<p className="text-sm text-muted-foreground">
Pilih berkas dan unggah dengan aman untuk melanjutkan.
</p>
</DialogHeader>
{/* === Upload Section === */}
<div className="border-2 border-dashed rounded-lg p-6 flex flex-col items-center justify-center text-center space-y-2 w-full">
<p className="text-sm text-muted-foreground">
Seret dan jatuhkan berkas Anda
</p>
<p className="text-xs text-muted-foreground">
Format .PNG, .JPG, dan .JPEG hingga 50MB
</p>
<label htmlFor="fileInput">
<Button
variant="outline"
size="sm"
className="mt-2 cursor-pointer"
>
Pilih Berkas
</Button>
<Input
id="fileInput"
type="file"
multiple
className="hidden"
onChange={handleFileUpload}
/>
</label>
</div>
{/* === Upload via URL === */}
<div className="flex flex-col sm:flex-row items-center gap-2 mt-4 w-full">
<Input
type="url"
placeholder="Tambahkan URL berkas"
value={url}
onChange={(e) => setUrl(e.target.value)}
className="flex-1"
/>
<Button onClick={handleUploadFromUrl} className="w-full sm:w-auto">
Unggah
</Button>
</div>
{/* === Uploaded Files === */}
{files.length > 0 && (
<div className="mt-5 space-y-3 max-h-[60vh] overflow-y-auto">
<h4 className="text-sm font-semibold">Uploaded Files</h4>
<div className="space-y-2">
{files.map((f, i) => (
<div
key={i}
className="border rounded-lg p-3 flex flex-wrap sm:flex-nowrap justify-between items-start sm:items-center gap-3"
>
<div className="flex flex-col min-w-0 flex-1">
<p className="text-sm font-medium truncate max-w-[250px]">
{f.file.name}
</p>
<p className="text-xs text-muted-foreground">
{(f.file.size / (1024 * 1024)).toFixed(1)}MB {" "}
{f.uploaded ? (
<span className="text-green-600 font-medium">
Uploaded Successfully
</span>
) : (
<span className="text-blue-600 font-medium">
{f.progress}% Uploading...
</span>
)}
</p>
{!f.uploaded && (
<Progress
value={f.progress}
className="h-1 mt-1 w-full bg-gray-200"
/>
)}
</div>
<Button
variant="ghost"
size="icon"
onClick={() => removeFile(i)}
className="shrink-0"
>
<Trash2 className="h-4 w-4 text-muted-foreground" />
</Button>
</div>
))}
</div>
</div>
)}
<DialogFooter className="mt-4 flex flex-col sm:flex-row justify-end gap-2 sm:gap-4">
<Button
variant="outline"
onClick={() => setIsUploadOpen(false)}
className="w-full sm:w-auto"
>
Batal
</Button>
<Button
onClick={() => setIsUploadOpen(false)}
className="w-full sm:w-auto"
>
Lampirkan Berkas
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
);
}