From f0f3485bee8459f6f4ee07a604685b3e66e6f268 Mon Sep 17 00:00:00 2001 From: Codex Review Integration Date: Thu, 20 Aug 2026 20:59:27 -0300 Subject: [PATCH] fix(vendors): preserve status during roster edits --- .../_components/use-vendor-roster-form.ts | 14 +++++- .../_components/vendor-detail-drawer.tsx | 50 ++++++++++++------- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/app/(protected)/vendors/_components/use-vendor-roster-form.ts b/src/app/(protected)/vendors/_components/use-vendor-roster-form.ts index 82ae4333..ea04d62d 100644 --- a/src/app/(protected)/vendors/_components/use-vendor-roster-form.ts +++ b/src/app/(protected)/vendors/_components/use-vendor-roster-form.ts @@ -97,6 +97,7 @@ export interface VendorRosterForm { selectedCompanyId: string | number | null; selectCompany: (company: VendorFacetCompany | null) => Promise; clearSelectedCompany: (nextName?: string) => void; + setTechnicianActive: (index: number, isActive: boolean) => void; resetForm: () => void; } @@ -133,7 +134,7 @@ export function useVendorRosterForm({ values: mode === "update" && routeRoster ? toFormValues(routeRoster) : undefined, 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 // render. Reading dirtyFields inside the submit callback would not subscribe and would come // back empty, so it is resolved here on every render. @@ -163,6 +164,16 @@ export function useVendorRosterForm({ clearConflict(); }, [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) => { setConflict(null); const values = withoutBlankNewTechnicians(formValues); @@ -228,6 +239,7 @@ export function useVendorRosterForm({ selectedCompanyId: selection.selectedCompanyId, selectCompany: selection.selectCompany, clearSelectedCompany: selection.clearSelectedCompany, + setTechnicianActive, resetForm, }; } diff --git a/src/app/(protected)/vendors/_components/vendor-detail-drawer.tsx b/src/app/(protected)/vendors/_components/vendor-detail-drawer.tsx index 22ab7cd0..52b328be 100644 --- a/src/app/(protected)/vendors/_components/vendor-detail-drawer.tsx +++ b/src/app/(protected)/vendors/_components/vendor-detail-drawer.tsx @@ -1,5 +1,5 @@ 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 EditOutlinedIcon from "@mui/icons-material/EditOutlined"; 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 ( + + {isActive ? "Active" : "Inactive"} + { + if (persistedIsActive && !checked) onRequestDeactivation(); + else onChange(checked); + }} + /> + + ); +} + function DrawerEditor({ vendor, onClose, @@ -312,23 +338,11 @@ function DrawerEditor({ Total Jobs - ( - - {field.value ? "Active" : "Inactive"} - { - if (persistedIsActive && !checked) onRequestDeactivation(vendor); - else field.onChange(checked); - }} - /> - - )} + onRequestDeactivation(vendor)} + onChange={(checked) => form.setTechnicianActive(selectedIndex, checked)} />