refactor: modularize road management modules

This commit is contained in:
2026-06-17 13:31:25 +05:30
parent 9bb740e446
commit 182d4ac293
41 changed files with 2386 additions and 1894 deletions

View File

@@ -0,0 +1,170 @@
'use client';
import type { ComponentProps } from 'react';
import type { FieldErrors, UseFormRegister, UseFormReturn } from 'react-hook-form';
import { Globe, Loader2, Package as PackageIcon } from 'lucide-react';
import { FormField } from '@/components/form';
import { Button } from '@/components/ui/button';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import type { Project } from '@/types';
import type { PackageFormValues } from '../hooks/usePackageForm';
interface PackageDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
packageId?: string;
projects: Project[];
isProjectsLoading: boolean;
projectId: string;
onProjectChange: (projectId: string) => void;
register: UseFormRegister<PackageFormValues>;
errors: FieldErrors<PackageFormValues>;
touchedFields: UseFormReturn<PackageFormValues>['formState']['touchedFields'];
onSubmit: ComponentProps<'form'>['onSubmit'];
canSubmit: boolean;
isSaving: boolean;
}
export function PackageDialog({
open,
onOpenChange,
packageId,
projects,
isProjectsLoading,
projectId,
onProjectChange,
register,
errors,
touchedFields,
onSubmit,
canSubmit,
isSaving,
}: PackageDialogProps) {
const projectErrorMessage = touchedFields.project_id ? errors.project_id?.message : undefined;
const nameErrorMessage = touchedFields.name ? errors.name?.message : undefined;
const startErrorMessage = touchedFields.chainage_start_km
? errors.chainage_start_km?.message
: undefined;
const endErrorMessage = touchedFields.chainage_end_km
? errors.chainage_end_km?.message
: undefined;
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-2xl" onOpenAutoFocus={(event) => event.preventDefault()}>
<DialogHeader className="gap-2">
<DialogTitle className="flex items-center gap-3 text-xl">
<div className="rounded-lg bg-primary p-2 text-primary-foreground shadow-sm">
<PackageIcon className="size-5" />
</div>
{packageId ? 'Edit Package Details' : 'Create New Package'}
</DialogTitle>
<DialogDescription className="text-sm">
{packageId
? 'Update the technical specifications for your road infrastructure package.'
: 'Select a project and provide the essential data to establish a new package.'}
</DialogDescription>
</DialogHeader>
<form onSubmit={onSubmit} className="space-y-6">
{!packageId ? (
<FormField label="Project" required error={projectErrorMessage}>
<Select value={projectId} onValueChange={onProjectChange}>
<SelectTrigger aria-invalid={!!projectErrorMessage}>
{isProjectsLoading ? (
<span className="flex items-center gap-2 text-sm text-muted-foreground">
<Loader2 className="size-4 animate-spin" />
Loading...
</span>
) : (
<SelectValue placeholder="Choose a project" />
)}
</SelectTrigger>
<SelectContent>
{projects.map((project) => (
<SelectItem key={project.id} value={project.id}>
{project.name}
</SelectItem>
))}
</SelectContent>
</Select>
<input type="hidden" {...register('project_id')} value={projectId} readOnly />
</FormField>
) : null}
<div className="grid gap-5 md:grid-cols-2">
<FormField id="package-name" label="Package Name" required error={nameErrorMessage}>
<Input
id="package-name"
placeholder="e.g. Package 01"
aria-invalid={!!nameErrorMessage}
{...register('name')}
/>
</FormField>
<FormField
id="package-region"
label={
<span className="inline-flex items-center gap-2">
<Globe className="size-3.5 opacity-60" />
Region
</span>
}
>
<Input id="package-region" placeholder="e.g. North Zone" {...register('region')} />
</FormField>
<FormField id="package-start" label="Segment Start (km)" error={startErrorMessage}>
<Input
id="package-start"
type="number"
step="0.01"
placeholder="0.00"
aria-invalid={!!startErrorMessage}
{...register('chainage_start_km')}
/>
</FormField>
<FormField id="package-end" label="Segment End (km)" error={endErrorMessage}>
<Input
id="package-end"
type="number"
step="0.01"
placeholder="0.00"
aria-invalid={!!endErrorMessage}
{...register('chainage_end_km')}
/>
</FormField>
</div>
<DialogFooter>
<Button type="button" variant="outline" onClick={() => onOpenChange(false)} disabled={isSaving}>
Cancel
</Button>
<Button type="submit" disabled={isSaving || !canSubmit}>
{isSaving ? <Loader2 className="size-4 animate-spin" /> : null}
{packageId ? 'Update Package' : 'Create Package'}
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
);
}