fix(vendors): preserve status during roster edits

This commit is contained in:
Codex Review Integration 2026-08-20 20:59:27 -03:00
parent 146491fafb
commit f0f3485bee
2 changed files with 45 additions and 19 deletions

View file

@ -97,6 +97,7 @@ export interface VendorRosterForm {
selectedCompanyId: string | number | null; selectedCompanyId: string | number | null;
selectCompany: (company: VendorFacetCompany | null) => Promise<void>; selectCompany: (company: VendorFacetCompany | null) => Promise<void>;
clearSelectedCompany: (nextName?: string) => void; clearSelectedCompany: (nextName?: string) => void;
setTechnicianActive: (index: number, isActive: boolean) => void;
resetForm: () => void; resetForm: () => void;
} }
@ -133,7 +134,7 @@ export function useVendorRosterForm({
values: mode === "update" && routeRoster ? toFormValues(routeRoster) : undefined, values: mode === "update" && routeRoster ? toFormValues(routeRoster) : undefined,
mode: "onChange", mode: "onChange",
}); });
const { control, handleSubmit, reset, formState } = form; const { control, handleSubmit, reset, setValue, formState } = form;
// react-hook-form exposes formState through a Proxy that only tracks properties read during // react-hook-form exposes formState through a Proxy that only tracks properties read during
// render. Reading dirtyFields inside the submit callback would not subscribe and would come // render. Reading dirtyFields inside the submit callback would not subscribe and would come
// back empty, so it is resolved here on every render. // back empty, so it is resolved here on every render.
@ -163,6 +164,16 @@ export function useVendorRosterForm({
clearConflict(); clearConflict();
}, [clearConflict, createDefaults, reset, resetSelection]); }, [clearConflict, createDefaults, reset, resetSelection]);
const setTechnicianActive = useCallback(
(index: number, isActive: boolean) => {
setValue(`technicians.${index}.isActive`, isActive, {
shouldDirty: true,
shouldValidate: true,
});
},
[setValue],
);
const submit = (formValues: VendorCompanyRosterFormValues) => { const submit = (formValues: VendorCompanyRosterFormValues) => {
setConflict(null); setConflict(null);
const values = withoutBlankNewTechnicians(formValues); const values = withoutBlankNewTechnicians(formValues);
@ -228,6 +239,7 @@ export function useVendorRosterForm({
selectedCompanyId: selection.selectedCompanyId, selectedCompanyId: selection.selectedCompanyId,
selectCompany: selection.selectCompany, selectCompany: selection.selectCompany,
clearSelectedCompany: selection.clearSelectedCompany, clearSelectedCompany: selection.clearSelectedCompany,
setTechnicianActive,
resetForm, resetForm,
}; };
} }

View file

@ -1,5 +1,5 @@
import { useEffect, useState, type ReactNode } from "react"; import { useEffect, useState, type ReactNode } from "react";
import { Controller, useWatch } from "react-hook-form"; import { useWatch } from "react-hook-form";
import CloseIcon from "@mui/icons-material/Close"; import CloseIcon from "@mui/icons-material/Close";
import EditOutlinedIcon from "@mui/icons-material/EditOutlined"; import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
import LaunchIcon from "@mui/icons-material/Launch"; import LaunchIcon from "@mui/icons-material/Launch";
@ -240,6 +240,32 @@ function DrawerActions({ onEdit }: { onEdit: () => void }) {
); );
} }
function TechnicianStatusControl({
isActive,
persistedIsActive,
onRequestDeactivation,
onChange,
}: {
isActive: boolean;
persistedIsActive: boolean;
onRequestDeactivation: () => void;
onChange: (checked: boolean) => void;
}) {
return (
<Stack direction="row" spacing={1} sx={{ alignItems: "center" }}>
<Text variant="description">{isActive ? "Active" : "Inactive"}</Text>
<Switch
checked={isActive}
slotProps={{ input: { "aria-label": "Active status" } }}
onChange={(_event, checked) => {
if (persistedIsActive && !checked) onRequestDeactivation();
else onChange(checked);
}}
/>
</Stack>
);
}
function DrawerEditor({ function DrawerEditor({
vendor, vendor,
onClose, onClose,
@ -312,23 +338,11 @@ function DrawerEditor({
Total Jobs Total Jobs
</Text> </Text>
</Box> </Box>
<Controller <TechnicianStatusControl
control={form.control} isActive={Boolean(technicians[selectedIndex]?.isActive)}
name={`technicians.${selectedIndex}.isActive`} persistedIsActive={persistedIsActive}
shouldUnregister onRequestDeactivation={() => onRequestDeactivation(vendor)}
render={({ field }) => ( onChange={(checked) => form.setTechnicianActive(selectedIndex, checked)}
<Stack direction="row" spacing={1} sx={{ alignItems: "center" }}>
<Text variant="description">{field.value ? "Active" : "Inactive"}</Text>
<Switch
checked={Boolean(field.value)}
slotProps={{ input: { "aria-label": "Active status" } }}
onChange={(_event, checked) => {
if (persistedIsActive && !checked) onRequestDeactivation(vendor);
else field.onChange(checked);
}}
/>
</Stack>
)}
/> />
</Stack> </Stack>
</> </>