fix(billing): standardised 403 permission-required UI on Contracts + Rate Cards (MAPPS-271) #314

Merged
YousifShkara merged 1 commit from fix/MAPPS-271-standardize-403-permission-ui into main 2026-06-23 06:40:52 +02:00
Owner

The Invoices and Payments lists already short-circuited to a friendly locked-state empty UI when the signed-in user lacked can_manage_billing(). The Contracts and Rate Cards lists did not - their server endpoints (list_contracts, list_rate_cards) are both RequireFinance-gated, so a non-finance role hit a 403, fell through to the generic "Could not load X. Refresh the page to retry." sentence, and the user could not tell whether the failure was transient or a permission boundary. The QA report specifically flagged this.

Lift the existing NoFinancePermission shape into a shared PermissionRequired component (src/components/permission_state.rs) parameterised on title + body, then short-circuit the ContractListPage and RateCardListPage to that component when use_can_manage_billing() is false. The user now sees the same posture across all four billing-adjacent lists: an icon, a clear heading naming the gated surface, a one-line explanation, and the viewer's current role for context.

PMS-447 (deployed) floor-promotes Bunyip subscribers to Mokosh Admin (which passes can_manage_billing()), so most real users won't hit this branch any more. The standardised UI still matters for tenant-internal role-grant changes, and was the QA's specific request. The Invoices / Payments pages keep their existing NoFinancePermission rendering for now - the messaging is identical, just the component name differs; a future refactor can collapse them, this PR doesn't touch the already-correct surfaces.

#MAPPS-271

The Invoices and Payments lists already short-circuited to a friendly locked-state empty UI when the signed-in user lacked `can_manage_billing()`. The Contracts and Rate Cards lists did not - their server endpoints (`list_contracts`, `list_rate_cards`) are both `RequireFinance`-gated, so a non-finance role hit a 403, fell through to the generic "Could not load X. Refresh the page to retry." sentence, and the user could not tell whether the failure was transient or a permission boundary. The QA report specifically flagged this. Lift the existing `NoFinancePermission` shape into a shared `PermissionRequired` component (`src/components/permission_state.rs`) parameterised on title + body, then short-circuit the ContractListPage and RateCardListPage to that component when `use_can_manage_billing()` is false. The user now sees the same posture across all four billing-adjacent lists: an icon, a clear heading naming the gated surface, a one-line explanation, and the viewer's current role for context. PMS-447 (deployed) floor-promotes Bunyip subscribers to Mokosh Admin (which passes `can_manage_billing()`), so most real users won't hit this branch any more. The standardised UI still matters for tenant-internal role-grant changes, and was the QA's specific request. The Invoices / Payments pages keep their existing `NoFinancePermission` rendering for now - the messaging is identical, just the component name differs; a future refactor can collapse them, this PR doesn't touch the already-correct surfaces. #MAPPS-271
fix(billing): standardised 403 permission-required UI on Contracts + Rate Cards (MAPPS-271)
All checks were successful
Check / fmt + clippy + tests (pull_request) Successful in 8m22s
Create release / Create release from merged PR (pull_request) Has been skipped
6efd48987e
The Invoices and Payments lists already short-circuited to a friendly locked-state empty UI when the signed-in user lacked `can_manage_billing()`. The Contracts and Rate Cards lists did not - their server endpoints (`list_contracts`, `list_rate_cards`) are both `RequireFinance`-gated, so a non-finance role hit a 403, fell through to the generic "Could not load X. Refresh the page to retry." sentence, and the user could not tell whether the failure was transient or a permission boundary. The QA report specifically flagged this.

Lift the existing `NoFinancePermission` shape into a shared `PermissionRequired` component (`src/components/permission_state.rs`) parameterised on title + body, then short-circuit the ContractListPage and RateCardListPage to that component when `use_can_manage_billing()` is false. The user now sees the same posture across all four billing-adjacent lists: an icon, a clear heading naming the gated surface, a one-line explanation, and the viewer's current role for context.

PMS-447 (deployed) floor-promotes Bunyip subscribers to Mokosh Admin (which passes `can_manage_billing()`), so most real users won't hit this branch any more. The standardised UI still matters for tenant-internal role-grant changes, and was the QA's specific request. The Invoices / Payments pages keep their existing `NoFinancePermission` rendering for now - the messaging is identical, just the component name differs; a future refactor can collapse them, this PR doesn't touch the already-correct surfaces.

#MAPPS-271
YousifShkara deleted branch fix/MAPPS-271-standardize-403-permission-ui 2026-06-23 06:40:52 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-apps!314
No description provided.