| @@ -32,8 +32,9 @@ | ||
| 32 | 32 | CardHeader, |
| 33 | 33 | CardTitle, |
| 34 | 34 | } from "../components/ui/card"; |
| 35 | 35 | import { ConditionalRender } from "../components/ui/conditional-render"; |
| 36 | +import { CustomerSummaryCard } from "../components/ai/CustomerSummaryCard"; | |
| 36 | 37 | import { |
| 37 | 38 | Table, |
| 38 | 39 | TableBody, |
| 39 | 40 | TableCell, |
| @@ -41,9 +42,9 @@ | ||
| 41 | 42 | TableHeader, |
| 42 | 43 | TableRow, |
| 43 | 44 | } from "../components/ui/table"; |
| 44 | 45 | import { Skeleton } from "../components/ui/skeleton"; |
| 45 | -import { getCurrencySymbol, getCurrency } from "../data/currencies"; | |
| 46 | +import { formatYatraMoney } from "../lib/currency-display"; | |
| 46 | 47 | |
| 47 | 48 | interface Customer { |
| 48 | 49 | id: number; |
| 49 | 50 | user_id: number; |
| @@ -132,9 +133,9 @@ | ||
| 132 | 133 | emergency.relationship ?? |
| 133 | 134 | null, |
| 134 | 135 | } as Customer; |
| 135 | 136 | }, |
| 136 | - enabled: !!customerId && can("yatra_view_bookings"), | |
| 137 | + enabled: !!customerId && can("yatra_view_customers"), | |
| 137 | 138 | }); |
| 138 | 139 | |
| 139 | 140 | // Fetch customer bookings |
| 140 | 141 | const { data: bookings, isLoading: isLoadingBookings } = useQuery<Booking[]>({ |
| @@ -161,19 +162,13 @@ | ||
| 161 | 162 | const formatShortDate = (dateString: string | null | undefined) => { |
| 162 | 163 | return formatDateUtil(dateString); |
| 163 | 164 | }; |
| 164 | 165 | |
| 165 | - const formatPrice = (price: number, currencyCode: string = "USD") => { | |
| 166 | - const symbol = getCurrencySymbol(currencyCode); | |
| 167 | - const currencyData = getCurrency(currencyCode); | |
| 168 | - const decimals = currencyData?.decimalDigits ?? 2; | |
| 166 | + const formatPrice = (price: number, currencyCode: string = "USD") => | |
| 167 | + formatYatraMoney(Number(price) || 0, currencyCode, { | |
| 168 | + zeroAsUnknown: false, | |
| 169 | + }); | |
| 169 | 170 | |
| 170 | - return `${symbol}${new Intl.NumberFormat(undefined, { | |
| 171 | - minimumFractionDigits: decimals, | |
| 172 | - maximumFractionDigits: decimals, | |
| 173 | - }).format(price)}`; | |
| 174 | - }; | |
| 175 | - | |
| 176 | 171 | const getStatusBadge = (status: string) => { |
| 177 | 172 | const statusMap: Record<string, { className: string; label: string }> = { |
| 178 | 173 | active: { |
| 179 | 174 | className: |
| @@ -404,9 +399,9 @@ | ||
| 404 | 399 | title={__("Customer Details", "yatra")} |
| 405 | 400 | description={__("View complete customer information", "yatra")} |
| 406 | 401 | actions={ |
| 407 | 402 | <div className="flex gap-2"> |
| 408 | - <ConditionalRender capability="yatra_edit_bookings"> | |
| 403 | + <ConditionalRender capability="yatra_edit_customers"> | |
| 409 | 404 | <Button onClick={handleEdit} className="flex items-center gap-2"> |
| 410 | 405 | <Edit className="w-4 h-4" /> |
| 411 | 406 | {__("Edit Customer", "yatra")} |
| 412 | 407 | </Button> |
| @@ -422,12 +417,17 @@ | ||
| 422 | 417 | </div> |
| 423 | 418 | } |
| 424 | 419 | /> |
| 425 | 420 | |
| 426 | - <ConditionalRender capability="yatra_view_bookings"> | |
| 421 | + <ConditionalRender capability="yatra_view_customers"> | |
| 427 | 422 | <div className="grid grid-cols-1 lg:grid-cols-3 gap-3"> |
| 428 | 423 | {/* Main Content */} |
| 429 | 424 | <div className="lg:col-span-2 space-y-3"> |
| 425 | + {/* AI Customer Summary — operator-triggered 3-line | |
| 426 | + snapshot. Self-gates on AI eligibility + module | |
| 427 | + state, so renders nothing in non-eligible tiers. */} | |
| 428 | + {customer?.id && <CustomerSummaryCard customerId={customer.id} />} | |
| 429 | + | |
| 430 | 430 | {/* Customer Overview */} |
| 431 | 431 | <Card> |
| 432 | 432 | <CardHeader className="pb-2"> |
| 433 | 433 | <div className="flex items-center justify-between"> |