Task #64: Service Orders — receiver page + admin role toggle
Backend (artifacts/api-server)
- Add admin-only role-toggle endpoints:
- POST /users/:id/roles { roleName } — idempotent, returns UserProfile
- DELETE /users/:id/roles/:roleName — idempotent, returns UserProfile
- Allow assigned receiver to cancel their own claimed order
(received/preparing) in PATCH /orders/:id/status. Owner & admin
rules unchanged.
- New backend test cases: receiver can cancel own assigned order;
another receiver gets 403.
API spec / codegen
- Add AddUserRoleBody schema and the two new role endpoints
under a new "roles" tag in lib/api-spec/openapi.yaml.
- Regenerated api-zod and api-client-react.
Frontend (artifacts/teaboy-os)
- New page src/pages/orders-incoming.tsx at /orders/incoming:
RBAC-gated (admin || order_receiver), shows "My active orders"
and "Awaiting receiver" sections, with claim, mark preparing,
mark completed and cancel buttons. Handles 409 already_claimed.
- Add Inbox button to home top bar, conditional on the same roles.
- Admin users table now has an "Order Receiver" Switch wired to
the new role-toggle hooks.
- Extend use-notifications-socket to invalidate the incoming-orders
query on order_incoming_changed and on notification_created with
type === "order".
- Bilingual locale keys (ar/en) for the new page and admin label.
Tests
- All 25 api-server tests pass (24 existing + 1 new receiver-cancel
case). All 3 teaboy-os e2e tests pass.
Follow-up filed: #67 (notify requester when receiver cancels).
This commit is contained in:
@@ -26,6 +26,8 @@ tags:
|
||||
description: Notifications
|
||||
- name: users
|
||||
description: User management
|
||||
- name: roles
|
||||
description: Role assignment
|
||||
- name: stats
|
||||
description: Dashboard stats
|
||||
- name: storage
|
||||
@@ -1123,6 +1125,73 @@ paths:
|
||||
"204":
|
||||
description: Deleted
|
||||
|
||||
/users/{id}/roles:
|
||||
post:
|
||||
operationId: addUserRole
|
||||
tags: [roles]
|
||||
summary: Idempotently add a role to a user (admin)
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/AddUserRoleBody"
|
||||
responses:
|
||||
"200":
|
||||
description: Role added (or already present)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/UserProfile"
|
||||
"400":
|
||||
description: Validation error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
"404":
|
||||
description: User or role not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
|
||||
/users/{id}/roles/{roleName}:
|
||||
delete:
|
||||
operationId: removeUserRole
|
||||
tags: [roles]
|
||||
summary: Idempotently remove a role from a user (admin)
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
- name: roleName
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: Role removed (or already absent)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/UserProfile"
|
||||
"404":
|
||||
description: User not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
|
||||
# Stats
|
||||
/stats/home:
|
||||
get:
|
||||
@@ -1551,6 +1620,15 @@ components:
|
||||
preferredLanguage:
|
||||
type: string
|
||||
|
||||
AddUserRoleBody:
|
||||
type: object
|
||||
properties:
|
||||
roleName:
|
||||
type: string
|
||||
minLength: 1
|
||||
required:
|
||||
- roleName
|
||||
|
||||
App:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
Reference in New Issue
Block a user