shoc-frontend-new/src/app/(protected)/vendors/_components/vendor-create-modal.tsx
Codex Review Integration 64caab1832 fix(vendors): do not fail open while the trades facet is loading (SH-249)
An empty tradeOptions array meant two different things: "facets query still in
flight" and "vocabulary genuinely unavailable". Both enabled fail-open free
text and showed the outage warning, so a normal cold fetch looked like an
outage. Anything committed in that window was added to knownTradesRef and stayed
selectable after the canonical list arrived, permanently undermining the gate.

Expose the facets query isLoading as tradesLoading, thread it to the field as
tradeOptionsLoading, and keep the canonical gate active while loading. The
outage warning now shows only once the query has settled empty.
2026-08-18 17:25:44 -03:00

95 lines
2.9 KiB
TypeScript

import { useEffect } from "react";
import {
Box,
Button,
CircularProgress,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Stack,
} from "@mui/material";
import { Text } from "@/components/ui/text";
import { VendorRosterConflictAlert } from "./vendor-roster-conflict-alert";
import { VendorRosterFormFields } from "./vendor-roster-form-fields";
import { VendorRosterLoadErrorAlert } from "./vendor-roster-load-error";
import { useVendorRosterForm } from "./use-vendor-roster-form";
interface VendorCreateModalProps {
open: boolean;
onClose: () => void;
}
export function VendorCreateModal({ open, onClose }: VendorCreateModalProps) {
const form = useVendorRosterForm({
mode: "create",
onSuccess: onClose,
startWithTechnician: true,
});
const { resetForm } = form;
useEffect(() => {
if (!open) resetForm();
}, [open, resetForm]);
return (
<Dialog
open={open}
onClose={form.isSaving ? undefined : onClose}
fullWidth
maxWidth="sm"
aria-labelledby="vendor-create-dialog-title"
slotProps={{
paper: {
role: "dialog",
sx: { maxHeight: "88vh", borderRadius: 2 },
},
}}
>
<DialogTitle id="vendor-create-dialog-title">
<Text variant="title" as="span">
Add Vendor
</Text>
<Text variant="description" tone="muted" sx={{ mt: 0.5 }}>
Register a vendor company and its technicians.
</Text>
</DialogTitle>
<DialogContent sx={{ maxHeight: "55vh" }}>
<Stack spacing={2} className="mt-1">
{form.loadErrorMessage !== null && (
<VendorRosterLoadErrorAlert message={form.loadErrorMessage} onRetry={form.retryLoad} />
)}
{form.conflict !== null && (
<VendorRosterConflictAlert conflict={form.conflict} onReload={form.reload} />
)}
<Box component="form" id="vendor-create-form" onSubmit={form.handleSubmit(form.submit)}>
<VendorRosterFormFields
control={form.control}
errors={form.errors}
companies={form.companies}
tradeOptions={form.trades}
tradeOptionsLoading={form.tradesLoading}
selectedCompanyId={form.selectedCompanyId}
onSelectCompany={form.selectCompany}
onClearSelectedCompany={form.clearSelectedCompany}
/>
</Box>
</Stack>
</DialogContent>
<DialogActions>
<Button onClick={onClose} disabled={form.isSaving}>
Cancel
</Button>
<Button
color="primary"
variant="contained"
type="submit"
form="vendor-create-form"
disabled={form.isSaving}
>
{form.isSaving ? <CircularProgress size={20} color="inherit" /> : "Add Vendor"}
</Button>
</DialogActions>
</Dialog>
);
}