shoc-frontend-new/src/app/(protected)/contacts/_components/contact-form.tsx

265 lines
9 KiB
TypeScript

import { useEffect } from "react";
import { 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 { contactSchema, type ContactFormValues } from "@/domain/contacts/schemas/contact-schema";
import { useContactDetail } from "@/domain/contacts/use-cases/use-contact-detail";
import { useCreateContact } from "@/domain/contacts/use-cases/use-create-contact";
import { useUpdateContact } from "@/domain/contacts/use-cases/use-update-contact";
const defaultValues: ContactFormValues = {
firstName: "",
middleName: "",
lastName: "",
title: "",
contactType: "",
gender: "",
dateOfBirth: "",
territory: "-1",
owner: "1",
privacySetting: "PublicReadWrite",
about: "",
tags: "",
street: "",
streetLineTwo: "",
city: "",
zip: "",
country: "US",
state: "",
county: "",
timeZone: "Eastern Standard Time",
smsAddress: "",
website: "",
facebookUrl: "",
linkedInUrl: "",
twitterUrl: "",
};
const CONTACT_TYPES = ["Corporate", "Store Mgr", "Facilities", "Area Leader"];
const US_STATES = ["AL", "AK", "AZ", "CA", "FL", "NY", "TX"];
export default function ContactFormPage() {
const { id } = useParams();
const navigate = useNavigate();
const isEdit = Boolean(id);
const { data: contact, isLoading, error } = useContactDetail(id);
const createContact = useCreateContact();
const updateContact = useUpdateContact();
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm<ContactFormValues>({
resolver: zodResolver(contactSchema),
defaultValues,
});
useEffect(() => {
if (contact && isEdit) {
reset({
firstName: contact.firstName,
middleName: contact.middleName,
lastName: contact.lastName,
title: contact.title,
contactType: contact.contactType,
gender: contact.gender,
dateOfBirth: contact.dateOfBirth,
territory: contact.territory || "-1",
owner: contact.owner || "1",
privacySetting: contact.privacySetting,
about: contact.about,
tags: contact.tags,
street: contact.street,
streetLineTwo: contact.streetLineTwo,
city: contact.city,
zip: contact.zip,
country: contact.country,
state: contact.state,
county: contact.county,
timeZone: contact.timeZone,
smsAddress: contact.smsAddress,
website: contact.website,
facebookUrl: contact.facebookUrl,
linkedInUrl: contact.linkedInUrl,
twitterUrl: contact.twitterUrl,
});
}
}, [contact, isEdit, reset]);
const isSaving = createContact.isPending || updateContact.isPending;
const onSubmit = (values: ContactFormValues) => {
if (isEdit && id) {
updateContact.mutate({ id, values });
return;
}
createContact.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}>
<Typography variant="h5">{isEdit ? "Edit Contact" : "Create Contact"}</Typography>
{Boolean(error) && (
<Alert severity="error">
{error instanceof Error ? error.message : "Failed to load contact"}
</Alert>
)}
<Box component="form" onSubmit={handleSubmit(onSubmit)}>
<Stack spacing={3}>
<Typography variant="subtitle2" className="font-semibold uppercase">
General Details
</Typography>
<Stack direction={{ xs: "column", sm: "row" }} spacing={2}>
<TextField
label="First Name"
required
fullWidth
error={Boolean(errors.firstName)}
helperText={errors.firstName?.message}
{...register("firstName")}
/>
<TextField label="Middle Name" fullWidth {...register("middleName")} />
<TextField
label="Last Name"
required
fullWidth
error={Boolean(errors.lastName)}
helperText={errors.lastName?.message}
{...register("lastName")}
/>
</Stack>
<Stack direction={{ xs: "column", sm: "row" }} spacing={2}>
<TextField label="Title" fullWidth {...register("title")} />
<FormControl fullWidth>
<InputLabel>Contact Type</InputLabel>
<Select label="Contact Type" defaultValue="" {...register("contactType")}>
<MenuItem value="">Select type</MenuItem>
{CONTACT_TYPES.map((type) => (
<MenuItem key={type} value={type}>
{type}
</MenuItem>
))}
</Select>
</FormControl>
</Stack>
<Stack direction={{ xs: "column", sm: "row" }} spacing={2}>
<FormControl fullWidth>
<InputLabel>Territory</InputLabel>
<Select label="Territory" required defaultValue="-1" {...register("territory")}>
<MenuItem value="">Select territory</MenuItem>
<MenuItem value="-1">No Territory</MenuItem>
</Select>
</FormControl>
<FormControl fullWidth>
<InputLabel>Owner</InputLabel>
<Select label="Owner" required defaultValue="1" {...register("owner")}>
<MenuItem value="">Select owner</MenuItem>
<MenuItem value="1">Employee 1</MenuItem>
<MenuItem value="2">Employee 2</MenuItem>
</Select>
</FormControl>
<FormControl fullWidth>
<InputLabel>Privacy</InputLabel>
<Select
label="Privacy"
defaultValue="PublicReadWrite"
{...register("privacySetting")}
>
<MenuItem value="PublicReadWrite">Public read/write</MenuItem>
<MenuItem value="PublicReadOnly">Public read only</MenuItem>
<MenuItem value="Private">Private</MenuItem>
</Select>
</FormControl>
</Stack>
<TextField label="About" fullWidth {...register("about")} />
<Typography variant="subtitle2" className="font-semibold uppercase">
Address
</Typography>
<Stack direction={{ xs: "column", sm: "row" }} spacing={2}>
<TextField label="Address 1" fullWidth {...register("street")} />
<TextField label="Address 2" fullWidth {...register("streetLineTwo")} />
</Stack>
<Stack direction={{ xs: "column", sm: "row" }} spacing={2}>
<TextField label="City" fullWidth {...register("city")} />
<TextField label="Zip" fullWidth {...register("zip")} />
</Stack>
<Stack direction={{ xs: "column", sm: "row" }} spacing={2}>
<FormControl fullWidth>
<InputLabel>State</InputLabel>
<Select label="State" defaultValue="" {...register("state")}>
<MenuItem value="">Select state</MenuItem>
{US_STATES.map((st) => (
<MenuItem key={st} value={st}>
{st}
</MenuItem>
))}
</Select>
</FormControl>
<TextField label="Country" fullWidth {...register("country")} />
</Stack>
<Typography variant="subtitle2" className="font-semibold uppercase">
Additional
</Typography>
<TextField label="Website" fullWidth placeholder="http://" {...register("website")} />
<TextField label="SMS Address" fullWidth {...register("smsAddress")} />
<Stack
direction="row"
spacing={2}
sx={{
justifyContent: "flex-end",
}}
>
<Button
variant="outlined"
onClick={() => navigate("/contacts")}
disabled={isSaving}
>
Cancel
</Button>
<Button type="submit" variant="contained" disabled={isSaving}>
{isSaving ? "Saving..." : isEdit ? "Update" : "Create"}
</Button>
</Stack>
</Stack>
</Box>
</Stack>
</Paper>
</Box>
);
}