Files
road-monitoring-ui/src/app/(modules)/segment/page.tsx

193 lines
5.4 KiB
TypeScript

'use client';
import { useCallback, useState } from 'react';
import { Milestone, Plus } from 'lucide-react';
import { PageHeader } from '@/components/page-header';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { Button } from '@/components/ui/button';
import type { Chainage } from '@/types';
import { SegmentDialog } from './components/SegmentDialog';
import { SegmentTable } from './components/SegmentTable';
import { useSegmentColumns } from './components/SegmentColumns';
import { useSegmentFilters } from './hooks/useSegmentFilters';
import { useSegmentForm } from './hooks/useSegmentForm';
import {
useAllPackageOptionsQuery,
useDeleteSegmentMutation,
useProjectOptionsQuery,
useSegmentsQuery,
} from './hooks/useSegmentQueries';
export default function SegmentPage() {
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [segmentToDelete, setSegmentToDelete] = useState<Chainage | null>(null);
const { skip, setSkip, limit, setLimit } = useSegmentFilters();
const segmentsQuery = useSegmentsQuery({ skip, limit });
const projectsQuery = useProjectOptionsQuery();
const allPackagesQuery = useAllPackageOptionsQuery();
const deleteSegmentMutation = useDeleteSegmentMutation();
const segmentForm = useSegmentForm({
onSaved: () => setIsDialogOpen(false),
});
const {
register,
onSubmit,
openCreate: prepareCreateSegment,
openEdit: prepareEditSegment,
resetForm,
segmentId,
projectId,
setProjectId,
packageId,
setPackageId,
direction,
setDirection,
errors,
isSubmitted,
canSubmit,
isSaving,
} = segmentForm;
const openCreate = useCallback(() => {
prepareCreateSegment();
setIsDialogOpen(true);
}, [prepareCreateSegment]);
const openEdit = useCallback(
(segment: Chainage) => {
const pkg = allPackagesQuery.data?.items.find(
(item) => item.id === segment.package_id,
);
prepareEditSegment(segment, pkg?.project_id || '');
setIsDialogOpen(true);
},
[allPackagesQuery.data?.items, prepareEditSegment],
);
const handleDialogOpenChange = useCallback(
(open: boolean) => {
setIsDialogOpen(open);
if (!open) {
resetForm();
}
},
[resetForm],
);
const deleteSegment = useCallback(
(segment: Chainage) => {
setSegmentToDelete(segment);
},
[],
);
const handleDeleteDialogOpenChange = useCallback((open: boolean) => {
if (!open) {
setSegmentToDelete(null);
}
}, []);
const confirmDeleteSegment = useCallback(() => {
if (!segmentToDelete) return;
deleteSegmentMutation.mutate(segmentToDelete, {
onSettled: () => setSegmentToDelete(null),
});
}, [deleteSegmentMutation, segmentToDelete]);
const projects = projectsQuery.data?.items ?? [];
const allPackages = allPackagesQuery.data?.items ?? [];
const segments = segmentsQuery.data?.items ?? [];
const total = segmentsQuery.data?.totalItems ?? 0;
const columns = useSegmentColumns(projects, allPackages);
return (
<>
<main className="relative z-10 space-y-5">
<PageHeader
title="Segment Management"
description="Manage road segments"
icon={Milestone}
actions={
<Button onClick={openCreate} size="sm">
<Plus />
Add Segment
</Button>
}
/>
<SegmentTable
columns={columns}
segments={segments}
isLoading={segmentsQuery.isLoading || deleteSegmentMutation.isPending}
skip={skip}
limit={limit}
total={total}
onPageChange={setSkip}
onLimitChange={setLimit}
onEdit={openEdit}
onDelete={deleteSegment}
/>
</main>
<SegmentDialog
open={isDialogOpen}
onOpenChange={handleDialogOpenChange}
segmentId={segmentId}
projectId={projectId}
onProjectChange={setProjectId}
packageId={packageId}
onPackageChange={setPackageId}
direction={direction}
onDirectionChange={setDirection}
register={register}
errors={errors}
isSubmitted={isSubmitted}
onSubmit={onSubmit}
canSubmit={canSubmit}
isSaving={isSaving}
/>
<AlertDialog
open={Boolean(segmentToDelete)}
onOpenChange={handleDeleteDialogOpenChange}
>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete segment?</AlertDialogTitle>
<AlertDialogDescription>
This will permanently delete{' '}
<span className="font-medium text-foreground">
{segmentToDelete?.segment_name}
</span>
. This action cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel disabled={deleteSegmentMutation.isPending}>
Cancel
</AlertDialogCancel>
<AlertDialogAction
variant="destructive"
disabled={deleteSegmentMutation.isPending}
onClick={confirmDeleteSegment}
>
Delete
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
);
}