kontenhumas-fe/components/landing-page/schedule.tsx

593 lines
18 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, useEffect } from "react";
import { format } from "date-fns";
import { Calendar } from "@/components/ui/calendar";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { CalendarIcon, ChevronRight } from "lucide-react";
import { cn } from "@/lib/utils";
import {
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem,
} from "@/components/ui/select";
import { Badge } from "@/components/ui/badge";
import { getAllSchedules } from "@/service/landing/landing";
import { getPublicClients } from "@/service/client/public-clients";
export default function Schedule() {
const [search, setSearch] = useState("");
const [startDate, setStartDate] = useState<Date | undefined>(new Date());
const [endDate, setEndDate] = useState<Date | undefined>(new Date());
const [selectedCategory, setSelectedCategory] = useState("SEMUA");
const [selectedSlug, setSelectedSlug] = useState<string | undefined>(
undefined
);
const [scheduleData, setScheduleData] = useState<any[]>([]);
const [clients, setClients] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
// 🔹 Fetch daftar client
useEffect(() => {
async function fetchClients() {
try {
const res = await getPublicClients();
if (res?.data?.success && res.data.data) {
setClients(res.data.data);
} else {
setClients([]);
}
} catch (error) {
console.error("Error fetching clients:", error);
setClients([]);
}
}
fetchClients();
}, []);
// 🔹 Fetch jadwal dari API (termasuk clientSlug)
const fetchSchedules = async () => {
try {
setLoading(true);
const params = {
title: search || undefined,
startDate: startDate ? format(startDate, "yyyy-MM-dd") : undefined,
endDate: endDate ? format(endDate, "yyyy-MM-dd") : undefined,
clientSlug: selectedSlug, // 🔥 Tambahkan clientSlug untuk filter
page: 1,
limit: 50,
sortBy: "startDate",
sort: "asc",
};
const res = await getAllSchedules(params);
if (!res.error) {
const apiData = Array.isArray(res.data)
? res.data
: Array.isArray(res.data?.data)
? res.data.data
: Array.isArray(res.data?.records)
? res.data.records
: [];
setScheduleData(apiData);
} else {
console.error("Gagal memuat jadwal:", res.message);
setScheduleData([]);
}
} catch (error) {
console.error("Error fetching schedules:", error);
setScheduleData([]);
} finally {
setLoading(false);
}
};
// 🔹 Re-fetch setiap kali filter berubah
useEffect(() => {
fetchSchedules();
}, [startDate, endDate, search, selectedSlug]);
return (
<div className="p-6 max-w-[1350px] mx-auto">
{/* Filter Bar */}
<div className="flex flex-wrap gap-4 items-center mb-6">
<Input
placeholder="Pencarian"
className="w-70 mt-7"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
{/* Tanggal Mulai */}
<div className="flex flex-col gap-2">
<label className="text-sm font-medium">Tanggal Mulai</label>
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
className="w-[160px] justify-start text-left"
>
<CalendarIcon className="mr-2 h-4 w-4" />
{startDate ? format(startDate, "dd MMM yyyy") : "Pilih"}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar
mode="single"
selected={startDate}
onSelect={setStartDate}
initialFocus
/>
</PopoverContent>
</Popover>
</div>
{/* Tanggal Selesai */}
<div className="flex flex-col gap-2">
<label className="text-sm font-medium">Tanggal Selesai</label>
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
className="w-[160px] justify-start text-left"
>
<CalendarIcon className="mr-2 h-4 w-4" />
{endDate ? format(endDate, "dd MMM yyyy") : "Pilih"}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar
mode="single"
selected={endDate}
onSelect={setEndDate}
initialFocus
/>
</PopoverContent>
</Popover>
</div>
</div>
{/* 🔹 Dynamic Category dari API */}
<div className="flex w-full gap-5 overflow-x-auto pb-2 border-b border-[#C6A455] mb-6">
<Button
key="SEMUA"
variant={selectedCategory === "SEMUA" ? "default" : "outline"}
className={cn(
"rounded-sm whitespace-nowrap",
selectedCategory === "SEMUA" && "bg-[#C6A455] text-white"
)}
onClick={() => {
setSelectedCategory("SEMUA");
setSelectedSlug(undefined); // reset filter
}}
>
SEMUA
</Button>
{clients.map((client) => (
<Button
key={client.slug || client.name}
variant={
selectedCategory === client.name.toUpperCase()
? "default"
: "outline"
}
className={cn(
"rounded-sm whitespace-nowrap flex items-center gap-2",
selectedCategory === client.name.toUpperCase() &&
"bg-[#C6A455] text-white"
)}
onClick={() => {
setSelectedCategory(client.name.toUpperCase());
setSelectedSlug(client.slug); // 🔥 Set slug untuk filter API
}}
>
{client.logoUrl && (
<img
src={client.logoUrl}
alt={client.name}
className="w-5 h-5 rounded"
/>
)}
{client.name}
</Button>
))}
<Button variant="ghost">
<ChevronRight className="w-5 h-5" />
</Button>
</div>
{/* Schedule Table */}
<h2 className="text-md font-semibold text-muted-foreground mb-4">
Semua Jadwal
</h2>
{loading ? (
<div className="text-center text-muted-foreground py-10">
Memuat data jadwal...
</div>
) : scheduleData.length === 0 ? (
<div className="text-center text-muted-foreground py-10">
Tidak ada jadwal ditemukan.
</div>
) : (
<div className="flex flex-col gap-3 justify-between">
{scheduleData.map((item, index) => (
<div
key={index}
className="flex justify-between items-start border-b pb-2"
>
<div className="w-2/5">
{item.startDate ? (
<>
{format(new Date(item.startDate), "dd MMM yyyy")}
{item.endDate &&
item.endDate !== item.startDate &&
`${format(new Date(item.endDate), "dd MMM yyyy")}`}
</>
) : (
"-"
)}
</div>
<div className="w-2/5 text-xs text-gray-400 mt-0.5">
{item.startTime && item.endTime ? (
<>
{item.startTime.slice(0, 5)} {item.endTime.slice(0, 5)}
</>
) : item.startTime ? (
item.startTime.slice(0, 5)
) : (
""
)}
</div>
{/* Client */}
<div className="w-1/5">
<Badge className="bg-[#C6A455] text-white">
{item.clientName || "-"}
</Badge>
</div>
{/* Judul & Lokasi */}
<div className="w-2/5">{item.title}</div>
<div className="w-1/3 text-muted-foreground">{item.location}</div>
</div>
))}
</div>
)}
<div className="flex justify-between mt-6 text-sm text-blue-600">
<button>Preview</button>
<button>Next</button>
</div>
</div>
);
}
// "use client";
// import { useState } from "react";
// import { format } from "date-fns";
// import { Calendar } from "@/components/ui/calendar";
// import {
// Popover,
// PopoverContent,
// PopoverTrigger,
// } from "@/components/ui/popover";
// import { Button } from "@/components/ui/button";
// import { Input } from "@/components/ui/input";
// import { CalendarIcon, ChevronRight } from "lucide-react";
// import { cn } from "@/lib/utils";
// import {
// Select,
// SelectTrigger,
// SelectValue,
// SelectContent,
// SelectItem,
// } from "@/components/ui/select";
// import { Badge } from "@/components/ui/badge";
// const scheduleData = [
// {
// date: "Jul 1 2025",
// type: "POLRI",
// title: "HUT Bhayangkara RI - 79",
// location: "Mabes Polri, Jakarta, Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "POLRI",
// title: "Hari Lahir Pancasila",
// location: "Mabes Polri, Jakarta, Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "POLRI",
// title: "Pers Rilis Kasus",
// location: "Mabes Polri, Jakarta, Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "POLRI",
// title: "Rapat Koordinasi HUT Bhayangkara RI - 79",
// location: "Mabes Polri, Jakarta, Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "MPR",
// title: "Rapat PIMPINAN MPR RI",
// location: "Gedung MPR, Jakarta, Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "DPR",
// title: "Rapat Anggota Komisi I",
// location: "Gedung DPR, Jakarta, Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "MPR",
// title: "Sidang Paripurna",
// location: "Gedung MPR, Jakarta, Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "KEJAKSAAN AGUNG",
// title: "Hari Lahir Pancasila",
// location: "Kejaksaan Agung, Jakarta, Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "KPU",
// title: "Hari Lahir Pancasila",
// location: "Kantor KPU, Jakarta Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "DPR",
// title: "Rapat Anggota Komisi II",
// location: "Gedung DPR, Jakarta, Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "MPR",
// title: "Rapat DPR dan Basarnas",
// location: "Gedung MPR, Jakarta, Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "BUMN",
// title: "Hari Lahir Pancasila",
// location: "Kantor BUMN, Jakarta Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "BUMN",
// title: "Focus Group Discussion",
// location: "Kantor BUMN, Jakarta Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "MPR",
// title: "Rapat Anggota MPR RI",
// location: "Gedung MPR, Jakarta, Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "BUMN",
// title: "Seremoni Sinergi BUMN",
// location: "Kantor BUMN, Jakarta Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "MPR",
// title: "Sumpah Janji Anggota MPR RI",
// location: "Gedung MPR, Jakarta, Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "KPK",
// title: "Hari Lahir Pancasila",
// location: "Kantor KPK, Jakarta Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "BUMN",
// title: "Monitoring dan Evaluasi Keterbukaan Informasi Publik Tahun 2025",
// location: "Kantor BUMN, Jakarta Indonesia",
// },
// {
// date: "Jul 1 2025",
// type: "KEJAKSAAN AGUNG",
// title: "Hari Lahir Pancasila",
// location: "Kejaksaan Agung, Jakarta, Indonesia",
// },
// {
// date: "Jul 2 2025",
// type: "MPR",
// title: "Monitoring dan Evaluasi Informasi MPR Tahun 2025",
// location: "Gedung MPR, Jakarta, Indonesia",
// },
// ];
// const categories = [
// "SEMUA",
// "POLRI",
// "MAHKAMAH AGUNG",
// "DPR",
// "MPR",
// "KEJAKSAAN AGUNG",
// "KPK",
// "PUPR",
// "BSKDN",
// "BUMN",
// "KPU",
// ];
// export default function Schedule() {
// const [search, setSearch] = useState("");
// const [startDate, setStartDate] = useState<Date | undefined>(
// new Date("2025-07-01")
// );
// const [endDate, setEndDate] = useState<Date | undefined>(
// new Date("2025-07-30")
// );
// const [selectedCategory, setSelectedCategory] = useState("SEMUA");
// const filteredData = scheduleData.filter((item) => {
// const matchesCategory =
// selectedCategory === "SEMUA" || item.type === selectedCategory;
// const matchesSearch = item.title
// .toLowerCase()
// .includes(search.toLowerCase());
// return matchesCategory && matchesSearch;
// });
// return (
// <div className="p-6 max-w-[1350px] mx-auto">
// {/* Filter Bar */}
// <div className="flex flex-wrap gap-4 items-center mb-6">
// <Input
// placeholder="Pencarian"
// className="w-70 mt-7"
// value={search}
// onChange={(e) => setSearch(e.target.value)}
// />
// {/* Tanggal Mulai */}
// <div className="flex flex-col gap-2">
// <label className="text-sm font-medium">Tanggal Mulai</label>
// <Popover>
// <PopoverTrigger asChild>
// <Button
// variant="outline"
// className="w-[160px] justify-start text-left"
// >
// <CalendarIcon className="mr-2 h-4 w-4" />
// {startDate ? format(startDate, "dd MMM yyyy") : "Pilih"}
// </Button>
// </PopoverTrigger>
// <PopoverContent className="w-auto p-0">
// <Calendar
// mode="single"
// selected={startDate}
// onSelect={setStartDate}
// initialFocus
// />
// </PopoverContent>
// </Popover>
// </div>
// {/* Tanggal Selesai */}
// <div className="flex flex-col gap-2">
// <label className="text-sm font-medium">Tanggal Selesai</label>
// <Popover>
// <PopoverTrigger asChild>
// <Button
// variant="outline"
// className="w-[160px] justify-start text-left"
// >
// <CalendarIcon className="mr-2 h-4 w-4" />
// {endDate ? format(endDate, "dd MMM yyyy") : "Pilih"}
// </Button>
// </PopoverTrigger>
// <PopoverContent className="w-auto p-0">
// <Calendar
// mode="single"
// selected={endDate}
// onSelect={setEndDate}
// initialFocus
// />
// </PopoverContent>
// </Popover>
// </div>
// {/* Publikasi */}
// <div className="flex flex-col gap-2">
// <label className="text-sm font-medium">Publikasi</label>
// <Select>
// <SelectTrigger className="w-[150px]">
// <SelectValue placeholder="Semua" />
// </SelectTrigger>
// <SelectContent>
// <SelectItem value="semua">K/L</SelectItem>
// <SelectItem value="dipublikasikan">BUMN</SelectItem>
// <SelectItem value="belum">PEMERINTAH DAERAH</SelectItem>
// </SelectContent>
// </Select>
// </div>
// </div>
// {/* Filter Chips */}
// <div className="flex w-full gap-5 overflow-x-auto pb-2 border-b border-[#C6A455] mb-6">
// {categories.map((cat) => (
// <Button
// key={cat}
// variant={selectedCategory === cat ? "default" : "outline"}
// className={cn(
// "rounded-sm whitespace-nowrap",
// selectedCategory === cat && "bg-[#C6A455] text-white"
// )}
// onClick={() => setSelectedCategory(cat)}
// >
// {cat}
// </Button>
// ))}
// <Button variant="ghost">
// <ChevronRight className="w-5 h-5" />
// </Button>
// </div>
// {/* Schedule Table */}
// <h2 className="text-md font-semibold text-muted-foreground mb-4">
// Semua Jadwal
// </h2>
// <div className="flex flex-col gap-3">
// {filteredData.map((item, index) => (
// <div
// key={index}
// className="flex justify-between items-start border-b pb-2"
// >
// <div className="w-1/6 text-sm text-muted-foreground">
// {item.date}
// </div>
// <div className="w-1/5">
// <Badge
// className={cn("text-white", {
// "bg-red-600": item.type === "POLRI",
// "bg-yellow-500": item.type === "DPR",
// "bg-green-600": item.type === "KEJAKSAAN AGUNG",
// "bg-blue-700": item.type === "BUMN",
// "bg-amber-500": item.type === "MPR",
// "bg-pink-500": item.type === "KPU",
// "bg-red-700": item.type === "KPK",
// })}
// >
// {item.type}
// </Badge>
// </div>
// <div className="w-2/5 text-sm">{item.title}</div>
// <div className="w-1/3 text-sm text-muted-foreground">
// {item.location}
// </div>
// </div>
// ))}
// </div>
// <div className="flex justify-between mt-6 text-sm text-blue-600">
// <button>Preview</button>
// <button>Next</button>
// </div>
// </div>
// );
// }