diff --git a/src/apps/work/src/pages/challenges/ChallengeEditorPage/components/SubmissionsSection/SubmissionsSection.spec.tsx b/src/apps/work/src/pages/challenges/ChallengeEditorPage/components/SubmissionsSection/SubmissionsSection.spec.tsx index f0d58c0b4..df35ddd99 100644 --- a/src/apps/work/src/pages/challenges/ChallengeEditorPage/components/SubmissionsSection/SubmissionsSection.spec.tsx +++ b/src/apps/work/src/pages/challenges/ChallengeEditorPage/components/SubmissionsSection/SubmissionsSection.spec.tsx @@ -131,8 +131,8 @@ const submissions: Submission[] = [ challengeId: 'challenge-1', createdAt: '2026-07-01T10:00:00.000Z', createdBy: 'member-1', - id: 'system-submission', - memberHandle: 'system-user', + id: 'alpha-system-submission', + memberHandle: 'alpha', reviewSummation: [ { metadata: { @@ -146,8 +146,8 @@ const submissions: Submission[] = [ challengeId: 'challenge-1', createdAt: '2026-07-01T11:00:00.000Z', createdBy: 'member-2', - id: 'provisional-submission', - memberHandle: 'provisional-user', + id: 'bravo-provisional-submission', + memberHandle: 'bravo', reviewSummation: [ { metadata: { @@ -161,8 +161,9 @@ const submissions: Submission[] = [ challengeId: 'challenge-1', createdAt: '2026-07-01T12:00:00.000Z', createdBy: 'member-3', - id: 'example-submission', - memberHandle: 'example-user', + id: 'charlie-example-submission', + legacySubmissionId: 'legacy-charlie-id', + memberHandle: 'charlie', reviewSummation: [ { metadata: { @@ -199,6 +200,43 @@ describe('SubmissionsSection', () => { mockFetchMembersByUserIds.mockResolvedValue([]) }) + it('filters submissions by current or legacy submission ID', () => { + render( + , + ) + + fireEvent.change(screen.getByLabelText('Submission ID'), { + target: { + value: 'BRAVO', + }, + }) + + expect(screen.getByText('bravo-provisional-submission')) + .toBeTruthy() + expect(screen.queryByText('alpha-system-submission')) + .toBeNull() + expect(screen.queryByText('charlie-example-submission')) + .toBeNull() + expect(screen.getByTestId('pagination-total').textContent) + .toBe('1') + + fireEvent.change(screen.getByLabelText('Submission ID'), { + target: { + value: 'legacy-charlie', + }, + }) + + expect(screen.getByText('charlie-example-submission')) + .toBeTruthy() + expect(screen.queryByText('alpha-system-submission')) + .toBeNull() + expect(screen.queryByText('bravo-provisional-submission')) + .toBeNull() + }) + it('filters marathon submissions by test type', () => { render( { }, }) - expect(screen.getByText('system-submission')) + expect(screen.getByText('alpha-system-submission')) .toBeTruthy() - expect(screen.queryByText('provisional-submission')) + expect(screen.queryByText('bravo-provisional-submission')) .toBeNull() - expect(screen.queryByText('example-submission')) + expect(screen.queryByText('charlie-example-submission')) .toBeNull() expect(screen.getByTestId('pagination-total').textContent) .toBe('1') @@ -228,11 +266,11 @@ describe('SubmissionsSection', () => { }, }) - expect(screen.getByText('example-submission')) + expect(screen.getByText('charlie-example-submission')) .toBeTruthy() - expect(screen.queryByText('system-submission')) + expect(screen.queryByText('alpha-system-submission')) .toBeNull() - expect(screen.queryByText('provisional-submission')) + expect(screen.queryByText('bravo-provisional-submission')) .toBeNull() }) }) diff --git a/src/apps/work/src/pages/challenges/ChallengeEditorPage/components/SubmissionsSection/SubmissionsSection.tsx b/src/apps/work/src/pages/challenges/ChallengeEditorPage/components/SubmissionsSection/SubmissionsSection.tsx index f73961cd5..ace5be142 100644 --- a/src/apps/work/src/pages/challenges/ChallengeEditorPage/components/SubmissionsSection/SubmissionsSection.tsx +++ b/src/apps/work/src/pages/challenges/ChallengeEditorPage/components/SubmissionsSection/SubmissionsSection.tsx @@ -58,6 +58,7 @@ interface FilterState { handle: string minScore: string startDate: string + submissionId: string testType: string } @@ -332,6 +333,33 @@ function matchesFilterHandle(submission: Submission, handleFilter: string): bool .includes(normalizedHandleFilter) } +/** + * Checks whether a submission matches the submission ID filter. + * @param submission Submission row being evaluated. + * @param submissionIdFilter Case-insensitive partial submission ID entered by the user. + * @returns True when the filter is empty or matches the submission's current or legacy ID. + * Used by `matchesFilters` before the submissions table is sorted and paginated. + */ +function matchesFilterSubmissionId( + submission: Submission, + submissionIdFilter: string, +): boolean { + if (!submissionIdFilter) { + return true + } + + const normalizedSubmissionIdFilter = normalizeValue(submissionIdFilter) + .toLowerCase() + + return [ + submission.id, + submission.legacySubmissionId, + ] + .some(submissionId => normalizeValue(submissionId) + .toLowerCase() + .includes(normalizedSubmissionIdFilter)) +} + /** * Checks whether a submission matches the selected marathon test type. * @param submission Submission row being evaluated. @@ -372,6 +400,10 @@ function matchesFilters( return false } + if (!matchesFilterSubmissionId(submission, filters.submissionId)) { + return false + } + if (!matchesFilterDateRange(submission, filters.startDate, filters.endDate)) { return false } @@ -398,6 +430,7 @@ export const SubmissionsSection: FC = ( handle: '', minScore: '', startDate: '', + submissionId: '', testType: '', }) const [memberCache, setMemberCache] = useState({}) @@ -682,6 +715,19 @@ export const SubmissionsSection: FC = ( /> + + {isMarathonMatch ? (