shoc-frontend-new/src/app/(protected)/pmschedules/_components/pm-schedule-form.tsx
2026-07-24 11:32:58 -03:00

216 lines
7 KiB
TypeScript

import { useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useNavigate, useParams } from "react-router";
import {
Alert,
Box,
Button,
CircularProgress,
FormControl,
FormControlLabel,
InputLabel,
MenuItem,
Paper,
Select,
Stack,
Switch,
TextField,
Typography,
} from "@mui/material";
import {
pmScheduleDefaultValues,
pmScheduleSchema,
type PmScheduleFormValues,
} from "@/domain/pm-schedules/schemas/pm-schedule-schema";
import { usePmScheduleDetail } from "@/domain/pm-schedules/use-cases/use-pm-schedule-detail";
import { usePmScheduleFormOptions } from "@/domain/pm-schedules/use-cases/use-pm-schedule-form-options";
import { useSavePmSchedule } from "@/domain/pm-schedules/use-cases/use-save-pm-schedule";
import { toDateInputValue } from "@/lib/time-utils";
export default function PmScheduleFormPage() {
const { id } = useParams();
const navigate = useNavigate();
const isEdit = Boolean(id);
const { data: schedule, isLoading, error } = usePmScheduleDetail(id);
const {
assets,
locations,
isLoading: optionsLoading,
error: optionsError,
} = usePmScheduleFormOptions();
const savePmSchedule = useSavePmSchedule(id);
const {
register,
handleSubmit,
reset,
control,
formState: { errors },
} = useForm<PmScheduleFormValues>({
resolver: zodResolver(pmScheduleSchema),
defaultValues: pmScheduleDefaultValues,
});
useEffect(() => {
if (schedule && isEdit) {
reset({
name: schedule.name,
frequency: schedule.frequency as PmScheduleFormValues["frequency"],
startDate: toDateInputValue(schedule.startDate),
isActive: schedule.isActive,
assetId: schedule.assetId,
locationId: schedule.locationId,
});
}
}, [schedule, isEdit, reset]);
if ((isEdit && isLoading) || optionsLoading) {
return (
<Box className="flex justify-center p-10">
<CircularProgress />
</Box>
);
}
return (
<Box className="mx-auto max-w-3xl p-4">
<Paper variant="outlined" className="p-6">
<Stack spacing={3}>
<Typography variant="h5">{isEdit ? "Edit PM Schedule" : "Create PM Schedule"}</Typography>
{Boolean(error) && <Alert severity="error">Failed to load PM schedule</Alert>}
{Boolean(optionsError) && (
<Alert severity="error">
{optionsError instanceof Error ? optionsError.message : "Failed to load form options"}
</Alert>
)}
<Box component="form" onSubmit={handleSubmit((values) => savePmSchedule.mutate(values))}>
<Stack spacing={3}>
<TextField
label="Name"
required
fullWidth
error={Boolean(errors.name)}
helperText={errors.name?.message}
{...register("name")}
/>
<Controller
name="frequency"
control={control}
render={({ field }) => (
<FormControl fullWidth>
<InputLabel>Frequency</InputLabel>
<Select label="Frequency" value={field.value} onChange={field.onChange}>
{["Daily", "Weekly", "Monthly", "Quarterly", "Semi-Annual", "Annual"].map(
(value) => (
<MenuItem key={value} value={value}>
{value}
</MenuItem>
),
)}
</Select>
</FormControl>
)}
/>
<TextField
label="Start Date"
type="date"
required
fullWidth
slotProps={{ inputLabel: { shrink: true } }}
error={Boolean(errors.startDate)}
helperText={errors.startDate?.message}
{...register("startDate")}
/>
<Controller
name="assetId"
control={control}
render={({ field }) => (
<FormControl fullWidth>
<InputLabel>Asset</InputLabel>
<Select
label="Asset"
value={field.value ?? ""}
onChange={(event) => {
const value = String(event.target.value);
field.onChange(value === "" ? null : Number(value));
}}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
{assets.map((asset) => (
<MenuItem key={String(asset.id)} value={asset.id}>
{asset.name || asset.assetCode}
</MenuItem>
))}
</Select>
</FormControl>
)}
/>
<Controller
name="locationId"
control={control}
render={({ field }) => (
<FormControl fullWidth>
<InputLabel>Location</InputLabel>
<Select
label="Location"
value={field.value ?? ""}
onChange={(event) => {
const value = String(event.target.value);
field.onChange(value === "" ? null : Number(value));
}}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
{locations.map((location) => (
<MenuItem key={String(location.id)} value={location.id}>
{location.name}
</MenuItem>
))}
</Select>
</FormControl>
)}
/>
<Controller
name="isActive"
control={control}
render={({ field }) => (
<FormControlLabel
control={<Switch checked={field.value} onChange={field.onChange} />}
label="Active"
/>
)}
/>
<Stack
direction="row"
spacing={2}
sx={{
justifyContent: "flex-end",
}}
>
<Button variant="outlined" onClick={() => navigate("/pmschedules")}>
Cancel
</Button>
<Button type="submit" variant="contained" disabled={savePmSchedule.isPending}>
{savePmSchedule.isPending ? "Saving..." : isEdit ? "Update" : "Create"}
</Button>
</Stack>
</Stack>
</Box>
</Stack>
</Paper>
</Box>
);
}