Skip to content

feat: extract Deductions card from DashboardFlow into standalone management block#2008

Draft
serikjensen wants to merge 1 commit into
sj/chore/deductions-relocate-onboarding-flowfrom
sj/feat/deductions-card-to-block
Draft

feat: extract Deductions card from DashboardFlow into standalone management block#2008
serikjensen wants to merge 1 commit into
sj/chore/deductions-relocate-onboarding-flowfrom
sj/feat/deductions-card-to-block

Conversation

@serikjensen
Copy link
Copy Markdown
Member

Summary

Migrates the Deductions card off DashboardFlow's monolithic state machine and into a standalone EmployeeManagement.Deductions block under Deductions/management/, following the canonical pattern set by PaymentMethod/management/ and the per-card skill at .claude/skills/migrate-dashboard-card-to-block. After this PR a partner can drop in any of three pieces independently — the block, the card, or the edit form — and the dashboard composes the card + edit form pieces directly (the block is the partner convenience, not what DashboardFlow imports).

This PR is stacked on top of #1995 (the precursor PR that relocated the existing top-level Deductions onboarding flow into Deductions/onboarding/ to free up Deductions/management/). Merge #1995 first, then re-target this PR's base to main.

What changed

  • Standalone pieces under Deductions/management/
    • DeductionsCard/DeductionsCard.tsx (+ test, + index) — self-fetches via the existing useDeductionsList, owns its own delete-confirm dialog, emits scoped card events. Replaces the inline markup JobAndPayView had for the Deductions section.
    • DeductionsEditForm.tsx — thin per-flow wrapper around the shared DeductionsForm from onboarding/. Looks up the row to edit by id, translates the form's onSaved / onCancel callbacks into scoped management events.
    • Deductions.tsx + deductionsStateMachine.ts + DeductionsComponents.tsx — robot3-based orchestrator that swaps card ↔ edit form in-place inside the same Box, renders the success alert above the card via DeductionsCardContextual.
    • Deductions.test.tsx (block integration), DeductionsCard/DeductionsCard.test.tsx (card-in-isolation).
    • management/index.ts exports all three pieces; Employee/exports/employeeManagement.ts re-exports them under EmployeeManagement.{Deductions,DeductionsCard,DeductionsEditForm}.
  • DeleteDeductionDialog is now presentational. title / description / confirmLabel / cancelLabel are props, supplied per-consumer from their own namespace. Matches the same decoupling rule DeleteBankAccountDialog just adopted — partner overrides on one flow's namespace don't leak into another.
  • Dashboard consumes the pieces, not the block. JobAndPayView now renders <DeductionsCard employeeId={…} onEvent={onEvent} /> directly; dashboardStateMachine listens for the scoped card events and routes its editDeduction sub-state to <DeductionsEditFormContextual>. The dashboard chrome's deductionAdded / deductionUpdated / deductionDeleted alerts continue to render at the page level via the existing returnToIndexWithAlert(…) pattern — same event drives both the block-level alert and the dashboard-level alert.
  • Dedicated i18n namespace Employee.Management.Deductions. Card chrome, list columns, empty state, delete-dialog copy, row CTAs (editCta / deleteCta / hamburgerTitle), and success-alert labels all live here. The card and block read from this namespace and only this namespace. Dashboard-side alert keys stay in Employee.Dashboard (duplicated — intentional per the skill).
  • Polish to match the skill updates from feat: integrate DashboardFlow with standalone PaymentMethod management block #2006:
    • Event keys use EMPLOYEE_MANAGEMENT_DEDUCTIONS_* (reads as "management event for deductions"), split per-component (_CARD_* vs _EDIT_FORM_*).
    • i18n namespace is Employee.Management.Deductions.json (prefix-style), not the older suffix-style Employee.Deductions.Management.json.
    • Contextual adapter is DeductionsCardContextual (mirrors the wrapped component name) instead of the unqualified CardContextual.
    • BaseBoundaries componentName is Employee.Management.Deductions.
    • Card body uses withPadding={false} + <DataView isWithinBox /> so the table runs flush with the box edges, matching Compensation / Paystubs.

Scoped event surface

