refactor(vendors): isolate contact fields

This commit is contained in:
Codex Review Integration 2026-08-27 11:33:24 -03:00
parent 2b889aa277
commit 96415d59d0
2 changed files with 91 additions and 71 deletions

View file

@ -0,0 +1,89 @@
import { Controller, useWatch, type Control, type FieldErrors } from "react-hook-form";
import { Stack, TextField } from "@mui/material";
import { Text } from "@/components/ui/text";
import {
VENDOR_COMPANY_CONTACT_REQUIRED_MESSAGE,
type VendorCompanyRosterFormValues,
} from "@/domain/vendors/schemas/vendor-roster-schema";
import { formatNorthAmericanPhone } from "@/lib/format/na-phone";
const COMPANY_CONTACT_ERROR_ID = "vendor-company-contact-error";
const COMPANY_PHONE_HELPER_ID = "vendor-company-phone-helper";
const COMPANY_EMAIL_HELPER_ID = "vendor-company-email-helper";
interface VendorCompanyContactFieldsProps {
control: Control<VendorCompanyRosterFormValues>;
errors: FieldErrors<VendorCompanyRosterFormValues>;
}
export function VendorCompanyContactFields({ control, errors }: VendorCompanyContactFieldsProps) {
const companyPhone = useWatch({ control, name: "companyPhone" }) ?? "";
const companyEmail = useWatch({ control, name: "email" }) ?? "";
const showCompanyContactError = Boolean(
errors.companyContact && !companyPhone.trim() && !companyEmail.trim(),
);
const contactDescribedBy = (helperId: string, hasHelper: boolean) =>
[hasHelper ? helperId : null, showCompanyContactError ? COMPANY_CONTACT_ERROR_ID : null]
.filter(Boolean)
.join(" ") || undefined;
return (
<>
<Stack direction={{ xs: "column", sm: "row" }} spacing={2}>
<Controller
control={control}
name="companyPhone"
render={({ field }) => (
<TextField
{...field}
label="Company Phone (optional)"
placeholder="(214) 555-0100"
inputMode="tel"
value={field.value ?? ""}
onChange={(event) => field.onChange(formatNorthAmericanPhone(event.target.value))}
error={Boolean(errors.companyPhone)}
helperText={errors.companyPhone?.message}
slotProps={{
formHelperText: { id: COMPANY_PHONE_HELPER_ID },
htmlInput: {
"aria-describedby": contactDescribedBy(
COMPANY_PHONE_HELPER_ID,
Boolean(errors.companyPhone?.message),
),
},
}}
fullWidth
/>
)}
/>
<Controller
control={control}
name="email"
render={({ field }) => (
<TextField
{...field}
label="Email (optional)"
placeholder="dispatch@vendor.com"
type="email"
error={Boolean(errors.email)}
helperText={errors.email?.message}
slotProps={{
formHelperText: { id: COMPANY_EMAIL_HELPER_ID },
htmlInput: {
"aria-describedby": contactDescribedBy(
COMPANY_EMAIL_HELPER_ID,
Boolean(errors.email?.message),
),
},
}}
fullWidth
/>
)}
/>
</Stack>
<Text variant="error" id={COMPANY_CONTACT_ERROR_ID} when={showCompanyContactError}>
{VENDOR_COMPANY_CONTACT_REQUIRED_MESSAGE}
</Text>
</>
);
}

View file

@ -23,13 +23,12 @@ import {
import { VendorTradeSpecialtiesField } from "./vendor-trade-specialties-field";
import { formatNorthAmericanPhone } from "@/lib/format/na-phone";
import {
VENDOR_COMPANY_CONTACT_REQUIRED_MESSAGE,
VENDOR_NOTES_MAX_LENGTH,
type RosterTechnicianValues,
type VendorCompanyRosterFormValues,
} from "@/domain/vendors/schemas/vendor-roster-schema";
import type { VendorFacetCompany } from "@/domain/vendors/types/vendor";
import { Text } from "@/components/ui/text";
import { VendorCompanyContactFields } from "./vendor-company-contact-fields";
interface VendorRosterFormFieldsProps {
control: Control<VendorCompanyRosterFormValues>;
@ -43,10 +42,6 @@ interface VendorRosterFormFieldsProps {
showTechnicianStatus?: boolean;
}
const COMPANY_CONTACT_ERROR_ID = "vendor-company-contact-error";
const COMPANY_PHONE_HELPER_ID = "vendor-company-phone-helper";
const COMPANY_EMAIL_HELPER_ID = "vendor-company-email-helper";
function CompanyNameField({
control,
errors,
@ -142,16 +137,6 @@ function CompanyFields({
onClearSelectedCompany,
}: VendorRosterFormFieldsProps) {
const notes = useWatch({ control, name: "notes" }) ?? "";
const companyPhone = useWatch({ control, name: "companyPhone" }) ?? "";
const companyEmail = useWatch({ control, name: "email" }) ?? "";
const companyContactError = errors.companyContact;
const showCompanyContactError = Boolean(
companyContactError && !companyPhone.trim() && !companyEmail.trim(),
);
const contactDescribedBy = (helperId: string, hasHelper: boolean) =>
[hasHelper ? helperId : null, showCompanyContactError ? COMPANY_CONTACT_ERROR_ID : null]
.filter(Boolean)
.join(" ") || undefined;
return (
<Box>
@ -164,61 +149,7 @@ function CompanyFields({
onSelectCompany={onSelectCompany}
onClearSelectedCompany={onClearSelectedCompany}
/>
<Stack direction={{ xs: "column", sm: "row" }} spacing={2}>
<Controller
control={control}
name="companyPhone"
render={({ field }) => (
<TextField
{...field}
label="Company Phone (optional)"
placeholder="(214) 555-0100"
inputMode="tel"
value={field.value ?? ""}
onChange={(event) => field.onChange(formatNorthAmericanPhone(event.target.value))}
error={Boolean(errors.companyPhone)}
helperText={errors.companyPhone?.message}
slotProps={{
formHelperText: { id: COMPANY_PHONE_HELPER_ID },
htmlInput: {
"aria-describedby": contactDescribedBy(
COMPANY_PHONE_HELPER_ID,
Boolean(errors.companyPhone?.message),
),
},
}}
fullWidth
/>
)}
/>
<Controller
control={control}
name="email"
render={({ field }) => (
<TextField
{...field}
label="Email (optional)"
placeholder="dispatch@vendor.com"
type="email"
error={Boolean(errors.email)}
helperText={errors.email?.message}
slotProps={{
formHelperText: { id: COMPANY_EMAIL_HELPER_ID },
htmlInput: {
"aria-describedby": contactDescribedBy(
COMPANY_EMAIL_HELPER_ID,
Boolean(errors.email?.message),
),
},
}}
fullWidth
/>
)}
/>
</Stack>
<Text variant="error" id={COMPANY_CONTACT_ERROR_ID} when={showCompanyContactError}>
{VENDOR_COMPANY_CONTACT_REQUIRED_MESSAGE}
</Text>
<VendorCompanyContactFields control={control} errors={errors} />
<Controller
control={control}
name="address"