Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/ops-console/pages/CampaignAssignmentTab.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,22 @@ describe('CampaignAssignmentTab', () => {
expect(screen.getByRole('progressbar')).toBeInTheDocument();
});

it('keeps filters disabled until campaign grade metadata is loaded', async () => {
api.getAllGrades.mockResolvedValue(defaultGrades);
api.getCampaignAssignments.mockImplementation(
() => new Promise(() => undefined),
);

renderTab('campaign-1');

await waitFor(() => expect(api.getAllGrades).toHaveBeenCalled());
screen
.getAllByRole('combobox')
.forEach((combobox) =>
expect(combobox).toHaveAttribute('aria-disabled', 'true'),
);
});
Comment on lines +276 to +290

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current test has a false-positive risk. It asserts that the filters are disabled immediately after api.getAllGrades is called, but before the promise resolves. At this point, isLoadingFilters is still true, so the filters are disabled regardless of the new logic. To make the test robust, we should resolve api.getAllGrades and verify that the filters remain disabled while assignments are loading, and then verify they become enabled once assignments resolve.

  it('keeps filters disabled until campaign grade metadata and assignments are loaded', async () => {
    api.getAllGrades.mockResolvedValue(defaultGrades);

    let resolveAssignments: (value: any) => void = () => {};
    const assignmentsPromise = new Promise((resolve) => {
      resolveAssignments = resolve;
    });
    api.getCampaignAssignments.mockReturnValue(assignmentsPromise);

    renderTab('campaign-1');

    await waitFor(() => expect(api.getAllGrades).toHaveBeenCalled());

    screen
      .getAllByRole('combobox')
      .forEach((combobox) =>
        expect(combobox).toHaveAttribute('aria-disabled', 'true'),
      );

    resolveAssignments({
      assignments: defaultAssignments,
      uniqueSubjects: defaultSubjects,
      total: 1,
    });

    await waitFor(() => {
      screen
        .getAllByRole('combobox')
        .forEach((combobox) =>
          expect(combobox).not.toHaveAttribute('aria-disabled', 'true'),
        );
    });
  });


it('renders the default grade filter value', async () => {
primeApi();

Expand Down
14 changes: 9 additions & 5 deletions src/ops-console/pages/CampaignAssignmentTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,7 @@ const CampaignAssignmentTab: React.FC<CampaignAssignmentTabProps> = ({
subjects.flatMap((subject) => subject.gradeIds),
);

return relevantGradeIds.size === 0
? grades
: grades.filter((grade) => relevantGradeIds.has(grade.id));
return grades.filter((grade) => relevantGradeIds.has(grade.id));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve grades when subject metadata has no grade IDs

When get_campaign_assignments returns the shape in the checked-in Supabase contract (src/services/database.ts:7867-7870), unique_subjects has no grade_ids; the parser therefore assigns every subject gradeIds: [] (SupabaseApi.ts:10895-10902). This unconditional filter then removes every grade after loading any campaign, whereas the deleted fallback kept the grade selector usable. Either ensure the RPC contract and deployment supply grade_ids, or retain a fallback for metadata that lacks them.

Useful? React with 👍 / 👎.

}, [grades, subjects]);

useEffect(() => {
Expand Down Expand Up @@ -302,7 +300,10 @@ const CampaignAssignmentTab: React.FC<CampaignAssignmentTabProps> = ({
<FormControl
size="small"
className="campaign-assignment-filter"
disabled={isLoadingFilters}
disabled={
isLoadingFilters ||
(isLoadingAssignments && subjects.length === 0)
}
>
<Select
multiple
Expand Down Expand Up @@ -362,7 +363,10 @@ const CampaignAssignmentTab: React.FC<CampaignAssignmentTabProps> = ({
<FormControl
size="small"
className="campaign-assignment-filter campaign-assignment-filterField"
disabled={isLoadingFilters}
disabled={
isLoadingFilters ||
(isLoadingAssignments && subjects.length === 0)
}
>
<Select
multiple
Expand Down
Loading