fix: isolate paginated invite history cache

This commit is contained in:
Dotta committed 2026-04-13 08:26:01 -05:00
1 parent 06a05ccee5
commit ea97334ec7
3 files changed
+47 -2

No files matched your search

+1 -1
View File
@@ -89,7 +89,7 @@ export const queryKeys = {
},
access: {
invites: (companyId: string, state: string = "all", limit: number = 20) =>
["access", "invites", companyId, state, limit] as const,
["access", "invites", "paginated-v1", companyId, state, limit] as const,
joinRequests: (companyId: string, status: string = "pending_approval") =>
["access", "join-requests", companyId, status] as const,
companyMembers: (companyId: string) => ["access", "company-members", companyId] as const,
+37
View File
@@ -6,6 +6,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { MemoryRouter } from "react-router-dom";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { CompanyInvites } from "./CompanyInvites";
import { queryKeys } from "@/lib/queryKeys";
const listInvitesMock = vi.hoisted(() => vi.fn());
const createCompanyInviteMock = vi.hoisted(() => vi.fn());
@@ -227,4 +228,40 @@ describe("CompanyInvites", () => {
root.unmount();
});
});
it("ignores legacy cached invite arrays and refetches paginated history", async () => {
const root = createRoot(container);
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
queryClient.setQueryData(["access", "invites", "company-1", "all"], inviteHistory.slice(0, 2));
await act(async () => {
root.render(
<MemoryRouter>
<QueryClientProvider client={queryClient}>
<CompanyInvites />
</QueryClientProvider>
</MemoryRouter>,
);
});
await flushReact();
await flushReact();
expect(container.textContent).toContain("Board User 25");
expect(container.textContent).not.toContain("Board User 5");
expect(listInvitesMock).toHaveBeenCalledWith("company-1", { limit: 20, offset: 0 });
expect(queryClient.getQueryData(queryKeys.access.invites("company-1", "all", 20))).toMatchObject({
pages: [
{
invites: expect.any(Array),
nextOffset: 20,
},
],
});
await act(async () => {
root.unmount();
});
});
});
+9 -1
View File
@@ -39,6 +39,11 @@ const inviteRoleOptions = [
const INVITE_HISTORY_PAGE_SIZE = 20;
function isInviteHistoryRow(value: unknown): value is Awaited<ReturnType<typeof accessApi.listInvites>>["invites"][number] {
if (!value || typeof value !== "object") return false;
return "id" in value && "state" in value && "createdAt" in value;
}
export function CompanyInvites() {
const { selectedCompany, selectedCompanyId } = useCompany();
const { setBreadcrumbs } = useBreadcrumbs();
@@ -95,7 +100,10 @@ export function CompanyInvites() {
getNextPageParam: (lastPage) => lastPage.nextOffset ?? undefined,
});
const inviteHistory = useMemo(
() => invitesQuery.data?.pages.flatMap((page) => page.invites) ?? [],
() =>
invitesQuery.data?.pages.flatMap((page) =>
Array.isArray(page?.invites) ? page.invites.filter(isInviteHistoryRow) : [],
) ?? [],
[invitesQuery.data?.pages],
);