Task #63: Service Orders client UI (place order + My Orders)
Adds the user-facing half of the service ordering workflow on top of the backend foundation merged in Task #62. What's new: - Order button on each available service card (hidden when service is unavailable) opens a focused OrderServiceModal showing only the service name + image with a multi-line notes textarea (500-char cap with live counter). Submitting calls POST /orders, shows a toast, and invalidates the My Orders cache. - New /my-orders page lists the user's own orders newest-first with a status pill, a horizontal 4-step timeline (pending → received → preparing → completed), and a red terminal pill for cancelled orders. - Cancel action with confirm dialog is shown only while the order is pending or received; it calls PATCH /orders/:id/status with cancelled. - "My Orders" link added to the services page header. - Realtime: the existing notifications socket also invalidates the my-orders query on notification_created (when type === 'order') and on a new order_updated event. - Locale keys mirrored in ar.json and en.json for services.order/*, myOrders.*, and orderStatus.*. RTL/LTR handled. - Friendly load-error state with retry, plus client-side sort by createdAt desc. Verification: typecheck clean, all 3 e2e tests pass, manual end-to-end UI flow (place + cancel + locale switch) verified via testing skill, backend smoke test confirmed POST /orders + GET /orders/my wiring.
This commit is contained in:
@@ -120,6 +120,7 @@
|
||||
"title": "طلباتي",
|
||||
"loadError": "تعذّر تحميل الطلبات. حاول مرة أخرى.",
|
||||
"retry": "إعادة المحاولة",
|
||||
"back": "رجوع",
|
||||
"empty": "لا توجد طلبات بعد",
|
||||
"emptyHint": "ابدأ من كتالوج الخدمات.",
|
||||
"browseServices": "تصفّح الخدمات",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"title": "My Orders",
|
||||
"loadError": "Could not load your orders. Please try again.",
|
||||
"retry": "Retry",
|
||||
"back": "Back",
|
||||
"empty": "No orders yet",
|
||||
"emptyHint": "Start from the services catalog.",
|
||||
"browseServices": "Browse services",
|
||||
|
||||
@@ -274,7 +274,7 @@ export default function MyOrdersPage() {
|
||||
<button
|
||||
onClick={() => setLocation("/services")}
|
||||
className="p-2 rounded-xl hover:bg-slate-100 text-muted-foreground hover:text-foreground transition-colors"
|
||||
aria-label={t("common.cancel")}
|
||||
aria-label={t("myOrders.back")}
|
||||
>
|
||||
<BackIcon size={20} />
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user