mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-06 10:02:04 +00:00
265 lines
9 KiB
TypeScript
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>
|
|
);
|
|
}
|