From d1927e6b32656ab43269baf082ef8f341f793494 Mon Sep 17 00:00:00 2001 From: wjames111 Date: Wed, 12 Aug 2026 13:55:50 -0400 Subject: [PATCH 1/9] MPDX-9693 - Add bulk actions menu to MPD Goal Admin table Enables the More Actions menu when rows are selected, with Run & Send Selected and Assign Coach (one coach applied to every checked row) on mock data. Real mutation wiring lands in MPDX-9914/MPDX-9912. Co-Authored-By: Claude Fable 5 --- public/locales/en/translation.json | 3 + .../GoalsTableToolbar.test.tsx | 62 +++++++++++-- .../GoalsTableToolbar/GoalsTableToolbar.tsx | 86 ++++++++++++++++--- .../MpdGoalAdmin/MpdGoalAdminContext.test.tsx | 14 +++ .../MpdGoalAdmin/MpdGoalAdminContext.tsx | 16 ++++ .../HrTools/MpdGoalAdmin/mockData.ts | 12 +++ 6 files changed, 171 insertions(+), 22 deletions(-) diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 1ec9ac0169..fa1ad9cffa 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -250,6 +250,8 @@ "{{count}} selected_other": "{{count}} selected", "{{count}} Selected_one": "{{count}} Selected", "{{count}} Selected_other": "{{count}} Selected", + "{{count}} Selected Staff_one": "{{count}} Selected Staff", + "{{count}} Selected Staff_other": "{{count}} Selected Staff", "{{count}} years_one": "{{count}} years", "{{count}} years_other": "{{count}} years", "{{daysLate}}+ days late": "{{daysLate}}+ days late", @@ -796,6 +798,7 @@ "Close pivot settings": "Close pivot settings", "Closing Balance": "Closing Balance", "Coach": "Coach", + "Coach assigned successfully.": "Coach assigned successfully.", "Coaches": "Coaches", "Coaching": "Coaching", "Coaching Accounts": "Coaching Accounts", diff --git a/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.test.tsx b/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.test.tsx index d31596199d..44510b6744 100644 --- a/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.test.tsx +++ b/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.test.tsx @@ -1,5 +1,5 @@ import { ThemeProvider } from '@mui/material/styles'; -import { act, render } from '@testing-library/react'; +import { act, render, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { SnackbarProvider } from 'notistack'; import theme from 'src/theme'; @@ -32,18 +32,23 @@ describe('GoalsTableToolbar', () => { getByRole('button', { name: 'Run and Send All' }), ).toBeInTheDocument(); expect( - queryByRole('button', { name: 'Run & Send Selected' }), + queryByRole('button', { name: 'More Actions' }), ).not.toBeInTheDocument(); }); - it('shows selection actions once rows are selected', () => { + it('shows the More Actions menu once rows are selected', async () => { const { getByRole, getByText } = renderToolbar(); act(() => ctx.toggleRow('row-1')); expect(getByText('1 selected')).toBeInTheDocument(); + + await userEvent.click(getByRole('button', { name: 'More Actions' })); + const menu = getByRole('menu'); + expect( + within(menu).getByRole('menuitem', { name: 'Run & Send Selected' }), + ).toBeInTheDocument(); expect( - getByRole('button', { name: 'Run & Send Selected' }), + within(menu).getByRole('menuitem', { name: 'Assign Coach' }), ).toBeInTheDocument(); - expect(getByRole('button', { name: 'More Actions' })).toBeInTheDocument(); }); it('drops hidden rows from the selected count when a search filters them out', async () => { @@ -56,7 +61,7 @@ describe('GoalsTableToolbar', () => { await userEvent.type(getByRole('textbox', { name: 'Search' }), 'carlos'); expect(queryByText('1 selected')).not.toBeInTheDocument(); expect( - queryByRole('button', { name: 'Run & Send Selected' }), + queryByRole('button', { name: 'More Actions' }), ).not.toBeInTheDocument(); expect(getByRole('button', { name: 'Print All' })).toBeInTheDocument(); }); @@ -75,14 +80,17 @@ describe('GoalsTableToolbar', () => { ); }); - it('confirms and sends only the selected rows', async () => { + it('confirms and sends only the selected rows from the menu', async () => { const { getByRole, findByText } = renderToolbar(); // row-1 is Complete, row-7 is Incomplete → 1 sendable of 2. act(() => { ctx.toggleRow('row-1'); ctx.toggleRow('row-7'); }); - await userEvent.click(getByRole('button', { name: 'Run & Send Selected' })); + await userEvent.click(getByRole('button', { name: 'More Actions' })); + await userEvent.click( + getByRole('menuitem', { name: 'Run & Send Selected' }), + ); const dialog = getByRole('dialog'); expect(dialog).toHaveTextContent( @@ -96,4 +104,42 @@ describe('GoalsTableToolbar', () => { await findByText('1 MPD Goals were run and sent.'), ).toBeInTheDocument(); }); + + it('assigns a coach to every selected row from the menu', async () => { + const { getByRole, findByRole, findByText } = renderToolbar(); + // row-2 (Carlos & Michaela Everts) has no coach; row-1 has one already. + act(() => { + ctx.toggleRow('row-1'); + ctx.toggleRow('row-2'); + }); + await userEvent.click(getByRole('button', { name: 'More Actions' })); + await userEvent.click(getByRole('menuitem', { name: 'Assign Coach' })); + + const dialog = getByRole('dialog'); + expect(dialog).toHaveTextContent('Assign Coach for 2 Selected Staff'); + + userEvent.click(within(dialog).getByRole('combobox', { name: 'Coach' })); + userEvent.click(await findByRole('option', { name: 'Tom Harris' })); + await userEvent.click(getByRole('button', { name: 'Save' })); + + expect( + await findByText('Coach assigned successfully.'), + ).toBeInTheDocument(); + // Both rows now carry the coach, and the selection is cleared. + const rows = ctx.cohorts[0].rows; + expect(rows.find((row) => row.id === 'row-1')?.coach).toBe('Tom Harris'); + expect(rows.find((row) => row.id === 'row-2')?.coach).toBe('Tom Harris'); + expect(ctx.selectedRows).toHaveLength(0); + }); + + it("uses the staff member's name in the assign-coach title for a single selection", async () => { + const { getByRole } = renderToolbar(); + act(() => ctx.toggleRow('row-2')); + await userEvent.click(getByRole('button', { name: 'More Actions' })); + await userEvent.click(getByRole('menuitem', { name: 'Assign Coach' })); + + expect(getByRole('dialog')).toHaveTextContent( + 'Assign Coach for Carlos & Michaela Everts', + ); + }); }); diff --git a/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx b/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx index 30a866ff2b..05d6c25b8a 100644 --- a/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx +++ b/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx @@ -1,27 +1,40 @@ import React, { useState } from 'react'; +import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'; import SearchIcon from '@mui/icons-material/Search'; import { Box, Button, InputAdornment, + Menu, + MenuItem, Stack, TextField, Typography, } from '@mui/material'; import { useSnackbar } from 'notistack'; import { useTranslation } from 'react-i18next'; +import { AssignCoachModal } from '../AssignCoachModal/AssignCoachModal'; import { useMpdGoalAdmin } from '../MpdGoalAdminContext'; import { RunAndSendModal } from '../RunAndSendModal/RunAndSendModal'; +import { mockCoaches } from '../mockData'; import { StaffGoalRow } from '../mpdGoalAdminHelpers'; export const GoalsTableToolbar: React.FC = () => { const { t } = useTranslation(); const { enqueueSnackbar } = useSnackbar(); - const { search, setSearch, filteredRows, selectedRows, clearSelection } = - useMpdGoalAdmin(); + const { + search, + setSearch, + filteredRows, + selectedRows, + clearSelection, + assignCoach, + } = useMpdGoalAdmin(); const selectedCount = selectedRows.length; const hasSelection = selectedCount > 0; + const [menuAnchorEl, setMenuAnchorEl] = useState(null); + const [assignCoachOpen, setAssignCoachOpen] = useState(false); const [modalOpen, setModalOpen] = useState(false); // Kept separate from `modalOpen` so the target rows/title persist through the // dialog's close transition instead of flashing empty. @@ -44,6 +57,21 @@ export const GoalsTableToolbar: React.FC = () => { setModalOpen(false); }; + // TODO(MPDX-9914): call the assignCoach mutation instead of the mock + // context update once the backend field is wired up. + const handleAssignCoach = (coachId: string) => { + const coach = mockCoaches.find((option) => option.id === coachId); + if (!coach) { + return; + } + assignCoach( + selectedRows.map((row) => row.id), + coach.name, + ); + enqueueSnackbar(t('Coach assigned successfully.'), { variant: 'success' }); + clearSelection(); + }; + return ( { {t('{{count}} selected', { count: selectedCount })} - {/* Disabled until wired up so assistive tech announces the - inert state instead of a dead control (MPDX-9696). */} - + setMenuAnchorEl(null)} + > + { + setMenuAnchorEl(null); + openRunAndSend( + t('Run and Send Selected Complete MPD Goals?'), + selectedRows, + ); + }} + > + {t('Run & Send Selected')} + + { + setMenuAnchorEl(null); + setAssignCoachOpen(true); + }} + > + {t('Assign Coach')} + + ) : ( <> @@ -120,6 +166,18 @@ export const GoalsTableToolbar: React.FC = () => { onClose={() => setModalOpen(false)} onConfirm={handleConfirm} /> + {assignCoachOpen && ( + setAssignCoachOpen(false)} + /> + )} ); }; diff --git a/src/components/HrTools/MpdGoalAdmin/MpdGoalAdminContext.test.tsx b/src/components/HrTools/MpdGoalAdmin/MpdGoalAdminContext.test.tsx index 3b0bdeb65d..07373f1785 100644 --- a/src/components/HrTools/MpdGoalAdmin/MpdGoalAdminContext.test.tsx +++ b/src/components/HrTools/MpdGoalAdmin/MpdGoalAdminContext.test.tsx @@ -75,6 +75,20 @@ describe('MpdGoalAdminContext', () => { expect(result.current.selectedCohort?.trainingCostEntered).toBe(true); }); + it('assigns a coach to exactly the given rows', () => { + const { result } = renderHook(() => useMpdGoalAdmin(), { wrapper }); + + act(() => result.current.assignCoach(['row-1', 'row-2'], 'Tom Harris')); + + const rows = result.current.cohorts[0].rows; + expect(rows.find((row) => row.id === 'row-1')?.coach).toBe('Tom Harris'); + expect(rows.find((row) => row.id === 'row-2')?.coach).toBe('Tom Harris'); + // Untouched rows keep their original coach. + expect(rows.find((row) => row.id === 'row-3')?.coach).toBe( + mockCohorts[0].rows.find((row) => row.id === 'row-3')?.coach, + ); + }); + it('throws when used outside its provider', () => { expect(() => renderHook(() => useMpdGoalAdmin())).toThrow( 'useMpdGoalAdmin must be used within a MpdGoalAdminProvider', diff --git a/src/components/HrTools/MpdGoalAdmin/MpdGoalAdminContext.tsx b/src/components/HrTools/MpdGoalAdmin/MpdGoalAdminContext.tsx index 2a84d8cb32..130fc473ee 100644 --- a/src/components/HrTools/MpdGoalAdmin/MpdGoalAdminContext.tsx +++ b/src/components/HrTools/MpdGoalAdmin/MpdGoalAdminContext.tsx @@ -36,6 +36,8 @@ export interface MpdGoalAdminContextValue { clearSelection: () => void; /** Saves the training cost figures for a cohort and marks them as entered. */ saveTrainingCosts: (cohortId: string, costs: TrainingCosts) => void; + /** Assigns one coach to every row in `rowIds`, across all cohorts. */ + assignCoach: (rowIds: string[], coachName: string) => void; } const MpdGoalAdminContext = createContext( @@ -92,6 +94,18 @@ export const MpdGoalAdminProvider: React.FC<{ [], ); + const assignCoach = useCallback((rowIds: string[], coachName: string) => { + const idSet = new Set(rowIds); + setCohorts((prev) => + prev.map((cohort) => ({ + ...cohort, + rows: cohort.rows.map((row) => + idSet.has(row.id) ? { ...row, coach: coachName } : row, + ), + })), + ); + }, []); + // Switching cohorts clears the selection: selecting staff across different // training cohorts is meaningless, and stale ids would otherwise linger in // the set and mislead the selection count and any bulk action. @@ -148,6 +162,7 @@ export const MpdGoalAdminProvider: React.FC<{ toggleRows, clearSelection, saveTrainingCosts, + assignCoach, }), [ activeTab, @@ -163,6 +178,7 @@ export const MpdGoalAdminProvider: React.FC<{ toggleRows, clearSelection, saveTrainingCosts, + assignCoach, ], ); diff --git a/src/components/HrTools/MpdGoalAdmin/mockData.ts b/src/components/HrTools/MpdGoalAdmin/mockData.ts index 187eb51561..14f5d76794 100644 --- a/src/components/HrTools/MpdGoalAdmin/mockData.ts +++ b/src/components/HrTools/MpdGoalAdmin/mockData.ts @@ -1,5 +1,17 @@ +import { AssignCoachOption } from './AssignCoachModal/AssignCoachModal'; import { Cohort, GoalStatusEnum } from './mpdGoalAdminHelpers'; +// Assignable coaches for the Assign Coach modal (MPDX-9693). Mirrors the coach +// names used in the rows below; replaced by the real query in MPDX-9914. +export const mockCoaches: AssignCoachOption[] = [ + { id: 'coach-1', name: 'Amy Wilson' }, + { id: 'coach-2', name: 'Bea Christians' }, + { id: 'coach-3', name: 'Nelson Jones' }, + { id: 'coach-4', name: 'Phillip Song' }, + { id: 'coach-5', name: 'Rachel Adams' }, + { id: 'coach-6', name: 'Tom Harris' }, +]; + export const mockCohorts: Cohort[] = [ { id: 'fall-nso-2026', From f8e844a7e84309231cb7b70f02515e35e0c39914 Mon Sep 17 00:00:00 2001 From: wjames111 Date: Wed, 12 Aug 2026 13:59:45 -0400 Subject: [PATCH 2/9] MPDX-9693 - Keep toolbar static; move Print All into the actions menu More Actions is now always visible and disabled until a row is checked, with Print All (still inert until MPDX-9702), Run & Send Selected, and Assign Coach as its items. Run and Send All stays a standalone button. Co-Authored-By: Claude Fable 5 --- .../GoalsTableToolbar.test.tsx | 22 ++-- .../GoalsTableToolbar/GoalsTableToolbar.tsx | 112 +++++++++--------- 2 files changed, 63 insertions(+), 71 deletions(-) diff --git a/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.test.tsx b/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.test.tsx index 44510b6744..b73343093d 100644 --- a/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.test.tsx +++ b/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.test.tsx @@ -25,24 +25,25 @@ const renderToolbar = () => ); describe('GoalsTableToolbar', () => { - it('shows default bulk actions with no selection', () => { - const { getByRole, queryByRole } = renderToolbar(); - expect(getByRole('button', { name: 'Print All' })).toBeInTheDocument(); + it('disables More Actions with no selection', () => { + const { getByRole } = renderToolbar(); + expect(getByRole('button', { name: 'More Actions' })).toBeDisabled(); expect( getByRole('button', { name: 'Run and Send All' }), ).toBeInTheDocument(); - expect( - queryByRole('button', { name: 'More Actions' }), - ).not.toBeInTheDocument(); }); - it('shows the More Actions menu once rows are selected', async () => { + it('enables the More Actions menu once rows are selected', async () => { const { getByRole, getByText } = renderToolbar(); act(() => ctx.toggleRow('row-1')); expect(getByText('1 selected')).toBeInTheDocument(); await userEvent.click(getByRole('button', { name: 'More Actions' })); const menu = getByRole('menu'); + // Print All stays disabled until it is wired up (MPDX-9702). + expect( + within(menu).getByRole('menuitem', { name: 'Print All' }), + ).toHaveAttribute('aria-disabled', 'true'); expect( within(menu).getByRole('menuitem', { name: 'Run & Send Selected' }), ).toBeInTheDocument(); @@ -52,7 +53,7 @@ describe('GoalsTableToolbar', () => { }); it('drops hidden rows from the selected count when a search filters them out', async () => { - const { getByRole, getByText, queryByText, queryByRole } = renderToolbar(); + const { getByRole, getByText, queryByText } = renderToolbar(); act(() => ctx.toggleRow('row-1')); expect(getByText('1 selected')).toBeInTheDocument(); @@ -60,10 +61,7 @@ describe('GoalsTableToolbar', () => { // the count must not keep reporting a row the user can no longer see. await userEvent.type(getByRole('textbox', { name: 'Search' }), 'carlos'); expect(queryByText('1 selected')).not.toBeInTheDocument(); - expect( - queryByRole('button', { name: 'More Actions' }), - ).not.toBeInTheDocument(); - expect(getByRole('button', { name: 'Print All' })).toBeInTheDocument(); + expect(getByRole('button', { name: 'More Actions' })).toBeDisabled(); }); it('updates search on typing', async () => { diff --git a/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx b/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx index 05d6c25b8a..d71fdac901 100644 --- a/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx +++ b/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx @@ -97,66 +97,60 @@ export const GoalsTableToolbar: React.FC = () => { /> - {hasSelection ? ( - <> - - {t('{{count}} selected', { count: selectedCount })} - - - setMenuAnchorEl(null)} - > - { - setMenuAnchorEl(null); - openRunAndSend( - t('Run and Send Selected Complete MPD Goals?'), - selectedRows, - ); - }} - > - {t('Run & Send Selected')} - - { - setMenuAnchorEl(null); - setAssignCoachOpen(true); - }} - > - {t('Assign Coach')} - - - - ) : ( - <> - {/* Disabled until wired up so assistive tech announces the - inert state instead of a dead control (MPDX-9696). */} - - - + {hasSelection && ( + + {t('{{count}} selected', { count: selectedCount })} + )} + + setMenuAnchorEl(null)} + > + {/* Disabled until wired up so assistive tech announces the + inert state instead of a dead control (MPDX-9702). */} + {t('Print All')} + { + setMenuAnchorEl(null); + openRunAndSend( + t('Run and Send Selected Complete MPD Goals?'), + selectedRows, + ); + }} + > + {t('Run & Send Selected')} + + { + setMenuAnchorEl(null); + setAssignCoachOpen(true); + }} + > + {t('Assign Coach')} + + + Date: Wed, 12 Aug 2026 15:54:58 -0400 Subject: [PATCH 3/9] fix: address review comment on src/components/HrTools/MpdGoalAdmin/mockData.ts:6 Wire GoalsTable per-row Assign Coach to mockCoaches and the context assignCoach so the modal is completable Co-Authored-By: Claude Fable 5 --- .../GoalsTable/GoalsTable.test.tsx | 19 +++++++++++ .../MpdGoalAdmin/GoalsTable/GoalsTable.tsx | 33 ++++++++++++------- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/components/HrTools/MpdGoalAdmin/GoalsTable/GoalsTable.test.tsx b/src/components/HrTools/MpdGoalAdmin/GoalsTable/GoalsTable.test.tsx index 1728cb1205..408a8e6320 100644 --- a/src/components/HrTools/MpdGoalAdmin/GoalsTable/GoalsTable.test.tsx +++ b/src/components/HrTools/MpdGoalAdmin/GoalsTable/GoalsTable.test.tsx @@ -57,6 +57,25 @@ describe('GoalsTable', () => { ).toBeInTheDocument(); }); + it('assigns a coach to the row from the Assign Coach modal', async () => { + const { getByRole, findByRole } = renderTable(); + // 'Carlos & Michaela Everts' (row-2) has no coach on the first page. + userEvent.click(getByRole('button', { name: 'Assign Coach' })); + + const dialog = await findByRole('dialog'); + expect(dialog).toHaveTextContent( + 'Assign Coach for Carlos & Michaela Everts', + ); + + userEvent.click(getByRole('combobox', { name: 'Coach' })); + userEvent.click(await findByRole('option', { name: 'Tom Harris' })); + await userEvent.click(getByRole('button', { name: 'Save' })); + + expect( + ctx.cohorts[0].rows.find((row) => row.id === 'row-2')?.coach, + ).toBe('Tom Harris'); + }); + it('renders a View/Edit action and a menu button for each row on the page', () => { const { getAllByText, getAllByRole } = renderTable(); const onPage = Math.min(rows.length, DEFAULT_ROWS_PER_PAGE); diff --git a/src/components/HrTools/MpdGoalAdmin/GoalsTable/GoalsTable.tsx b/src/components/HrTools/MpdGoalAdmin/GoalsTable/GoalsTable.tsx index 21d31e8f68..3d525f41c8 100644 --- a/src/components/HrTools/MpdGoalAdmin/GoalsTable/GoalsTable.tsx +++ b/src/components/HrTools/MpdGoalAdmin/GoalsTable/GoalsTable.tsx @@ -21,11 +21,9 @@ import { visuallyHidden } from '@mui/utils'; import { useTranslation } from 'react-i18next'; import { useLocale } from 'src/hooks/useLocale'; import { currencyFormat } from 'src/lib/intlFormat'; -import { - AssignCoachModal, - AssignCoachOption, -} from '../AssignCoachModal/AssignCoachModal'; +import { AssignCoachModal } from '../AssignCoachModal/AssignCoachModal'; import { useMpdGoalAdmin } from '../MpdGoalAdminContext'; +import { mockCoaches } from '../mockData'; import { StaffGoalRow, isSendable } from '../mpdGoalAdminHelpers'; interface GoalsTableProps { @@ -37,20 +35,31 @@ export const DEFAULT_ROWS_PER_PAGE = 5; export const GoalsTable: React.FC = ({ rows }) => { const { t } = useTranslation(); const locale = useLocale(); - const { selectedRowIds, toggleRow, toggleRows, search, selectedCohortId } = - useMpdGoalAdmin(); + const { + selectedRowIds, + toggleRow, + toggleRows, + search, + selectedCohortId, + assignCoach, + } = useMpdGoalAdmin(); const [page, setPage] = useState(0); const [rowsPerPage, setRowsPerPage] = useState(DEFAULT_ROWS_PER_PAGE); // The staff row whose coach is being assigned; null when the modal is closed. const [coachRow, setCoachRow] = useState(null); - // TODO(MPDX-9699): populate from the assignable-coaches query once the - // backend field exists. Empty for now so the modal renders a UI-only dropdown. - const assignableCoaches: AssignCoachOption[] = []; + // TODO(MPDX-9914): populate from the assignable-coaches query once the + // backend field exists. Same mock list the toolbar's bulk path uses. + const assignableCoaches = mockCoaches; - const handleAssignCoach = async (_coachId: string) => { - // TODO(MPDX-9699): call the assign-coach mutation with { staffId, coachId } - // and refresh the goal-admin rows. Backend contract pending. + // TODO(MPDX-9914): call the assignCoach mutation instead of the mock + // context update once the backend field is wired up. + const handleAssignCoach = (coachId: string) => { + const coach = assignableCoaches.find((option) => option.id === coachId); + if (!coach || !coachRow) { + return; + } + assignCoach([coachRow.id], coach.name); }; // Reset to the first page whenever the filter inputs change, so the user From 28a3ddcee0502a07d85a5cb09fa249b3bbedc377 Mon Sep 17 00:00:00 2001 From: wjames111 Date: Wed, 12 Aug 2026 15:53:31 -0400 Subject: [PATCH 4/9] fix: address review comment on src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx:148 Demote 'Run and Send All' to outlined while rows are selected so only one contained CTA is on screen Co-Authored-By: Claude Fable 5 --- .../MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx b/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx index d71fdac901..f81072aab2 100644 --- a/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx +++ b/src/components/HrTools/MpdGoalAdmin/GoalsTableToolbar/GoalsTableToolbar.tsx @@ -141,7 +141,9 @@ export const GoalsTableToolbar: React.FC = () => {