Skip to content

fix(SDK-1171): keep payroll review actions from overflowing at narrow widths - #2608

Merged
dmortal merged 5 commits into
mainfrom
codex/sdk-1171-payroll-review-reflow
Sep 16, 2026
Merged

dmortal merged 5 commits into
mainfrom
codex/sdk-1171-payroll-review-reflow

Conversation

@hukid

@hukid hukid commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes the Payroll Overview at narrow reflow widths by keeping the unprocessed payroll Edit and Submit actions in one shrink-safe, equal-width row. The change preserves heading-first semantic order, desktop behavior, submission state and callbacks, while leaving processed payroll receipt/cancel actions stacked for their longer labels.

Changes

  • Use two minmax(0, 1fr) tracks for unprocessed base/mobile actions while retaining a single track for processed payroll actions.
  • Add regression coverage for action layout, semantic order, enabled callbacks, blocker disabled state, and processed-mobile stacking.
  • Add an exact 320x256 Storybook regression story using the existing wire-funds fixture.

Demo

Chromium verification at an exact 320x256 inspection region showed no horizontal overflow. Edit and Submit render on the same row at 156x40 each, both remain operable, the heading precedes the actions, and all later content is vertically reachable. The blocked state and the 639px / 640px breakpoint transition were also verified.

Safari with VoiceOver was not available in the execution environment. That browser and assistive-technology combination remains a manual verification item before merge.

Related

  • Jira ticket: SDK-1171
  • Tech spec: N/A - this is a localized, reversible presentation fix with no public API or backend contract change.

Testing

  • npm run test -- --run --exclude '.claude/**' src/components/Payroll/PayrollOverview/PayrollOverviewPresentation.test.tsx - 32/32 passing after synchronization with origin/main.
  • npm run tsc, npm run build, npm run build-storybook, scoped ESLint/Prettier, and diff checks passed during implementation verification.
  • Full workspace suite excluding preserved .claude/worktrees: 3,736 passing, 1 expected failure, and 5 unrelated date/time-boundary failures in untouched files.
  • Chromium at exact 320x256: no horizontal overflow; Edit and Submit each measured 156x40, shared one row, remained operable, and followed the heading in semantic order.
  • Chromium at 639px and 640px: no duplicate or missing action group across the base/desktop breakpoint. The blocked Submit state remained visible and disabled, and processed mobile actions remained stacked.
  • Backend E2E was not run because this deterministic presentation regression is covered through Storybook and unit tests; the repository E2E path requires external gws-flows and ZenPayroll services and does not provide the physical reflow assertion.
  • Manual follow-up: verify 320x256 reflow, focus order, accessible names, disabled state, and vertical reachability in Safari with VoiceOver.

🤖 AI Disclosure: This PR was authored by Codex AI Agent, orchestrated by @hukid. All code, tests, and this PR description were AI-generated under human supervision. Please review with this context in mind.

hukid and others added 4 commits August 20, 2026 18:04
…abled

The mobile action grid hardcoded two minmax(0, 1fr) tracks for any
unprocessed payroll, but Edit is conditional on canEdit. With
canEdit=false (readOnly mode) only Submit renders, leaving it pinned
to a half-width column with an empty second track. Size the columns
off canEdit so the lone action gets the full-width single-column
grid instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dmortal
dmortal marked this pull request as ready for review September 15, 2026 13:26
@dmortal
dmortal requested a review from a team as a code owner September 15, 2026 13:26
@dmortal dmortal changed the title [SDK-1171] Fix payroll review actions at narrow widths fix(SDK-1171): keep payroll review actions from overflowing at narrow widths Sep 15, 2026
@dmortal
dmortal enabled auto-merge September 15, 2026 14:31
Comment on lines +108 to +181
describe('base layout', () => {
beforeEach(() => {
mockUseContainerBreakpoints.mockReturnValue(['base'])
})

it('keeps the heading before enabled Edit and Submit actions in a shrink-safe row', async () => {
const user = userEvent.setup()
const onEdit = vi.fn()
const onSubmit = vi.fn()

renderWithProviders(
<PayrollOverviewPresentation {...defaultProps} onEdit={onEdit} onSubmit={onSubmit} />,
)

const heading = await screen.findByRole('heading', { level: 1, name: /Review payroll/i })
const editButton = screen.getByRole('button', { name: /^Edit$/i })
const submitButton = screen.getByRole('button', { name: /^Submit$/i })
const actionGrid = editButton.parentElement

expect(heading.compareDocumentPosition(editButton) & Node.DOCUMENT_POSITION_FOLLOWING).toBe(
Node.DOCUMENT_POSITION_FOLLOWING,
)
expect(submitButton.parentElement).toBe(actionGrid)
expect(actionGrid?.style.getPropertyValue('--g-grid-template-columns-base')).toBe(
'minmax(0, 1fr) minmax(0, 1fr)',
)
expect(editButton).toBeEnabled()
expect(submitButton).toBeEnabled()

await user.click(editButton)
await user.click(submitButton)

expect(onEdit).toHaveBeenCalledTimes(1)
expect(onSubmit).toHaveBeenCalledTimes(1)
})

it('keeps the lone Submit action full-width when editing is disabled', async () => {
renderWithProviders(<PayrollOverviewPresentation {...defaultProps} canEdit={false} />)

const submitButton = await screen.findByRole('button', { name: /^Submit$/i })
const actionGrid = submitButton.parentElement

expect(screen.queryByRole('button', { name: /^Edit$/i })).toBeNull()
expect(actionGrid?.style.getPropertyValue('--g-grid-template-columns-base')).toBe('1fr')
})

it('keeps Submit visible and disabled while a blocker has no selected resolution', async () => {
renderWithProviders(
<PayrollOverviewPresentation
{...defaultProps}
submissionBlockers={[mockFastAchBlocker]}
onUnblockOptionChange={vi.fn()}
/>,
)

expect(await screen.findByRole('button', { name: /^Submit$/i })).toBeDisabled()
})

it('keeps processed payroll actions stacked in a single-column grid', async () => {
renderWithProviders(
<PayrollOverviewPresentation {...defaultProps} isProcessed={true} canCancel={true} />,
)

const receiptButton = await screen.findByRole('button', {
name: /^View payroll receipt$/i,
})
const cancelButton = screen.getByRole('button', { name: /^Cancel payroll$/i })
const actionGrid = receiptButton.parentElement

expect(cancelButton.parentElement).toBe(actionGrid)
expect(actionGrid?.style.getPropertyValue('--g-grid-template-columns-base')).toBe('1fr')
})
})

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: I'm not sure these tests are super valuable for something that is presentational

@dmortal
dmortal added this pull request to the merge queue Sep 16, 2026
Merged via the queue into main with commit 7fe0765 Sep 16, 2026
39 checks passed
@dmortal
dmortal deleted the codex/sdk-1171-payroll-review-reflow branch September 16, 2026 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants