shoc-frontend-new/src/app/(protected)/accounts/_components/account-form.tsx

194 lines
6.2 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,
InputLabel,
MenuItem,
Paper,
Select,
Stack,
TextField,
Typography,
} from "@mui/material";
import { accountSchema, type AccountFormValues } from "@/domain/accounts/schemas/account-schema";
import { useAccountDetail } from "@/domain/accounts/use-cases/use-account-detail";
import { useCreateAccount } from "@/domain/accounts/use-cases/use-create-account";
import { useUpdateAccount } from "@/domain/accounts/use-cases/use-update-account";
const defaultValues: AccountFormValues = {
AccountName: "",
AccountNumber: "",
Industry: "",
Website: "",
Notes: "",
Address1: "",
Address2: "",
City: "",
State: "",
Zip: "",
Country: "US",
};
export default function AccountFormPage() {
const { id } = useParams();
const navigate = useNavigate();
const isEdit = Boolean(id);
const { data: account, isLoading, error } = useAccountDetail(id);
const createAccount = useCreateAccount();
const updateAccount = useUpdateAccount();
const {
register,
handleSubmit,
reset,
control,
formState: { errors },
} = useForm<AccountFormValues>({
resolver: zodResolver(accountSchema),
defaultValues,
});
useEffect(() => {
if (account && isEdit) {
reset({
AccountName: account.AccountName ?? "",
AccountNumber: account.AccountNumber ?? "",
Industry: account.Industry ?? "",
Website: account.Website ?? "",
Notes: account.Notes ?? "",
Address1: account.Address1 ?? "",
Address2: account.Address2 ?? "",
City: account.City ?? "",
State: account.State ?? "",
Zip: account.Zip ?? "",
Country: account.Country ?? "US",
});
}
}, [account, isEdit, reset]);
const isSaving = createAccount.isPending || updateAccount.isPending;
const onSubmit = (values: AccountFormValues) => {
if (isEdit && id) {
updateAccount.mutate({ id, values });
return;
}
createAccount.mutate(values);
};
if (isEdit && isLoading) {
return (
<Box className="flex justify-center p-10">
<CircularProgress />
</Box>
);
}
return (
<Box className="mx-auto max-w-4xl p-4">
<Paper variant="outlined" className="p-6">
<Stack spacing={4}>
<Stack
direction="row"
sx={{
justifyContent: "space-between",
alignItems: "center",
}}
>
<Typography variant="h5" component="h1">
{isEdit ? "Edit Account" : "Create an Account"}
</Typography>
<Button variant="text" onClick={() => navigate("/accounts")}>
Back to list
</Button>
</Stack>
{Boolean(error) && (
<Alert severity="error">
{error instanceof Error ? error.message : "Failed to load account"}
</Alert>
)}
<Box component="form" onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-6">
<Stack spacing={2}>
<Typography variant="subtitle1" className="font-semibold">
General Details
</Typography>
<Stack direction={{ xs: "column", md: "row" }} spacing={2}>
<TextField
{...register("AccountName")}
label="Account Name"
required
error={Boolean(errors.AccountName)}
helperText={errors.AccountName?.message}
fullWidth
/>
<TextField {...register("AccountNumber")} label="Account Number" fullWidth />
</Stack>
<Stack direction={{ xs: "column", md: "row" }} spacing={2}>
<TextField {...register("Industry")} label="Industry" fullWidth />
<TextField {...register("Website")} label="Website" fullWidth />
</Stack>
<TextField {...register("Notes")} label="Notes" fullWidth multiline minRows={2} />
</Stack>
<Stack spacing={2}>
<Typography variant="subtitle1" className="font-semibold">
Address
</Typography>
<Stack direction={{ xs: "column", md: "row" }} spacing={2}>
<TextField {...register("Address1")} label="Address 1" fullWidth />
<TextField {...register("Address2")} label="Address 2" fullWidth />
</Stack>
<Stack direction={{ xs: "column", md: "row" }} spacing={2}>
<TextField {...register("City")} label="City" fullWidth />
<TextField {...register("State")} label="State / Province" fullWidth />
<TextField {...register("Zip")} label="Zip/Postal Code" fullWidth />
</Stack>
<Controller
name="Country"
control={control}
render={({ field }) => (
<FormControl fullWidth>
<InputLabel id="country-label">Country</InputLabel>
<Select
{...field}
labelId="country-label"
label="Country"
value={field.value ?? "US"}
>
<MenuItem value="">Select Country</MenuItem>
<MenuItem value="US">United States</MenuItem>
</Select>
</FormControl>
)}
/>
</Stack>
<Stack
direction="row"
spacing={2}
sx={{
justifyContent: "flex-end",
}}
>
<Button variant="outlined" onClick={() => navigate("/accounts")} disabled={isSaving}>
Cancel
</Button>
<Button type="submit" variant="contained" disabled={isSaving}>
{isSaving ? "Saving..." : isEdit ? "Update Account" : "Create Account"}
</Button>
</Stack>
</Box>
</Stack>
</Paper>
</Box>
);
}