refactor: move vendor-portal dispatch actions and 2 pages onto proper data hooks
Two groups of components were calling the API directly instead of using
this codebase's standard React Query hooks, with no shared caching and
duplicated submit/error-handling boilerplate.
- checklist-section.tsx, comments-section.tsx, signoff-section.tsx,
uplift-requests-section.tsx: replace direct vendorPortalApi calls and
hand-rolled submitting/error state with mutation hooks in the new
use-vendor-portal-dispatch-actions.ts. uplift-requests-section keeps
its existing multi-step evidence-upload orchestration intact and only
swaps the 3 raw API calls for mutateAsync, since restructuring that
flow around declarative mutation callbacks carried more risk than
value. Caught and fixed a real bug along the way: two components were
passing a prop callback directly as a mutation's onSuccess, which
would have forwarded React Query's extra callback arguments into it.
- followups/index.tsx, vendors/preferences.tsx: split from a single
file doing state, API calls, and rendering into a hook (owns data
and handlers) plus small presentational components, matching the
task-templates refactor pattern. Added a missing centralized query
key (vendorOperations.sitePreferences) that preferences.tsx was
building as a raw inline array.
- use-list-page-filters.ts: small shared hook for search/page/pageSize
state, used by the new followups hook.
29 new/updated tests across all touched files; none of these had
coverage for their mutation/error paths before.
2026-09-25 10:53:23 -05:00
|
|
|
import { fireEvent, screen, waitFor } from "@testing-library/react";
|
|
|
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
2026-08-10 18:25:57 -03:00
|
|
|
import { SignoffSection } from "@/app/v/[token]/dispatch/_components/signoff-section";
|
refactor: move vendor-portal dispatch actions and 2 pages onto proper data hooks
Two groups of components were calling the API directly instead of using
this codebase's standard React Query hooks, with no shared caching and
duplicated submit/error-handling boilerplate.
- checklist-section.tsx, comments-section.tsx, signoff-section.tsx,
uplift-requests-section.tsx: replace direct vendorPortalApi calls and
hand-rolled submitting/error state with mutation hooks in the new
use-vendor-portal-dispatch-actions.ts. uplift-requests-section keeps
its existing multi-step evidence-upload orchestration intact and only
swaps the 3 raw API calls for mutateAsync, since restructuring that
flow around declarative mutation callbacks carried more risk than
value. Caught and fixed a real bug along the way: two components were
passing a prop callback directly as a mutation's onSuccess, which
would have forwarded React Query's extra callback arguments into it.
- followups/index.tsx, vendors/preferences.tsx: split from a single
file doing state, API calls, and rendering into a hook (owns data
and handlers) plus small presentational components, matching the
task-templates refactor pattern. Added a missing centralized query
key (vendorOperations.sitePreferences) that preferences.tsx was
building as a raw inline array.
- use-list-page-filters.ts: small shared hook for search/page/pageSize
state, used by the new followups hook.
29 new/updated tests across all touched files; none of these had
coverage for their mutation/error paths before.
2026-09-25 10:53:23 -05:00
|
|
|
import { vendorPortalApi } from "@/domain/vendor-portal/api/vendor-portal-api";
|
fix: stop duplicate global toasts on vendor-portal dispatch actions
All six vendor-portal dispatch mutation hooks lacked meta.suppressErrorToast,
so a failed checklist toggle, signoff, comment, or uplift request/withdraw/
revise raised both the global MutationCache toast (leaking the raw server
message) and the section's own inline error, contradicting this ticket's
"no behavior change" goal versus main's try/catch-only handling.
Also fixes a related gap in checklist-section.tsx: updateItem.isError only
reflects the latest call on the shared mutation observer, so a failed toggle
whose item was not the most recent click showed no error at all. Tracks
failure locally instead, mirroring main's per-call error state.
Added regression coverage with the app's real query client (createAppQueryClient)
for comments, signoff, and uplift withdraw, asserting the inline message shows
and the global toast does not fire; plus a mixed pass/fail concurrent-toggle
case for the checklist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-30 12:13:35 -05:00
|
|
|
import { createAppQueryClient } from "@/lib/query/query-client";
|
refactor: move vendor-portal dispatch actions and 2 pages onto proper data hooks
Two groups of components were calling the API directly instead of using
this codebase's standard React Query hooks, with no shared caching and
duplicated submit/error-handling boilerplate.
- checklist-section.tsx, comments-section.tsx, signoff-section.tsx,
uplift-requests-section.tsx: replace direct vendorPortalApi calls and
hand-rolled submitting/error state with mutation hooks in the new
use-vendor-portal-dispatch-actions.ts. uplift-requests-section keeps
its existing multi-step evidence-upload orchestration intact and only
swaps the 3 raw API calls for mutateAsync, since restructuring that
flow around declarative mutation callbacks carried more risk than
value. Caught and fixed a real bug along the way: two components were
passing a prop callback directly as a mutation's onSuccess, which
would have forwarded React Query's extra callback arguments into it.
- followups/index.tsx, vendors/preferences.tsx: split from a single
file doing state, API calls, and rendering into a hook (owns data
and handlers) plus small presentational components, matching the
task-templates refactor pattern. Added a missing centralized query
key (vendorOperations.sitePreferences) that preferences.tsx was
building as a raw inline array.
- use-list-page-filters.ts: small shared hook for search/page/pageSize
state, used by the new followups hook.
29 new/updated tests across all touched files; none of these had
coverage for their mutation/error paths before.
2026-09-25 10:53:23 -05:00
|
|
|
import { renderWithProviders } from "@/test/test-utils";
|
|
|
|
|
|
fix: stop duplicate global toasts on vendor-portal dispatch actions
All six vendor-portal dispatch mutation hooks lacked meta.suppressErrorToast,
so a failed checklist toggle, signoff, comment, or uplift request/withdraw/
revise raised both the global MutationCache toast (leaking the raw server
message) and the section's own inline error, contradicting this ticket's
"no behavior change" goal versus main's try/catch-only handling.
Also fixes a related gap in checklist-section.tsx: updateItem.isError only
reflects the latest call on the shared mutation observer, so a failed toggle
whose item was not the most recent click showed no error at all. Tracks
failure locally instead, mirroring main's per-call error state.
Added regression coverage with the app's real query client (createAppQueryClient)
for comments, signoff, and uplift withdraw, asserting the inline message shows
and the global toast does not fire; plus a mixed pass/fail concurrent-toggle
case for the checklist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-30 12:13:35 -05:00
|
|
|
const toastMocks = vi.hoisted(() => ({ success: vi.fn(), error: vi.fn() }));
|
|
|
|
|
vi.mock("react-toastify", () => ({ toast: toastMocks }));
|
|
|
|
|
|
refactor: move vendor-portal dispatch actions and 2 pages onto proper data hooks
Two groups of components were calling the API directly instead of using
this codebase's standard React Query hooks, with no shared caching and
duplicated submit/error-handling boilerplate.
- checklist-section.tsx, comments-section.tsx, signoff-section.tsx,
uplift-requests-section.tsx: replace direct vendorPortalApi calls and
hand-rolled submitting/error state with mutation hooks in the new
use-vendor-portal-dispatch-actions.ts. uplift-requests-section keeps
its existing multi-step evidence-upload orchestration intact and only
swaps the 3 raw API calls for mutateAsync, since restructuring that
flow around declarative mutation callbacks carried more risk than
value. Caught and fixed a real bug along the way: two components were
passing a prop callback directly as a mutation's onSuccess, which
would have forwarded React Query's extra callback arguments into it.
- followups/index.tsx, vendors/preferences.tsx: split from a single
file doing state, API calls, and rendering into a hook (owns data
and handlers) plus small presentational components, matching the
task-templates refactor pattern. Added a missing centralized query
key (vendorOperations.sitePreferences) that preferences.tsx was
building as a raw inline array.
- use-list-page-filters.ts: small shared hook for search/page/pageSize
state, used by the new followups hook.
29 new/updated tests across all touched files; none of these had
coverage for their mutation/error paths before.
2026-09-25 10:53:23 -05:00
|
|
|
afterEach(() => {
|
|
|
|
|
vi.restoreAllMocks();
|
fix: stop duplicate global toasts on vendor-portal dispatch actions
All six vendor-portal dispatch mutation hooks lacked meta.suppressErrorToast,
so a failed checklist toggle, signoff, comment, or uplift request/withdraw/
revise raised both the global MutationCache toast (leaking the raw server
message) and the section's own inline error, contradicting this ticket's
"no behavior change" goal versus main's try/catch-only handling.
Also fixes a related gap in checklist-section.tsx: updateItem.isError only
reflects the latest call on the shared mutation observer, so a failed toggle
whose item was not the most recent click showed no error at all. Tracks
failure locally instead, mirroring main's per-call error state.
Added regression coverage with the app's real query client (createAppQueryClient)
for comments, signoff, and uplift withdraw, asserting the inline message shows
and the global toast does not fire; plus a mixed pass/fail concurrent-toggle
case for the checklist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-30 12:13:35 -05:00
|
|
|
toastMocks.success.mockReset();
|
|
|
|
|
toastMocks.error.mockReset();
|
refactor: move vendor-portal dispatch actions and 2 pages onto proper data hooks
Two groups of components were calling the API directly instead of using
this codebase's standard React Query hooks, with no shared caching and
duplicated submit/error-handling boilerplate.
- checklist-section.tsx, comments-section.tsx, signoff-section.tsx,
uplift-requests-section.tsx: replace direct vendorPortalApi calls and
hand-rolled submitting/error state with mutation hooks in the new
use-vendor-portal-dispatch-actions.ts. uplift-requests-section keeps
its existing multi-step evidence-upload orchestration intact and only
swaps the 3 raw API calls for mutateAsync, since restructuring that
flow around declarative mutation callbacks carried more risk than
value. Caught and fixed a real bug along the way: two components were
passing a prop callback directly as a mutation's onSuccess, which
would have forwarded React Query's extra callback arguments into it.
- followups/index.tsx, vendors/preferences.tsx: split from a single
file doing state, API calls, and rendering into a hook (owns data
and handlers) plus small presentational components, matching the
task-templates refactor pattern. Added a missing centralized query
key (vendorOperations.sitePreferences) that preferences.tsx was
building as a raw inline array.
- use-list-page-filters.ts: small shared hook for search/page/pageSize
state, used by the new followups hook.
29 new/updated tests across all touched files; none of these had
coverage for their mutation/error paths before.
2026-09-25 10:53:23 -05:00
|
|
|
});
|
2026-08-10 18:25:57 -03:00
|
|
|
|
fix: stop duplicate global toasts on vendor-portal dispatch actions
All six vendor-portal dispatch mutation hooks lacked meta.suppressErrorToast,
so a failed checklist toggle, signoff, comment, or uplift request/withdraw/
revise raised both the global MutationCache toast (leaking the raw server
message) and the section's own inline error, contradicting this ticket's
"no behavior change" goal versus main's try/catch-only handling.
Also fixes a related gap in checklist-section.tsx: updateItem.isError only
reflects the latest call on the shared mutation observer, so a failed toggle
whose item was not the most recent click showed no error at all. Tracks
failure locally instead, mirroring main's per-call error state.
Added regression coverage with the app's real query client (createAppQueryClient)
for comments, signoff, and uplift withdraw, asserting the inline message shows
and the global toast does not fire; plus a mixed pass/fail concurrent-toggle
case for the checklist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-30 12:13:35 -05:00
|
|
|
function renderSection(
|
|
|
|
|
overrides: Partial<React.ComponentProps<typeof SignoffSection>> = {},
|
|
|
|
|
options: { useAppQueryClient?: boolean } = {},
|
|
|
|
|
) {
|
refactor: move vendor-portal dispatch actions and 2 pages onto proper data hooks
Two groups of components were calling the API directly instead of using
this codebase's standard React Query hooks, with no shared caching and
duplicated submit/error-handling boilerplate.
- checklist-section.tsx, comments-section.tsx, signoff-section.tsx,
uplift-requests-section.tsx: replace direct vendorPortalApi calls and
hand-rolled submitting/error state with mutation hooks in the new
use-vendor-portal-dispatch-actions.ts. uplift-requests-section keeps
its existing multi-step evidence-upload orchestration intact and only
swaps the 3 raw API calls for mutateAsync, since restructuring that
flow around declarative mutation callbacks carried more risk than
value. Caught and fixed a real bug along the way: two components were
passing a prop callback directly as a mutation's onSuccess, which
would have forwarded React Query's extra callback arguments into it.
- followups/index.tsx, vendors/preferences.tsx: split from a single
file doing state, API calls, and rendering into a hook (owns data
and handlers) plus small presentational components, matching the
task-templates refactor pattern. Added a missing centralized query
key (vendorOperations.sitePreferences) that preferences.tsx was
building as a raw inline array.
- use-list-page-filters.ts: small shared hook for search/page/pageSize
state, used by the new followups hook.
29 new/updated tests across all touched files; none of these had
coverage for their mutation/error paths before.
2026-09-25 10:53:23 -05:00
|
|
|
return renderWithProviders(
|
2026-08-10 18:25:57 -03:00
|
|
|
<SignoffSection
|
|
|
|
|
token="portal-token"
|
|
|
|
|
dispatchId={9}
|
|
|
|
|
existing={[]}
|
|
|
|
|
signoffType="customer"
|
|
|
|
|
nameLabel="Customer name"
|
|
|
|
|
onAdded={vi.fn()}
|
|
|
|
|
{...overrides}
|
|
|
|
|
/>,
|
fix: stop duplicate global toasts on vendor-portal dispatch actions
All six vendor-portal dispatch mutation hooks lacked meta.suppressErrorToast,
so a failed checklist toggle, signoff, comment, or uplift request/withdraw/
revise raised both the global MutationCache toast (leaking the raw server
message) and the section's own inline error, contradicting this ticket's
"no behavior change" goal versus main's try/catch-only handling.
Also fixes a related gap in checklist-section.tsx: updateItem.isError only
reflects the latest call on the shared mutation observer, so a failed toggle
whose item was not the most recent click showed no error at all. Tracks
failure locally instead, mirroring main's per-call error state.
Added regression coverage with the app's real query client (createAppQueryClient)
for comments, signoff, and uplift withdraw, asserting the inline message shows
and the global toast does not fire; plus a mixed pass/fail concurrent-toggle
case for the checklist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-30 12:13:35 -05:00
|
|
|
{
|
|
|
|
|
withAuth: false,
|
|
|
|
|
...(options.useAppQueryClient ? { queryClient: createAppQueryClient() } : {}),
|
|
|
|
|
},
|
2026-08-10 18:25:57 -03:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
fix: stop duplicate global toasts on vendor-portal dispatch actions
All six vendor-portal dispatch mutation hooks lacked meta.suppressErrorToast,
so a failed checklist toggle, signoff, comment, or uplift request/withdraw/
revise raised both the global MutationCache toast (leaking the raw server
message) and the section's own inline error, contradicting this ticket's
"no behavior change" goal versus main's try/catch-only handling.
Also fixes a related gap in checklist-section.tsx: updateItem.isError only
reflects the latest call on the shared mutation observer, so a failed toggle
whose item was not the most recent click showed no error at all. Tracks
failure locally instead, mirroring main's per-call error state.
Added regression coverage with the app's real query client (createAppQueryClient)
for comments, signoff, and uplift withdraw, asserting the inline message shows
and the global toast does not fire; plus a mixed pass/fail concurrent-toggle
case for the checklist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-30 12:13:35 -05:00
|
|
|
function submitTypedSignoff(name = "Jane Doe") {
|
|
|
|
|
fireEvent.click(screen.getByRole("radio", { name: "Typed" }));
|
|
|
|
|
const [nameInput, signatureInput] = screen.getAllByRole("textbox");
|
|
|
|
|
fireEvent.change(nameInput, { target: { value: name } });
|
|
|
|
|
fireEvent.change(signatureInput, { target: { value: name } });
|
|
|
|
|
fireEvent.click(screen.getByRole("button", { name: "Submit Signoff" }));
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-10 18:25:57 -03:00
|
|
|
describe("SignoffSection", () => {
|
|
|
|
|
it("shows status-neutral locked copy when submission is locked", () => {
|
|
|
|
|
renderSection({ submissionLocked: true });
|
|
|
|
|
|
|
|
|
|
expect(screen.getByText(/Signoff is unavailable for this dispatch/i)).toBeInTheDocument();
|
|
|
|
|
expect(screen.queryByText(/refused/i)).not.toBeInTheDocument();
|
|
|
|
|
expect(screen.queryByRole("button", { name: "Submit Signoff" })).not.toBeInTheDocument();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("shows the submission form when unlocked", () => {
|
|
|
|
|
renderSection();
|
|
|
|
|
|
|
|
|
|
expect(screen.getByRole("button", { name: "Submit Signoff" })).toBeInTheDocument();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("shows an existing signoff even while locked", () => {
|
|
|
|
|
renderSection({
|
|
|
|
|
signoffType: "vendor",
|
|
|
|
|
nameLabel: "Your name",
|
|
|
|
|
submissionLocked: true,
|
|
|
|
|
existing: [{ signoffType: "vendor", name: "Grace Hopper", signatureMethod: "typed" }],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(screen.getByText("Grace Hopper")).toBeInTheDocument();
|
|
|
|
|
expect(screen.queryByText(/Signoff is unavailable/i)).not.toBeInTheDocument();
|
|
|
|
|
expect(screen.queryByRole("button", { name: "Submit Signoff" })).not.toBeInTheDocument();
|
|
|
|
|
});
|
refactor: move vendor-portal dispatch actions and 2 pages onto proper data hooks
Two groups of components were calling the API directly instead of using
this codebase's standard React Query hooks, with no shared caching and
duplicated submit/error-handling boilerplate.
- checklist-section.tsx, comments-section.tsx, signoff-section.tsx,
uplift-requests-section.tsx: replace direct vendorPortalApi calls and
hand-rolled submitting/error state with mutation hooks in the new
use-vendor-portal-dispatch-actions.ts. uplift-requests-section keeps
its existing multi-step evidence-upload orchestration intact and only
swaps the 3 raw API calls for mutateAsync, since restructuring that
flow around declarative mutation callbacks carried more risk than
value. Caught and fixed a real bug along the way: two components were
passing a prop callback directly as a mutation's onSuccess, which
would have forwarded React Query's extra callback arguments into it.
- followups/index.tsx, vendors/preferences.tsx: split from a single
file doing state, API calls, and rendering into a hook (owns data
and handlers) plus small presentational components, matching the
task-templates refactor pattern. Added a missing centralized query
key (vendorOperations.sitePreferences) that preferences.tsx was
building as a raw inline array.
- use-list-page-filters.ts: small shared hook for search/page/pageSize
state, used by the new followups hook.
29 new/updated tests across all touched files; none of these had
coverage for their mutation/error paths before.
2026-09-25 10:53:23 -05:00
|
|
|
|
|
|
|
|
it("requires a name and signature before submitting", () => {
|
|
|
|
|
const addSignoff = vi.spyOn(vendorPortalApi, "addSignoff");
|
|
|
|
|
renderSection();
|
|
|
|
|
|
|
|
|
|
fireEvent.click(screen.getByRole("button", { name: "Submit Signoff" }));
|
|
|
|
|
|
|
|
|
|
expect(screen.getByText("Name and signature are required.")).toBeInTheDocument();
|
|
|
|
|
expect(addSignoff).not.toHaveBeenCalled();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("submits a typed signoff and calls onAdded", async () => {
|
|
|
|
|
vi.spyOn(vendorPortalApi, "addSignoff").mockResolvedValue({
|
|
|
|
|
signoffType: "customer",
|
|
|
|
|
name: "Jane Doe",
|
|
|
|
|
signatureMethod: "typed",
|
|
|
|
|
});
|
|
|
|
|
const onAdded = vi.fn();
|
|
|
|
|
renderSection({ onAdded });
|
|
|
|
|
|
fix: stop duplicate global toasts on vendor-portal dispatch actions
All six vendor-portal dispatch mutation hooks lacked meta.suppressErrorToast,
so a failed checklist toggle, signoff, comment, or uplift request/withdraw/
revise raised both the global MutationCache toast (leaking the raw server
message) and the section's own inline error, contradicting this ticket's
"no behavior change" goal versus main's try/catch-only handling.
Also fixes a related gap in checklist-section.tsx: updateItem.isError only
reflects the latest call on the shared mutation observer, so a failed toggle
whose item was not the most recent click showed no error at all. Tracks
failure locally instead, mirroring main's per-call error state.
Added regression coverage with the app's real query client (createAppQueryClient)
for comments, signoff, and uplift withdraw, asserting the inline message shows
and the global toast does not fire; plus a mixed pass/fail concurrent-toggle
case for the checklist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-30 12:13:35 -05:00
|
|
|
submitTypedSignoff();
|
refactor: move vendor-portal dispatch actions and 2 pages onto proper data hooks
Two groups of components were calling the API directly instead of using
this codebase's standard React Query hooks, with no shared caching and
duplicated submit/error-handling boilerplate.
- checklist-section.tsx, comments-section.tsx, signoff-section.tsx,
uplift-requests-section.tsx: replace direct vendorPortalApi calls and
hand-rolled submitting/error state with mutation hooks in the new
use-vendor-portal-dispatch-actions.ts. uplift-requests-section keeps
its existing multi-step evidence-upload orchestration intact and only
swaps the 3 raw API calls for mutateAsync, since restructuring that
flow around declarative mutation callbacks carried more risk than
value. Caught and fixed a real bug along the way: two components were
passing a prop callback directly as a mutation's onSuccess, which
would have forwarded React Query's extra callback arguments into it.
- followups/index.tsx, vendors/preferences.tsx: split from a single
file doing state, API calls, and rendering into a hook (owns data
and handlers) plus small presentational components, matching the
task-templates refactor pattern. Added a missing centralized query
key (vendorOperations.sitePreferences) that preferences.tsx was
building as a raw inline array.
- use-list-page-filters.ts: small shared hook for search/page/pageSize
state, used by the new followups hook.
29 new/updated tests across all touched files; none of these had
coverage for their mutation/error paths before.
2026-09-25 10:53:23 -05:00
|
|
|
|
|
|
|
|
await waitFor(() => expect(onAdded).toHaveBeenCalled());
|
|
|
|
|
expect(vendorPortalApi.addSignoff).toHaveBeenCalledWith("portal-token", 9, {
|
|
|
|
|
name: "Jane Doe",
|
|
|
|
|
signature: "Jane Doe",
|
|
|
|
|
signatureMethod: "typed",
|
|
|
|
|
signoffType: "customer",
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("shows an error message when the submission fails", async () => {
|
|
|
|
|
vi.spyOn(vendorPortalApi, "addSignoff").mockRejectedValue(new Error("boom"));
|
|
|
|
|
renderSection();
|
|
|
|
|
|
fix: stop duplicate global toasts on vendor-portal dispatch actions
All six vendor-portal dispatch mutation hooks lacked meta.suppressErrorToast,
so a failed checklist toggle, signoff, comment, or uplift request/withdraw/
revise raised both the global MutationCache toast (leaking the raw server
message) and the section's own inline error, contradicting this ticket's
"no behavior change" goal versus main's try/catch-only handling.
Also fixes a related gap in checklist-section.tsx: updateItem.isError only
reflects the latest call on the shared mutation observer, so a failed toggle
whose item was not the most recent click showed no error at all. Tracks
failure locally instead, mirroring main's per-call error state.
Added regression coverage with the app's real query client (createAppQueryClient)
for comments, signoff, and uplift withdraw, asserting the inline message shows
and the global toast does not fire; plus a mixed pass/fail concurrent-toggle
case for the checklist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-30 12:13:35 -05:00
|
|
|
submitTypedSignoff();
|
|
|
|
|
|
|
|
|
|
expect(
|
|
|
|
|
await screen.findByText("Unable to submit the signoff. Please try again."),
|
|
|
|
|
).toBeInTheDocument();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("shows only the inline error on a failed submit, not a duplicate global toast", async () => {
|
|
|
|
|
vi.spyOn(vendorPortalApi, "addSignoff").mockRejectedValue(new Error("boom"));
|
|
|
|
|
renderSection({}, { useAppQueryClient: true });
|
|
|
|
|
|
|
|
|
|
submitTypedSignoff();
|
refactor: move vendor-portal dispatch actions and 2 pages onto proper data hooks
Two groups of components were calling the API directly instead of using
this codebase's standard React Query hooks, with no shared caching and
duplicated submit/error-handling boilerplate.
- checklist-section.tsx, comments-section.tsx, signoff-section.tsx,
uplift-requests-section.tsx: replace direct vendorPortalApi calls and
hand-rolled submitting/error state with mutation hooks in the new
use-vendor-portal-dispatch-actions.ts. uplift-requests-section keeps
its existing multi-step evidence-upload orchestration intact and only
swaps the 3 raw API calls for mutateAsync, since restructuring that
flow around declarative mutation callbacks carried more risk than
value. Caught and fixed a real bug along the way: two components were
passing a prop callback directly as a mutation's onSuccess, which
would have forwarded React Query's extra callback arguments into it.
- followups/index.tsx, vendors/preferences.tsx: split from a single
file doing state, API calls, and rendering into a hook (owns data
and handlers) plus small presentational components, matching the
task-templates refactor pattern. Added a missing centralized query
key (vendorOperations.sitePreferences) that preferences.tsx was
building as a raw inline array.
- use-list-page-filters.ts: small shared hook for search/page/pageSize
state, used by the new followups hook.
29 new/updated tests across all touched files; none of these had
coverage for their mutation/error paths before.
2026-09-25 10:53:23 -05:00
|
|
|
|
|
|
|
|
expect(
|
|
|
|
|
await screen.findByText("Unable to submit the signoff. Please try again."),
|
|
|
|
|
).toBeInTheDocument();
|
fix: stop duplicate global toasts on vendor-portal dispatch actions
All six vendor-portal dispatch mutation hooks lacked meta.suppressErrorToast,
so a failed checklist toggle, signoff, comment, or uplift request/withdraw/
revise raised both the global MutationCache toast (leaking the raw server
message) and the section's own inline error, contradicting this ticket's
"no behavior change" goal versus main's try/catch-only handling.
Also fixes a related gap in checklist-section.tsx: updateItem.isError only
reflects the latest call on the shared mutation observer, so a failed toggle
whose item was not the most recent click showed no error at all. Tracks
failure locally instead, mirroring main's per-call error state.
Added regression coverage with the app's real query client (createAppQueryClient)
for comments, signoff, and uplift withdraw, asserting the inline message shows
and the global toast does not fire; plus a mixed pass/fail concurrent-toggle
case for the checklist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-30 12:13:35 -05:00
|
|
|
expect(toastMocks.error).not.toHaveBeenCalled();
|
refactor: move vendor-portal dispatch actions and 2 pages onto proper data hooks
Two groups of components were calling the API directly instead of using
this codebase's standard React Query hooks, with no shared caching and
duplicated submit/error-handling boilerplate.
- checklist-section.tsx, comments-section.tsx, signoff-section.tsx,
uplift-requests-section.tsx: replace direct vendorPortalApi calls and
hand-rolled submitting/error state with mutation hooks in the new
use-vendor-portal-dispatch-actions.ts. uplift-requests-section keeps
its existing multi-step evidence-upload orchestration intact and only
swaps the 3 raw API calls for mutateAsync, since restructuring that
flow around declarative mutation callbacks carried more risk than
value. Caught and fixed a real bug along the way: two components were
passing a prop callback directly as a mutation's onSuccess, which
would have forwarded React Query's extra callback arguments into it.
- followups/index.tsx, vendors/preferences.tsx: split from a single
file doing state, API calls, and rendering into a hook (owns data
and handlers) plus small presentational components, matching the
task-templates refactor pattern. Added a missing centralized query
key (vendorOperations.sitePreferences) that preferences.tsx was
building as a raw inline array.
- use-list-page-filters.ts: small shared hook for search/page/pageSize
state, used by the new followups hook.
29 new/updated tests across all touched files; none of these had
coverage for their mutation/error paths before.
2026-09-25 10:53:23 -05:00
|
|
|
});
|
2026-08-10 18:25:57 -03:00
|
|
|
});
|