299 lines
11 KiB
TypeScript
Executable File
299 lines
11 KiB
TypeScript
Executable File
"use client";
|
|
|
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
import { useAtom } from "jotai";
|
|
import { useRouter, useParams } from "next/navigation";
|
|
import { useEffect } from "react";
|
|
import { Loader2 } from "lucide-react";
|
|
import { toast } from "sonner";
|
|
|
|
import categoryApi from "@/shared/services/category";
|
|
import classificationApi from "@/shared/services/classification";
|
|
import mapProjectionSystemApi from "@/shared/services/map-projection-system";
|
|
import organizationApi from "@/shared/services/organization";
|
|
import mapSourceApi from "@/shared/services/map-source";
|
|
import mapsetApi from "@/shared/services/mapset";
|
|
|
|
import { MapsetInfoForm } from "../../_components/form/mapset-info-form";
|
|
import { MapsetMetadataForm } from "../../_components/form/mapset-metadata-form";
|
|
import { MapsetVersionForm } from "../../_components/form/mapset-version-form";
|
|
import MapsetTab from "../../_components/form/mapset-tab";
|
|
|
|
import { PaginatedResponse } from "@/shared/types/api-response";
|
|
import { MapsetSubmitPayload } from "@/shared/types/mapset";
|
|
import StatusValidation from "@/shared/config/status-validation";
|
|
import { activeTabAtom, mapsetFormAtom, MapsetFormState, MapsetFormTab } from "../../state";
|
|
import PageHeader from "../../../_components/page-header";
|
|
import { MapsetClassificationForm } from "../../_components/form/mapset-classification-form";
|
|
import { useAuthSession } from "@/shared/hooks/use-session";
|
|
|
|
interface SelectOption {
|
|
id: string;
|
|
name: string;
|
|
}
|
|
|
|
export default function EditMapsPageClient() {
|
|
const router = useRouter();
|
|
const params = useParams();
|
|
const mapsetId = params.id as string;
|
|
const queryClient = useQueryClient();
|
|
const [activeTab, setActiveTab] = useAtom(activeTabAtom);
|
|
const [formState, setFormState] = useAtom(mapsetFormAtom);
|
|
|
|
const { session } = useAuthSession();
|
|
const isDataManager = session?.user?.role?.name === "data_manager";
|
|
|
|
const {
|
|
data: mapset,
|
|
isLoading: isLoadingMapset,
|
|
refetch,
|
|
} = useQuery({
|
|
queryKey: ["mapset", mapsetId],
|
|
queryFn: () => mapsetApi.getMapsetById(mapsetId),
|
|
enabled: !!mapsetId && !!session?.user,
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (mapsetId && session?.user?.role?.name) {
|
|
refetch();
|
|
}
|
|
}, [mapsetId, session, refetch]);
|
|
|
|
const { data: projectionSystemsResponse, isLoading: isLoadingProjections } = useQuery({
|
|
queryKey: ["projectionSystems"],
|
|
queryFn: () => mapProjectionSystemApi.getMapProjectionSystems(),
|
|
staleTime: 5 * 60 * 1000,
|
|
refetchOnMount: false,
|
|
enabled: !!session?.user,
|
|
});
|
|
|
|
const { data: categoriesResponse, isLoading: isLoadingCategories } = useQuery({
|
|
queryKey: ["categories"],
|
|
queryFn: () => categoryApi.getCategories(),
|
|
staleTime: 5 * 60 * 1000,
|
|
refetchOnMount: false,
|
|
enabled: !!session?.user,
|
|
});
|
|
|
|
const { data: classificationsResponse, isLoading: isLoadingClassifications } = useQuery({
|
|
queryKey: ["classifications"],
|
|
queryFn: () => classificationApi.getClassifications(),
|
|
staleTime: 5 * 60 * 1000,
|
|
refetchOnMount: false,
|
|
enabled: !!session?.user,
|
|
});
|
|
|
|
const { data: organizationsResponse, isLoading: isLoadingOrganizations } = useQuery({
|
|
queryKey: ["organizations"],
|
|
queryFn: () => organizationApi.getOrganizations(),
|
|
staleTime: 5 * 60 * 1000,
|
|
refetchOnMount: false,
|
|
enabled: !!session?.user,
|
|
});
|
|
|
|
const { data: mapSourcesResponse, isLoading: isLoadingMapSources } = useQuery({
|
|
queryKey: ["map-sources"],
|
|
queryFn: () => mapSourceApi.getMapSources(),
|
|
staleTime: 5 * 60 * 1000,
|
|
refetchOnMount: false,
|
|
enabled: !!session?.user,
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (mapset) {
|
|
const geoserverSource = mapset.sources.find((source) => source.url?.includes("geoserver"));
|
|
|
|
const geonetworkSource = mapset.sources.find((source) => source.url?.includes("geonetwork"));
|
|
setFormState({
|
|
info: {
|
|
name: mapset.name,
|
|
description: mapset.description,
|
|
scale: mapset.scale,
|
|
projection_system_id: mapset?.projection_system?.id,
|
|
category_id: mapset?.category?.id,
|
|
data_status: mapset.data_status,
|
|
classification_id: mapset?.classification?.id,
|
|
organization_id: mapset?.producer?.id,
|
|
is_popular: mapset.is_popular,
|
|
layer_type: mapset?.layer_type,
|
|
},
|
|
metadata: {
|
|
source_id: geoserverSource?.id || null,
|
|
layer_url: mapset.layer_url,
|
|
metadata_source_id: geonetworkSource?.id || null,
|
|
metadata_url: mapset.metadata_url,
|
|
},
|
|
classification: {
|
|
coverage_level: mapset.coverage_level,
|
|
coverage_area: mapset.coverage_area,
|
|
},
|
|
version: {
|
|
data_update_period: mapset.data_update_period,
|
|
data_version: mapset.data_version,
|
|
},
|
|
});
|
|
}
|
|
}, [mapset, setFormState]);
|
|
|
|
useEffect(() => {
|
|
if (session?.user && !mapset && !isLoadingMapset) {
|
|
const currentUrl = window.location.pathname + window.location.search;
|
|
router.replace(currentUrl);
|
|
}
|
|
}, [session, mapset, isLoadingMapset, router]);
|
|
|
|
const isLoading =
|
|
isLoadingMapset ||
|
|
isLoadingProjections ||
|
|
isLoadingCategories ||
|
|
isLoadingClassifications ||
|
|
isLoadingOrganizations ||
|
|
isLoadingMapSources ||
|
|
!projectionSystemsResponse ||
|
|
!categoriesResponse ||
|
|
!classificationsResponse ||
|
|
!organizationsResponse ||
|
|
!mapSourcesResponse;
|
|
|
|
const mapDataToOptions = <T extends { id: string; name: string }>(response: PaginatedResponse<T[]> | undefined): SelectOption[] => {
|
|
if (!response || !response.items) return [];
|
|
return response.items.map((item) => ({ id: item.id, name: item.name }));
|
|
};
|
|
|
|
const projectionSystemOptions = mapDataToOptions(projectionSystemsResponse);
|
|
const categoryOptions = mapDataToOptions(categoriesResponse);
|
|
const classificationOptions = mapDataToOptions(classificationsResponse);
|
|
const organizationOptions = mapDataToOptions(organizationsResponse);
|
|
const mapSourceOptions = mapDataToOptions(mapSourcesResponse);
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const updateFormData = (tabKey: keyof MapsetFormState, data: any) => {
|
|
setFormState({
|
|
...formState,
|
|
[tabKey]: data,
|
|
});
|
|
};
|
|
|
|
const handleContinue = () => {
|
|
if (activeTab < MapsetFormTab.VERSION) {
|
|
setActiveTab((prev) => prev + 1);
|
|
}
|
|
};
|
|
|
|
const handlePrevious = () => {
|
|
if (activeTab > MapsetFormTab.INFO) {
|
|
setActiveTab(activeTab - 1);
|
|
}
|
|
};
|
|
|
|
const updateMapsetMutation = useMutation({
|
|
mutationFn: (mapsetData: MapsetSubmitPayload) => {
|
|
return mapsetApi.updateMapset(mapsetId, mapsetData);
|
|
},
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ["mapsets"] });
|
|
queryClient.invalidateQueries({ queryKey: ["mapset", mapsetId] });
|
|
toast.success("Mapset berhasil diperbarui!");
|
|
router.push("/admin/mapset");
|
|
},
|
|
onError: (error: Error) => {
|
|
toast.error(error.message || "Terjadi kesalahan saat memperbarui data");
|
|
},
|
|
});
|
|
|
|
const handleSubmitMapset = (versionData: { data_update_period: string; data_version: string }) => {
|
|
updateFormData("version", versionData);
|
|
|
|
const payload: MapsetSubmitPayload = {
|
|
name: formState.info.name,
|
|
description: formState.info.description,
|
|
scale: formState.info.scale,
|
|
projection_system_id: formState.info.projection_system_id,
|
|
category_id: formState.info.category_id,
|
|
data_status: formState.info.data_status,
|
|
classification_id: formState.info.classification_id,
|
|
producer_id: formState.info.organization_id,
|
|
layer_type: formState.info.layer_type,
|
|
source_id: [formState.metadata.source_id, formState.metadata.metadata_source_id].filter((id) => id !== "lainnya" && id !== null) as string[],
|
|
layer_url: formState.metadata.layer_url,
|
|
metadata_url: formState.metadata.metadata_url,
|
|
coverage_level: formState.classification.coverage_level,
|
|
coverage_area: formState.classification.coverage_area,
|
|
data_update_period: versionData.data_update_period,
|
|
data_version: versionData.data_version,
|
|
is_popular: formState.info.is_popular || false,
|
|
is_active: mapset?.is_active || true,
|
|
regional_id: mapset?.regional.id || "01968b53-a910-7a67-bd10-975b8923b92e",
|
|
status_validation: mapset?.status_validation || StatusValidation.ON_VERIFICATION,
|
|
};
|
|
|
|
updateMapsetMutation.mutate(payload);
|
|
};
|
|
|
|
if (isLoading || !mapset) {
|
|
return (
|
|
<div className="flex items-center justify-center min-h-[400px]">
|
|
<div className="flex flex-col items-center space-y-2">
|
|
<Loader2 className="h-8 w-8 animate-spin text-blue-500" />
|
|
<p className="text-sm text-gray-500">Memuat data...</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<PageHeader className="bg-zinc-50" title="Ubah Mapset dan Metadata" description="Ubah mapset dan metadata untuk memperbarui data geospasial di Satu Peta." />
|
|
<MapsetTab formState={formState} activeTab={activeTab} handleTabChange={(e: number) => setActiveTab(e)} />
|
|
<div className="max-w-xl">
|
|
{activeTab === MapsetFormTab.INFO && (
|
|
<MapsetInfoForm
|
|
initialData={formState.info}
|
|
projectionSystems={projectionSystemOptions}
|
|
categories={categoryOptions}
|
|
classifications={classificationOptions}
|
|
organizations={organizationOptions}
|
|
isOrgFieldDisabled={isDataManager}
|
|
onSubmit={(data) => {
|
|
updateFormData("info", data);
|
|
handleContinue();
|
|
}}
|
|
/>
|
|
)}
|
|
{activeTab === MapsetFormTab.METADATA && (
|
|
<MapsetMetadataForm
|
|
initialData={formState.metadata}
|
|
mapSources={mapSourceOptions}
|
|
onSubmit={(data) => {
|
|
updateFormData("metadata", data);
|
|
handleContinue();
|
|
}}
|
|
onPrevious={handlePrevious}
|
|
/>
|
|
)}
|
|
{activeTab === MapsetFormTab.CLASSIFICATION && (
|
|
<MapsetClassificationForm
|
|
initialData={formState.classification}
|
|
onSubmit={(data) => {
|
|
updateFormData("classification", data);
|
|
handleContinue();
|
|
}}
|
|
onPrevious={handlePrevious}
|
|
/>
|
|
)}
|
|
{activeTab === MapsetFormTab.VERSION && (
|
|
<MapsetVersionForm
|
|
initialData={formState.version}
|
|
onSubmit={handleSubmitMapset}
|
|
onPrevious={handlePrevious}
|
|
isSubmitting={updateMapsetMutation.isPending}
|
|
onDataChange={(data) => {
|
|
updateFormData("version", data);
|
|
}}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|