satupeta-main/app/(modules)/maps/components/mapset-dialog/main/dataset-detail-sidebar.tsx

116 lines
5.5 KiB
TypeScript
Raw Normal View History

2026-01-27 02:31:12 +00:00
"use client";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/shared/components/ui/tabs";
import { cn } from "@/shared/utils/utils";
import { useAtomValue } from "jotai";
import { selectedMapsetAtom } from "../../../state/mapset-dialog";
import DownloadGeojsonBtn from "./download-geojson-btn";
import DownloadShpBtn from "./download-shp-btn";
import DownloadKmlBtn from "./download-kml-btn";
import { statusValidationLabel } from "@/shared/config/status-validation";
export function DatasetDetailSidebar({
open,
onCloseAction,
onOpenAction,
}: Readonly<{
open: boolean;
onCloseAction: () => void;
onOpenAction: () => void;
}>) {
const selectedMapset = useAtomValue(selectedMapsetAtom);
if (!selectedMapset) return null;
return (
<>
{/* Sliding panel */}
<div className={cn("absolute z-[400] top-0 right-0 h-full w-[480px] bg-white shadow-lg border-l transition-transform duration-300 flex flex-col", open ? "translate-x-0" : "translate-x-full")}>
<div className="relative flex items-center justify-between px-6 py-4 border-b">
<h2 className="font-semibold text-lg">{selectedMapset.name}</h2>
</div>
{/* Make Tabs fill available space and be flex column */}
<Tabs defaultValue="informasi" className="w-full flex-1 min-h-0 flex flex-col">
<TabsList className="grid grid-cols-2 rounded-none w-full p-0 h-auto bg-white border-b border-gray-200">
<TabsTrigger value="informasi" className="cursor-pointer data-[state=active]:text-white data-[state=active]:bg-primary data-[state=active]:border-t border-primary h-full border-0 rounded-none p-3">
Informasi Dataset Geospasial
</TabsTrigger>
<TabsTrigger value="penanggung" className="cursor-pointer data-[state=active]:text-white data-[state=active]:bg-primary h-full rounded-none p-3">
Penanggung Jawab
</TabsTrigger>
</TabsList>
<TabsContent value="informasi" className="p-6 pb-20 overflow-y-auto">
<div className="space-y-3 text-sm">
<Row label="Klasifikasi" value={`: ${selectedMapset.classification.name}`} />
<Row label="Deskripsi" value={`: ${selectedMapset.description}`} />
<Row label="Kategori" value={`: ${selectedMapset.category.name}`} />
<Row label="Skala" value={`: ${selectedMapset.scale}`} />
<Row label="Status Data" value={`: ${selectedMapset.data_status}`} />
<Row label="Periode Update" value={`: ${selectedMapset.data_update_period}`} />
<Row label="Versi Data" value={`: ${selectedMapset.data_version}`} />
<Row label="Sistem Proyeksi" value={`: ${selectedMapset.projection_system.name}`} />
<Row label="Status Validasi" value={`: ${statusValidationLabel[selectedMapset.status_validation as keyof typeof statusValidationLabel]}`} />
<Row
label="Link Metadata"
value={
<span className="break-words">
:{" "}
{selectedMapset.metadata_url ? (
<a href={selectedMapset.metadata_url} target="_blank" rel="noopener noreferrer" className="text-primary underline break-all max-w-full">
{selectedMapset.metadata_url}
</a>
) : (
""
)}
</span>
}
/>
</div>
</TabsContent>
<TabsContent value="penanggung" className="p-6">
<div className="space-y-3 text-sm">
<Row label="Nama Organisasi" value={`: ${selectedMapset.producer.name}`} />
<Row label="Deskripsi" value={`: ${selectedMapset.producer.description}`} />
<Row label="Alamat" value={`: ${selectedMapset.producer.address}`} />
<Row label="Telepon" value={`: ${selectedMapset.producer.phone_number}`} />
<Row label="Email" value={`: ${selectedMapset.producer.email}`} />
<Row label="Website" value={`: ${selectedMapset.producer.website}`} />
</div>
</TabsContent>
</Tabs>
<div className="absolute bottom-0 w-full bg-zinc-100 py-2.5 px-4 grid grid-cols-3 gap-2">
<DownloadGeojsonBtn mapset={selectedMapset} />
<DownloadShpBtn mapset={selectedMapset} />
<DownloadKmlBtn mapset={selectedMapset} />
</div>
</div>
{/* Right-edge handle: at page edge when closed, moves to seam when open */}
<button
type="button"
aria-label={open ? "Tutup panel" : "Buka panel"}
onClick={() => (open ? onCloseAction() : onOpenAction())}
className={cn(
"fixed top-1/2 -translate-y-1/2 right-0 z-[450] h-16 w-10 rounded-l-2xl rounded-r-none bg-white shadow border border-zinc-200 flex items-center justify-center hover:bg-zinc-50 focus:outline-none cursor-pointer",
open ? "translate-x-[-480px]" : "translate-x-0"
)}
>
{open ? <ChevronRight className="w-5 h-5 text-zinc-800" /> : <ChevronLeft className="w-5 h-5 text-zinc-800" />}
</button>
</>
);
}
function Row({ label, value }: { label: string; value: React.ReactNode }) {
return (
<div className="flex items-start">
<span className="w-[160px] font-medium">{label}</span>
<span className="flex-1 min-w-0">{value}</span>
</div>
);
}