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,180 @@
'use client';
import type { ComponentProps } from 'react';
import type { FieldErrors, UseFormRegister, UseFormReturn } from 'react-hook-form';
import { Layers, Loader2, MapPin, Route } 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 type { ProjectFormValues } from '../hooks/useProjectForm';
interface ProjectDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
projectId?: string;
register: UseFormRegister<ProjectFormValues>;
errors: FieldErrors<ProjectFormValues>;
touchedFields: UseFormReturn<ProjectFormValues>['formState']['touchedFields'];
onSubmit: ComponentProps<'form'>['onSubmit'];
canSubmit: boolean;
isSaving: boolean;
}
export function ProjectDialog({
open,
onOpenChange,
projectId,
register,
errors,
touchedFields,
onSubmit,
canSubmit,
isSaving,
}: ProjectDialogProps) {
const nameErrorMessage = touchedFields.name ? errors.name?.message : undefined;
const startLatErrorMessage = touchedFields.start_lat ? errors.start_lat?.message : undefined;
const startLngErrorMessage = touchedFields.start_lng ? errors.start_lng?.message : undefined;
const endLatErrorMessage = touchedFields.end_lat ? errors.end_lat?.message : undefined;
const endLngErrorMessage = touchedFields.end_lng ? errors.end_lng?.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">
<Layers className="size-5" />
</div>
{projectId ? 'Edit Project Details' : 'Create New Project'}
</DialogTitle>
<DialogDescription className="text-sm">
{projectId
? 'Update the technical specifications for your road infrastructure project.'
: 'Provide the essential road data to establish a new analysis project.'}
</DialogDescription>
</DialogHeader>
<form onSubmit={onSubmit} className="space-y-6">
<FormField id="project-name" label="Project Name" required error={nameErrorMessage}>
<Input
id="project-name"
placeholder="Enter a descriptive project name"
aria-invalid={!!nameErrorMessage}
{...register('name')}
/>
</FormField>
<div className="grid gap-5 md:grid-cols-2">
<FormField id="project-state" label="State">
<Input id="project-state" placeholder="e.g. Maharashtra" {...register('state')} />
</FormField>
<FormField
id="project-corridor"
label={
<span className="inline-flex items-center gap-2">
<Route className="size-3.5 opacity-60" />
Corridor Name
</span>
}
>
<Input
id="project-corridor"
placeholder="e.g. Mumbai-Goa Highway"
{...register('corridor_name')}
/>
</FormField>
</div>
<div className="grid gap-8 pt-2 md:grid-cols-2">
<div className="space-y-4">
<p className="flex items-center gap-2 text-[11px] font-black tracking-widest text-muted-foreground">
<MapPin className="size-3.5 opacity-60" />
START POINT
</p>
<div className="grid grid-cols-2 gap-4">
<FormField id="project-start-lat" label="Lat" error={startLatErrorMessage}>
<Input
id="project-start-lat"
type="number"
step="any"
placeholder="0.0000"
className="font-mono text-xs"
aria-invalid={!!startLatErrorMessage}
{...register('start_lat')}
/>
</FormField>
<FormField id="project-start-lng" label="Lng" error={startLngErrorMessage}>
<Input
id="project-start-lng"
type="number"
step="any"
placeholder="0.0000"
className="font-mono text-xs"
aria-invalid={!!startLngErrorMessage}
{...register('start_lng')}
/>
</FormField>
</div>
</div>
<div className="space-y-4">
<p className="flex items-center gap-2 text-[11px] font-black tracking-widest text-muted-foreground">
<MapPin className="size-3.5 opacity-60" />
END POINT
</p>
<div className="grid grid-cols-2 gap-4">
<FormField id="project-end-lat" label="Lat" error={endLatErrorMessage}>
<Input
id="project-end-lat"
type="number"
step="any"
placeholder="0.0000"
className="font-mono text-xs"
aria-invalid={!!endLatErrorMessage}
{...register('end_lat')}
/>
</FormField>
<FormField id="project-end-lng" label="Lng" error={endLngErrorMessage}>
<Input
id="project-end-lng"
type="number"
step="any"
placeholder="0.0000"
className="font-mono text-xs"
aria-invalid={!!endLngErrorMessage}
{...register('end_lng')}
/>
</FormField>
</div>
</div>
</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}
{projectId ? 'Update Project' : 'Create Project'}
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
);
}