Merge pull request #120 from Sea-Haven-Industries/feat/sh-255-deactivate-toggle-gate

fix(vendors): gate deactivation prompt on saved status (SH-255)
This commit is contained in:
Alexandre Brandizzi 2026-08-20 11:11:40 -03:00 • committed by GitHub
commit 3ade310a1a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
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);
});
});