116 lines
5.5 KiB
TypeScript
116 lines
5.5 KiB
TypeScript
|
|
"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>
|
||
|
|
);
|
||
|
|
}
|