@burdenoff/microfe-kadaikodi 2026.801.1 → 2026.802.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/kadaikodi/KadaikodiRoutes.js +1 -1
  2. package/dist/kadaikodi/KadaikodiRoutes.js.map +1 -1
  3. package/dist/kadaikodi/context/KadaikodiContext.js +1 -1
  4. package/dist/kadaikodi/context/KadaikodiContext.js.map +1 -1
  5. package/dist/kadaikodi/pages/customer/BookingDetailsPage.d.ts.map +1 -1
  6. package/dist/kadaikodi/pages/customer/BookingDetailsPage.js +1 -1
  7. package/dist/kadaikodi/pages/customer/BookingDetailsPage.js.map +1 -1
  8. package/dist/kadaikodi/pages/customer/CartDetailPage.js +1 -1
  9. package/dist/kadaikodi/pages/customer/CartDetailPage.js.map +1 -1
  10. package/dist/kadaikodi/pages/customer/DirectServiceBookingPage.js +1 -1
  11. package/dist/kadaikodi/pages/customer/DirectServiceBookingPage.js.map +1 -1
  12. package/dist/kadaikodi/pages/customer/OrderTrackingPage.js +1 -1
  13. package/dist/kadaikodi/pages/customer/OrderTrackingPage.js.map +1 -1
  14. package/dist/kadaikodi/pages/investor/InvestmentDetailsPage.js +1 -1
  15. package/dist/kadaikodi/pages/investor/InvestmentDetailsPage.js.map +1 -1
  16. package/dist/kadaikodi/pages/worker/TaskDetailsPage.js +1 -1
  17. package/dist/kadaikodi/pages/worker/TaskDetailsPage.js.map +1 -1
  18. package/dist/services/createSandboxAssistantTransport.js +6 -4
  19. package/dist/services/createSandboxAssistantTransport.js.map +1 -1
  20. package/dist/stories/CartCard.stories.d.ts +16 -0
  21. package/dist/stories/CartCard.stories.d.ts.map +1 -0
  22. package/dist/stories/InvestmentCard.stories.d.ts +17 -0
  23. package/dist/stories/InvestmentCard.stories.d.ts.map +1 -0
  24. package/dist/stories/OrderCard.stories.d.ts +17 -0
  25. package/dist/stories/OrderCard.stories.d.ts.map +1 -0
  26. package/dist/stories/RatingDisplay.stories.d.ts +16 -0
  27. package/dist/stories/RatingDisplay.stories.d.ts.map +1 -0
  28. package/dist/utils/pageContext.js +54 -0
  29. package/dist/utils/pageContext.js.map +1 -0
  30. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"OrderTrackingPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/customer/OrderTrackingPage.tsx"],"sourcesContent":["/**\n * Order Tracking Page\n * @module kadaikodi/pages/customer\n *\n * Real-time order tracking with status timeline, delivery partner info,\n * price breakdown, Need Help sidebar, and rate order functionality.\n */\n\nimport { useEffect, useRef, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n CheckCircle2,\n Clock,\n MapPin,\n Phone,\n Star,\n ShoppingBag,\n WifiOff,\n XCircle,\n MessageCircle,\n Loader2,\n X,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Timeline, type TimelineItem } from '../../components/viz';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport { useOrder, useCreateReview } from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatDate } from '../../utils/formatters';\nimport { notifyOrderStatusChange } from '../../utils/orderStatusNotifier';\nimport { useKadaikodiStore } from '../../store';\nimport type { OrderStatus } from '../../types';\nimport { StylizedRouteMap } from './shared';\n\nconst statusOrder: OrderStatus[] = [\n 'pending',\n 'confirmed',\n 'preparing',\n 'ready',\n 'out_for_delivery',\n 'delivered',\n];\n\nconst statusLabels: Record<string, string> = {\n pending: 'Order Placed',\n confirmed: 'Confirmed',\n preparing: 'Preparing',\n ready: 'Ready',\n out_for_delivery: 'Out for Delivery',\n delivered: 'Delivered',\n};\n\nconst statusDescriptions: Record<string, string> = {\n pending: 'Your order has been received',\n confirmed: 'Cart has accepted your order',\n preparing: 'Your food is being prepared',\n ready: 'Order is ready for pickup/delivery',\n out_for_delivery: 'Your order is on the way',\n delivered: 'Order has been delivered',\n};\n\nexport function OrderTrackingPage() {\n const { orderId } = useParams<{ orderId: string }>();\n const { navigateTo, currentUser } = useKadaikodi();\n const { data: order, isLoading, isError } = useOrder(orderId, { pollWhileActive: true });\n const createReview = useCreateReview();\n const [showRateModal, setShowRateModal] = useState(false);\n const [rating, setRating] = useState(5);\n const [reviewText, setReviewText] = useState('');\n const [statusMessage, setStatusMessage] = useState<string | null>(null);\n\n const showStatus = (msg: string) => {\n setStatusMessage(msg);\n setTimeout(() => setStatusMessage(null), 3000);\n };\n\n // Offline-cached order status (BOFF-4301). `cachedOrder` is what OS-level\n // notifications and the offline fallback view below both key off; it\n // outlives an app kill/reload because it's persisted, unlike the\n // in-memory react-query cache `order` comes from.\n const cachedOrder = useKadaikodiStore((s) =>\n orderId ? s.lastKnownOrderStatus[orderId] : undefined\n );\n const setLastKnownOrderStatus = useKadaikodiStore((s) => s.setLastKnownOrderStatus);\n const hasNotifiedRef = useRef<Set<string>>(new Set());\n\n useEffect(() => {\n if (!order || !orderId) return;\n const previousStatus = cachedOrder?.status;\n const changed = previousStatus !== undefined && previousStatus !== order.status;\n // De-dupe within a single mount: React Query's polling can re-fire the\n // same status more than once before the store write is observed.\n const changeKey = `${orderId}:${order.status}`;\n if (changed && !hasNotifiedRef.current.has(changeKey)) {\n hasNotifiedRef.current.add(changeKey);\n const label = statusLabels[order.status] ?? order.status;\n showStatus(`Order status updated: ${label}`);\n void notifyOrderStatusChange({\n orderId,\n title: `${order.cartName} — ${label}`,\n body: statusDescriptions[order.status] ?? `Your order is now ${label.toLowerCase()}.`,\n });\n }\n setLastKnownOrderStatus(orderId, {\n status: order.status,\n orderNumber: order.id,\n cartName: order.cartName,\n total: order.total,\n cachedAt: new Date().toISOString(),\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only order.status changes should re-run this; cachedOrder/setLastKnownOrderStatus would otherwise loop against the write this effect itself performs.\n }, [order?.status, order?.id, orderId]);\n\n const handleSubmitRating = () => {\n if (!order || !currentUser?.id) {\n showStatus('Please sign in to rate this order.');\n return;\n }\n createReview.mutate(\n {\n providerId: order.cartId,\n orderId: order.id,\n customerId: currentUser.id,\n rating,\n review: reviewText.trim() || undefined,\n },\n {\n onSuccess: () => {\n setShowRateModal(false);\n setReviewText('');\n showStatus('Thanks! Your rating has been submitted.');\n },\n onError: () => showStatus('Could not submit your rating. Please try again.'),\n }\n );\n };\n\n if (isLoading) {\n return (\n <PageLayout title=\"Track Order\">\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <div className=\"animate-spin rounded-full h-12 w-12 border-b-2 border-foreground mx-auto mb-4\" />\n <p className=\"text-sm text-text-secondary\">Loading order details...</p>\n </div>\n </PageLayout>\n );\n }\n\n if (!order) {\n // BOFF-4301: the live fetch failed (most likely offline) but a\n // previous session cached this order's last-known status on-device —\n // show that instead of a bare \"not found\", which would be misleading\n // (the order does exist; we just can't reach the network right now).\n if (isError && cachedOrder) {\n return (\n <PageLayout title=\"Track Order\">\n <div className=\"mb-4 flex items-start gap-3 rounded-lg border border-status-warning-text/30 bg-status-warning-bg-subtle p-4\">\n <WifiOff className=\"h-5 w-5 text-status-warning-text mt-0.5 shrink-0\" />\n <div>\n <p className=\"text-sm font-medium text-status-warning-text\">\n You&apos;re offline — showing the last known status\n </p>\n <p className=\"text-xs text-status-warning-text/80 mt-0.5\">\n Cached {formatDate(cachedOrder.cachedAt)}. Reconnect to see live updates.\n </p>\n </div>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5\">\n <div className=\"flex items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n Order #{cachedOrder.orderNumber}\n </h2>\n <p className=\"text-sm text-text-secondary\">{cachedOrder.cartName}</p>\n </div>\n <StatusBadge status={cachedOrder.status as OrderStatus} />\n </div>\n <p className=\"mt-3 text-sm text-text-primary\">\n Last known total: {formatCurrency(cachedOrder.total, { minimumFractionDigits: 0 })}\n </p>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title=\"Order Not Found\">\n <EmptyState\n icon={<ShoppingBag className=\"h-12 w-12\" />}\n title=\"Order not found\"\n description={`The order you're looking for doesn't exist.`}\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/orders')}\n className=\"rounded-lg bg-foreground px-4 py-2 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n View All Orders\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n const currentStatusIndex = statusOrder.indexOf(order.status);\n const isCancelled = order.status === 'cancelled';\n const isDelivered = order.status === 'delivered';\n\n // Honest ETA: only derived when the backend supplies a real estimated time.\n const etaMinutes = order.estimatedDeliveryTime\n ? Math.max(\n 0,\n Math.round((new Date(order.estimatedDeliveryTime).getTime() - Date.now()) / 60000)\n )\n : null;\n\n // Route progress along the illustrative map (0..1) from the live status index.\n const routeProgress = currentStatusIndex < 0 ? 0 : currentStatusIndex / (statusOrder.length - 1);\n\n const timelineItems: TimelineItem[] = statusOrder.map((stepStatus, i) => {\n const tone = i < currentStatusIndex ? 'success' : i === currentStatusIndex ? 'accent' : 'muted';\n const isCurrent = i === currentStatusIndex;\n return {\n id: stepStatus,\n title: statusLabels[stepStatus],\n tone,\n meta: (\n <span className={cn(isCurrent ? 'text-text-primary' : undefined)}>\n {statusDescriptions[stepStatus]}\n </span>\n ),\n };\n });\n\n return (\n <PageLayout\n title={\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/orders')}\n className=\"rounded-md p-1 text-text-secondary hover:bg-accent hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"h-5 w-5\" />\n </button>\n <span>Track Order</span>\n </div>\n }\n actions={<StatusBadge status={order.status} />}\n >\n <PagePurpose className=\"mb-6\">\n Follow your order in real time — see exactly where it is from kitchen to doorstep, who's\n delivering it, and reach out for help if anything looks off. The live status updates as your\n order moves through each stage.\n </PagePurpose>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Left: Order Details & Timeline */}\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Order Header — the one emphasis zone (live status) */}\n <GlassCard treatment=\"glass\" glow className=\"p-5\">\n <div className=\"flex flex-col sm:flex-row sm:justify-between sm:items-start gap-3\">\n <div className=\"flex-1\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Order #{order.id}</h2>\n <p className=\"text-sm text-text-secondary\">{order.cartName}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">{formatDate(order.orderDate)}</p>\n </div>\n <div className=\"text-left sm:text-right\">\n <p className=\"text-xl font-bold text-text-primary\">\n {formatCurrency(order.total, { minimumFractionDigits: 0 })}\n </p>\n <p className=\"text-xs text-text-secondary uppercase\">{order.paymentMethod}</p>\n </div>\n </div>\n\n {/* Status Banner */}\n {isCancelled ? (\n <div className=\"mt-4 flex items-start gap-3 rounded-lg bg-status-error-bg/10 p-4 border border-status-error-border/20\">\n <XCircle className=\"h-5 w-5 text-status-error-text mt-0.5 shrink-0\" />\n <div>\n <p className=\"font-medium text-status-error-text\">Order Cancelled</p>\n {order.cancellationReason && (\n <p className=\"text-sm text-status-error-text/80 mt-0.5\">\n {order.cancellationReason}\n </p>\n )}\n </div>\n </div>\n ) : (\n <div\n className={cn(\n 'mt-4 flex items-start gap-3 rounded-lg p-4 border',\n isDelivered\n ? 'bg-status-success-bg-subtle border-status-success-text/20'\n : 'bg-[var(--color-accent-soft)] border-border-focus/20'\n )}\n >\n {isDelivered ? (\n <CheckCircle2 className=\"h-5 w-5 text-status-success-text mt-0.5 shrink-0\" />\n ) : (\n <Clock className=\"h-5 w-5 text-text-primary mt-0.5 shrink-0\" />\n )}\n <p\n className={cn(\n 'text-sm font-medium',\n isDelivered ? 'text-status-success-text' : 'text-text-primary'\n )}\n >\n {isDelivered\n ? `Delivered at ${formatDate(order.actualDeliveryTime!)}`\n : order.estimatedDeliveryTime\n ? `Estimated delivery by ${formatDate(order.estimatedDeliveryTime)}`\n : 'Estimated delivery time: TBD'}\n </p>\n </div>\n )}\n </GlassCard>\n\n {/* Live tracking: ETA + stylised route + status timeline */}\n {!isCancelled && (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5\">\n <div className=\"mb-4 flex flex-wrap items-center justify-between gap-2\">\n <h3 className=\"text-base font-semibold text-text-primary\">Order Status</h3>\n {!isDelivered && etaMinutes != null && (\n <span className=\"inline-flex items-center gap-1.5 rounded-full bg-[var(--color-accent-soft)] px-3 py-1 text-sm font-semibold text-accent-primary\">\n <Clock className=\"h-3.5 w-3.5\" />\n Arriving in ~{etaMinutes} min\n </span>\n )}\n </div>\n <StylizedRouteMap\n progress={routeProgress}\n originLabel={order.cartName}\n destinationLabel=\"You\"\n className=\"mb-6 h-44\"\n />\n <Timeline items={timelineItems} />\n </div>\n )}\n\n {/* Order Items & Price Breakdown */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5\">\n <h3 className=\"text-base font-semibold text-text-primary mb-3\">Order Items</h3>\n <div className=\"space-y-2\">\n {order.items.map((item, index) => (\n <div\n key={index}\n className=\"flex justify-between items-start pb-2 border-b border-border-subtle last:border-b-0\"\n >\n <div className=\"flex-1 pr-2\">\n <p className=\"text-sm font-medium text-text-primary\">{item.name}</p>\n {item.customizations && item.customizations.length > 0 && (\n <p className=\"text-xs text-text-secondary\">\n {item.customizations.join(', ')}\n </p>\n )}\n <p className=\"text-xs text-text-secondary\">\n {formatCurrency(item.price, { minimumFractionDigits: 0 })} x {item.quantity}\n </p>\n </div>\n <p className=\"text-sm font-medium text-text-primary\">\n {formatCurrency(item.price * item.quantity, { minimumFractionDigits: 0 })}\n </p>\n </div>\n ))}\n </div>\n\n {/* Price Breakdown */}\n <div className=\"mt-4 pt-4 border-t border-border-subtle space-y-2 text-sm\">\n <div className=\"flex justify-between text-text-secondary\">\n <span>Subtotal</span>\n <span>{formatCurrency(order.subtotal, { minimumFractionDigits: 0 })}</span>\n </div>\n <div className=\"flex justify-between text-text-secondary\">\n <span>Delivery Fee</span>\n <span>\n {order.deliveryFee === 0\n ? 'FREE'\n : formatCurrency(order.deliveryFee, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <div className=\"flex justify-between text-text-secondary\">\n <span>Tax</span>\n <span>{formatCurrency(order.taxes, { minimumFractionDigits: 0 })}</span>\n </div>\n {order.discount && order.discount > 0 && (\n <div className=\"flex justify-between text-status-success-text\">\n <span>Discount</span>\n <span>-{formatCurrency(order.discount, { minimumFractionDigits: 0 })}</span>\n </div>\n )}\n <div className=\"flex justify-between font-semibold pt-2 border-t border-border-subtle text-text-primary\">\n <span>Total</span>\n <span>{formatCurrency(order.total, { minimumFractionDigits: 0 })}</span>\n </div>\n </div>\n </div>\n </div>\n\n {/* Right: Sidebar */}\n <div className=\"lg:col-span-1 space-y-6\">\n {/* Delivery Details */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5\">\n <h3 className=\"text-base font-semibold text-text-primary mb-3\">Delivery Details</h3>\n <div className=\"space-y-3\">\n <div className=\"flex items-start gap-2\">\n <MapPin className=\"mt-0.5 h-4 w-4 shrink-0 text-text-secondary\" />\n <div>\n <p className=\"text-xs text-text-secondary\">Delivery Address</p>\n <p className=\"text-sm font-medium text-text-primary\">\n {order.deliveryAddress.street}\n </p>\n <p className=\"text-sm text-text-secondary\">{order.deliveryAddress.area}</p>\n <p className=\"text-sm text-text-secondary\">\n {order.deliveryAddress.city}, {order.deliveryAddress.pincode}\n </p>\n {order.deliveryAddress.landmark && (\n <p className=\"text-xs text-text-secondary mt-0.5\">\n Landmark: {order.deliveryAddress.landmark}\n </p>\n )}\n </div>\n </div>\n\n {/* Customer Notes */}\n {order.customerNotes && (\n <div>\n <p className=\"text-xs text-text-secondary\">Customer Notes</p>\n <p className=\"text-sm text-text-primary\">{order.customerNotes}</p>\n </div>\n )}\n\n {/* Payment */}\n <div>\n <p className=\"text-xs text-text-secondary\">Payment Method</p>\n <p className=\"text-sm font-medium text-text-primary capitalize\">\n {order.paymentMethod}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {order.paymentStatus === 'completed' ? 'Paid' : 'Payment Pending'}\n </p>\n </div>\n </div>\n </div>\n\n {/* Delivery Partner */}\n {order.assignedWorker && (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5\">\n <h3 className=\"text-base font-semibold text-text-primary mb-3\">Delivery Partner</h3>\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-bg-sunken text-text-secondary\">\n <span className=\"text-sm font-semibold\">\n {order.assignedWorker.name.charAt(0)}\n </span>\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-text-primary\">\n {order.assignedWorker.name}\n </p>\n <div className=\"flex items-center gap-1.5 mt-0.5\">\n <Star className=\"h-3 w-3 fill-status-warning-text text-status-warning-text\" />\n <span className=\"text-xs text-text-secondary\">\n {order.assignedWorker.rating}/5\n </span>\n </div>\n </div>\n <a\n href={`tel:${order.assignedWorker.phone}`}\n className=\"flex h-9 w-9 items-center justify-center rounded-full bg-bg-sunken text-text-secondary hover:bg-accent hover:text-text-primary transition-colors\"\n >\n <Phone className=\"h-4 w-4\" />\n </a>\n </div>\n <div className=\"grid grid-cols-2 gap-2\">\n <a\n href={`tel:${order.assignedWorker.phone}`}\n className=\"flex items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-3 py-2.5 text-sm font-semibold text-action-primary-text hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Phone className=\"h-4 w-4\" />\n Call\n </a>\n <button\n type=\"button\"\n disabled\n title=\"In-app chat is coming soon\"\n className=\"flex items-center justify-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-sm font-medium text-text-secondary cursor-not-allowed opacity-70\"\n >\n <MessageCircle className=\"h-4 w-4\" />\n Chat\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Need Help */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5\">\n <h3 className=\"text-base font-semibold text-text-primary mb-3\">Need Help?</h3>\n <div className=\"space-y-2\">\n <a\n href=\"mailto:support@kadaikodi.com\"\n className=\"w-full flex items-center justify-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <MessageCircle className=\"h-4 w-4\" />\n Email Support\n </a>\n <button\n type=\"button\"\n onClick={() => (window.location.href = 'tel:7012270561')}\n className=\"w-full flex items-center justify-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Phone className=\"h-4 w-4\" />\n Call Support\n </button>\n {isDelivered && !order.rating && (\n <button\n type=\"button\"\n onClick={() => setShowRateModal(true)}\n className=\"w-full flex items-center justify-center gap-2 rounded-lg bg-foreground px-3 py-2.5 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n <Star className=\"h-4 w-4\" />\n Rate Order\n </button>\n )}\n </div>\n </div>\n </div>\n </div>\n\n {/* Status message */}\n {statusMessage && (\n <div className=\"fixed bottom-4 left-1/2 z-50 -translate-x-1/2 rounded-lg border border-status-success-text/30 bg-status-success-bg-subtle px-4 py-3 shadow-lg flex items-center gap-2\">\n <CheckCircle2 className=\"h-4 w-4 text-status-success-text shrink-0\" />\n <p className=\"text-sm text-status-success-text\">{statusMessage}</p>\n </div>\n )}\n\n {/* Rate Order Modal */}\n {showRateModal && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\">\n <div className=\"w-full max-w-md rounded-lg border border-border-subtle bg-bg-surface shadow-lg\">\n <div className=\"p-5\">\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-lg font-semibold text-text-primary\">Rate your order</h3>\n <button\n type=\"button\"\n onClick={() => setShowRateModal(false)}\n className=\"rounded-md p-2 text-text-secondary hover:bg-accent hover:text-text-primary transition-colors\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n\n <div className=\"mb-4\">\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n Your rating\n </label>\n <div className=\"flex items-center gap-1\">\n {[1, 2, 3, 4, 5].map((star) => (\n <button\n key={star}\n type=\"button\"\n onClick={() => setRating(star)}\n className=\"p-0.5\"\n aria-label={`${star} star${star > 1 ? 's' : ''}`}\n >\n <Star\n className={cn(\n 'h-7 w-7',\n star <= rating\n ? 'fill-status-warning-text text-status-warning-text'\n : 'fill-none text-text-secondary/40'\n )}\n />\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"mb-5\">\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Review <span className=\"text-text-secondary font-normal\">(optional)</span>\n </label>\n <textarea\n rows={4}\n value={reviewText}\n onChange={(e) => setReviewText(e.target.value)}\n placeholder=\"How was your order?\"\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none\"\n />\n </div>\n\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={handleSubmitRating}\n disabled={createReview.isPending}\n className={cn(\n 'flex-1 inline-flex items-center justify-center gap-2 rounded-lg bg-foreground px-4 py-2.5 text-sm font-medium text-background transition-opacity',\n createReview.isPending ? 'opacity-60 cursor-not-allowed' : 'hover:opacity-90'\n )}\n >\n {createReview.isPending && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n Submit Rating\n </button>\n <button\n type=\"button\"\n onClick={() => setShowRateModal(false)}\n className=\"rounded-lg border border-border-subtle px-4 py-2.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Cancel\n </button>\n </div>\n </div>\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"OrderTrackingPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/customer/OrderTrackingPage.tsx"],"sourcesContent":["/**\n * Order Tracking Page\n * @module kadaikodi/pages/customer\n *\n * Real-time order tracking with status timeline, delivery partner info,\n * price breakdown, Need Help sidebar, and rate order functionality.\n */\n\nimport { useEffect, useRef, useState } from 'react';\nimport { useParams } from 'react-router';\nimport {\n ArrowLeft,\n CheckCircle2,\n Clock,\n MapPin,\n Phone,\n Star,\n ShoppingBag,\n WifiOff,\n XCircle,\n MessageCircle,\n Loader2,\n X,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Timeline, type TimelineItem } from '../../components/viz';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport { useOrder, useCreateReview } from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatDate } from '../../utils/formatters';\nimport { notifyOrderStatusChange } from '../../utils/orderStatusNotifier';\nimport { useKadaikodiStore } from '../../store';\nimport type { OrderStatus } from '../../types';\nimport { StylizedRouteMap } from './shared';\n\nconst statusOrder: OrderStatus[] = [\n 'pending',\n 'confirmed',\n 'preparing',\n 'ready',\n 'out_for_delivery',\n 'delivered',\n];\n\nconst statusLabels: Record<string, string> = {\n pending: 'Order Placed',\n confirmed: 'Confirmed',\n preparing: 'Preparing',\n ready: 'Ready',\n out_for_delivery: 'Out for Delivery',\n delivered: 'Delivered',\n};\n\nconst statusDescriptions: Record<string, string> = {\n pending: 'Your order has been received',\n confirmed: 'Cart has accepted your order',\n preparing: 'Your food is being prepared',\n ready: 'Order is ready for pickup/delivery',\n out_for_delivery: 'Your order is on the way',\n delivered: 'Order has been delivered',\n};\n\nexport function OrderTrackingPage() {\n const { orderId } = useParams<{ orderId: string }>();\n const { navigateTo, currentUser } = useKadaikodi();\n const { data: order, isLoading, isError } = useOrder(orderId, { pollWhileActive: true });\n const createReview = useCreateReview();\n const [showRateModal, setShowRateModal] = useState(false);\n const [rating, setRating] = useState(5);\n const [reviewText, setReviewText] = useState('');\n const [statusMessage, setStatusMessage] = useState<string | null>(null);\n\n const showStatus = (msg: string) => {\n setStatusMessage(msg);\n setTimeout(() => setStatusMessage(null), 3000);\n };\n\n // Offline-cached order status (BOFF-4301). `cachedOrder` is what OS-level\n // notifications and the offline fallback view below both key off; it\n // outlives an app kill/reload because it's persisted, unlike the\n // in-memory react-query cache `order` comes from.\n const cachedOrder = useKadaikodiStore((s) =>\n orderId ? s.lastKnownOrderStatus[orderId] : undefined\n );\n const setLastKnownOrderStatus = useKadaikodiStore((s) => s.setLastKnownOrderStatus);\n const hasNotifiedRef = useRef<Set<string>>(new Set());\n\n useEffect(() => {\n if (!order || !orderId) return;\n const previousStatus = cachedOrder?.status;\n const changed = previousStatus !== undefined && previousStatus !== order.status;\n // De-dupe within a single mount: React Query's polling can re-fire the\n // same status more than once before the store write is observed.\n const changeKey = `${orderId}:${order.status}`;\n if (changed && !hasNotifiedRef.current.has(changeKey)) {\n hasNotifiedRef.current.add(changeKey);\n const label = statusLabels[order.status] ?? order.status;\n showStatus(`Order status updated: ${label}`);\n void notifyOrderStatusChange({\n orderId,\n title: `${order.cartName} — ${label}`,\n body: statusDescriptions[order.status] ?? `Your order is now ${label.toLowerCase()}.`,\n });\n }\n setLastKnownOrderStatus(orderId, {\n status: order.status,\n orderNumber: order.id,\n cartName: order.cartName,\n total: order.total,\n cachedAt: new Date().toISOString(),\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only order.status changes should re-run this; cachedOrder/setLastKnownOrderStatus would otherwise loop against the write this effect itself performs.\n }, [order?.status, order?.id, orderId]);\n\n const handleSubmitRating = () => {\n if (!order || !currentUser?.id) {\n showStatus('Please sign in to rate this order.');\n return;\n }\n createReview.mutate(\n {\n providerId: order.cartId,\n orderId: order.id,\n customerId: currentUser.id,\n rating,\n review: reviewText.trim() || undefined,\n },\n {\n onSuccess: () => {\n setShowRateModal(false);\n setReviewText('');\n showStatus('Thanks! Your rating has been submitted.');\n },\n onError: () => showStatus('Could not submit your rating. Please try again.'),\n }\n );\n };\n\n if (isLoading) {\n return (\n <PageLayout title=\"Track Order\">\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <div className=\"animate-spin rounded-full h-12 w-12 border-b-2 border-foreground mx-auto mb-4\" />\n <p className=\"text-sm text-text-secondary\">Loading order details...</p>\n </div>\n </PageLayout>\n );\n }\n\n if (!order) {\n // BOFF-4301: the live fetch failed (most likely offline) but a\n // previous session cached this order's last-known status on-device —\n // show that instead of a bare \"not found\", which would be misleading\n // (the order does exist; we just can't reach the network right now).\n if (isError && cachedOrder) {\n return (\n <PageLayout title=\"Track Order\">\n <div className=\"mb-4 flex items-start gap-3 rounded-lg border border-status-warning-text/30 bg-status-warning-bg-subtle p-4\">\n <WifiOff className=\"h-5 w-5 text-status-warning-text mt-0.5 shrink-0\" />\n <div>\n <p className=\"text-sm font-medium text-status-warning-text\">\n You&apos;re offline — showing the last known status\n </p>\n <p className=\"text-xs text-status-warning-text/80 mt-0.5\">\n Cached {formatDate(cachedOrder.cachedAt)}. Reconnect to see live updates.\n </p>\n </div>\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5\">\n <div className=\"flex items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n Order #{cachedOrder.orderNumber}\n </h2>\n <p className=\"text-sm text-text-secondary\">{cachedOrder.cartName}</p>\n </div>\n <StatusBadge status={cachedOrder.status as OrderStatus} />\n </div>\n <p className=\"mt-3 text-sm text-text-primary\">\n Last known total: {formatCurrency(cachedOrder.total, { minimumFractionDigits: 0 })}\n </p>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title=\"Order Not Found\">\n <EmptyState\n icon={<ShoppingBag className=\"h-12 w-12\" />}\n title=\"Order not found\"\n description={`The order you're looking for doesn't exist.`}\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/orders')}\n className=\"rounded-lg bg-foreground px-4 py-2 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n View All Orders\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n const currentStatusIndex = statusOrder.indexOf(order.status);\n const isCancelled = order.status === 'cancelled';\n const isDelivered = order.status === 'delivered';\n\n // Honest ETA: only derived when the backend supplies a real estimated time.\n const etaMinutes = order.estimatedDeliveryTime\n ? Math.max(\n 0,\n Math.round((new Date(order.estimatedDeliveryTime).getTime() - Date.now()) / 60000)\n )\n : null;\n\n // Route progress along the illustrative map (0..1) from the live status index.\n const routeProgress = currentStatusIndex < 0 ? 0 : currentStatusIndex / (statusOrder.length - 1);\n\n const timelineItems: TimelineItem[] = statusOrder.map((stepStatus, i) => {\n const tone = i < currentStatusIndex ? 'success' : i === currentStatusIndex ? 'accent' : 'muted';\n const isCurrent = i === currentStatusIndex;\n return {\n id: stepStatus,\n title: statusLabels[stepStatus],\n tone,\n meta: (\n <span className={cn(isCurrent ? 'text-text-primary' : undefined)}>\n {statusDescriptions[stepStatus]}\n </span>\n ),\n };\n });\n\n return (\n <PageLayout\n title={\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/orders')}\n className=\"rounded-md p-1 text-text-secondary hover:bg-accent hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"h-5 w-5\" />\n </button>\n <span>Track Order</span>\n </div>\n }\n actions={<StatusBadge status={order.status} />}\n >\n <PagePurpose className=\"mb-6\">\n Follow your order in real time — see exactly where it is from kitchen to doorstep, who's\n delivering it, and reach out for help if anything looks off. The live status updates as your\n order moves through each stage.\n </PagePurpose>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Left: Order Details & Timeline */}\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Order Header — the one emphasis zone (live status) */}\n <GlassCard treatment=\"glass\" glow className=\"p-5\">\n <div className=\"flex flex-col sm:flex-row sm:justify-between sm:items-start gap-3\">\n <div className=\"flex-1\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Order #{order.id}</h2>\n <p className=\"text-sm text-text-secondary\">{order.cartName}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">{formatDate(order.orderDate)}</p>\n </div>\n <div className=\"text-left sm:text-right\">\n <p className=\"text-xl font-bold text-text-primary\">\n {formatCurrency(order.total, { minimumFractionDigits: 0 })}\n </p>\n <p className=\"text-xs text-text-secondary uppercase\">{order.paymentMethod}</p>\n </div>\n </div>\n\n {/* Status Banner */}\n {isCancelled ? (\n <div className=\"mt-4 flex items-start gap-3 rounded-lg bg-status-error-bg/10 p-4 border border-status-error-border/20\">\n <XCircle className=\"h-5 w-5 text-status-error-text mt-0.5 shrink-0\" />\n <div>\n <p className=\"font-medium text-status-error-text\">Order Cancelled</p>\n {order.cancellationReason && (\n <p className=\"text-sm text-status-error-text/80 mt-0.5\">\n {order.cancellationReason}\n </p>\n )}\n </div>\n </div>\n ) : (\n <div\n className={cn(\n 'mt-4 flex items-start gap-3 rounded-lg p-4 border',\n isDelivered\n ? 'bg-status-success-bg-subtle border-status-success-text/20'\n : 'bg-[var(--color-accent-soft)] border-border-focus/20'\n )}\n >\n {isDelivered ? (\n <CheckCircle2 className=\"h-5 w-5 text-status-success-text mt-0.5 shrink-0\" />\n ) : (\n <Clock className=\"h-5 w-5 text-text-primary mt-0.5 shrink-0\" />\n )}\n <p\n className={cn(\n 'text-sm font-medium',\n isDelivered ? 'text-status-success-text' : 'text-text-primary'\n )}\n >\n {isDelivered\n ? `Delivered at ${formatDate(order.actualDeliveryTime!)}`\n : order.estimatedDeliveryTime\n ? `Estimated delivery by ${formatDate(order.estimatedDeliveryTime)}`\n : 'Estimated delivery time: TBD'}\n </p>\n </div>\n )}\n </GlassCard>\n\n {/* Live tracking: ETA + stylised route + status timeline */}\n {!isCancelled && (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5\">\n <div className=\"mb-4 flex flex-wrap items-center justify-between gap-2\">\n <h3 className=\"text-base font-semibold text-text-primary\">Order Status</h3>\n {!isDelivered && etaMinutes != null && (\n <span className=\"inline-flex items-center gap-1.5 rounded-full bg-[var(--color-accent-soft)] px-3 py-1 text-sm font-semibold text-accent-primary\">\n <Clock className=\"h-3.5 w-3.5\" />\n Arriving in ~{etaMinutes} min\n </span>\n )}\n </div>\n <StylizedRouteMap\n progress={routeProgress}\n originLabel={order.cartName}\n destinationLabel=\"You\"\n className=\"mb-6 h-44\"\n />\n <Timeline items={timelineItems} />\n </div>\n )}\n\n {/* Order Items & Price Breakdown */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5\">\n <h3 className=\"text-base font-semibold text-text-primary mb-3\">Order Items</h3>\n <div className=\"space-y-2\">\n {order.items.map((item, index) => (\n <div\n key={index}\n className=\"flex justify-between items-start pb-2 border-b border-border-subtle last:border-b-0\"\n >\n <div className=\"flex-1 pr-2\">\n <p className=\"text-sm font-medium text-text-primary\">{item.name}</p>\n {item.customizations && item.customizations.length > 0 && (\n <p className=\"text-xs text-text-secondary\">\n {item.customizations.join(', ')}\n </p>\n )}\n <p className=\"text-xs text-text-secondary\">\n {formatCurrency(item.price, { minimumFractionDigits: 0 })} x {item.quantity}\n </p>\n </div>\n <p className=\"text-sm font-medium text-text-primary\">\n {formatCurrency(item.price * item.quantity, { minimumFractionDigits: 0 })}\n </p>\n </div>\n ))}\n </div>\n\n {/* Price Breakdown */}\n <div className=\"mt-4 pt-4 border-t border-border-subtle space-y-2 text-sm\">\n <div className=\"flex justify-between text-text-secondary\">\n <span>Subtotal</span>\n <span>{formatCurrency(order.subtotal, { minimumFractionDigits: 0 })}</span>\n </div>\n <div className=\"flex justify-between text-text-secondary\">\n <span>Delivery Fee</span>\n <span>\n {order.deliveryFee === 0\n ? 'FREE'\n : formatCurrency(order.deliveryFee, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <div className=\"flex justify-between text-text-secondary\">\n <span>Tax</span>\n <span>{formatCurrency(order.taxes, { minimumFractionDigits: 0 })}</span>\n </div>\n {order.discount && order.discount > 0 && (\n <div className=\"flex justify-between text-status-success-text\">\n <span>Discount</span>\n <span>-{formatCurrency(order.discount, { minimumFractionDigits: 0 })}</span>\n </div>\n )}\n <div className=\"flex justify-between font-semibold pt-2 border-t border-border-subtle text-text-primary\">\n <span>Total</span>\n <span>{formatCurrency(order.total, { minimumFractionDigits: 0 })}</span>\n </div>\n </div>\n </div>\n </div>\n\n {/* Right: Sidebar */}\n <div className=\"lg:col-span-1 space-y-6\">\n {/* Delivery Details */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5\">\n <h3 className=\"text-base font-semibold text-text-primary mb-3\">Delivery Details</h3>\n <div className=\"space-y-3\">\n <div className=\"flex items-start gap-2\">\n <MapPin className=\"mt-0.5 h-4 w-4 shrink-0 text-text-secondary\" />\n <div>\n <p className=\"text-xs text-text-secondary\">Delivery Address</p>\n <p className=\"text-sm font-medium text-text-primary\">\n {order.deliveryAddress.street}\n </p>\n <p className=\"text-sm text-text-secondary\">{order.deliveryAddress.area}</p>\n <p className=\"text-sm text-text-secondary\">\n {order.deliveryAddress.city}, {order.deliveryAddress.pincode}\n </p>\n {order.deliveryAddress.landmark && (\n <p className=\"text-xs text-text-secondary mt-0.5\">\n Landmark: {order.deliveryAddress.landmark}\n </p>\n )}\n </div>\n </div>\n\n {/* Customer Notes */}\n {order.customerNotes && (\n <div>\n <p className=\"text-xs text-text-secondary\">Customer Notes</p>\n <p className=\"text-sm text-text-primary\">{order.customerNotes}</p>\n </div>\n )}\n\n {/* Payment */}\n <div>\n <p className=\"text-xs text-text-secondary\">Payment Method</p>\n <p className=\"text-sm font-medium text-text-primary capitalize\">\n {order.paymentMethod}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {order.paymentStatus === 'completed' ? 'Paid' : 'Payment Pending'}\n </p>\n </div>\n </div>\n </div>\n\n {/* Delivery Partner */}\n {order.assignedWorker && (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5\">\n <h3 className=\"text-base font-semibold text-text-primary mb-3\">Delivery Partner</h3>\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-bg-sunken text-text-secondary\">\n <span className=\"text-sm font-semibold\">\n {order.assignedWorker.name.charAt(0)}\n </span>\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-text-primary\">\n {order.assignedWorker.name}\n </p>\n <div className=\"flex items-center gap-1.5 mt-0.5\">\n <Star className=\"h-3 w-3 fill-status-warning-text text-status-warning-text\" />\n <span className=\"text-xs text-text-secondary\">\n {order.assignedWorker.rating}/5\n </span>\n </div>\n </div>\n <a\n href={`tel:${order.assignedWorker.phone}`}\n className=\"flex h-9 w-9 items-center justify-center rounded-full bg-bg-sunken text-text-secondary hover:bg-accent hover:text-text-primary transition-colors\"\n >\n <Phone className=\"h-4 w-4\" />\n </a>\n </div>\n <div className=\"grid grid-cols-2 gap-2\">\n <a\n href={`tel:${order.assignedWorker.phone}`}\n className=\"flex items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-3 py-2.5 text-sm font-semibold text-action-primary-text hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Phone className=\"h-4 w-4\" />\n Call\n </a>\n <button\n type=\"button\"\n disabled\n title=\"In-app chat is coming soon\"\n className=\"flex items-center justify-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-sm font-medium text-text-secondary cursor-not-allowed opacity-70\"\n >\n <MessageCircle className=\"h-4 w-4\" />\n Chat\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Need Help */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5\">\n <h3 className=\"text-base font-semibold text-text-primary mb-3\">Need Help?</h3>\n <div className=\"space-y-2\">\n <a\n href=\"mailto:support@kadaikodi.com\"\n className=\"w-full flex items-center justify-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <MessageCircle className=\"h-4 w-4\" />\n Email Support\n </a>\n <button\n type=\"button\"\n onClick={() => (window.location.href = 'tel:7012270561')}\n className=\"w-full flex items-center justify-center gap-2 rounded-lg border border-border-subtle px-3 py-2.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <Phone className=\"h-4 w-4\" />\n Call Support\n </button>\n {isDelivered && !order.rating && (\n <button\n type=\"button\"\n onClick={() => setShowRateModal(true)}\n className=\"w-full flex items-center justify-center gap-2 rounded-lg bg-foreground px-3 py-2.5 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n <Star className=\"h-4 w-4\" />\n Rate Order\n </button>\n )}\n </div>\n </div>\n </div>\n </div>\n\n {/* Status message */}\n {statusMessage && (\n <div className=\"fixed bottom-4 left-1/2 z-50 -translate-x-1/2 rounded-lg border border-status-success-text/30 bg-status-success-bg-subtle px-4 py-3 shadow-lg flex items-center gap-2\">\n <CheckCircle2 className=\"h-4 w-4 text-status-success-text shrink-0\" />\n <p className=\"text-sm text-status-success-text\">{statusMessage}</p>\n </div>\n )}\n\n {/* Rate Order Modal */}\n {showRateModal && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\">\n <div className=\"w-full max-w-md rounded-lg border border-border-subtle bg-bg-surface shadow-lg\">\n <div className=\"p-5\">\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-lg font-semibold text-text-primary\">Rate your order</h3>\n <button\n type=\"button\"\n onClick={() => setShowRateModal(false)}\n className=\"rounded-md p-2 text-text-secondary hover:bg-accent hover:text-text-primary transition-colors\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n\n <div className=\"mb-4\">\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n Your rating\n </label>\n <div className=\"flex items-center gap-1\">\n {[1, 2, 3, 4, 5].map((star) => (\n <button\n key={star}\n type=\"button\"\n onClick={() => setRating(star)}\n className=\"p-0.5\"\n aria-label={`${star} star${star > 1 ? 's' : ''}`}\n >\n <Star\n className={cn(\n 'h-7 w-7',\n star <= rating\n ? 'fill-status-warning-text text-status-warning-text'\n : 'fill-none text-text-secondary/40'\n )}\n />\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"mb-5\">\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Review <span className=\"text-text-secondary font-normal\">(optional)</span>\n </label>\n <textarea\n rows={4}\n value={reviewText}\n onChange={(e) => setReviewText(e.target.value)}\n placeholder=\"How was your order?\"\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none\"\n />\n </div>\n\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={handleSubmitRating}\n disabled={createReview.isPending}\n className={cn(\n 'flex-1 inline-flex items-center justify-center gap-2 rounded-lg bg-foreground px-4 py-2.5 text-sm font-medium text-background transition-opacity',\n createReview.isPending ? 'opacity-60 cursor-not-allowed' : 'hover:opacity-90'\n )}\n >\n {createReview.isPending && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n Submit Rating\n </button>\n <button\n type=\"button\"\n onClick={() => setShowRateModal(false)}\n className=\"rounded-lg border border-border-subtle px-4 py-2.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Cancel\n </button>\n </div>\n </div>\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -11,7 +11,7 @@ import "../../components/viz/index.js";
11
11
  import { InvestmentMarketplaceComingSoon as d, useInvestmentMarketplaceEnabled as f } from "../../components/InvestmentMarketplaceGate.js";
12
12
  import { useCallback as p, useMemo as m, useState as h } from "react";
13
13
  import { ArrowLeft as ne, CheckCircle2 as re, IndianRupee as g, Lock as ie, MessageSquare as _, Receipt as v, Shield as y, Star as ae, Tag as oe, Target as se, TrendingUp as b, Users as x } from "lucide-react";
14
- import { useParams as S } from "react-router-dom";
14
+ import { useParams as S } from "react-router";
15
15
  import { jsx as C, jsxs as w } from "react/jsx-runtime";
16
16
  import { EmphasisPanel as T, GlassCard as E, PagePurpose as ce } from "@burdenoff/fe-libs/ui";
17
17
  //#region src/kadaikodi/pages/investor/InvestmentDetailsPage.tsx
@@ -1 +1 @@
1
- {"version":3,"file":"InvestmentDetailsPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/investor/InvestmentDetailsPage.tsx"],"sourcesContent":["/**\n * Investment Details Page\n * @module kadaikodi/pages/investor\n *\n * Serves both /investor/opportunity/:id and /investor/investments/:id. Resolves\n * the opportunity (and the investor's holding, if any) from the live backend by\n * route id. Business metrics are read from the real service-provider record\n * (useProvider by cartId) — never fabricated. The invest panel is wired to the\n * live useInvest mutation; the projected-returns curve is a transparent forecast\n * computed from the stated expected return, not invented performance data.\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n TrendingUp,\n Shield,\n Users,\n IndianRupee,\n Star,\n MessageSquare,\n Receipt,\n Tag,\n CheckCircle2,\n Lock,\n Target,\n} from 'lucide-react';\nimport { EmphasisPanel, GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport {\n InvestmentMarketplaceComingSoon,\n useInvestmentMarketplaceEnabled,\n} from '../../components/InvestmentMarketplaceGate';\nimport { AreaChart, ProgressRing, StatCard } from '../../components/viz';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport {\n useInvestmentOpportunities,\n useInvestments,\n useInvest,\n useProvider,\n} from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatDate } from '../../utils/formatters';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getRiskConfig(risk: string): { label: string; color: string; badge: string } {\n switch (risk) {\n case 'low':\n return {\n label: 'Low risk',\n color: 'text-status-success-text',\n badge: 'border-status-success-border bg-status-success-bg-subtle text-status-success-text',\n };\n case 'medium':\n return {\n label: 'Medium risk',\n color: 'text-status-warning-text',\n badge: 'border-status-warning-border bg-status-warning-bg-subtle text-status-warning-text',\n };\n case 'high':\n return {\n label: 'High risk',\n color: 'text-status-error-text',\n badge: 'border-status-error-border bg-status-error-bg-subtle text-status-error-text',\n };\n default:\n return { label: risk, color: 'text-text-secondary', badge: 'border-border-default' };\n }\n}\n\n/** Compact rupee formatter for chart axes / tooltips. */\nfunction formatRupeeCompact(value: number): string {\n return formatCurrency(value, { minimumFractionDigits: 0, notation: 'compact' });\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function InvestmentDetailsPage() {\n const { navigateTo, currentUser } = useKadaikodi();\n const { id } = useParams<{ id: string }>();\n\n const { data: opportunities = [], isLoading: opportunitiesLoading } =\n useInvestmentOpportunities();\n const { data: investments = [], isLoading: investmentsLoading } = useInvestments(\n currentUser?.id || ''\n );\n\n const isLoading = opportunitiesLoading || investmentsLoading;\n\n // The route id may be an investment id or an opportunity id. Resolve the\n // holding first (if it belongs to this investor), then the opportunity.\n const investment = useMemo(() => investments.find((inv) => inv.id === id), [investments, id]);\n const opportunity = useMemo(\n () =>\n opportunities.find((opp) => opp.id === id || opp.id === investment?.opportunityId) ?? null,\n [opportunities, id, investment]\n );\n\n // Real business metrics come from the underlying service-provider record.\n const { data: provider } = useProvider(opportunity?.cartId);\n\n // Invest panel state (wired to the live mutation) ------------------------\n const invest = useInvest();\n const investmentMarketplaceEnabled = useInvestmentMarketplaceEnabled();\n const [amount, setAmount] = useState('');\n const [investStatus, setInvestStatus] = useState<'idle' | 'success' | 'error'>('idle');\n\n const minInvestment = opportunity?.minimumInvestment ?? 0;\n const remaining = opportunity\n ? Math.max(0, opportunity.targetAmount - opportunity.raisedAmount)\n : 0;\n const maxInvestment = Math.max(minInvestment, remaining);\n const parsedAmount = Number.parseInt(amount, 10);\n const amountValid =\n !Number.isNaN(parsedAmount) && parsedAmount >= minInvestment && parsedAmount <= maxInvestment;\n\n const handleInvest = useCallback(() => {\n if (!opportunity || !amountValid) {\n setInvestStatus('error');\n return;\n }\n invest.mutate(\n { amount: parsedAmount, investorId: currentUser?.id ?? '', opportunityId: opportunity.id },\n {\n onSuccess: () => {\n setInvestStatus('success');\n window.setTimeout(() => navigateTo('/investor/portfolio'), 1400);\n },\n onError: () => setInvestStatus('error'),\n }\n );\n }, [opportunity, amountValid, invest, parsedAmount, currentUser?.id, navigateTo]);\n\n // Projected-returns forecast: a transparent linear glide from the amount put\n // in today to amount × (1 + expected return) at the end of the lock-in. It is\n // a computed projection from the stated rate, clearly labelled — not data.\n const projection = useMemo(() => {\n if (!opportunity) return [];\n const base = amountValid ? parsedAmount : minInvestment || opportunity.targetAmount / 10;\n const finalValue = base * (1 + opportunity.expectedReturns / 100);\n const months = Math.min(Math.max(opportunity.investmentPeriod, 3), 12);\n const steps = 6;\n return Array.from({ length: steps + 1 }, (_, i) => {\n const monthLabel =\n i === 0 ? 'Now' : i === steps ? `${months}mo` : `M${Math.round((months * i) / steps)}`;\n return { label: monthLabel, value: base + (finalValue - base) * (i / steps) };\n });\n }, [opportunity, amountValid, parsedAmount, minInvestment]);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Investment Details\" description=\"Loading...\">\n <div className=\"space-y-4\">\n <div className=\"h-28 animate-pulse rounded-[var(--radius-card)] bg-bg-sunken\" />\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <div className=\"h-96 animate-pulse rounded-[var(--radius-card)] bg-bg-sunken lg:col-span-2\" />\n <div className=\"h-96 animate-pulse rounded-[var(--radius-card)] bg-bg-sunken\" />\n </div>\n </div>\n </PageLayout>\n );\n }\n\n if (!opportunity && !investment) {\n return (\n <PageLayout title=\"Investment Not Found\">\n <EmptyState\n illustration=\"empty-generic\"\n title=\"Investment not found\"\n description=\"We couldn't find this investment. It may have been closed or the link is out of date.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/portfolio')}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Back to Portfolio\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n const cartName = opportunity?.cartName ?? investment?.cartName ?? 'Investment';\n const risk = opportunity ? getRiskConfig(opportunity.riskLevel) : null;\n const fundingPct =\n opportunity && opportunity.targetAmount > 0\n ? Math.min((opportunity.raisedAmount / opportunity.targetAmount) * 100, 100)\n : 0;\n const daysLeft = opportunity?.expiresAt\n ? Math.max(0, Math.ceil((new Date(opportunity.expiresAt).getTime() - Date.now()) / 86400000))\n : null;\n\n const holdingReturns = investment ? investment.currentValue - investment.investedAmount : 0;\n const holdingReturnsPct =\n investment && investment.investedAmount > 0\n ? (holdingReturns / investment.investedAmount) * 100\n : 0;\n\n const canInvest = Boolean(opportunity) && opportunity?.status === 'active';\n\n return (\n <PageLayout\n title={cartName}\n description=\"Investment details & performance\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/portfolio')}\n className=\"flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">Back to Portfolio</span>\n <span className=\"sm:hidden\">Back</span>\n </button>\n }\n >\n <PagePurpose className=\"mb-6\">\n A deep dive into this investment. Review the business behind it, funding progress, expected\n returns and terms on offer, and — if you already hold a stake — exactly what you&apos;ve put\n in and what it&apos;s worth today.\n </PagePurpose>\n\n {/* Existing holding summary — the one emphasis zone when you own a stake */}\n {investment && (\n <EmphasisPanel>\n <h2 className=\"mb-4 text-base font-semibold text-text-primary\">Your Position</h2>\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n <StatCard\n label=\"Your Investment\"\n value={formatCurrency(investment.investedAmount, { minimumFractionDigits: 0 })}\n icon={<IndianRupee className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Current Value\"\n value={formatCurrency(investment.currentValue, { minimumFractionDigits: 0 })}\n icon={<TrendingUp className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Returns\"\n value={`${holdingReturnsPct >= 0 ? '+' : ''}${holdingReturnsPct.toFixed(1)}%`}\n delta={Number(holdingReturnsPct.toFixed(1))}\n deltaLabel=\"on invested\"\n icon={<TrendingUp className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Realised Returns\"\n value={formatCurrency(investment.returns, { minimumFractionDigits: 0 })}\n icon={<Receipt className=\"h-4 w-4\" />}\n />\n </div>\n </EmphasisPanel>\n )}\n\n <div className=\"mt-6 grid gap-6 lg:grid-cols-3\">\n {/* Left — the business & funding story */}\n <div className=\"space-y-6 lg:col-span-2\">\n {/* Hero header with risk badge */}\n {opportunity && (\n <GlassCard treatment=\"glass\" className=\"p-5 sm:p-6\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"text-sm text-text-secondary\">{opportunity.businessOwner}</p>\n <h2 className=\"mt-0.5 text-xl font-bold tracking-tight text-text-primary sm:text-2xl\">\n {opportunity.cartName}\n </h2>\n </div>\n {risk && (\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-sm font-semibold',\n risk.badge\n )}\n >\n <Shield className=\"h-4 w-4\" />\n {risk.label}\n </span>\n )}\n </div>\n {opportunity.description && (\n <p className=\"mt-4 text-sm leading-relaxed text-text-secondary\">\n {opportunity.description}\n </p>\n )}\n </GlassCard>\n )}\n\n {/* Business Metrics — real provider figures */}\n {provider && (\n <section>\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">Business Metrics</h3>\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4 sm:gap-4\">\n <StatCard\n label=\"Rating\"\n value={provider.rating > 0 ? provider.rating.toFixed(1) : '—'}\n icon={<Star className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Reviews\"\n value={provider.totalRatings.toLocaleString('en-IN')}\n icon={<MessageSquare className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Avg Order\"\n value={\n provider.averageOrderValue\n ? formatCurrency(provider.averageOrderValue, { minimumFractionDigits: 0 })\n : '—'\n }\n icon={<Receipt className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Category\"\n value={\n <span className=\"text-lg font-semibold capitalize\">\n {provider.category || '—'}\n </span>\n }\n icon={<Tag className=\"h-4 w-4\" />}\n />\n </div>\n </section>\n )}\n\n {/* Funding progress with a ProgressRing */}\n {opportunity && (\n <GlassCard treatment=\"plain\" className=\"p-5 sm:p-6\">\n <h3 className=\"mb-4 text-lg font-semibold text-text-primary\">Funding Progress</h3>\n <div className=\"flex flex-col items-center gap-6 sm:flex-row sm:gap-8\">\n <ProgressRing\n value={fundingPct}\n size={140}\n label={`${fundingPct.toFixed(0)}%`}\n caption=\"funded\"\n />\n <div className=\"w-full flex-1 space-y-4\">\n <div>\n <div className=\"flex items-baseline justify-between\">\n <span className=\"text-2xl font-bold text-text-primary\">\n {formatCurrency(opportunity.raisedAmount, { minimumFractionDigits: 0 })}\n </span>\n <span className=\"text-sm text-text-secondary\">\n of {formatCurrency(opportunity.targetAmount, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">raised so far</p>\n </div>\n <div className=\"grid grid-cols-3 gap-3 border-t border-border-subtle pt-4 text-center\">\n <div>\n <p className=\"text-base font-bold text-text-primary sm:text-lg\">\n {opportunity.investors.length}\n </p>\n <p className=\"text-xs text-text-secondary\">Investors</p>\n </div>\n <div>\n <p className=\"text-base font-bold text-text-primary sm:text-lg\">\n {formatCurrency(remaining, {\n minimumFractionDigits: 0,\n notation: 'compact',\n })}\n </p>\n <p className=\"text-xs text-text-secondary\">To Go</p>\n </div>\n <div>\n <p className=\"text-base font-bold text-text-primary sm:text-lg\">\n {daysLeft !== null ? `${daysLeft}` : '—'}\n </p>\n <p className=\"text-xs text-text-secondary\">Days Left</p>\n </div>\n </div>\n </div>\n </div>\n </GlassCard>\n )}\n\n {/* Your holding detail */}\n {investment && (\n <GlassCard treatment=\"plain\" className=\"p-5 sm:p-6\">\n <h3 className=\"mb-4 text-lg font-semibold text-text-primary\">Your Holding</h3>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div>\n <p className=\"text-sm text-text-secondary\">Invested Amount</p>\n <p className=\"font-medium text-text-primary\">\n {formatCurrency(investment.investedAmount, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Current Value</p>\n <p className=\"font-medium text-text-primary\">\n {formatCurrency(investment.currentValue, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Returns Realised</p>\n <p className=\"font-medium text-text-primary\">\n {formatCurrency(investment.returns, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Invested On</p>\n <p className=\"font-medium text-text-primary\">\n {formatDate(investment.investmentDate, { hour: undefined, minute: undefined })}\n </p>\n </div>\n </div>\n </GlassCard>\n )}\n </div>\n\n {/* Right — sticky invest panel */}\n <div className=\"space-y-6\">\n <div className=\"lg:sticky lg:top-6\">\n <GlassCard treatment=\"glass\" glow className=\"p-5 sm:p-6\">\n <h3 className=\"mb-4 text-lg font-semibold text-text-primary\">\n {canInvest ? 'Invest' : 'Investment Terms'}\n </h3>\n\n {/* Terms */}\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <TrendingUp className=\"h-4 w-4\" />\n Expected returns\n </span>\n <span className=\"font-semibold text-status-success-text\">\n {opportunity?.expectedReturns ?? investment?.returnsPercentage}% p.a.\n </span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Lock className=\"h-4 w-4\" />\n Lock-in\n </span>\n <span className=\"font-semibold text-text-primary\">\n {opportunity?.investmentPeriod ?? '—'} months\n </span>\n </div>\n {opportunity && (\n <div className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <IndianRupee className=\"h-4 w-4\" />\n Minimum\n </span>\n <span className=\"font-semibold text-text-primary\">\n {formatCurrency(opportunity.minimumInvestment, { minimumFractionDigits: 0 })}\n </span>\n </div>\n )}\n {opportunity && opportunity.investors.length > 0 && (\n <div className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Users className=\"h-4 w-4\" />\n Investors\n </span>\n <span className=\"font-semibold text-text-primary\">\n {opportunity.investors.length}\n </span>\n </div>\n )}\n </div>\n\n {canInvest && investStatus !== 'success' && !investmentMarketplaceEnabled && (\n <div className=\"mt-5 border-t border-border-subtle pt-5\">\n <InvestmentMarketplaceComingSoon />\n </div>\n )}\n\n {canInvest && investStatus !== 'success' && investmentMarketplaceEnabled && (\n <div className=\"mt-5 space-y-4 border-t border-border-subtle pt-5\">\n <div>\n <label\n htmlFor=\"invest-amount\"\n className=\"mb-1.5 block text-sm font-medium text-text-primary\"\n >\n Amount\n </label>\n <div className=\"relative\">\n <IndianRupee className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n id=\"invest-amount\"\n type=\"number\"\n inputMode=\"numeric\"\n value={amount}\n onChange={(e) => {\n setAmount(e.target.value);\n setInvestStatus('idle');\n }}\n placeholder={String(minInvestment)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2.5 pl-9 pr-3 text-base font-semibold text-text-primary placeholder:font-normal placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <p className=\"mt-1.5 text-xs text-text-secondary\">\n {formatCurrency(minInvestment, { minimumFractionDigits: 0 })} –{' '}\n {formatCurrency(maxInvestment, { minimumFractionDigits: 0 })}\n </p>\n {investStatus === 'error' && (\n <p className=\"mt-1 text-xs text-status-error-text\">\n Enter an amount between{' '}\n {formatCurrency(minInvestment, { minimumFractionDigits: 0 })} and{' '}\n {formatCurrency(maxInvestment, { minimumFractionDigits: 0 })}.\n </p>\n )}\n </div>\n\n {/* Projected returns forecast */}\n <div>\n <p className=\"mb-1 text-sm font-medium text-text-primary\">Projected returns</p>\n <p className=\"mb-2 text-xs text-text-muted\">\n Forecast at {opportunity?.expectedReturns}% over{' '}\n {opportunity?.investmentPeriod} months\n </p>\n <AreaChart\n series={projection}\n height={140}\n valueFormatter={formatRupeeCompact}\n title=\"Projected value over the lock-in period\"\n />\n {amountValid && (\n <div className=\"mt-2 flex items-center justify-between rounded-lg bg-bg-sunken/60 px-3 py-2 text-sm\">\n <span className=\"text-text-secondary\">Projected value</span>\n <span className=\"font-semibold text-status-success-text\">\n {formatCurrency(\n parsedAmount * (1 + (opportunity?.expectedReturns ?? 0) / 100),\n { minimumFractionDigits: 0 }\n )}\n </span>\n </div>\n )}\n </div>\n\n <button\n type=\"button\"\n onClick={handleInvest}\n disabled={!amountValid || invest.isPending}\n className={cn(\n 'flex w-full items-center justify-center gap-2 rounded-lg px-4 py-3 text-sm font-semibold transition-colors',\n amountValid && !invest.isPending\n ? 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover'\n : 'cursor-not-allowed bg-bg-sunken text-text-secondary'\n )}\n >\n {invest.isPending ? 'Processing…' : 'Invest Now'}\n </button>\n </div>\n )}\n\n {investStatus === 'success' && (\n <div className=\"mt-5 border-t border-border-subtle pt-5 text-center\">\n <CheckCircle2 className=\"mx-auto mb-2 h-10 w-10 text-status-success-text\" />\n <p className=\"text-sm font-medium text-text-primary\">Investment successful!</p>\n <p className=\"mt-1 text-xs text-text-secondary\">Redirecting to your portfolio…</p>\n </div>\n )}\n\n {!canInvest && !investment && opportunity && (\n <div className=\"mt-5 flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-sunken/50 p-3 text-sm text-text-secondary\">\n <Target className=\"h-4 w-4 shrink-0\" />\n This opportunity is {opportunity.status}. It&apos;s no longer accepting\n investments.\n </div>\n )}\n </GlassCard>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"InvestmentDetailsPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/investor/InvestmentDetailsPage.tsx"],"sourcesContent":["/**\n * Investment Details Page\n * @module kadaikodi/pages/investor\n *\n * Serves both /investor/opportunity/:id and /investor/investments/:id. Resolves\n * the opportunity (and the investor's holding, if any) from the live backend by\n * route id. Business metrics are read from the real service-provider record\n * (useProvider by cartId) — never fabricated. The invest panel is wired to the\n * live useInvest mutation; the projected-returns curve is a transparent forecast\n * computed from the stated expected return, not invented performance data.\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport { useParams } from 'react-router';\nimport {\n ArrowLeft,\n TrendingUp,\n Shield,\n Users,\n IndianRupee,\n Star,\n MessageSquare,\n Receipt,\n Tag,\n CheckCircle2,\n Lock,\n Target,\n} from 'lucide-react';\nimport { EmphasisPanel, GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport {\n InvestmentMarketplaceComingSoon,\n useInvestmentMarketplaceEnabled,\n} from '../../components/InvestmentMarketplaceGate';\nimport { AreaChart, ProgressRing, StatCard } from '../../components/viz';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport {\n useInvestmentOpportunities,\n useInvestments,\n useInvest,\n useProvider,\n} from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatDate } from '../../utils/formatters';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getRiskConfig(risk: string): { label: string; color: string; badge: string } {\n switch (risk) {\n case 'low':\n return {\n label: 'Low risk',\n color: 'text-status-success-text',\n badge: 'border-status-success-border bg-status-success-bg-subtle text-status-success-text',\n };\n case 'medium':\n return {\n label: 'Medium risk',\n color: 'text-status-warning-text',\n badge: 'border-status-warning-border bg-status-warning-bg-subtle text-status-warning-text',\n };\n case 'high':\n return {\n label: 'High risk',\n color: 'text-status-error-text',\n badge: 'border-status-error-border bg-status-error-bg-subtle text-status-error-text',\n };\n default:\n return { label: risk, color: 'text-text-secondary', badge: 'border-border-default' };\n }\n}\n\n/** Compact rupee formatter for chart axes / tooltips. */\nfunction formatRupeeCompact(value: number): string {\n return formatCurrency(value, { minimumFractionDigits: 0, notation: 'compact' });\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function InvestmentDetailsPage() {\n const { navigateTo, currentUser } = useKadaikodi();\n const { id } = useParams<{ id: string }>();\n\n const { data: opportunities = [], isLoading: opportunitiesLoading } =\n useInvestmentOpportunities();\n const { data: investments = [], isLoading: investmentsLoading } = useInvestments(\n currentUser?.id || ''\n );\n\n const isLoading = opportunitiesLoading || investmentsLoading;\n\n // The route id may be an investment id or an opportunity id. Resolve the\n // holding first (if it belongs to this investor), then the opportunity.\n const investment = useMemo(() => investments.find((inv) => inv.id === id), [investments, id]);\n const opportunity = useMemo(\n () =>\n opportunities.find((opp) => opp.id === id || opp.id === investment?.opportunityId) ?? null,\n [opportunities, id, investment]\n );\n\n // Real business metrics come from the underlying service-provider record.\n const { data: provider } = useProvider(opportunity?.cartId);\n\n // Invest panel state (wired to the live mutation) ------------------------\n const invest = useInvest();\n const investmentMarketplaceEnabled = useInvestmentMarketplaceEnabled();\n const [amount, setAmount] = useState('');\n const [investStatus, setInvestStatus] = useState<'idle' | 'success' | 'error'>('idle');\n\n const minInvestment = opportunity?.minimumInvestment ?? 0;\n const remaining = opportunity\n ? Math.max(0, opportunity.targetAmount - opportunity.raisedAmount)\n : 0;\n const maxInvestment = Math.max(minInvestment, remaining);\n const parsedAmount = Number.parseInt(amount, 10);\n const amountValid =\n !Number.isNaN(parsedAmount) && parsedAmount >= minInvestment && parsedAmount <= maxInvestment;\n\n const handleInvest = useCallback(() => {\n if (!opportunity || !amountValid) {\n setInvestStatus('error');\n return;\n }\n invest.mutate(\n { amount: parsedAmount, investorId: currentUser?.id ?? '', opportunityId: opportunity.id },\n {\n onSuccess: () => {\n setInvestStatus('success');\n window.setTimeout(() => navigateTo('/investor/portfolio'), 1400);\n },\n onError: () => setInvestStatus('error'),\n }\n );\n }, [opportunity, amountValid, invest, parsedAmount, currentUser?.id, navigateTo]);\n\n // Projected-returns forecast: a transparent linear glide from the amount put\n // in today to amount × (1 + expected return) at the end of the lock-in. It is\n // a computed projection from the stated rate, clearly labelled — not data.\n const projection = useMemo(() => {\n if (!opportunity) return [];\n const base = amountValid ? parsedAmount : minInvestment || opportunity.targetAmount / 10;\n const finalValue = base * (1 + opportunity.expectedReturns / 100);\n const months = Math.min(Math.max(opportunity.investmentPeriod, 3), 12);\n const steps = 6;\n return Array.from({ length: steps + 1 }, (_, i) => {\n const monthLabel =\n i === 0 ? 'Now' : i === steps ? `${months}mo` : `M${Math.round((months * i) / steps)}`;\n return { label: monthLabel, value: base + (finalValue - base) * (i / steps) };\n });\n }, [opportunity, amountValid, parsedAmount, minInvestment]);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Investment Details\" description=\"Loading...\">\n <div className=\"space-y-4\">\n <div className=\"h-28 animate-pulse rounded-[var(--radius-card)] bg-bg-sunken\" />\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <div className=\"h-96 animate-pulse rounded-[var(--radius-card)] bg-bg-sunken lg:col-span-2\" />\n <div className=\"h-96 animate-pulse rounded-[var(--radius-card)] bg-bg-sunken\" />\n </div>\n </div>\n </PageLayout>\n );\n }\n\n if (!opportunity && !investment) {\n return (\n <PageLayout title=\"Investment Not Found\">\n <EmptyState\n illustration=\"empty-generic\"\n title=\"Investment not found\"\n description=\"We couldn't find this investment. It may have been closed or the link is out of date.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/portfolio')}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Back to Portfolio\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n const cartName = opportunity?.cartName ?? investment?.cartName ?? 'Investment';\n const risk = opportunity ? getRiskConfig(opportunity.riskLevel) : null;\n const fundingPct =\n opportunity && opportunity.targetAmount > 0\n ? Math.min((opportunity.raisedAmount / opportunity.targetAmount) * 100, 100)\n : 0;\n const daysLeft = opportunity?.expiresAt\n ? Math.max(0, Math.ceil((new Date(opportunity.expiresAt).getTime() - Date.now()) / 86400000))\n : null;\n\n const holdingReturns = investment ? investment.currentValue - investment.investedAmount : 0;\n const holdingReturnsPct =\n investment && investment.investedAmount > 0\n ? (holdingReturns / investment.investedAmount) * 100\n : 0;\n\n const canInvest = Boolean(opportunity) && opportunity?.status === 'active';\n\n return (\n <PageLayout\n title={cartName}\n description=\"Investment details & performance\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/investor/portfolio')}\n className=\"flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">Back to Portfolio</span>\n <span className=\"sm:hidden\">Back</span>\n </button>\n }\n >\n <PagePurpose className=\"mb-6\">\n A deep dive into this investment. Review the business behind it, funding progress, expected\n returns and terms on offer, and — if you already hold a stake — exactly what you&apos;ve put\n in and what it&apos;s worth today.\n </PagePurpose>\n\n {/* Existing holding summary — the one emphasis zone when you own a stake */}\n {investment && (\n <EmphasisPanel>\n <h2 className=\"mb-4 text-base font-semibold text-text-primary\">Your Position</h2>\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n <StatCard\n label=\"Your Investment\"\n value={formatCurrency(investment.investedAmount, { minimumFractionDigits: 0 })}\n icon={<IndianRupee className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Current Value\"\n value={formatCurrency(investment.currentValue, { minimumFractionDigits: 0 })}\n icon={<TrendingUp className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Returns\"\n value={`${holdingReturnsPct >= 0 ? '+' : ''}${holdingReturnsPct.toFixed(1)}%`}\n delta={Number(holdingReturnsPct.toFixed(1))}\n deltaLabel=\"on invested\"\n icon={<TrendingUp className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Realised Returns\"\n value={formatCurrency(investment.returns, { minimumFractionDigits: 0 })}\n icon={<Receipt className=\"h-4 w-4\" />}\n />\n </div>\n </EmphasisPanel>\n )}\n\n <div className=\"mt-6 grid gap-6 lg:grid-cols-3\">\n {/* Left — the business & funding story */}\n <div className=\"space-y-6 lg:col-span-2\">\n {/* Hero header with risk badge */}\n {opportunity && (\n <GlassCard treatment=\"glass\" className=\"p-5 sm:p-6\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"text-sm text-text-secondary\">{opportunity.businessOwner}</p>\n <h2 className=\"mt-0.5 text-xl font-bold tracking-tight text-text-primary sm:text-2xl\">\n {opportunity.cartName}\n </h2>\n </div>\n {risk && (\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-sm font-semibold',\n risk.badge\n )}\n >\n <Shield className=\"h-4 w-4\" />\n {risk.label}\n </span>\n )}\n </div>\n {opportunity.description && (\n <p className=\"mt-4 text-sm leading-relaxed text-text-secondary\">\n {opportunity.description}\n </p>\n )}\n </GlassCard>\n )}\n\n {/* Business Metrics — real provider figures */}\n {provider && (\n <section>\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">Business Metrics</h3>\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4 sm:gap-4\">\n <StatCard\n label=\"Rating\"\n value={provider.rating > 0 ? provider.rating.toFixed(1) : '—'}\n icon={<Star className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Reviews\"\n value={provider.totalRatings.toLocaleString('en-IN')}\n icon={<MessageSquare className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Avg Order\"\n value={\n provider.averageOrderValue\n ? formatCurrency(provider.averageOrderValue, { minimumFractionDigits: 0 })\n : '—'\n }\n icon={<Receipt className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Category\"\n value={\n <span className=\"text-lg font-semibold capitalize\">\n {provider.category || '—'}\n </span>\n }\n icon={<Tag className=\"h-4 w-4\" />}\n />\n </div>\n </section>\n )}\n\n {/* Funding progress with a ProgressRing */}\n {opportunity && (\n <GlassCard treatment=\"plain\" className=\"p-5 sm:p-6\">\n <h3 className=\"mb-4 text-lg font-semibold text-text-primary\">Funding Progress</h3>\n <div className=\"flex flex-col items-center gap-6 sm:flex-row sm:gap-8\">\n <ProgressRing\n value={fundingPct}\n size={140}\n label={`${fundingPct.toFixed(0)}%`}\n caption=\"funded\"\n />\n <div className=\"w-full flex-1 space-y-4\">\n <div>\n <div className=\"flex items-baseline justify-between\">\n <span className=\"text-2xl font-bold text-text-primary\">\n {formatCurrency(opportunity.raisedAmount, { minimumFractionDigits: 0 })}\n </span>\n <span className=\"text-sm text-text-secondary\">\n of {formatCurrency(opportunity.targetAmount, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">raised so far</p>\n </div>\n <div className=\"grid grid-cols-3 gap-3 border-t border-border-subtle pt-4 text-center\">\n <div>\n <p className=\"text-base font-bold text-text-primary sm:text-lg\">\n {opportunity.investors.length}\n </p>\n <p className=\"text-xs text-text-secondary\">Investors</p>\n </div>\n <div>\n <p className=\"text-base font-bold text-text-primary sm:text-lg\">\n {formatCurrency(remaining, {\n minimumFractionDigits: 0,\n notation: 'compact',\n })}\n </p>\n <p className=\"text-xs text-text-secondary\">To Go</p>\n </div>\n <div>\n <p className=\"text-base font-bold text-text-primary sm:text-lg\">\n {daysLeft !== null ? `${daysLeft}` : '—'}\n </p>\n <p className=\"text-xs text-text-secondary\">Days Left</p>\n </div>\n </div>\n </div>\n </div>\n </GlassCard>\n )}\n\n {/* Your holding detail */}\n {investment && (\n <GlassCard treatment=\"plain\" className=\"p-5 sm:p-6\">\n <h3 className=\"mb-4 text-lg font-semibold text-text-primary\">Your Holding</h3>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div>\n <p className=\"text-sm text-text-secondary\">Invested Amount</p>\n <p className=\"font-medium text-text-primary\">\n {formatCurrency(investment.investedAmount, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Current Value</p>\n <p className=\"font-medium text-text-primary\">\n {formatCurrency(investment.currentValue, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Returns Realised</p>\n <p className=\"font-medium text-text-primary\">\n {formatCurrency(investment.returns, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Invested On</p>\n <p className=\"font-medium text-text-primary\">\n {formatDate(investment.investmentDate, { hour: undefined, minute: undefined })}\n </p>\n </div>\n </div>\n </GlassCard>\n )}\n </div>\n\n {/* Right — sticky invest panel */}\n <div className=\"space-y-6\">\n <div className=\"lg:sticky lg:top-6\">\n <GlassCard treatment=\"glass\" glow className=\"p-5 sm:p-6\">\n <h3 className=\"mb-4 text-lg font-semibold text-text-primary\">\n {canInvest ? 'Invest' : 'Investment Terms'}\n </h3>\n\n {/* Terms */}\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <TrendingUp className=\"h-4 w-4\" />\n Expected returns\n </span>\n <span className=\"font-semibold text-status-success-text\">\n {opportunity?.expectedReturns ?? investment?.returnsPercentage}% p.a.\n </span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Lock className=\"h-4 w-4\" />\n Lock-in\n </span>\n <span className=\"font-semibold text-text-primary\">\n {opportunity?.investmentPeriod ?? '—'} months\n </span>\n </div>\n {opportunity && (\n <div className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <IndianRupee className=\"h-4 w-4\" />\n Minimum\n </span>\n <span className=\"font-semibold text-text-primary\">\n {formatCurrency(opportunity.minimumInvestment, { minimumFractionDigits: 0 })}\n </span>\n </div>\n )}\n {opportunity && opportunity.investors.length > 0 && (\n <div className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Users className=\"h-4 w-4\" />\n Investors\n </span>\n <span className=\"font-semibold text-text-primary\">\n {opportunity.investors.length}\n </span>\n </div>\n )}\n </div>\n\n {canInvest && investStatus !== 'success' && !investmentMarketplaceEnabled && (\n <div className=\"mt-5 border-t border-border-subtle pt-5\">\n <InvestmentMarketplaceComingSoon />\n </div>\n )}\n\n {canInvest && investStatus !== 'success' && investmentMarketplaceEnabled && (\n <div className=\"mt-5 space-y-4 border-t border-border-subtle pt-5\">\n <div>\n <label\n htmlFor=\"invest-amount\"\n className=\"mb-1.5 block text-sm font-medium text-text-primary\"\n >\n Amount\n </label>\n <div className=\"relative\">\n <IndianRupee className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n id=\"invest-amount\"\n type=\"number\"\n inputMode=\"numeric\"\n value={amount}\n onChange={(e) => {\n setAmount(e.target.value);\n setInvestStatus('idle');\n }}\n placeholder={String(minInvestment)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2.5 pl-9 pr-3 text-base font-semibold text-text-primary placeholder:font-normal placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <p className=\"mt-1.5 text-xs text-text-secondary\">\n {formatCurrency(minInvestment, { minimumFractionDigits: 0 })} –{' '}\n {formatCurrency(maxInvestment, { minimumFractionDigits: 0 })}\n </p>\n {investStatus === 'error' && (\n <p className=\"mt-1 text-xs text-status-error-text\">\n Enter an amount between{' '}\n {formatCurrency(minInvestment, { minimumFractionDigits: 0 })} and{' '}\n {formatCurrency(maxInvestment, { minimumFractionDigits: 0 })}.\n </p>\n )}\n </div>\n\n {/* Projected returns forecast */}\n <div>\n <p className=\"mb-1 text-sm font-medium text-text-primary\">Projected returns</p>\n <p className=\"mb-2 text-xs text-text-muted\">\n Forecast at {opportunity?.expectedReturns}% over{' '}\n {opportunity?.investmentPeriod} months\n </p>\n <AreaChart\n series={projection}\n height={140}\n valueFormatter={formatRupeeCompact}\n title=\"Projected value over the lock-in period\"\n />\n {amountValid && (\n <div className=\"mt-2 flex items-center justify-between rounded-lg bg-bg-sunken/60 px-3 py-2 text-sm\">\n <span className=\"text-text-secondary\">Projected value</span>\n <span className=\"font-semibold text-status-success-text\">\n {formatCurrency(\n parsedAmount * (1 + (opportunity?.expectedReturns ?? 0) / 100),\n { minimumFractionDigits: 0 }\n )}\n </span>\n </div>\n )}\n </div>\n\n <button\n type=\"button\"\n onClick={handleInvest}\n disabled={!amountValid || invest.isPending}\n className={cn(\n 'flex w-full items-center justify-center gap-2 rounded-lg px-4 py-3 text-sm font-semibold transition-colors',\n amountValid && !invest.isPending\n ? 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover'\n : 'cursor-not-allowed bg-bg-sunken text-text-secondary'\n )}\n >\n {invest.isPending ? 'Processing…' : 'Invest Now'}\n </button>\n </div>\n )}\n\n {investStatus === 'success' && (\n <div className=\"mt-5 border-t border-border-subtle pt-5 text-center\">\n <CheckCircle2 className=\"mx-auto mb-2 h-10 w-10 text-status-success-text\" />\n <p className=\"text-sm font-medium text-text-primary\">Investment successful!</p>\n <p className=\"mt-1 text-xs text-text-secondary\">Redirecting to your portfolio…</p>\n </div>\n )}\n\n {!canInvest && !investment && opportunity && (\n <div className=\"mt-5 flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-sunken/50 p-3 text-sm text-text-secondary\">\n <Target className=\"h-4 w-4 shrink-0\" />\n This opportunity is {opportunity.status}. It&apos;s no longer accepting\n investments.\n </div>\n )}\n </GlassCard>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -9,7 +9,7 @@ import { StepProgress as u } from "../../components/viz/StepProgress.js";
9
9
  import "../../components/viz/index.js";
10
10
  import { useEffect as d, useMemo as f, useState as p } from "react";
11
11
  import { AlertTriangle as m, ArrowLeft as ee, CheckCircle2 as te, Clock as h, FileText as g, IndianRupee as _, Loader2 as v, MapPin as y, Navigation as b, Package as x, Phone as S, ShoppingBag as C, ShoppingCart as w, StickyNote as T, Truck as E, User as D } from "lucide-react";
12
- import { useParams as O } from "react-router-dom";
12
+ import { useParams as O } from "react-router";
13
13
  import { jsx as k, jsxs as A } from "react/jsx-runtime";
14
14
  import { GlassCard as j, PagePurpose as M } from "@burdenoff/fe-libs/ui";
15
15
  //#region src/kadaikodi/pages/worker/TaskDetailsPage.tsx
@@ -1 +1 @@
1
- {"version":3,"file":"TaskDetailsPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/worker/TaskDetailsPage.tsx"],"sourcesContent":["/**\n * Task Details Page\n *\n * A delivery-job detail screen, elevated to the kk-worker-02-task-details\n * concept: a stylised (honest, not-to-scale) pickup → drop route panel, a\n * StepProgress tracker for the delivery flow, separate Pickup and Drop cards\n * with Call / Navigate actions, an earnings summary, a delivery-note field and\n * a single primary CTA that advances the task (Mark Picked Up → Mark Delivered).\n *\n * All data is real (useWorkerTasks). Status transitions use\n * useUpdateWorkerTaskStatus; the delivery note uses useUpdateWorkerTask. Nothing\n * is fabricated — fields the worker-task backend does not carry (per-item order\n * breakdown, payment badge) are simply omitted.\n *\n * @module kadaikodi/pages/worker\n */\n\nimport { useState, useEffect, useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n Package,\n Phone,\n MapPin,\n Clock,\n Navigation,\n CheckCircle2,\n Loader2,\n Truck,\n ShoppingBag,\n User,\n AlertTriangle,\n FileText,\n StickyNote,\n IndianRupee,\n ShoppingCart,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { StepProgress, Timeline, type TimelineItem } from '../../components/viz';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport {\n useWorkerTasks,\n useUpdateWorkerTask,\n useUpdateWorkerTaskStatus,\n} from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatDate } from '../../utils/formatters';\nimport type { TaskStatus, WorkerTask } from '../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface TaskCustomerInfo {\n name: string;\n phone: string;\n address: string;\n}\n\ninterface TaskDetails {\n id: string;\n orderId: string;\n cartId: string;\n cartName: string;\n type: WorkerTask['type'];\n status: TaskStatus;\n priority: WorkerTask['priority'];\n title: string;\n description: string;\n estimatedTime: number;\n assignedBy: string;\n assignedTime: string;\n dueTime: string;\n location?: string;\n earnings: number;\n distance?: number;\n customerInfo: TaskCustomerInfo;\n specialInstructions?: string;\n notes?: string;\n completedAt?: string;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nconst typeLabels: Record<string, string> = {\n delivery: 'Delivery',\n pickup: 'Pickup',\n service: 'Service',\n};\n\nfunction getTaskTypeIcon(type: string) {\n switch (type) {\n case 'delivery':\n return Truck;\n case 'pickup':\n return ShoppingBag;\n case 'service':\n return Package;\n default:\n return FileText;\n }\n}\n\nfunction getPriorityStyle(priority: string): string {\n switch (priority) {\n case 'urgent':\n case 'high':\n return 'bg-status-error-bg-subtle text-status-error-text';\n case 'medium':\n return 'bg-status-warning-bg-subtle text-status-warning-text';\n case 'low':\n return 'bg-status-success-bg-subtle text-status-success-text';\n default:\n return 'bg-bg-sunken text-text-secondary';\n }\n}\n\nfunction formatTime(dateString: string): string {\n const d = new Date(dateString);\n if (Number.isNaN(d.getTime())) return dateString;\n return d.toLocaleTimeString('en-IN', { hour: 'numeric', minute: '2-digit', hour12: true });\n}\n\n/** Map a real worker task into the page's detail view-model (no fabricated fields). */\nfunction mapWorkerTaskToDetails(t: WorkerTask): TaskDetails {\n const address = t.deliveryAddress\n ? [\n t.deliveryAddress.street,\n t.deliveryAddress.area,\n t.deliveryAddress.city,\n t.deliveryAddress.pincode,\n ]\n .filter(Boolean)\n .join(', ')\n : '';\n return {\n id: t.id,\n orderId: t.orderId,\n cartId: t.cartId,\n cartName: t.cartName,\n type: t.type,\n status: t.status,\n priority: t.priority,\n title: t.title ?? t.description ?? 'Task',\n description: t.description,\n estimatedTime: t.estimatedTime ?? 0,\n assignedBy: t.assignedBy ?? '',\n assignedTime: t.assignedAt || '',\n dueTime: t.dueAt,\n location: t.location,\n earnings: t.earnings,\n distance: t.distance,\n customerInfo: { name: t.customerName, phone: t.customerPhone, address },\n specialInstructions: t.notes ?? undefined,\n notes: t.notes ?? '',\n completedAt: t.completedAt,\n };\n}\n\nconst DELIVERY_STEPS = [{ label: 'Assigned' }, { label: 'Picked Up' }, { label: 'Delivered' }];\n\nfunction currentStep(status: TaskStatus): number {\n switch (status) {\n case 'pending':\n return 1;\n case 'in_progress':\n return 2;\n case 'completed':\n return 3;\n default:\n return 0;\n }\n}\n\n/**\n * Honest, illustrative pickup → drop panel. This is a stylised schematic (clearly\n * labelled \"not to scale\"), NOT a real map — the worker-task backend does not\n * expose geo-coordinates, so we never imply a real position.\n */\nfunction RouteSchematic({\n pickupLabel,\n dropLabel,\n distance,\n}: {\n pickupLabel: string;\n dropLabel: string;\n distance?: number;\n}) {\n return (\n <div className=\"relative overflow-hidden rounded-[var(--radius-card)] border border-border-subtle bg-bg-sunken\">\n <svg\n viewBox=\"0 0 400 190\"\n className=\"block w-full\"\n role=\"img\"\n aria-label={`Illustrative route from ${pickupLabel} to ${dropLabel}`}\n >\n {/* faint street grid */}\n <g stroke=\"var(--color-border-subtle)\" strokeWidth=\"1\" opacity=\"0.7\">\n <path d=\"M0 45 H400 M0 95 H400 M0 145 H400\" />\n <path d=\"M70 0 V190 M160 0 V190 M250 0 V190 M330 0 V190\" />\n </g>\n {/* route */}\n <path\n d=\"M70 55 H150 Q165 55 165 70 V120 Q165 135 180 135 H300\"\n fill=\"none\"\n stroke=\"var(--color-accent-primary)\"\n strokeWidth=\"3.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeDasharray=\"1 0\"\n />\n {/* pickup node */}\n <circle cx=\"70\" cy=\"55\" r=\"7\" fill=\"var(--color-accent-primary)\" />\n <circle cx=\"70\" cy=\"55\" r=\"12\" fill=\"var(--color-accent-primary)\" opacity=\"0.18\" />\n {/* drop node */}\n <circle cx=\"300\" cy=\"135\" r=\"7\" fill=\"var(--color-status-success-text)\" />\n <circle cx=\"300\" cy=\"135\" r=\"12\" fill=\"var(--color-status-success-text)\" opacity=\"0.18\" />\n </svg>\n <div className=\"pointer-events-none absolute left-3 top-3 flex items-center gap-1.5 rounded-md bg-bg-surface/85 px-2 py-1 backdrop-blur\">\n <Package className=\"h-3.5 w-3.5 text-accent-primary\" />\n <span className=\"max-w-[9rem] truncate text-[11px] font-medium text-text-primary\">\n {pickupLabel}\n </span>\n </div>\n <div className=\"pointer-events-none absolute bottom-3 right-3 flex items-center gap-1.5 rounded-md bg-bg-surface/85 px-2 py-1 backdrop-blur\">\n <MapPin className=\"h-3.5 w-3.5 text-status-success-text\" />\n <span className=\"max-w-[9rem] truncate text-[11px] font-medium text-text-primary\">\n {dropLabel}\n </span>\n </div>\n <div className=\"flex items-center justify-between border-t border-border-subtle px-3 py-2\">\n <span className=\"text-[11px] text-text-muted\">Illustrative route · not to scale</span>\n {distance != null && (\n <span className=\"text-[11px] font-medium text-text-secondary tabular-nums\">\n {distance} km\n </span>\n )}\n </div>\n </div>\n );\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function TaskDetailsPage() {\n const { taskId } = useParams<{ taskId: string }>();\n const { navigateTo, currentUser } = useKadaikodi();\n const workerId = currentUser?.id ?? '';\n const { data: tasks = [], isLoading: loading } = useWorkerTasks(workerId);\n const updateStatus = useUpdateWorkerTaskStatus();\n const updateNotes = useUpdateWorkerTask();\n const [task, setTask] = useState<TaskDetails | null>(null);\n const [notes, setNotes] = useState('');\n const [notesSaved, setNotesSaved] = useState(false);\n\n useEffect(() => {\n const found = tasks.find((t) => t.id === taskId);\n if (found) {\n const mapped = mapWorkerTaskToDetails(found);\n setTask(mapped);\n setNotes(mapped.notes ?? '');\n } else {\n setTask(null);\n }\n }, [tasks, taskId]);\n\n const handleAdvanceStatus = () => {\n if (!task) return;\n if (task.status === 'pending') {\n setTask({ ...task, status: 'in_progress' });\n updateStatus.mutate({ taskId: task.id, status: 'IN_PROGRESS' });\n } else if (task.status === 'in_progress') {\n setTask({ ...task, status: 'completed' });\n updateStatus.mutate({ taskId: task.id, status: 'COMPLETED' });\n }\n };\n\n const handleCallCustomer = () => {\n if (task?.customerInfo?.phone) {\n window.location.href = `tel:${task.customerInfo.phone.replace(/\\s/g, '')}`;\n }\n };\n\n const handleNavigate = (query: string) => {\n if (query) {\n window.open(`https://maps.google.com?q=${encodeURIComponent(query)}`, '_blank');\n }\n };\n\n const handleSaveNotes = () => {\n if (!task) return;\n setNotesSaved(false);\n updateNotes.mutate(\n { taskId: task.id, notes },\n {\n onSuccess: () => {\n setTask((t) => (t ? { ...t, notes } : t));\n setNotesSaved(true);\n },\n }\n );\n };\n\n const timeline = useMemo<TimelineItem[]>(() => {\n if (!task) return [];\n return [\n {\n title: 'Task assigned',\n time: task.assignedTime ? formatTime(task.assignedTime) : undefined,\n meta: task.assignedBy || undefined,\n tone: 'success',\n },\n {\n title: 'Picked up',\n time: task.status === 'in_progress' || task.status === 'completed' ? 'Done' : undefined,\n tone: task.status === 'in_progress' || task.status === 'completed' ? 'success' : 'muted',\n },\n {\n title: 'Delivered',\n time:\n task.status === 'completed'\n ? task.completedAt\n ? formatTime(task.completedAt)\n : 'Done'\n : undefined,\n tone: task.status === 'completed' ? 'success' : 'muted',\n },\n ];\n }, [task]);\n\n if (loading) {\n return (\n <PageLayout title=\"Task Details\">\n <div className=\"flex items-center justify-center py-24\">\n <div className=\"text-center\">\n <Loader2 className=\"h-10 w-10 animate-spin text-text-secondary mx-auto mb-4\" />\n <p className=\"text-sm text-text-secondary\">Loading task details...</p>\n </div>\n </div>\n </PageLayout>\n );\n }\n\n if (!task) {\n return (\n <PageLayout title=\"Task Not Found\">\n <EmptyState\n icon={<FileText className=\"h-12 w-12\" />}\n title=\"Task not found\"\n description={`No task found with ID \"${taskId}\".`}\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/worker/orders')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg-hover transition-colors\"\n >\n View All Orders\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n const TaskTypeIcon = getTaskTypeIcon(task.type);\n const typeLabel = typeLabels[task.type] ?? 'Task';\n const pickupLabel = task.cartName || 'Pickup';\n const dropLabel = task.customerInfo.address || task.customerInfo.name || 'Drop-off';\n const ctaLabel =\n task.status === 'pending'\n ? 'Mark Picked Up'\n : task.status === 'in_progress'\n ? 'Mark Delivered'\n : 'Delivered';\n\n return (\n <PageLayout\n title={\n <div className=\"flex items-center gap-3 min-w-0\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/worker/orders')}\n className=\"rounded-md p-1 text-text-secondary hover:bg-bg-sunken hover:text-text-primary transition-colors shrink-0\"\n aria-label=\"Back to orders\"\n >\n <ArrowLeft className=\"h-5 w-5\" />\n </button>\n <span className=\"truncate\">\n {typeLabel}\n {task.orderId ? <span className=\"text-text-secondary\"> · #{task.orderId}</span> : null}\n </span>\n </div>\n }\n description=\"Everything you need to complete this delivery\"\n >\n <PagePurpose className=\"mb-6\">\n One delivery, start to finish. Reach the customer, follow the route, jot a note, and advance\n the job — mark it picked up, then delivered — so nothing gets missed and your completion\n stats stay strong.\n </PagePurpose>\n\n <div className=\"space-y-6\">\n {/* Delivery step tracker */}\n <GlassCard treatment=\"metric\" className=\"p-5\">\n <div className=\"mb-4 flex flex-wrap items-center gap-2\">\n <span className=\"flex h-8 w-8 items-center justify-center rounded-lg bg-accent-primary/12 text-accent-primary\">\n <TaskTypeIcon className=\"h-4.5 w-4.5\" />\n </span>\n <h2 className=\"text-base font-semibold text-text-primary\">{task.title}</h2>\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium uppercase',\n getPriorityStyle(task.priority)\n )}\n >\n {task.priority}\n </span>\n </div>\n <StepProgress steps={DELIVERY_STEPS} current={currentStep(task.status)} />\n </GlassCard>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Main column */}\n <div className=\"lg:col-span-2 space-y-6\">\n <RouteSchematic\n pickupLabel={pickupLabel}\n dropLabel={dropLabel}\n distance={task.distance}\n />\n\n {/* Pickup + Drop cards */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n {/* Pickup */}\n <GlassCard className=\"p-5\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-muted\">\n Pickup\n </p>\n <p className=\"mt-1 text-sm font-semibold text-text-primary\">{task.cartName}</p>\n {task.location && (\n <p className=\"mt-0.5 text-xs text-text-secondary\">{task.location}</p>\n )}\n <div className=\"mt-4\">\n <button\n type=\"button\"\n onClick={() => handleNavigate(task.location || task.cartName)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-xs font-medium text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Navigation className=\"h-3.5 w-3.5\" />\n Navigate\n </button>\n </div>\n </GlassCard>\n\n {/* Drop */}\n <GlassCard className=\"p-5\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-muted\">Drop</p>\n <p className=\"mt-1 text-sm font-semibold text-text-primary\">\n {task.customerInfo.name || 'Customer'}\n </p>\n {task.customerInfo.address && (\n <p className=\"mt-0.5 text-xs text-text-secondary\">{task.customerInfo.address}</p>\n )}\n {task.customerInfo.phone && (\n <p className=\"mt-0.5 text-xs text-text-secondary\">{task.customerInfo.phone}</p>\n )}\n <div className=\"mt-4 flex gap-2\">\n {task.customerInfo.phone && (\n <button\n type=\"button\"\n onClick={handleCallCustomer}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-xs font-medium text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Phone className=\"h-3.5 w-3.5\" />\n Call\n </button>\n )}\n {task.customerInfo.address && (\n <button\n type=\"button\"\n onClick={() => handleNavigate(task.customerInfo.address)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-xs font-medium text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Navigation className=\"h-3.5 w-3.5\" />\n Navigate\n </button>\n )}\n </div>\n </GlassCard>\n </div>\n\n {/* Earnings summary */}\n <GlassCard treatment=\"insight\" className=\"p-5\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex items-center gap-3\">\n <span className=\"flex h-9 w-9 items-center justify-center rounded-lg bg-status-success-bg-subtle text-status-success-text\">\n <IndianRupee className=\"h-4.5 w-4.5\" />\n </span>\n <div>\n <p className=\"text-xs text-text-secondary\">You earn</p>\n <p className=\"text-lg font-bold text-text-primary\">\n {formatCurrency(task.earnings, { minimumFractionDigits: 0 })}\n </p>\n </div>\n </div>\n <div className=\"flex flex-wrap items-center gap-4 text-sm\">\n <span className=\"flex items-center gap-1.5 text-text-secondary\">\n <ShoppingCart className=\"h-4 w-4\" />\n {task.cartName}\n </span>\n {task.dueTime && (\n <span className=\"flex items-center gap-1.5 text-text-secondary\">\n <Clock className=\"h-4 w-4\" />\n Due {formatTime(task.dueTime)}\n </span>\n )}\n </div>\n </div>\n </GlassCard>\n\n {/* Special Instructions */}\n {task.specialInstructions && (\n <div className=\"rounded-[var(--radius-card)] border border-status-warning-text/20 bg-status-warning-bg-subtle p-4\">\n <p className=\"text-sm text-status-warning-text flex items-start gap-2\">\n <AlertTriangle className=\"h-4 w-4 shrink-0 mt-0.5\" />\n {task.specialInstructions}\n </p>\n </div>\n )}\n\n {/* Delivery note */}\n <GlassCard className=\"p-5\">\n <h3 className=\"mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <StickyNote className=\"h-4 w-4 text-text-secondary\" />\n Delivery note\n </h3>\n <textarea\n value={notes}\n onChange={(e) => {\n setNotes(e.target.value);\n setNotesSaved(false);\n }}\n placeholder=\"Add a delivery note...\"\n rows={3}\n className=\"w-full resize-none rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-border-focus/40\"\n />\n <div className=\"mt-3 flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={handleSaveNotes}\n disabled={updateNotes.isPending}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-surface px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken transition-colors disabled:opacity-50\"\n >\n {updateNotes.isPending ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <StickyNote className=\"h-3.5 w-3.5\" />\n )}\n {updateNotes.isPending ? 'Saving...' : 'Save note'}\n </button>\n {notesSaved && !updateNotes.isPending && (\n <span className=\"text-xs text-status-success-text\">Note saved</span>\n )}\n {updateNotes.isError && (\n <span className=\"text-xs text-status-error-text\">Couldn&apos;t save — retry</span>\n )}\n </div>\n </GlassCard>\n\n {/* Primary CTA */}\n <button\n type=\"button\"\n onClick={handleAdvanceStatus}\n disabled={task.status === 'completed' || updateStatus.isPending}\n className={cn(\n 'w-full inline-flex items-center justify-center gap-2 rounded-[var(--radius-card)] px-4 py-3.5 text-base font-semibold transition-colors',\n task.status === 'completed'\n ? 'bg-status-success-bg-subtle text-status-success-text cursor-default'\n : 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-60'\n )}\n >\n {updateStatus.isPending ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n <CheckCircle2 className=\"h-5 w-5\" />\n )}\n {ctaLabel}\n </button>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-6\">\n <GlassCard className=\"p-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Delivery timeline</h3>\n <Timeline items={timeline} />\n </GlassCard>\n\n <GlassCard className=\"p-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Job details</h3>\n <dl className=\"space-y-3 text-sm\">\n {task.orderId && (\n <div className=\"flex items-center gap-2\">\n <FileText className=\"h-4 w-4 text-text-secondary shrink-0\" />\n <div>\n <dt className=\"text-xs text-text-secondary\">Order ID</dt>\n <dd className=\"font-mono font-medium text-text-primary\">{task.orderId}</dd>\n </div>\n </div>\n )}\n {task.customerInfo.name && (\n <div className=\"flex items-center gap-2\">\n <User className=\"h-4 w-4 text-text-secondary shrink-0\" />\n <div>\n <dt className=\"text-xs text-text-secondary\">Customer</dt>\n <dd className=\"font-medium text-text-primary\">{task.customerInfo.name}</dd>\n </div>\n </div>\n )}\n {task.distance != null && (\n <div className=\"flex items-center gap-2\">\n <Navigation className=\"h-4 w-4 text-text-secondary shrink-0\" />\n <div>\n <dt className=\"text-xs text-text-secondary\">Distance</dt>\n <dd className=\"font-medium text-text-primary\">{task.distance} km</dd>\n </div>\n </div>\n )}\n {task.assignedTime && (\n <div className=\"flex items-center gap-2\">\n <Clock className=\"h-4 w-4 text-text-secondary shrink-0\" />\n <div>\n <dt className=\"text-xs text-text-secondary\">Assigned</dt>\n <dd className=\"font-medium text-text-primary\">\n {formatDate(task.assignedTime)}\n </dd>\n </div>\n </div>\n )}\n </dl>\n </GlassCard>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TaskDetailsPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/worker/TaskDetailsPage.tsx"],"sourcesContent":["/**\n * Task Details Page\n *\n * A delivery-job detail screen, elevated to the kk-worker-02-task-details\n * concept: a stylised (honest, not-to-scale) pickup → drop route panel, a\n * StepProgress tracker for the delivery flow, separate Pickup and Drop cards\n * with Call / Navigate actions, an earnings summary, a delivery-note field and\n * a single primary CTA that advances the task (Mark Picked Up → Mark Delivered).\n *\n * All data is real (useWorkerTasks). Status transitions use\n * useUpdateWorkerTaskStatus; the delivery note uses useUpdateWorkerTask. Nothing\n * is fabricated — fields the worker-task backend does not carry (per-item order\n * breakdown, payment badge) are simply omitted.\n *\n * @module kadaikodi/pages/worker\n */\n\nimport { useState, useEffect, useMemo } from 'react';\nimport { useParams } from 'react-router';\nimport {\n ArrowLeft,\n Package,\n Phone,\n MapPin,\n Clock,\n Navigation,\n CheckCircle2,\n Loader2,\n Truck,\n ShoppingBag,\n User,\n AlertTriangle,\n FileText,\n StickyNote,\n IndianRupee,\n ShoppingCart,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { StepProgress, Timeline, type TimelineItem } from '../../components/viz';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport {\n useWorkerTasks,\n useUpdateWorkerTask,\n useUpdateWorkerTaskStatus,\n} from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency, formatDate } from '../../utils/formatters';\nimport type { TaskStatus, WorkerTask } from '../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface TaskCustomerInfo {\n name: string;\n phone: string;\n address: string;\n}\n\ninterface TaskDetails {\n id: string;\n orderId: string;\n cartId: string;\n cartName: string;\n type: WorkerTask['type'];\n status: TaskStatus;\n priority: WorkerTask['priority'];\n title: string;\n description: string;\n estimatedTime: number;\n assignedBy: string;\n assignedTime: string;\n dueTime: string;\n location?: string;\n earnings: number;\n distance?: number;\n customerInfo: TaskCustomerInfo;\n specialInstructions?: string;\n notes?: string;\n completedAt?: string;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nconst typeLabels: Record<string, string> = {\n delivery: 'Delivery',\n pickup: 'Pickup',\n service: 'Service',\n};\n\nfunction getTaskTypeIcon(type: string) {\n switch (type) {\n case 'delivery':\n return Truck;\n case 'pickup':\n return ShoppingBag;\n case 'service':\n return Package;\n default:\n return FileText;\n }\n}\n\nfunction getPriorityStyle(priority: string): string {\n switch (priority) {\n case 'urgent':\n case 'high':\n return 'bg-status-error-bg-subtle text-status-error-text';\n case 'medium':\n return 'bg-status-warning-bg-subtle text-status-warning-text';\n case 'low':\n return 'bg-status-success-bg-subtle text-status-success-text';\n default:\n return 'bg-bg-sunken text-text-secondary';\n }\n}\n\nfunction formatTime(dateString: string): string {\n const d = new Date(dateString);\n if (Number.isNaN(d.getTime())) return dateString;\n return d.toLocaleTimeString('en-IN', { hour: 'numeric', minute: '2-digit', hour12: true });\n}\n\n/** Map a real worker task into the page's detail view-model (no fabricated fields). */\nfunction mapWorkerTaskToDetails(t: WorkerTask): TaskDetails {\n const address = t.deliveryAddress\n ? [\n t.deliveryAddress.street,\n t.deliveryAddress.area,\n t.deliveryAddress.city,\n t.deliveryAddress.pincode,\n ]\n .filter(Boolean)\n .join(', ')\n : '';\n return {\n id: t.id,\n orderId: t.orderId,\n cartId: t.cartId,\n cartName: t.cartName,\n type: t.type,\n status: t.status,\n priority: t.priority,\n title: t.title ?? t.description ?? 'Task',\n description: t.description,\n estimatedTime: t.estimatedTime ?? 0,\n assignedBy: t.assignedBy ?? '',\n assignedTime: t.assignedAt || '',\n dueTime: t.dueAt,\n location: t.location,\n earnings: t.earnings,\n distance: t.distance,\n customerInfo: { name: t.customerName, phone: t.customerPhone, address },\n specialInstructions: t.notes ?? undefined,\n notes: t.notes ?? '',\n completedAt: t.completedAt,\n };\n}\n\nconst DELIVERY_STEPS = [{ label: 'Assigned' }, { label: 'Picked Up' }, { label: 'Delivered' }];\n\nfunction currentStep(status: TaskStatus): number {\n switch (status) {\n case 'pending':\n return 1;\n case 'in_progress':\n return 2;\n case 'completed':\n return 3;\n default:\n return 0;\n }\n}\n\n/**\n * Honest, illustrative pickup → drop panel. This is a stylised schematic (clearly\n * labelled \"not to scale\"), NOT a real map — the worker-task backend does not\n * expose geo-coordinates, so we never imply a real position.\n */\nfunction RouteSchematic({\n pickupLabel,\n dropLabel,\n distance,\n}: {\n pickupLabel: string;\n dropLabel: string;\n distance?: number;\n}) {\n return (\n <div className=\"relative overflow-hidden rounded-[var(--radius-card)] border border-border-subtle bg-bg-sunken\">\n <svg\n viewBox=\"0 0 400 190\"\n className=\"block w-full\"\n role=\"img\"\n aria-label={`Illustrative route from ${pickupLabel} to ${dropLabel}`}\n >\n {/* faint street grid */}\n <g stroke=\"var(--color-border-subtle)\" strokeWidth=\"1\" opacity=\"0.7\">\n <path d=\"M0 45 H400 M0 95 H400 M0 145 H400\" />\n <path d=\"M70 0 V190 M160 0 V190 M250 0 V190 M330 0 V190\" />\n </g>\n {/* route */}\n <path\n d=\"M70 55 H150 Q165 55 165 70 V120 Q165 135 180 135 H300\"\n fill=\"none\"\n stroke=\"var(--color-accent-primary)\"\n strokeWidth=\"3.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeDasharray=\"1 0\"\n />\n {/* pickup node */}\n <circle cx=\"70\" cy=\"55\" r=\"7\" fill=\"var(--color-accent-primary)\" />\n <circle cx=\"70\" cy=\"55\" r=\"12\" fill=\"var(--color-accent-primary)\" opacity=\"0.18\" />\n {/* drop node */}\n <circle cx=\"300\" cy=\"135\" r=\"7\" fill=\"var(--color-status-success-text)\" />\n <circle cx=\"300\" cy=\"135\" r=\"12\" fill=\"var(--color-status-success-text)\" opacity=\"0.18\" />\n </svg>\n <div className=\"pointer-events-none absolute left-3 top-3 flex items-center gap-1.5 rounded-md bg-bg-surface/85 px-2 py-1 backdrop-blur\">\n <Package className=\"h-3.5 w-3.5 text-accent-primary\" />\n <span className=\"max-w-[9rem] truncate text-[11px] font-medium text-text-primary\">\n {pickupLabel}\n </span>\n </div>\n <div className=\"pointer-events-none absolute bottom-3 right-3 flex items-center gap-1.5 rounded-md bg-bg-surface/85 px-2 py-1 backdrop-blur\">\n <MapPin className=\"h-3.5 w-3.5 text-status-success-text\" />\n <span className=\"max-w-[9rem] truncate text-[11px] font-medium text-text-primary\">\n {dropLabel}\n </span>\n </div>\n <div className=\"flex items-center justify-between border-t border-border-subtle px-3 py-2\">\n <span className=\"text-[11px] text-text-muted\">Illustrative route · not to scale</span>\n {distance != null && (\n <span className=\"text-[11px] font-medium text-text-secondary tabular-nums\">\n {distance} km\n </span>\n )}\n </div>\n </div>\n );\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function TaskDetailsPage() {\n const { taskId } = useParams<{ taskId: string }>();\n const { navigateTo, currentUser } = useKadaikodi();\n const workerId = currentUser?.id ?? '';\n const { data: tasks = [], isLoading: loading } = useWorkerTasks(workerId);\n const updateStatus = useUpdateWorkerTaskStatus();\n const updateNotes = useUpdateWorkerTask();\n const [task, setTask] = useState<TaskDetails | null>(null);\n const [notes, setNotes] = useState('');\n const [notesSaved, setNotesSaved] = useState(false);\n\n useEffect(() => {\n const found = tasks.find((t) => t.id === taskId);\n if (found) {\n const mapped = mapWorkerTaskToDetails(found);\n setTask(mapped);\n setNotes(mapped.notes ?? '');\n } else {\n setTask(null);\n }\n }, [tasks, taskId]);\n\n const handleAdvanceStatus = () => {\n if (!task) return;\n if (task.status === 'pending') {\n setTask({ ...task, status: 'in_progress' });\n updateStatus.mutate({ taskId: task.id, status: 'IN_PROGRESS' });\n } else if (task.status === 'in_progress') {\n setTask({ ...task, status: 'completed' });\n updateStatus.mutate({ taskId: task.id, status: 'COMPLETED' });\n }\n };\n\n const handleCallCustomer = () => {\n if (task?.customerInfo?.phone) {\n window.location.href = `tel:${task.customerInfo.phone.replace(/\\s/g, '')}`;\n }\n };\n\n const handleNavigate = (query: string) => {\n if (query) {\n window.open(`https://maps.google.com?q=${encodeURIComponent(query)}`, '_blank');\n }\n };\n\n const handleSaveNotes = () => {\n if (!task) return;\n setNotesSaved(false);\n updateNotes.mutate(\n { taskId: task.id, notes },\n {\n onSuccess: () => {\n setTask((t) => (t ? { ...t, notes } : t));\n setNotesSaved(true);\n },\n }\n );\n };\n\n const timeline = useMemo<TimelineItem[]>(() => {\n if (!task) return [];\n return [\n {\n title: 'Task assigned',\n time: task.assignedTime ? formatTime(task.assignedTime) : undefined,\n meta: task.assignedBy || undefined,\n tone: 'success',\n },\n {\n title: 'Picked up',\n time: task.status === 'in_progress' || task.status === 'completed' ? 'Done' : undefined,\n tone: task.status === 'in_progress' || task.status === 'completed' ? 'success' : 'muted',\n },\n {\n title: 'Delivered',\n time:\n task.status === 'completed'\n ? task.completedAt\n ? formatTime(task.completedAt)\n : 'Done'\n : undefined,\n tone: task.status === 'completed' ? 'success' : 'muted',\n },\n ];\n }, [task]);\n\n if (loading) {\n return (\n <PageLayout title=\"Task Details\">\n <div className=\"flex items-center justify-center py-24\">\n <div className=\"text-center\">\n <Loader2 className=\"h-10 w-10 animate-spin text-text-secondary mx-auto mb-4\" />\n <p className=\"text-sm text-text-secondary\">Loading task details...</p>\n </div>\n </div>\n </PageLayout>\n );\n }\n\n if (!task) {\n return (\n <PageLayout title=\"Task Not Found\">\n <EmptyState\n icon={<FileText className=\"h-12 w-12\" />}\n title=\"Task not found\"\n description={`No task found with ID \"${taskId}\".`}\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/worker/orders')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg-hover transition-colors\"\n >\n View All Orders\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n const TaskTypeIcon = getTaskTypeIcon(task.type);\n const typeLabel = typeLabels[task.type] ?? 'Task';\n const pickupLabel = task.cartName || 'Pickup';\n const dropLabel = task.customerInfo.address || task.customerInfo.name || 'Drop-off';\n const ctaLabel =\n task.status === 'pending'\n ? 'Mark Picked Up'\n : task.status === 'in_progress'\n ? 'Mark Delivered'\n : 'Delivered';\n\n return (\n <PageLayout\n title={\n <div className=\"flex items-center gap-3 min-w-0\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/worker/orders')}\n className=\"rounded-md p-1 text-text-secondary hover:bg-bg-sunken hover:text-text-primary transition-colors shrink-0\"\n aria-label=\"Back to orders\"\n >\n <ArrowLeft className=\"h-5 w-5\" />\n </button>\n <span className=\"truncate\">\n {typeLabel}\n {task.orderId ? <span className=\"text-text-secondary\"> · #{task.orderId}</span> : null}\n </span>\n </div>\n }\n description=\"Everything you need to complete this delivery\"\n >\n <PagePurpose className=\"mb-6\">\n One delivery, start to finish. Reach the customer, follow the route, jot a note, and advance\n the job — mark it picked up, then delivered — so nothing gets missed and your completion\n stats stay strong.\n </PagePurpose>\n\n <div className=\"space-y-6\">\n {/* Delivery step tracker */}\n <GlassCard treatment=\"metric\" className=\"p-5\">\n <div className=\"mb-4 flex flex-wrap items-center gap-2\">\n <span className=\"flex h-8 w-8 items-center justify-center rounded-lg bg-accent-primary/12 text-accent-primary\">\n <TaskTypeIcon className=\"h-4.5 w-4.5\" />\n </span>\n <h2 className=\"text-base font-semibold text-text-primary\">{task.title}</h2>\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium uppercase',\n getPriorityStyle(task.priority)\n )}\n >\n {task.priority}\n </span>\n </div>\n <StepProgress steps={DELIVERY_STEPS} current={currentStep(task.status)} />\n </GlassCard>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Main column */}\n <div className=\"lg:col-span-2 space-y-6\">\n <RouteSchematic\n pickupLabel={pickupLabel}\n dropLabel={dropLabel}\n distance={task.distance}\n />\n\n {/* Pickup + Drop cards */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n {/* Pickup */}\n <GlassCard className=\"p-5\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-muted\">\n Pickup\n </p>\n <p className=\"mt-1 text-sm font-semibold text-text-primary\">{task.cartName}</p>\n {task.location && (\n <p className=\"mt-0.5 text-xs text-text-secondary\">{task.location}</p>\n )}\n <div className=\"mt-4\">\n <button\n type=\"button\"\n onClick={() => handleNavigate(task.location || task.cartName)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-xs font-medium text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Navigation className=\"h-3.5 w-3.5\" />\n Navigate\n </button>\n </div>\n </GlassCard>\n\n {/* Drop */}\n <GlassCard className=\"p-5\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-muted\">Drop</p>\n <p className=\"mt-1 text-sm font-semibold text-text-primary\">\n {task.customerInfo.name || 'Customer'}\n </p>\n {task.customerInfo.address && (\n <p className=\"mt-0.5 text-xs text-text-secondary\">{task.customerInfo.address}</p>\n )}\n {task.customerInfo.phone && (\n <p className=\"mt-0.5 text-xs text-text-secondary\">{task.customerInfo.phone}</p>\n )}\n <div className=\"mt-4 flex gap-2\">\n {task.customerInfo.phone && (\n <button\n type=\"button\"\n onClick={handleCallCustomer}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-xs font-medium text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Phone className=\"h-3.5 w-3.5\" />\n Call\n </button>\n )}\n {task.customerInfo.address && (\n <button\n type=\"button\"\n onClick={() => handleNavigate(task.customerInfo.address)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-xs font-medium text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Navigation className=\"h-3.5 w-3.5\" />\n Navigate\n </button>\n )}\n </div>\n </GlassCard>\n </div>\n\n {/* Earnings summary */}\n <GlassCard treatment=\"insight\" className=\"p-5\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex items-center gap-3\">\n <span className=\"flex h-9 w-9 items-center justify-center rounded-lg bg-status-success-bg-subtle text-status-success-text\">\n <IndianRupee className=\"h-4.5 w-4.5\" />\n </span>\n <div>\n <p className=\"text-xs text-text-secondary\">You earn</p>\n <p className=\"text-lg font-bold text-text-primary\">\n {formatCurrency(task.earnings, { minimumFractionDigits: 0 })}\n </p>\n </div>\n </div>\n <div className=\"flex flex-wrap items-center gap-4 text-sm\">\n <span className=\"flex items-center gap-1.5 text-text-secondary\">\n <ShoppingCart className=\"h-4 w-4\" />\n {task.cartName}\n </span>\n {task.dueTime && (\n <span className=\"flex items-center gap-1.5 text-text-secondary\">\n <Clock className=\"h-4 w-4\" />\n Due {formatTime(task.dueTime)}\n </span>\n )}\n </div>\n </div>\n </GlassCard>\n\n {/* Special Instructions */}\n {task.specialInstructions && (\n <div className=\"rounded-[var(--radius-card)] border border-status-warning-text/20 bg-status-warning-bg-subtle p-4\">\n <p className=\"text-sm text-status-warning-text flex items-start gap-2\">\n <AlertTriangle className=\"h-4 w-4 shrink-0 mt-0.5\" />\n {task.specialInstructions}\n </p>\n </div>\n )}\n\n {/* Delivery note */}\n <GlassCard className=\"p-5\">\n <h3 className=\"mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <StickyNote className=\"h-4 w-4 text-text-secondary\" />\n Delivery note\n </h3>\n <textarea\n value={notes}\n onChange={(e) => {\n setNotes(e.target.value);\n setNotesSaved(false);\n }}\n placeholder=\"Add a delivery note...\"\n rows={3}\n className=\"w-full resize-none rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-border-focus/40\"\n />\n <div className=\"mt-3 flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={handleSaveNotes}\n disabled={updateNotes.isPending}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-surface px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken transition-colors disabled:opacity-50\"\n >\n {updateNotes.isPending ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <StickyNote className=\"h-3.5 w-3.5\" />\n )}\n {updateNotes.isPending ? 'Saving...' : 'Save note'}\n </button>\n {notesSaved && !updateNotes.isPending && (\n <span className=\"text-xs text-status-success-text\">Note saved</span>\n )}\n {updateNotes.isError && (\n <span className=\"text-xs text-status-error-text\">Couldn&apos;t save — retry</span>\n )}\n </div>\n </GlassCard>\n\n {/* Primary CTA */}\n <button\n type=\"button\"\n onClick={handleAdvanceStatus}\n disabled={task.status === 'completed' || updateStatus.isPending}\n className={cn(\n 'w-full inline-flex items-center justify-center gap-2 rounded-[var(--radius-card)] px-4 py-3.5 text-base font-semibold transition-colors',\n task.status === 'completed'\n ? 'bg-status-success-bg-subtle text-status-success-text cursor-default'\n : 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-60'\n )}\n >\n {updateStatus.isPending ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n <CheckCircle2 className=\"h-5 w-5\" />\n )}\n {ctaLabel}\n </button>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-6\">\n <GlassCard className=\"p-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Delivery timeline</h3>\n <Timeline items={timeline} />\n </GlassCard>\n\n <GlassCard className=\"p-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Job details</h3>\n <dl className=\"space-y-3 text-sm\">\n {task.orderId && (\n <div className=\"flex items-center gap-2\">\n <FileText className=\"h-4 w-4 text-text-secondary shrink-0\" />\n <div>\n <dt className=\"text-xs text-text-secondary\">Order ID</dt>\n <dd className=\"font-mono font-medium text-text-primary\">{task.orderId}</dd>\n </div>\n </div>\n )}\n {task.customerInfo.name && (\n <div className=\"flex items-center gap-2\">\n <User className=\"h-4 w-4 text-text-secondary shrink-0\" />\n <div>\n <dt className=\"text-xs text-text-secondary\">Customer</dt>\n <dd className=\"font-medium text-text-primary\">{task.customerInfo.name}</dd>\n </div>\n </div>\n )}\n {task.distance != null && (\n <div className=\"flex items-center gap-2\">\n <Navigation className=\"h-4 w-4 text-text-secondary shrink-0\" />\n <div>\n <dt className=\"text-xs text-text-secondary\">Distance</dt>\n <dd className=\"font-medium text-text-primary\">{task.distance} km</dd>\n </div>\n </div>\n )}\n {task.assignedTime && (\n <div className=\"flex items-center gap-2\">\n <Clock className=\"h-4 w-4 text-text-secondary shrink-0\" />\n <div>\n <dt className=\"text-xs text-text-secondary\">Assigned</dt>\n <dd className=\"font-medium text-text-primary\">\n {formatDate(task.assignedTime)}\n </dd>\n </div>\n </div>\n )}\n </dl>\n </GlassCard>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}