Event Where it fires
EMPLOYEE_MANAGEMENT_DEDUCTIONS_CARD_ADD_REQUESTED DeductionsCard Add deduction button
EMPLOYEE_MANAGEMENT_DEDUCTIONS_CARD_EDIT_REQUESTED DeductionsCard row Edit menu item
EMPLOYEE_MANAGEMENT_DEDUCTIONS_CARD_DELETED DeductionsCard delete-dialog confirm
EMPLOYEE_MANAGEMENT_DEDUCTIONS_EDIT_FORM_CREATED DeductionsEditForm save in add mode
EMPLOYEE_MANAGEMENT_DEDUCTIONS_EDIT_FORM_UPDATED DeductionsEditForm save in edit mode
EMPLOYEE_MANAGEMENT_DEDUCTIONS_EDIT_FORM_CANCELLED DeductionsEditForm cancel
EMPLOYEE_MANAGEMENT_DEDUCTIONS_ALERT_DISMISSED Block-rendered success alert dismiss

The pre-existing un-scoped componentEvents.EMPLOYEE_DEDUCTION_* constants used by useDeductionForm / useDeductionsList are unchanged — those continue to fire from the underlying form/list hooks for any partner already listening to them.

Test plan

  • npm run test -- --run — 2999 passed, 1 expected fail (no regressions vs. pre-rebase baseline)
  • npm run lint:check — 0 errors (26 pre-existing warnings unrelated)
  • npm run format:check — clean
  • npm run tsc — clean
  • Block integration test (management/Deductions.test.tsx) covers card ↔ edit transitions, cancel, soft-delete via PUT, and alert dismissal
  • Card-in-isolation test (management/DeductionsCard/DeductionsCard.test.tsx) covers empty / ready branches and event emission for each CTA
  • Dashboard regression tests (Dashboard.test.tsx) updated to assert the new scoped event names
  • SDK dev app registry regenerated — EmployeeManagement.{Deductions,DeductionsCard,DeductionsEditForm} show up under "Employee Management"
  • Partner-facing doc entry added to docs/workflows-overview/employee-management/employee-management.md with composition example

Made with Cursor

…gement block

Migrates the Deductions card on the Dashboard's Job & Pay tab into a
card-as-block following the pattern documented in
.claude/skills/migrate-dashboard-card-to-block.

Adds four standalone-consumable surfaces:

- `EmployeeManagement.Deductions` — orchestrated block (card + add/edit
  form + success-alert chrome), wired via a local robot3 state machine.
- `EmployeeManagement.DeductionsCard` — self-fetching standalone card
  that emits scoped `EMPLOYEE_DEDUCTION_MANAGEMENT_*` events.
- `EmployeeManagement.DeductionsEditForm` — standalone add/edit form
  that adapts the shared onboarding `DeductionsForm` and emits scoped
  events on save/cancel.
- `useDeductionsList` (existing) — already returns the `BaseHookReady`
  shape; now consumed directly by the card and the edit form.

Dashboard integration:

- `dashboardStateMachine` and `DashboardComponents` retargeted to the
  scoped `EMPLOYEE_DEDUCTION_MANAGEMENT_*` events; the dashboard's
  Job & Pay view now renders `<DeductionsCard />` inline and routes
  to `<DeductionsEditForm />` via the renamed `editDeduction` state.
- Card chrome strings and success-alert labels relocated from
  `Employee.Dashboard:jobAndPay.deductions.*` into the new
  `Employee.Deductions.Management.json` namespace; alert labels
  duplicated into `Employee.Dashboard.json` so dashboard chrome
  still renders the toast above the tabs.

Testing:

- `DeductionsCard.test.tsx` — card-in-isolation contract (loading,
  ready, empty, scoped event emission for add/edit/delete).
- `Deductions.test.tsx` — block integration (card↔edit transitions,
  cancel, delete + alert dismissal).
- `Dashboard.test.tsx` — existing assertions retargeted to the
  scoped event names; all other dashboard coverage retained.

Dev app: `npx tsx sdk-app/scripts/analyze-component-props.ts` re-run;
the registry now surfaces `EmployeeManagement.Deductions`,
`EmployeeManagement.DeductionsCard`, and
`EmployeeManagement.DeductionsEditForm` under the Employee Management
sidebar section.

Docs: partner-facing entry added to
`docs/workflows-overview/employee-management/employee-management.md`
covering the block, the per-piece composition pattern, props,
and the full scoped event surface.

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