fix(vendors): gate deactivation prompt on saved status (SH-255)

The drawer's Active toggle asked to deactivate whenever the switch moved
from on to off, reading the unsaved form value. An inactive vendor toggled
on and back off without saving therefore raised "Deactivate this vendor"
for a vendor that was already inactive.

Gate on the persisted technician status from the loaded roster instead,
falling back to the clicked row. Deactivation is a property of the saved
vendor, not of the toggle.
This commit is contained in:
Codex Review Integration 2026-08-19 13:18:17 -03:00
parent 772d7f94df
commit 90a5256dee
2 changed files with 66 additions and 5 deletions

View file

@ -254,10 +254,13 @@ function DrawerEditor({
const selectedIndex = technicians.findIndex(
(technician) => technician.id != null && String(technician.id) === String(vendor.id),
);
const selectedTotalJobs =
roster?.technicians.find(
(technician) => technician.id != null && String(technician.id) === String(vendor.id),
)?.totalJobs ?? vendor.totalJobs;
const persistedTechnician = roster?.technicians.find(
(technician) => technician.id != null && String(technician.id) === String(vendor.id),
);
const selectedTotalJobs = persistedTechnician?.totalJobs ?? vendor.totalJobs;
// Deactivation is a property of the saved vendor, not of the toggle: flipping an
// inactive vendor on and back off without saving must not ask to deactivate it.
const persistedIsActive = persistedTechnician?.isActive ?? vendor.isActive;
if (form.isLoading) {
return <CircularProgress size={28} sx={{ m: "auto" }} />;
@ -310,7 +313,7 @@ function DrawerEditor({
checked={Boolean(field.value)}
slotProps={{ input: { "aria-label": "Active status" } }}
onChange={(_event, checked) => {
if (field.value && !checked) onRequestDeactivation(vendor);
if (persistedIsActive && !checked) onRequestDeactivation(vendor);
else field.onChange(checked);
}}
/>

View file

@ -1,4 +1,5 @@
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import { VendorDetailDrawer } from "@/app/(protected)/vendors/_components/vendor-detail-drawer";
import { renderWithProviders } from "@/test/test-utils";
@ -134,3 +135,60 @@ describe("VendorDetailDrawer selected-technician display", () => {
expect(screen.queryByRole("switch", { name: "Active status" })).not.toBeInTheDocument();
});
});
describe("VendorDetailDrawer deactivation prompt", () => {
const inactiveVendor: VendorListItem = { ...vendor, isActive: false };
it("does not prompt to deactivate a saved-inactive vendor toggled on and back off", async () => {
useVendorCompanyRoster.mockReturnValue(
rosterWith([
{ id: 1, contactName: "Adam", phone: "314-555-0198", isActive: false, totalJobs: 5 },
]),
);
const onRequestDeactivation = vi.fn();
renderWithProviders(
<VendorDetailDrawer
open={true}
vendor={inactiveVendor}
startInEdit={true}
onRequestDeactivation={onRequestDeactivation}
onClose={vi.fn()}
/>,
{ route: "/vendors", withAuth: false },
);
const toggle = screen.getByRole("switch", { name: "Active status" });
await userEvent.click(toggle);
expect(toggle).toBeChecked();
await userEvent.click(toggle);
expect(toggle).not.toBeChecked();
expect(onRequestDeactivation).not.toHaveBeenCalled();
});
it("prompts to deactivate a saved-active vendor when the toggle is switched off", async () => {
useVendorCompanyRoster.mockReturnValue(
rosterWith([
{ id: 1, contactName: "Adam", phone: "314-555-0198", isActive: true, totalJobs: 5 },
]),
);
const onRequestDeactivation = vi.fn();
renderWithProviders(
<VendorDetailDrawer
open={true}
vendor={vendor}
startInEdit={true}
onRequestDeactivation={onRequestDeactivation}
onClose={vi.fn()}
/>,
{ route: "/vendors", withAuth: false },
);
await userEvent.click(screen.getByRole("switch", { name: "Active status" }));
expect(onRequestDeactivation).toHaveBeenCalledWith(vendor);
});
});