From a60339e534836cbf9e338eec47edd54c019e07ce Mon Sep 17 00:00:00 2001 From: Justin Gasper Date: Fri, 25 Sep 2026 15:20:52 +1000 Subject: [PATCH] fix(PM-6415): expose My Projects filtering for talent managers --- .../ProjectsFilter/ProjectsFilter.spec.tsx | 29 ++++++++++++++++++- .../ProjectsFilter/ProjectsFilter.tsx | 7 ++++- .../ProjectsListPage.spec.tsx | 2 ++ .../ProjectsListPage/ProjectsListPage.tsx | 8 ++++- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/apps/work/src/lib/components/ProjectsFilter/ProjectsFilter.spec.tsx b/src/apps/work/src/lib/components/ProjectsFilter/ProjectsFilter.spec.tsx index 1f4c8b693..68f062ca1 100644 --- a/src/apps/work/src/lib/components/ProjectsFilter/ProjectsFilter.spec.tsx +++ b/src/apps/work/src/lib/components/ProjectsFilter/ProjectsFilter.spec.tsx @@ -1,7 +1,10 @@ /* eslint-disable import/no-extraneous-dependencies, ordered-imports/ordered-imports */ import { act, + fireEvent, + screen, render, + RenderResult, } from '@testing-library/react' import { @@ -47,7 +50,9 @@ jest.mock('~/libs/ui', () => ({ IconOutline: { SearchIcon: () => false, }, - InputCheckbox: () => false, + InputCheckbox: (props: { checked: boolean; label: string; onClick: () => void }) => ( + + ), }), { virtual: true, }) @@ -64,6 +69,28 @@ describe('ProjectsFilter', () => { searchBillingAccountsMock.mockResolvedValue([]) }) + it('toggles My Projects while retaining search and status filters', () => { + const onFiltersChange = jest.fn() + const filters: { keyword: string; status: 'active' } = { keyword: 'client', status: 'active' } + const { rerender }: RenderResult = render( + , + ) + fireEvent.click(screen.getByRole('checkbox', { name: 'My Projects' })) + expect(onFiltersChange) + .toHaveBeenLastCalledWith({ ...filters, memberOnly: true }) + rerender( + , + ) + fireEvent.click(screen.getByRole('checkbox', { name: 'My Projects' })) + expect(onFiltersChange) + .toHaveBeenLastCalledWith({ ...filters, memberOnly: false }) + }) + it('includes matching billing accounts from visible project rows for project managers', async () => { render( = (props: ProjectsFilterPro const noopCheckboxChange = (() => undefined) as (event: Event) => void + /** + * Toggles membership filtering while preserving the other project filters. + * @returns Nothing; notifies the listing through onFiltersChange. + * @throws Does not throw. + */ function handleOnlyMyProjectsToggle(): void { updateFilters({ memberOnly: !filters.memberOnly, @@ -434,7 +439,7 @@ export const ProjectsFilter: FC = (props: ProjectsFilterPro diff --git a/src/apps/work/src/pages/projects/ProjectsListPage/ProjectsListPage.spec.tsx b/src/apps/work/src/pages/projects/ProjectsListPage/ProjectsListPage.spec.tsx index 3ca846f69..a32fdd789 100644 --- a/src/apps/work/src/pages/projects/ProjectsListPage/ProjectsListPage.spec.tsx +++ b/src/apps/work/src/pages/projects/ProjectsListPage/ProjectsListPage.spec.tsx @@ -79,12 +79,14 @@ jest.mock('../../../lib/hooks', () => ({ useFetchProjectsList: jest.fn(), })) jest.mock('../../../lib/constants', () => ({ + PROJECT_ROLES: jest.requireActual('../../../lib/constants/project-roles.constants').PROJECT_ROLES, PROJECTS_PAGE_SIZE: 10, })) jest.mock('../../../lib/utils', () => ({ checkCanEditProjectDetails: jest.requireActual('../../../lib/utils/permissions.utils').checkCanEditProjectDetails, checkCanManageProject: jest.requireActual('../../../lib/utils/permissions.utils').checkCanManageProject, + checkTalentManager: jest.requireActual('../../../lib/utils/permissions.utils').checkTalentManager, })) const mockedUseFetchProjectsList = useFetchProjectsList as jest.Mock diff --git a/src/apps/work/src/pages/projects/ProjectsListPage/ProjectsListPage.tsx b/src/apps/work/src/pages/projects/ProjectsListPage/ProjectsListPage.tsx index 56af8d257..031623bdd 100644 --- a/src/apps/work/src/pages/projects/ProjectsListPage/ProjectsListPage.tsx +++ b/src/apps/work/src/pages/projects/ProjectsListPage/ProjectsListPage.tsx @@ -38,6 +38,7 @@ import { import { checkCanEditProjectDetails, checkCanManageProject, + checkTalentManager, } from '../../../lib/utils' import styles from '../../../lib/components/ProjectsListPage/ProjectsListPage.module.scss' @@ -115,6 +116,11 @@ function renderProjectsContent(params: RenderProjectsContentParams): JSX.Element ) } +/** + * Lists visible Work projects with paging and a membership filter for managers and TMs. + * @returns Project list; My Projects sends memberOnly and resets pagination. + * @throws Does not throw; request errors are displayed with a retry action. + */ export const ProjectsListPage: FC = () => { const { isManager, @@ -209,7 +215,7 @@ export const ProjectsListPage: FC = () => {