Skip to content

feat: extract Paystubs card from DashboardFlow into standalone management block#2011

Draft
serikjensen wants to merge 1 commit into
mainfrom
migrate-paystubs-card-to-block
Draft

feat: extract Paystubs card from DashboardFlow into standalone management block#2011
serikjensen wants to merge 1 commit into
mainfrom
migrate-paystubs-card-to-block

Conversation

@serikjensen
Copy link
Copy Markdown
Member

Summary

Migrates the inline paystubs UI out of JobAndPayView and into a new Employee/Paystubs feature folder, following the standalone-card pattern established by HomeAddress (#1992) and PaymentMethod (#2006).

Four independently consumable pieces under the new Employee/Paystubs/ folder:

  • shared/usePaystubsListBaseHookReady-shaped data hook that fetches the paginated paystubs list and exposes a downloadPayStub(payrollId) action returning a PDF Blob. Partners can build a fully custom paystubs UI on top of this hook.
  • management/PaystubsCard — self-fetching card that renders the paystubs table and owns the per-row download UX (new-tab spinner page → Blob URL navigation → revoke). Emits scoped EMPLOYEE_MANAGEMENT_PAYSTUBS_CARD_DOWNLOAD_REQUESTED / _DOWNLOADED events. Cross-fetches usePaymentMethodList internally for the "Payment method" column.
  • management/Paystubs — thin block that wraps the card in BaseBoundaries and registers the Employee.Management.Paystubs i18n namespace.
  • Public exports added to Employee/exports/employeeManagement.ts and the SDK dev-app registry.

State-machine exception

Paystubs is a read-only surface — the only interaction is a per-row PDF download that resolves as a side effect (opens a new tab). With zero transitions, the block has no robot3 state machine, no Flow orchestration, and no contextual adapter. The Paystubs block doc comment explicitly documents this exception so future maintainers know which shape to adopt if/when an edit/review state is ever added.

Cleanup in Dashboard/

  • useEmployeeCompensation no longer fetches paystubs (and its return type drops payStubs / payStubsPagination / isPayStubsLoading). Callers embed <PaystubsCard /> directly.
  • JobAndPayView deletes ~160 lines of inline paystubs code (download handler, columns, DataView, loading branch) and replaces them with <PaystubsCard employeeId={employeeId} onEvent={onEvent} />.
  • jobAndPay.paystubs.* keys move from Employee.DashboardEmployee.Management.Paystubs (regenerated i18n types).

Bug fix included

While QA'ing manually I noticed the per-row download spinner spun forever after a successful download — the payroll UUID was added to the in-flight set but never removed. Added a finally block in handleDownload that drops it on success, failure, or empty result, plus a regression assertion in PaystubsCard.test.tsx.

Test plan

  • Unit tests
    • usePaystubsList.test.tsx — loading state, ready state, pagination, downloadPayStub success returning a Blob, downloadPayStub API failure surfacing through errorHandling.errors
    • PaystubsCard.test.tsx — title + per-row download buttons render, empty state, event emission on request + success, spinner clears after download completes (regression for the bug above)
    • Paystubs.test.tsx — block renders the card, events propagate
    • useEmployeeCompensation.test.tsx — paystubs assertions removed; remaining compensation/cancel-pending-change behavior still passes
  • Full suite: npm run test -- --run — green
  • npm run tsc — clean
  • npm run lint:check — clean (warnings only, all pre-existing)
  • Manual: download a paystub from the dashboard; verifies the new-tab spinner page → PDF, button spinner clears on success
  • Partner-facing docs review of docs/workflows-overview/employee-management/employee-management.md additions

Refs

Made with Cursor

…ment block

Moves the inline paystubs UI out of `JobAndPayView` and into a new
`Employee/Paystubs/management` block following the standalone card
pattern established by HomeAddress (#1992) and PaymentMethod (#2006):

- `shared/usePaystubsList` — `BaseHookReady`-shaped data hook that
  fetches the paginated paystubs list and exposes a `downloadPayStub`
  action returning a PDF Blob.
- `management/PaystubsCard` — self-fetching card that renders the table
  and owns the per-row download UX (new-tab spinner page, Blob URL
  navigation, scoped `EMPLOYEE_MANAGEMENT_PAYSTUBS_CARD_*` events).
- `management/Paystubs` — thin block that wraps the card in
  `BaseBoundaries` and registers the `Employee.Management.Paystubs`
  i18n namespace. Paystubs is a read-only surface, so the block has no
  `robot3` state machine, no `Flow` orchestration, and no contextual
  adapter — the doc comment documents this exception so future
  maintainers know the shape to adopt if/when an edit state appears.

`useEmployeeCompensation` no longer fetches paystubs (callers now
embed `<PaystubsCard />` directly), and the `jobAndPay.paystubs.*`
keys move from `Employee.Dashboard` to `Employee.Management.Paystubs`.

Also fixes a regression caught during manual QA: the per-row download
spinner never cleared because the payroll UUID was added to the
in-flight set but never removed. A `finally` block now drops it on
success, failure, or empty result; covered by a new assertion in
`PaystubsCard.test.tsx`.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

1 participant