diff --git a/frontend/src/app/(portal)/reviewer/applications/components/ApplicationsClient.tsx b/frontend/src/app/(portal)/reviewer/applications/components/ApplicationsClient.tsx index 6eaf199..2f4508f 100644 --- a/frontend/src/app/(portal)/reviewer/applications/components/ApplicationsClient.tsx +++ b/frontend/src/app/(portal)/reviewer/applications/components/ApplicationsClient.tsx @@ -2,8 +2,7 @@ import { PageContainer } from '@/components/PageContainer' import { useMemo, useState } from 'react' -import { Loader2, Search, List, Columns } from 'lucide-react' -import { Button } from '@/components/ui/button' +import { Search, List, Columns } from 'lucide-react' import { Select, SelectContent, @@ -26,7 +25,7 @@ import { pickDefaultCycleId, useCycles } from '@/lib/queries/cycles' import { useQuestionsByCycleRoles } from '@/lib/queries/questions' import { useCurrentUser } from '@/lib/queries/users' import { ROLE_COLUMNS, ROLE_LABEL } from '@/lib/roles' -import { ORDERED_STAGES, stageLabel } from './constants' +import { BulkActionBar } from './BulkActionBar' import { AVAILABILITY_DAY_OPTIONS, availabilityOptionsFor, @@ -218,6 +217,14 @@ export function ApplicationsClient() { }) } + // Dropping the selection also drops the bar's transient state, so a failure + // notice from a previous batch can't linger into the next one. + function clearSelection() { + setSelectedIds(new Set()) + setBulkStage('') + setBulkFailed(0) + } + async function applyBulkStage() { if (!bulkStage || selectedIds.size === 0) return setApplyingBulk(true) @@ -352,49 +359,6 @@ export function ApplicationsClient() { - {view === 'table' && isChief && ( -
- - {selectedIds.size} selected - - {bulkFailed > 0 && ( - - {bulkFailed} update{bulkFailed === 1 ? '' : 's'} failed - - )} -
- - -
-
- )} -
{view === 'table' ? ( 0 ? ( + + ) : undefined + } /> ) : ( void + onApply: () => void + onClear: () => void + applying: boolean + failedCount: number +}) { + return ( +
+ + {selectedCount} selected + + + {failedCount > 0 && ( + + {failedCount} update{failedCount === 1 ? '' : 's'} failed + + )} +
+ + +
+
+ ) +} diff --git a/frontend/src/app/(portal)/reviewer/applications/components/TableView.tsx b/frontend/src/app/(portal)/reviewer/applications/components/TableView.tsx index b4b2e31..e1eafd0 100644 --- a/frontend/src/app/(portal)/reviewer/applications/components/TableView.tsx +++ b/frontend/src/app/(portal)/reviewer/applications/components/TableView.tsx @@ -26,6 +26,7 @@ export function TableView({ onSelectApplication, filters, onFilterChange, + bulkBar, }: { applicants: ApplicantApplication[] allApplicants: ApplicantApplication[] @@ -48,6 +49,9 @@ export function TableView({ filter: AnswerFilter | null, action: 'add' | 'remove' ) => void + // Rendered in the filter row's place while a selection is active. Owned by + // the parent, which holds the selection and the bulk mutation. + bulkBar?: React.ReactNode }) { const countByStage = (stage: ApplicationStage | 'all') => stage === 'all' @@ -72,11 +76,13 @@ export function TableView({ return (
- + {bulkBar ?? ( + + )}
{FILTER_STAGES.map(({ label, value }) => (