@burdenoff/microfe-kadaikodi 2026.802.1 → 2026.830.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.
- package/dist/kadaikodi/KadaikodiRoot.d.ts.map +1 -1
- package/dist/kadaikodi/KadaikodiRoot.js +69 -72
- package/dist/kadaikodi/KadaikodiRoot.js.map +1 -1
- package/dist/kadaikodi/components/InvestmentCard.d.ts.map +1 -1
- package/dist/kadaikodi/components/InvestmentCard.js +58 -54
- package/dist/kadaikodi/components/InvestmentCard.js.map +1 -1
- package/dist/kadaikodi/components/OrderCard.d.ts.map +1 -1
- package/dist/kadaikodi/components/StatusBadge.d.ts.map +1 -1
- package/dist/kadaikodi/components/StatusBadge.js +25 -14
- package/dist/kadaikodi/components/StatusBadge.js.map +1 -1
- package/dist/kadaikodi/hooks/useKadaikodiApi.d.ts +24 -0
- package/dist/kadaikodi/hooks/useKadaikodiApi.d.ts.map +1 -1
- package/dist/kadaikodi/hooks/useKadaikodiApi.js +177 -132
- package/dist/kadaikodi/hooks/useKadaikodiApi.js.map +1 -1
- package/dist/kadaikodi/pages/HomePage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/HomePage.js +284 -282
- package/dist/kadaikodi/pages/HomePage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.d.ts +7 -2
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.js +319 -228
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminOrdersPage.js +1 -1
- package/dist/kadaikodi/pages/admin/AdminOrdersPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/CartManagementPage.d.ts +10 -4
- package/dist/kadaikodi/pages/admin/CartManagementPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/admin/CartManagementPage.js +320 -279
- package/dist/kadaikodi/pages/admin/CartManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/MerchantOnboardingPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/MerchantOnboardingPage.js +365 -292
- package/dist/kadaikodi/pages/cart-owner/MerchantOnboardingPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.d.ts +7 -2
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.js +300 -158
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/common/SettingsPage.js +286 -286
- package/dist/kadaikodi/pages/common/SettingsPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDetailPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDetailPage.js +3 -3
- package/dist/kadaikodi/pages/customer/CartDetailPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.d.ts +13 -3
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.js +270 -220
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CustomerDashboard.js +97 -97
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.js +1 -1
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.d.ts +5 -3
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.js +286 -199
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.js.map +1 -1
- package/dist/kadaikodi/types/index.d.ts +46 -2
- package/dist/kadaikodi/types/index.d.ts.map +1 -1
- package/dist/shared/hooks/useTr.d.ts +2 -0
- package/dist/shared/hooks/useTr.d.ts.map +1 -0
- package/dist/shared/hooks/useTr.js +14 -0
- package/dist/shared/hooks/useTr.js.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CartDetailPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/customer/CartDetailPage.tsx"],"sourcesContent":["/**\n * Cart Detail Page\n * @module kadaikodi/pages/customer\n *\n * Full detail view with shopping cart sidebar (Your Order with +/- controls,\n * remove, total, Proceed to Checkout), product customization modal,\n * category-grouped product listing, search, category filter,\n * investment opportunity card, scheduled stops, direct service card,\n * veg/vegan icons, availability badges, calories, original price\n * strikethrough, and cart closed warning banner.\n */\n\nimport { useState, useMemo, useEffect } from 'react';\nimport { useParams } from 'react-router';\nimport {\n ArrowLeft,\n Star,\n MapPin,\n Clock,\n CheckCircle2,\n ShoppingCart,\n Search,\n Leaf,\n Minus,\n Plus,\n X,\n TrendingUp,\n Home,\n Calendar,\n Flame,\n Heart,\n MessageSquare,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { RatingStars, SegmentedTabs } from '../../components/viz';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport { useKadaikodiStore, type PersistedCartItem } from '../../store';\nimport {\n useProviders,\n useOfferings,\n useInvestmentOpportunities,\n useReviews,\n} from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport {\n formatCurrency,\n formatDistance,\n formatDuration,\n formatRelativeTime,\n} from '../../utils/formatters';\nimport type { CartMenuItem, InvestmentOpportunity } from '../../types';\nimport { ProviderImage, useFavorites } from './shared';\n\ntype DetailTab = 'menu' | 'reviews' | 'info';\n\n// The cart line-item shape is persisted (BOFF-4301) — see PersistedCartItem\n// in ../../store/kadaikodiStore.ts. Aliased locally so this file doesn't\n// need to change if callers keep importing `CartItem` from here elsewhere.\ntype CartItem = PersistedCartItem;\n\ninterface CustomizationState {\n product: CartMenuItem;\n quantity: number;\n specialInstructions: string;\n}\n\nconst DAY_LABELS: Record<string, string> = {\n monday: 'Mon',\n tuesday: 'Tue',\n wednesday: 'Wed',\n thursday: 'Thu',\n friday: 'Fri',\n saturday: 'Sat',\n sunday: 'Sun',\n};\n\nexport function CartDetailPage() {\n const { cartId } = useParams<{ cartId: string }>();\n const { navigateTo } = useKadaikodi();\n\n const { data: providers = [], isLoading: isLoadingProviders } = useProviders();\n const { data: offerings = [], isLoading: isLoadingOfferings } = useOfferings(cartId);\n const { data: investments = [], isLoading: isLoadingInvestments } = useInvestmentOpportunities();\n\n const { data: reviews = [] } = useReviews(cartId ?? '');\n const favorites = useFavorites();\n\n const cart = useMemo(() => providers.find((p) => p.id === cartId), [providers, cartId]);\n const investment = useMemo(\n () => investments.find((i) => i.cartId === cartId),\n [investments, cartId]\n );\n\n const [activeTab, setActiveTab] = useState<DetailTab>('menu');\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedCategory, setSelectedCategory] = useState('');\n\n // Offline-cached active cart (BOFF-4301) — persisted per cart/provider so\n // it survives an app kill, backgrounding, or a reload while offline. Was\n // previously plain `useState`, which silently discarded the customer's\n // in-progress order the moment the tab/app closed.\n const cartsByProviderId = useKadaikodiStore((s) => s.cartsByProviderId);\n const setCartItemsForProvider = useKadaikodiStore((s) => s.setCartItems);\n const cartItems = useMemo<CartItem[]>(\n () => (cartId ? (cartsByProviderId[cartId] ?? []) : []),\n [cartsByProviderId, cartId]\n );\n\n const [showCustomization, setShowCustomization] = useState(false);\n const [customization, setCustomization] = useState<CustomizationState | null>(null);\n\n const menuItems = useMemo(\n () =>\n offerings.map((o) => ({\n id: o.id,\n name: o.name,\n price: o.price,\n description: o.description ?? '',\n image: o.media?.[0] ?? '',\n category: o.category,\n isVeg: true,\n duration: o.durationMinutes ?? undefined,\n serviceType: (o.serviceType ?? undefined) as CartMenuItem['serviceType'],\n })),\n [offerings]\n );\n\n const menuCategories = useMemo(() => {\n const cats = [...new Set(menuItems.map((item) => item.category))];\n return cats;\n }, [menuItems]);\n\n const filteredMenu = useMemo(() => {\n let items = menuItems;\n\n if (selectedCategory) {\n items = items.filter((item) => item.category === selectedCategory);\n }\n\n if (searchQuery.trim()) {\n const q = searchQuery.toLowerCase();\n items = items.filter(\n (item) => item.name.toLowerCase().includes(q) || item.description.toLowerCase().includes(q)\n );\n }\n\n return items;\n }, [menuItems, selectedCategory, searchQuery]);\n\n const isLoading = isLoadingProviders || isLoadingOfferings || isLoadingInvestments;\n\n const groupedMenu = useMemo(() => {\n const groups: Record<string, CartMenuItem[]> = {};\n filteredMenu.forEach((item) => {\n if (!groups[item.category]) groups[item.category] = [];\n groups[item.category].push(item);\n });\n return groups;\n }, [filteredMenu]);\n\n // Cart operations — write through to the persisted, per-provider store\n // (BOFF-4301) so the active cart survives an app kill/reload offline.\n const addToCart = (product: CartMenuItem, qty: number = 1, instructions?: string) => {\n if (!cartId) return;\n const existing = cartItems.find((item) => item.productId === product.id);\n const next = existing\n ? cartItems.map((item) =>\n item.productId === product.id ? { ...item, quantity: item.quantity + qty } : item\n )\n : [\n ...cartItems,\n {\n id: `cart-${Date.now()}`,\n productId: product.id,\n name: product.name,\n price: product.price,\n quantity: qty,\n specialInstructions: instructions,\n },\n ];\n setCartItemsForProvider(cartId, next);\n };\n\n const updateQuantity = (productId: string, delta: number) => {\n if (!cartId) return;\n const next = cartItems\n .map((item) =>\n item.productId === productId\n ? { ...item, quantity: Math.max(0, item.quantity + delta) }\n : item\n )\n .filter((item) => item.quantity > 0);\n setCartItemsForProvider(cartId, next);\n };\n\n const removeFromCart = (productId: string) => {\n if (!cartId) return;\n setCartItemsForProvider(\n cartId,\n cartItems.filter((item) => item.productId !== productId)\n );\n };\n\n const getItemQuantity = (productId: string) => {\n return cartItems.find((item) => item.productId === productId)?.quantity ?? 0;\n };\n\n const cartTotal = cartItems.reduce((sum, item) => sum + item.price * item.quantity, 0);\n const cartCount = cartItems.reduce((sum, item) => sum + item.quantity, 0);\n\n const handleAddToCart = (product: CartMenuItem) => {\n setCustomization({ product, quantity: 1, specialInstructions: '' });\n setShowCustomization(true);\n };\n\n const confirmAddToCart = () => {\n if (!customization) return;\n addToCart(customization.product, customization.quantity, customization.specialInstructions);\n setShowCustomization(false);\n setCustomization(null);\n alert(`${customization.product.name} added to cart`);\n };\n\n if (!cart) {\n return (\n <PageLayout title=\"Cart Not Found\">\n <EmptyState\n icon={<ShoppingCart className=\"h-12 w-12\" />}\n title=\"Cart not found\"\n description={`No cart found with ID \"${cartId}\".`}\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/discover')}\n className=\"rounded-lg bg-foreground px-4 py-2 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n Browse Carts\n </button>\n }\n />\n </PageLayout>\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/discover')}\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 className=\"truncate\">{cart.name}</span>\n {cart.isVerified && <CheckCircle2 className=\"h-5 w-5 text-text-primary shrink-0\" />}\n </div>\n }\n description={cart.category}\n >\n <PagePurpose className=\"mb-4\">\n Everything about this cart in one place — browse its menu, check ratings, location and\n opening hours, then add items to your order. When you're ready, head to checkout to confirm\n and pay.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"kadaikodi-cart-detail\"\n className=\"mb-4\"\n steps={[\n {\n id: 'menu',\n label: 'Browse the menu and add items',\n description: 'Tap items below to build your order.',\n },\n {\n id: 'reviews',\n label: 'Read what others say',\n description: 'Check ratings and reviews before you order.',\n onClick: () => navigateTo('/customer/reviews'),\n },\n {\n id: 'checkout',\n label: 'Proceed to checkout',\n description: 'Review your order, choose payment and confirm.',\n onClick: () => navigateTo('/customer/checkout'),\n },\n ]}\n />\n\n {/* Hero Image — the one emphasis zone */}\n <GlassCard treatment=\"glass\" glow className=\"relative h-48 overflow-hidden p-0\">\n <ProviderImage src={cart.image} alt={cart.name} seed={cart.name} />\n <button\n type=\"button\"\n onClick={() => favorites.toggle(cart.id)}\n aria-pressed={favorites.has(cart.id)}\n aria-label={favorites.has(cart.id) ? 'Remove from favorites' : 'Save to favorites'}\n className=\"absolute top-3 right-3 flex h-9 w-9 items-center justify-center rounded-full bg-bg-surface/80 backdrop-blur-sm text-text-secondary hover:text-status-error-text transition-colors\"\n >\n <Heart\n className={cn(\n 'h-4.5 w-4.5',\n favorites.has(cart.id) && 'fill-status-error-text text-status-error-text'\n )}\n />\n </button>\n <div className=\"absolute bottom-0 inset-x-0 bg-gradient-to-t from-black/60 to-transparent p-4\">\n <div className=\"flex items-center gap-3\">\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium',\n cart.isOpen\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-status-error-bg-subtle text-status-error-text'\n )}\n >\n {cart.isOpen ? 'Open Now' : 'Closed'}\n </span>\n <div className=\"flex items-center gap-1.5 text-white text-sm\">\n <RatingStars value={cart.rating} size={14} />\n <span className=\"font-medium\">{cart.rating}</span>\n <span className=\"text-white/70\">({cart.totalRatings} reviews)</span>\n </div>\n </div>\n </div>\n </GlassCard>\n\n {/* Cart Closed Warning */}\n {!cart.isOpen && (\n <div className=\"mt-4 rounded-lg border border-status-warning-text/30 bg-status-warning-bg-subtle p-3\">\n <p className=\"text-sm text-status-warning-text\">\n <strong>This cart is currently closed.</strong> You can browse the offerings but orders\n are not being accepted.\n </p>\n </div>\n )}\n\n {/* Menu / Reviews / Info tabs */}\n <div className=\"mt-5\">\n <SegmentedTabs\n aria-label=\"Cart sections\"\n variant=\"underline\"\n tabs={[\n { id: 'menu', label: 'Menu' },\n { id: 'reviews', label: 'Reviews', count: reviews.length || undefined },\n { id: 'info', label: 'Info' },\n ]}\n value={activeTab}\n onChange={(id) => setActiveTab(id as DetailTab)}\n />\n </div>\n\n {/* ── Info tab ─────────────────────────────────────────── */}\n {activeTab === 'info' && (\n <>\n <div className=\"mt-4 grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3\">\n <div className=\"flex items-center gap-2 text-text-secondary text-xs mb-1\">\n <MapPin className=\"h-3.5 w-3.5\" />\n <span className=\"font-medium uppercase tracking-wider\">Location</span>\n </div>\n <p className=\"text-sm text-text-primary\">{cart.location.address}</p>\n {cart.distance != null && (\n <p className=\"text-xs text-text-secondary\">{formatDistance(cart.distance)} away</p>\n )}\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3\">\n <div className=\"flex items-center gap-2 text-text-secondary text-xs mb-1\">\n <Clock className=\"h-3.5 w-3.5\" />\n <span className=\"font-medium uppercase tracking-wider\">Estimated Time</span>\n </div>\n <p className=\"text-sm text-text-primary\">\n {cart.estimatedTime != null ? formatDuration(cart.estimatedTime) : '—'}\n </p>\n {cart.averageOrderValue && (\n <p className=\"text-xs text-text-secondary\">\n Avg {formatCurrency(cart.averageOrderValue, { minimumFractionDigits: 0 })}\n </p>\n )}\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3\">\n <div className=\"flex items-center gap-2 text-text-secondary text-xs mb-1\">\n <Star className=\"h-3.5 w-3.5\" />\n <span className=\"font-medium uppercase tracking-wider\">Rating</span>\n </div>\n <p className=\"text-sm text-text-primary\">{cart.rating} / 5.0</p>\n <p className=\"text-xs text-text-secondary\">{cart.totalRatings} reviews</p>\n </div>\n </div>\n\n {/* Business Hours */}\n {cart.businessHours && Object.keys(cart.businessHours).length > 0 && (\n <section className=\"mt-6\">\n <h2 className=\"text-base font-semibold text-text-primary mb-2\">Operating Hours</h2>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface overflow-hidden\">\n {Object.entries(cart.businessHours).map(([day, hours]) => (\n <div\n key={day}\n className=\"flex items-center justify-between px-4 py-2 border-b border-border-subtle last:border-b-0\"\n >\n <span className=\"text-sm font-medium text-text-primary capitalize\">{day}</span>\n {hours.isOpen ? (\n <span className=\"text-sm text-text-secondary\">\n {hours.open} - {hours.close}\n </span>\n ) : (\n <span className=\"text-sm text-status-error-text\">Closed</span>\n )}\n </div>\n ))}\n </div>\n </section>\n )}\n </>\n )}\n\n {/* ── Reviews tab ──────────────────────────────────────── */}\n {activeTab === 'reviews' && (\n <div className=\"mt-4 space-y-4\">\n {/* Aggregate */}\n <div className=\"flex flex-wrap items-center gap-4 rounded-xl border border-border-subtle bg-bg-surface p-5\">\n <div className=\"text-center\">\n <p className=\"text-4xl font-bold leading-none text-text-primary\">\n {cart.rating.toFixed(1)}\n </p>\n <div className=\"mt-1.5 flex justify-center\">\n <RatingStars value={cart.rating} size={16} />\n </div>\n <p className=\"mt-1 text-xs text-text-secondary\">{cart.totalRatings} ratings</p>\n </div>\n <div className=\"flex-1 min-w-[180px] space-y-1.5\">\n {[5, 4, 3, 2, 1].map((star) => {\n const count = reviews.filter((r) => Math.round(r.rating) === star).length;\n const pct = reviews.length ? (count / reviews.length) * 100 : 0;\n return (\n <div key={star} className=\"flex items-center gap-2 text-xs\">\n <span className=\"flex w-6 items-center gap-0.5 text-text-secondary\">\n {star}\n <Star className=\"h-3 w-3 fill-status-warning-text text-status-warning-text\" />\n </span>\n <div className=\"h-2 flex-1 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-accent-primary transition-all\"\n style={{ width: `${pct}%` }}\n />\n </div>\n <span className=\"w-6 text-right tabular-nums text-text-muted\">{count}</span>\n </div>\n );\n })}\n </div>\n </div>\n\n {/* Review list */}\n {reviews.length === 0 ? (\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-8 text-center\">\n <MessageSquare className=\"mx-auto h-10 w-10 text-text-secondary/40\" />\n <p className=\"mt-3 text-sm text-text-secondary\">\n No written reviews yet. Order and be the first to review this cart.\n </p>\n </div>\n ) : (\n <div className=\"space-y-3\">\n {reviews.map((review) => (\n <div\n key={review.id}\n className=\"rounded-xl border border-border-subtle bg-bg-surface p-4\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <RatingStars value={review.rating} size={14} showValue />\n <span className=\"text-xs text-text-muted\">\n {formatRelativeTime(review.createdAt)}\n </span>\n </div>\n {review.review && (\n <p className=\"mt-2 text-sm text-text-primary leading-relaxed\">\n {review.review}\n </p>\n )}\n {review.response && (\n <div className=\"mt-3 rounded-lg border-l-2 border-accent-primary bg-[var(--color-accent-soft)] p-3\">\n <p className=\"mb-1 text-xs font-medium text-text-primary\">Owner response</p>\n <p className=\"text-xs text-text-primary leading-relaxed\">{review.response}</p>\n </div>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n )}\n\n {/* ── Menu tab: Menu + Sidebar ─────────────────────────── */}\n {activeTab === 'menu' && (\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Menu Section */}\n <div className=\"lg:col-span-2\">\n {/* Search and Filter */}\n <div className=\"flex flex-col gap-3 sm:flex-row mb-4\">\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"text\"\n placeholder=\"Search offerings...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-10 pr-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <select\n value={selectedCategory}\n onChange={(e) => setSelectedCategory(e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Categories</option>\n {menuCategories.map((cat) => (\n <option key={cat} value={cat}>\n {cat}\n </option>\n ))}\n </select>\n </div>\n\n {/* Menu Items */}\n <h2 className=\"text-lg font-semibold text-text-primary mb-3\">\n Menu & Services ({filteredMenu.length})\n </h2>\n\n {filteredMenu.length === 0 ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-8 text-center\">\n <Search className=\"mx-auto h-10 w-10 text-text-secondary/50\" />\n <p className=\"mt-3 text-sm text-text-secondary\">No offerings found</p>\n </div>\n ) : (\n <div className=\"space-y-6\">\n {Object.entries(groupedMenu).map(([category, items]) => (\n <div key={category}>\n <h3 className=\"text-sm font-semibold text-text-primary mb-2 px-1\">\n {category}\n </h3>\n <div className=\"space-y-2\">\n {items.map((item) => {\n const qty = getItemQuantity(item.id);\n return (\n <div\n key={item.id}\n className=\"flex gap-4 rounded-lg border border-border-subtle bg-bg-surface p-4\"\n >\n <div className=\"h-20 w-20 shrink-0 rounded-md bg-bg-sunken overflow-hidden\">\n <ProviderImage src={item.image} alt={item.name} seed={item.name} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-start justify-between gap-2\">\n <div>\n <div className=\"flex items-center gap-2\">\n <h4 className=\"text-sm font-semibold text-text-primary\">\n {item.name}\n </h4>\n {item.isVeg && (\n <Leaf className=\"h-3.5 w-3.5 text-status-success-text\" />\n )}\n </div>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {item.category}\n </p>\n </div>\n <span className=\"text-sm font-bold text-text-primary whitespace-nowrap\">\n {formatCurrency(item.price, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <p className=\"mt-1 text-xs text-text-secondary line-clamp-2\">\n {item.description}\n </p>\n <div className=\"mt-2 flex flex-wrap items-center gap-2 text-[10px] text-text-secondary\">\n {item.duration != null && item.duration > 0 && (\n <span className=\"flex items-center gap-0.5\">\n <Clock className=\"h-3 w-3\" />\n {formatDuration(item.duration)}\n </span>\n )}\n {item.serviceType && (\n <span className=\"rounded bg-bg-sunken px-1.5 py-0.5 capitalize\">\n {item.serviceType}\n </span>\n )}\n {item.spiceLevel && (\n <span className=\"flex items-center gap-0.5 rounded bg-bg-sunken px-1.5 py-0.5 capitalize\">\n <Flame className=\"h-3 w-3\" />\n {item.spiceLevel}\n </span>\n )}\n </div>\n {/* Add/Quantity Controls */}\n <div className=\"mt-2 flex justify-end\">\n {qty > 0 ? (\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => updateQuantity(item.id, -1)}\n className=\"flex h-7 w-7 items-center justify-center rounded-full bg-bg-sunken text-text-primary hover:bg-accent\"\n >\n <Minus className=\"h-3.5 w-3.5\" />\n </button>\n <span className=\"min-w-[2ch] text-center text-sm font-medium text-text-primary\">\n {qty}\n </span>\n <button\n type=\"button\"\n onClick={() => updateQuantity(item.id, 1)}\n className=\"flex h-7 w-7 items-center justify-center rounded-full bg-foreground text-background hover:opacity-90\"\n >\n <Plus className=\"h-3.5 w-3.5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => removeFromCart(item.id)}\n className=\"ml-1 flex h-7 w-7 items-center justify-center rounded-full text-status-error-text hover:bg-status-error-bg/10\"\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n ) : (\n <button\n type=\"button\"\n disabled={!cart.isOpen}\n onClick={() => handleAddToCart(item)}\n className={cn(\n 'rounded-lg px-4 py-1.5 text-xs font-medium transition-opacity',\n cart.isOpen\n ? 'bg-foreground text-background hover:opacity-90'\n : 'bg-bg-sunken text-text-secondary cursor-not-allowed'\n )}\n >\n Add\n </button>\n )}\n </div>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-4\">\n {/* Shopping Cart */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 lg:sticky lg:top-6\">\n <h3 className=\"text-base font-semibold text-text-primary mb-3 flex items-center gap-2\">\n <ShoppingCart className=\"h-4 w-4\" />\n Your Order\n </h3>\n {cartItems.length === 0 ? (\n <div className=\"py-6 text-center\">\n <ShoppingCart className=\"mx-auto h-8 w-8 text-text-secondary/40\" />\n <p className=\"mt-2 text-sm text-text-secondary\">Your cart is empty</p>\n </div>\n ) : (\n <>\n <div className=\"space-y-2 max-h-64 overflow-y-auto mb-3\">\n {cartItems.map((item) => (\n <div key={item.id} className=\"flex items-center justify-between gap-2\">\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">\n {item.name}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {formatCurrency(item.price, { minimumFractionDigits: 0 })} x{' '}\n {item.quantity}\n </p>\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => updateQuantity(item.productId, -1)}\n className=\"flex h-6 w-6 items-center justify-center rounded bg-bg-sunken text-text-primary text-xs\"\n >\n -\n </button>\n <span className=\"min-w-[2ch] text-center text-xs font-medium\">\n {item.quantity}\n </span>\n <button\n type=\"button\"\n onClick={() => updateQuantity(item.productId, 1)}\n className=\"flex h-6 w-6 items-center justify-center rounded bg-bg-sunken text-text-primary text-xs\"\n >\n +\n </button>\n <button\n type=\"button\"\n onClick={() => removeFromCart(item.productId)}\n className=\"ml-1 text-status-error-text hover:text-status-error-text/80\"\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n </div>\n ))}\n </div>\n <div className=\"border-t border-border-subtle pt-3\">\n <div className=\"flex justify-between items-center mb-3\">\n <span className=\"text-sm font-semibold text-text-primary\">\n Total: {formatCurrency(cartTotal, { minimumFractionDigits: 0 })}\n </span>\n <span className=\"text-xs text-text-secondary\">{cartCount} items</span>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/checkout')}\n className=\"w-full rounded-lg bg-foreground py-2.5 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n Proceed to Checkout\n </button>\n </div>\n </>\n )}\n </div>\n\n {/* Direct Service Card */}\n {cart.serviceTypes?.includes('direct_service') && (\n <div className=\"rounded-lg border border-accent-purple/30 bg-accent-purple-subtle p-4\">\n <h3 className=\"text-sm font-semibold text-text-primary flex items-center gap-2 mb-2\">\n <Home className=\"h-4 w-4 text-text-primary\" />\n Direct Service\n </h3>\n <p className=\"text-xs text-text-secondary mb-3\">Cart comes to your location!</p>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/customer/cart/${cart.id}/direct-service`)}\n className=\"w-full rounded-lg bg-accent-purple py-2 text-xs font-medium text-white hover:bg-accent-purple transition-colors\"\n >\n Book Direct Service\n </button>\n </div>\n )}\n\n {/* Scheduled Stops */}\n {cart.serviceTypes?.includes('appointment') && (\n <div className=\"rounded-lg border border-border-focus/30 bg-[var(--color-accent-soft)] p-4\">\n <h3 className=\"text-sm font-semibold text-text-primary flex items-center gap-2 mb-2\">\n <Calendar className=\"h-4 w-4 text-text-primary\" />\n Appointments Available\n </h3>\n <p className=\"text-xs text-text-secondary\">\n This service provider accepts appointments. Contact them to schedule.\n </p>\n </div>\n )}\n\n {/* Investment Opportunity */}\n {investment && (\n <div className=\"rounded-lg border border-status-success-text/30 bg-status-success-bg-subtle p-4\">\n <h3 className=\"text-sm font-semibold text-text-primary flex items-center gap-2 mb-2\">\n <TrendingUp className=\"h-4 w-4 text-status-success-text\" />\n Investment Opportunity\n </h3>\n <p className=\"text-xs text-text-secondary mb-2\">{investment.description}</p>\n <div className=\"space-y-1 text-xs text-text-secondary mb-3\">\n <p>\n Target: {formatCurrency(investment.targetAmount, { minimumFractionDigits: 0 })}\n </p>\n <p>\n Raised: {formatCurrency(investment.raisedAmount, { minimumFractionDigits: 0 })}\n </p>\n <p>Expected Returns: {investment.expectedReturns}%</p>\n <p>\n Min Investment:{' '}\n {formatCurrency(investment.minimumInvestment, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/investor/opportunity/${investment.id}`)}\n className=\"w-full rounded-lg bg-status-success-text py-2 text-xs font-medium text-white hover:bg-status-success-text transition-colors\"\n >\n Fund This Business\n </button>\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* Sticky mobile cart bar (mockup: \"View Cart · N items · ₹X\") */}\n {activeTab === 'menu' && cartCount > 0 && (\n <>\n <div className=\"h-20 lg:hidden\" aria-hidden=\"true\" />\n <div className=\"fixed inset-x-0 bottom-0 z-40 border-t border-border-subtle bg-bg-surface/95 p-3 backdrop-blur-sm shadow-elevation-2 lg:hidden\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/checkout')}\n className=\"flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg py-3 text-sm font-semibold text-action-primary-text hover:bg-action-primary-bg-hover transition-colors\"\n >\n <ShoppingCart className=\"h-4 w-4\" />\n View Cart · {cartCount} {cartCount === 1 ? 'item' : 'items'} ·{' '}\n {formatCurrency(cartTotal, { minimumFractionDigits: 0 })}\n </button>\n </div>\n </>\n )}\n\n {/* Customization Modal */}\n {showCustomization && customization && (\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 max-h-[90vh] overflow-y-auto rounded-lg border border-border-subtle bg-bg-surface\">\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\">\n {customization.product.name}\n </h3>\n <button\n type=\"button\"\n onClick={() => {\n setShowCustomization(false);\n setCustomization(null);\n }}\n className=\"rounded-md p-1 text-text-secondary hover:text-text-primary\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n\n <p className=\"text-sm text-text-secondary mb-4\">\n {customization.product.description}\n </p>\n <p className=\"text-lg font-bold text-text-primary mb-4\">\n {formatCurrency(customization.product.price, { minimumFractionDigits: 0 })}\n </p>\n\n {/* Quantity */}\n <div className=\"mb-4\">\n <label className=\"block text-sm font-medium text-text-primary mb-2\">Quantity</label>\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() =>\n setCustomization((prev) =>\n prev ? { ...prev, quantity: Math.max(1, prev.quantity - 1) } : prev\n )\n }\n className=\"flex h-8 w-8 items-center justify-center rounded-full bg-bg-sunken text-text-primary\"\n >\n <Minus className=\"h-4 w-4\" />\n </button>\n <span className=\"min-w-[2ch] text-center font-medium text-text-primary\">\n {customization.quantity}\n </span>\n <button\n type=\"button\"\n onClick={() =>\n setCustomization((prev) =>\n prev ? { ...prev, quantity: prev.quantity + 1 } : prev\n )\n }\n className=\"flex h-8 w-8 items-center justify-center rounded-full bg-bg-sunken text-text-primary\"\n >\n <Plus className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n\n {/* Special Instructions */}\n <div className=\"mb-4\">\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n Special Instructions\n </label>\n <textarea\n value={customization.specialInstructions}\n onChange={(e) =>\n setCustomization((prev) =>\n prev ? { ...prev, specialInstructions: e.target.value } : prev\n )\n }\n placeholder=\"Any special requests...\"\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface p-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n rows={3}\n />\n </div>\n\n <button\n type=\"button\"\n onClick={confirmAddToCart}\n className=\"w-full rounded-lg bg-foreground py-2.5 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n Add to Cart -{' '}\n {formatCurrency(customization.product.price * customization.quantity, {\n minimumFractionDigits: 0,\n })}\n </button>\n </div>\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CartDetailPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/customer/CartDetailPage.tsx"],"sourcesContent":["/**\n * Cart Detail Page\n * @module kadaikodi/pages/customer\n *\n * Full detail view with shopping cart sidebar (Your Order with +/- controls,\n * remove, total, Proceed to Checkout), product customization modal,\n * category-grouped product listing, search, category filter,\n * investment opportunity card, scheduled stops, direct service card,\n * veg/vegan icons, availability badges, calories, original price\n * strikethrough, and cart closed warning banner.\n */\n\nimport { useState, useMemo, useEffect } from 'react';\nimport { useParams } from 'react-router';\nimport {\n ArrowLeft,\n Star,\n MapPin,\n Clock,\n CheckCircle2,\n ShoppingCart,\n Search,\n Leaf,\n Minus,\n Plus,\n X,\n TrendingUp,\n Home,\n Calendar,\n Flame,\n Heart,\n MessageSquare,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { RatingStars, SegmentedTabs } from '../../components/viz';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport { useKadaikodiStore, type PersistedCartItem } from '../../store';\nimport {\n useProviders,\n useOfferings,\n useInvestmentOpportunities,\n useReviews,\n} from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport {\n formatCurrency,\n formatDistance,\n formatDuration,\n formatRelativeTime,\n} from '../../utils/formatters';\nimport type { CartMenuItem, InvestmentOpportunity } from '../../types';\nimport { ProviderImage, useFavorites } from './shared';\n\ntype DetailTab = 'menu' | 'reviews' | 'info';\n\n// The cart line-item shape is persisted (BOFF-4301) — see PersistedCartItem\n// in ../../store/kadaikodiStore.ts. Aliased locally so this file doesn't\n// need to change if callers keep importing `CartItem` from here elsewhere.\ntype CartItem = PersistedCartItem;\n\ninterface CustomizationState {\n product: CartMenuItem;\n quantity: number;\n specialInstructions: string;\n}\n\nconst DAY_LABELS: Record<string, string> = {\n monday: 'Mon',\n tuesday: 'Tue',\n wednesday: 'Wed',\n thursday: 'Thu',\n friday: 'Fri',\n saturday: 'Sat',\n sunday: 'Sun',\n};\n\nexport function CartDetailPage() {\n const { cartId } = useParams<{ cartId: string }>();\n const { navigateTo } = useKadaikodi();\n\n const { data: providers = [], isLoading: isLoadingProviders } = useProviders();\n const { data: offerings = [], isLoading: isLoadingOfferings } = useOfferings(cartId);\n const { data: investments = [], isLoading: isLoadingInvestments } = useInvestmentOpportunities();\n\n const { data: reviews = [] } = useReviews(cartId ?? '');\n const favorites = useFavorites();\n\n const cart = useMemo(() => providers.find((p) => p.id === cartId), [providers, cartId]);\n const investment = useMemo(\n () => investments.find((i) => i.cartId === cartId),\n [investments, cartId]\n );\n\n const [activeTab, setActiveTab] = useState<DetailTab>('menu');\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedCategory, setSelectedCategory] = useState('');\n\n // Offline-cached active cart (BOFF-4301) — persisted per cart/provider so\n // it survives an app kill, backgrounding, or a reload while offline. Was\n // previously plain `useState`, which silently discarded the customer's\n // in-progress order the moment the tab/app closed.\n const cartsByProviderId = useKadaikodiStore((s) => s.cartsByProviderId);\n const setCartItemsForProvider = useKadaikodiStore((s) => s.setCartItems);\n const cartItems = useMemo<CartItem[]>(\n () => (cartId ? (cartsByProviderId[cartId] ?? []) : []),\n [cartsByProviderId, cartId]\n );\n\n const [showCustomization, setShowCustomization] = useState(false);\n const [customization, setCustomization] = useState<CustomizationState | null>(null);\n\n const menuItems = useMemo(\n () =>\n offerings.map((o) => ({\n id: o.id,\n name: o.name,\n price: o.price,\n description: o.description ?? '',\n image: o.media?.[0] ?? '',\n category: o.category,\n isVeg: true,\n duration: o.durationMinutes ?? undefined,\n serviceType: (o.serviceType ?? undefined) as CartMenuItem['serviceType'],\n })),\n [offerings]\n );\n\n const menuCategories = useMemo(() => {\n const cats = [...new Set(menuItems.map((item) => item.category))];\n return cats;\n }, [menuItems]);\n\n const filteredMenu = useMemo(() => {\n let items = menuItems;\n\n if (selectedCategory) {\n items = items.filter((item) => item.category === selectedCategory);\n }\n\n if (searchQuery.trim()) {\n const q = searchQuery.toLowerCase();\n items = items.filter(\n (item) => item.name.toLowerCase().includes(q) || item.description.toLowerCase().includes(q)\n );\n }\n\n return items;\n }, [menuItems, selectedCategory, searchQuery]);\n\n const isLoading = isLoadingProviders || isLoadingOfferings || isLoadingInvestments;\n\n const groupedMenu = useMemo(() => {\n const groups: Record<string, CartMenuItem[]> = {};\n filteredMenu.forEach((item) => {\n if (!groups[item.category]) groups[item.category] = [];\n groups[item.category].push(item);\n });\n return groups;\n }, [filteredMenu]);\n\n // Cart operations — write through to the persisted, per-provider store\n // (BOFF-4301) so the active cart survives an app kill/reload offline.\n const addToCart = (product: CartMenuItem, qty: number = 1, instructions?: string) => {\n if (!cartId) return;\n const existing = cartItems.find((item) => item.productId === product.id);\n const next = existing\n ? cartItems.map((item) =>\n item.productId === product.id ? { ...item, quantity: item.quantity + qty } : item\n )\n : [\n ...cartItems,\n {\n id: `cart-${Date.now()}`,\n productId: product.id,\n name: product.name,\n price: product.price,\n quantity: qty,\n specialInstructions: instructions,\n },\n ];\n setCartItemsForProvider(cartId, next);\n };\n\n const updateQuantity = (productId: string, delta: number) => {\n if (!cartId) return;\n const next = cartItems\n .map((item) =>\n item.productId === productId\n ? { ...item, quantity: Math.max(0, item.quantity + delta) }\n : item\n )\n .filter((item) => item.quantity > 0);\n setCartItemsForProvider(cartId, next);\n };\n\n const removeFromCart = (productId: string) => {\n if (!cartId) return;\n setCartItemsForProvider(\n cartId,\n cartItems.filter((item) => item.productId !== productId)\n );\n };\n\n const getItemQuantity = (productId: string) => {\n return cartItems.find((item) => item.productId === productId)?.quantity ?? 0;\n };\n\n const cartTotal = cartItems.reduce((sum, item) => sum + item.price * item.quantity, 0);\n const cartCount = cartItems.reduce((sum, item) => sum + item.quantity, 0);\n\n const handleAddToCart = (product: CartMenuItem) => {\n setCustomization({ product, quantity: 1, specialInstructions: '' });\n setShowCustomization(true);\n };\n\n const confirmAddToCart = () => {\n if (!customization) return;\n addToCart(customization.product, customization.quantity, customization.specialInstructions);\n setShowCustomization(false);\n setCustomization(null);\n alert(`${customization.product.name} added to cart`);\n };\n\n if (!cart) {\n return (\n <PageLayout title=\"Cart Not Found\">\n <EmptyState\n icon={<ShoppingCart className=\"h-12 w-12\" />}\n title=\"Cart not found\"\n description={`No cart found with ID \"${cartId}\".`}\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/discover')}\n className=\"rounded-lg bg-foreground px-4 py-2 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n Browse Carts\n </button>\n }\n />\n </PageLayout>\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/discover')}\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 className=\"truncate\">{cart.name}</span>\n {cart.isVerified && <CheckCircle2 className=\"h-5 w-5 text-text-primary shrink-0\" />}\n </div>\n }\n description={cart.category}\n >\n <PagePurpose className=\"mb-4\">\n Everything about this cart in one place — browse its menu, check ratings, location and\n opening hours, then add items to your order. When you're ready, head to checkout to confirm\n and pay.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"kadaikodi-cart-detail\"\n className=\"mb-4\"\n steps={[\n {\n id: 'menu',\n label: 'Browse the menu and add items',\n description: 'Tap items below to build your order.',\n },\n {\n id: 'reviews',\n label: 'Read what others say',\n description: 'Check ratings and reviews before you order.',\n onClick: () => navigateTo('/customer/reviews'),\n },\n {\n id: 'checkout',\n label: 'Proceed to checkout',\n description: 'Review your order, choose payment and confirm.',\n onClick: () => navigateTo('/customer/checkout'),\n },\n ]}\n />\n\n {/* Hero Image — the one emphasis zone */}\n <GlassCard treatment=\"glass\" glow className=\"relative h-48 overflow-hidden p-0\">\n <ProviderImage src={cart.image} alt={cart.name} seed={cart.name} />\n <button\n type=\"button\"\n onClick={() => favorites.toggle(cart.id)}\n aria-pressed={favorites.has(cart.id)}\n aria-label={favorites.has(cart.id) ? 'Remove from favorites' : 'Save to favorites'}\n className=\"absolute top-3 right-3 flex h-9 w-9 items-center justify-center rounded-full bg-bg-surface/80 backdrop-blur-sm text-text-secondary hover:text-status-error-text transition-colors\"\n >\n <Heart\n className={cn(\n 'h-4.5 w-4.5',\n favorites.has(cart.id) && 'fill-status-error-text text-status-error-text'\n )}\n />\n </button>\n <div className=\"absolute bottom-0 inset-x-0 bg-gradient-to-t from-black/60 to-transparent p-4\">\n <div className=\"flex items-center gap-3\">\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium',\n cart.isOpen\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-status-error-bg-subtle text-status-error-text'\n )}\n >\n {cart.isOpen ? 'Open Now' : 'Closed'}\n </span>\n <div className=\"flex items-center gap-1.5 text-white text-sm\">\n <RatingStars value={cart.rating} size={14} />\n <span className=\"font-medium\">{cart.rating}</span>\n <span className=\"text-white/70\">({cart.totalRatings} reviews)</span>\n </div>\n </div>\n </div>\n </GlassCard>\n\n {/* Cart Closed Warning */}\n {!cart.isOpen && (\n <div className=\"mt-4 rounded-lg border border-status-warning-text/30 bg-status-warning-bg-subtle p-3\">\n <p className=\"text-sm text-status-warning-text\">\n <strong>This cart is currently closed.</strong> You can browse the offerings but orders\n are not being accepted.\n </p>\n </div>\n )}\n\n {/* Menu / Reviews / Info tabs */}\n <div className=\"mt-5\">\n <SegmentedTabs\n aria-label=\"Cart sections\"\n variant=\"underline\"\n tabs={[\n { id: 'menu', label: 'Menu' },\n { id: 'reviews', label: 'Reviews', count: reviews.length || undefined },\n { id: 'info', label: 'Info' },\n ]}\n value={activeTab}\n onChange={(id) => setActiveTab(id as DetailTab)}\n />\n </div>\n\n {/* ── Info tab ─────────────────────────────────────────── */}\n {activeTab === 'info' && (\n <>\n <div className=\"mt-4 grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3\">\n <div className=\"flex items-center gap-2 text-text-secondary text-xs mb-1\">\n <MapPin className=\"h-3.5 w-3.5\" />\n <span className=\"font-medium uppercase tracking-wider\">Location</span>\n </div>\n <p className=\"text-sm text-text-primary\">{cart.location.address}</p>\n {cart.distance != null && (\n <p className=\"text-xs text-text-secondary\">{formatDistance(cart.distance)} away</p>\n )}\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3\">\n <div className=\"flex items-center gap-2 text-text-secondary text-xs mb-1\">\n <Clock className=\"h-3.5 w-3.5\" />\n <span className=\"font-medium uppercase tracking-wider\">Estimated Time</span>\n </div>\n <p className=\"text-sm text-text-primary\">\n {cart.estimatedTime != null ? formatDuration(cart.estimatedTime) : '—'}\n </p>\n {cart.averageOrderValue && (\n <p className=\"text-xs text-text-secondary\">\n Avg {formatCurrency(cart.averageOrderValue, { minimumFractionDigits: 0 })}\n </p>\n )}\n </div>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3\">\n <div className=\"flex items-center gap-2 text-text-secondary text-xs mb-1\">\n <Star className=\"h-3.5 w-3.5\" />\n <span className=\"font-medium uppercase tracking-wider\">Rating</span>\n </div>\n <p className=\"text-sm text-text-primary\">{cart.rating} / 5.0</p>\n <p className=\"text-xs text-text-secondary\">{cart.totalRatings} reviews</p>\n </div>\n </div>\n\n {/* Business Hours */}\n {cart.businessHours && Object.keys(cart.businessHours).length > 0 && (\n <section className=\"mt-6\">\n <h2 className=\"text-base font-semibold text-text-primary mb-2\">Operating Hours</h2>\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface overflow-hidden\">\n {Object.entries(cart.businessHours).map(([day, hours]) => (\n <div\n key={day}\n className=\"flex items-center justify-between px-4 py-2 border-b border-border-subtle last:border-b-0\"\n >\n <span className=\"text-sm font-medium text-text-primary capitalize\">{day}</span>\n {hours.isOpen ? (\n <span className=\"text-sm text-text-secondary\">\n {hours.open} - {hours.close}\n </span>\n ) : (\n <span className=\"text-sm text-status-error-text\">Closed</span>\n )}\n </div>\n ))}\n </div>\n </section>\n )}\n </>\n )}\n\n {/* ── Reviews tab ──────────────────────────────────────── */}\n {activeTab === 'reviews' && (\n <div className=\"mt-4 space-y-4\">\n {/* Aggregate */}\n <div className=\"flex flex-wrap items-center gap-4 rounded-xl border border-border-subtle bg-bg-surface p-5\">\n <div className=\"text-center\">\n <p className=\"text-4xl font-bold leading-none text-text-primary\">\n {cart.rating.toFixed(1)}\n </p>\n <div className=\"mt-1.5 flex justify-center\">\n <RatingStars value={cart.rating} size={16} />\n </div>\n <p className=\"mt-1 text-xs text-text-secondary\">{cart.totalRatings} ratings</p>\n </div>\n <div className=\"flex-1 min-w-[180px] space-y-1.5\">\n {[5, 4, 3, 2, 1].map((star) => {\n const count = reviews.filter((r) => Math.round(r.rating) === star).length;\n const pct = reviews.length ? (count / reviews.length) * 100 : 0;\n return (\n <div key={star} className=\"flex items-center gap-2 text-xs\">\n <span className=\"flex w-6 items-center gap-0.5 text-text-secondary\">\n {star}\n <Star className=\"h-3 w-3 fill-status-warning-text text-status-warning-text\" />\n </span>\n <div className=\"h-2 flex-1 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-accent-primary transition-all\"\n style={{ width: `${pct}%` }}\n />\n </div>\n <span className=\"w-6 text-right tabular-nums text-text-muted\">{count}</span>\n </div>\n );\n })}\n </div>\n </div>\n\n {/* Review list */}\n {reviews.length === 0 ? (\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-8 text-center\">\n <MessageSquare className=\"mx-auto h-10 w-10 text-text-secondary/40\" />\n <p className=\"mt-3 text-sm text-text-secondary\">\n No written reviews yet. Order and be the first to review this cart.\n </p>\n </div>\n ) : (\n <div className=\"space-y-3\">\n {reviews.map((review) => (\n <div\n key={review.id}\n className=\"rounded-xl border border-border-subtle bg-bg-surface p-4\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <RatingStars value={review.rating} size={14} showValue />\n <span className=\"text-xs text-text-muted\">\n {formatRelativeTime(review.createdAt)}\n </span>\n </div>\n {review.review && (\n <p className=\"mt-2 text-sm text-text-primary leading-relaxed\">\n {review.review}\n </p>\n )}\n {review.response && (\n <div className=\"mt-3 rounded-lg border-l-2 border-accent-primary bg-[var(--color-accent-soft)] p-3\">\n <p className=\"mb-1 text-xs font-medium text-text-primary\">Owner response</p>\n <p className=\"text-xs text-text-primary leading-relaxed\">{review.response}</p>\n </div>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n )}\n\n {/* ── Menu tab: Menu + Sidebar ─────────────────────────── */}\n {activeTab === 'menu' && (\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Menu Section */}\n <div className=\"lg:col-span-2\">\n {/* Search and Filter */}\n <div className=\"flex flex-col gap-3 sm:flex-row mb-4\">\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"text\"\n placeholder=\"Search offerings...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-10 pr-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <select\n value={selectedCategory}\n onChange={(e) => setSelectedCategory(e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Categories</option>\n {menuCategories.map((cat) => (\n <option key={cat} value={cat}>\n {cat}\n </option>\n ))}\n </select>\n </div>\n\n {/* Menu Items */}\n <h2 className=\"text-lg font-semibold text-text-primary mb-3\">\n Menu & Services ({filteredMenu.length})\n </h2>\n\n {filteredMenu.length === 0 ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-8 text-center\">\n <Search className=\"mx-auto h-10 w-10 text-text-secondary/50\" />\n <p className=\"mt-3 text-sm text-text-secondary\">No offerings found</p>\n </div>\n ) : (\n <div className=\"space-y-6\">\n {Object.entries(groupedMenu).map(([category, items]) => (\n <div key={category}>\n <h3 className=\"text-sm font-semibold text-text-primary mb-2 px-1\">\n {category}\n </h3>\n <div className=\"space-y-2\">\n {items.map((item) => {\n const qty = getItemQuantity(item.id);\n return (\n <div\n key={item.id}\n className=\"flex gap-4 rounded-lg border border-border-subtle bg-bg-surface p-4\"\n >\n <div className=\"h-20 w-20 shrink-0 rounded-md bg-bg-sunken overflow-hidden\">\n <ProviderImage src={item.image} alt={item.name} seed={item.name} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-start justify-between gap-2\">\n <div>\n <div className=\"flex items-center gap-2\">\n <h4 className=\"text-sm font-semibold text-text-primary\">\n {item.name}\n </h4>\n {item.isVeg && (\n <Leaf className=\"h-3.5 w-3.5 text-status-success-text\" />\n )}\n </div>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {item.category}\n </p>\n </div>\n <span className=\"text-sm font-bold text-text-primary whitespace-nowrap\">\n {formatCurrency(item.price, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <p className=\"mt-1 text-xs text-text-secondary line-clamp-2\">\n {item.description}\n </p>\n <div className=\"mt-2 flex flex-wrap items-center gap-2 text-[10px] text-text-secondary\">\n {item.duration != null && item.duration > 0 && (\n <span className=\"flex items-center gap-0.5\">\n <Clock className=\"h-3 w-3\" />\n {formatDuration(item.duration)}\n </span>\n )}\n {item.serviceType && (\n <span className=\"rounded bg-bg-sunken px-1.5 py-0.5 capitalize\">\n {item.serviceType}\n </span>\n )}\n {item.spiceLevel && (\n <span className=\"flex items-center gap-0.5 rounded bg-bg-sunken px-1.5 py-0.5 capitalize\">\n <Flame className=\"h-3 w-3\" />\n {item.spiceLevel}\n </span>\n )}\n </div>\n {/* Add/Quantity Controls */}\n <div className=\"mt-2 flex justify-end\">\n {qty > 0 ? (\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => updateQuantity(item.id, -1)}\n className=\"flex h-7 w-7 items-center justify-center rounded-full bg-bg-sunken text-text-primary hover:bg-accent\"\n >\n <Minus className=\"h-3.5 w-3.5\" />\n </button>\n <span className=\"min-w-[2ch] text-center text-sm font-medium text-text-primary\">\n {qty}\n </span>\n <button\n type=\"button\"\n onClick={() => updateQuantity(item.id, 1)}\n className=\"flex h-7 w-7 items-center justify-center rounded-full bg-foreground text-background hover:opacity-90\"\n >\n <Plus className=\"h-3.5 w-3.5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => removeFromCart(item.id)}\n className=\"ml-1 flex h-7 w-7 items-center justify-center rounded-full text-status-error-text hover:bg-status-error-bg/10\"\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n ) : (\n <button\n type=\"button\"\n disabled={!cart.isOpen}\n onClick={() => handleAddToCart(item)}\n className={cn(\n 'rounded-lg px-4 py-1.5 text-xs font-medium transition-opacity',\n cart.isOpen\n ? 'bg-foreground text-background hover:opacity-90'\n : 'bg-bg-sunken text-text-secondary cursor-not-allowed'\n )}\n >\n Add\n </button>\n )}\n </div>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-4\">\n {/* Shopping Cart */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 lg:sticky lg:top-6\">\n <h3 className=\"text-base font-semibold text-text-primary mb-3 flex items-center gap-2\">\n <ShoppingCart className=\"h-4 w-4\" />\n Your Order\n </h3>\n {cartItems.length === 0 ? (\n <div className=\"py-6 text-center\">\n <ShoppingCart className=\"mx-auto h-8 w-8 text-text-secondary/40\" />\n <p className=\"mt-2 text-sm text-text-secondary\">Your cart is empty</p>\n </div>\n ) : (\n <>\n <div className=\"space-y-2 max-h-64 overflow-y-auto mb-3\">\n {cartItems.map((item) => (\n <div key={item.id} className=\"flex items-center justify-between gap-2\">\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">\n {item.name}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {formatCurrency(item.price, { minimumFractionDigits: 0 })} x{' '}\n {item.quantity}\n </p>\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => updateQuantity(item.productId, -1)}\n className=\"flex h-6 w-6 items-center justify-center rounded bg-bg-sunken text-text-primary text-xs\"\n >\n -\n </button>\n <span className=\"min-w-[2ch] text-center text-xs font-medium\">\n {item.quantity}\n </span>\n <button\n type=\"button\"\n onClick={() => updateQuantity(item.productId, 1)}\n className=\"flex h-6 w-6 items-center justify-center rounded bg-bg-sunken text-text-primary text-xs\"\n >\n +\n </button>\n <button\n type=\"button\"\n onClick={() => removeFromCart(item.productId)}\n className=\"ml-1 text-status-error-text hover:text-status-error-text/80\"\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n </div>\n ))}\n </div>\n <div className=\"border-t border-border-subtle pt-3\">\n <div className=\"flex justify-between items-center mb-3\">\n <span className=\"text-sm font-semibold text-text-primary\">\n Total: {formatCurrency(cartTotal, { minimumFractionDigits: 0 })}\n </span>\n <span className=\"text-xs text-text-secondary\">{cartCount} items</span>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/checkout')}\n className=\"w-full rounded-lg bg-foreground py-2.5 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n Proceed to Checkout\n </button>\n </div>\n </>\n )}\n </div>\n\n {/* Direct Service Card */}\n {cart.serviceTypes?.includes('direct_service') && (\n <div className=\"rounded-lg border border-accent-purple/30 bg-accent-purple-subtle p-4\">\n <h3 className=\"text-sm font-semibold text-text-primary flex items-center gap-2 mb-2\">\n <Home className=\"h-4 w-4 text-text-primary\" />\n Direct Service\n </h3>\n <p className=\"text-xs text-text-secondary mb-3\">Cart comes to your location!</p>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/customer/cart/${cart.id}/direct-service`)}\n className=\"w-full rounded-lg bg-accent-purple py-2 text-xs font-medium text-white hover:bg-accent-purple transition-colors\"\n >\n Book Direct Service\n </button>\n </div>\n )}\n\n {/* Scheduled Stops — matches the 'scheduled_stop' value the merchant's\n Service Config writes to serviceTypes. ('appointment' lives on\n Offering.serviceType and never reaches a provider's serviceTypes.) */}\n {cart.serviceTypes?.includes('scheduled_stop') && (\n <div className=\"rounded-lg border border-border-focus/30 bg-[var(--color-accent-soft)] p-4\">\n <h3 className=\"text-sm font-semibold text-text-primary flex items-center gap-2 mb-2\">\n <Calendar className=\"h-4 w-4 text-text-primary\" />\n Scheduled Stops\n </h3>\n <p className=\"text-xs text-text-secondary\">\n This cart runs scheduled stops. Contact them for the current route and timings.\n </p>\n </div>\n )}\n\n {/* Investment Opportunity */}\n {investment && (\n <div className=\"rounded-lg border border-status-success-text/30 bg-status-success-bg-subtle p-4\">\n <h3 className=\"text-sm font-semibold text-text-primary flex items-center gap-2 mb-2\">\n <TrendingUp className=\"h-4 w-4 text-status-success-text\" />\n Investment Opportunity\n </h3>\n <p className=\"text-xs text-text-secondary mb-2\">{investment.description}</p>\n <div className=\"space-y-1 text-xs text-text-secondary mb-3\">\n <p>\n Target: {formatCurrency(investment.targetAmount, { minimumFractionDigits: 0 })}\n </p>\n <p>\n Raised: {formatCurrency(investment.raisedAmount, { minimumFractionDigits: 0 })}\n </p>\n <p>Expected Returns: {investment.expectedReturns}%</p>\n <p>\n Min Investment:{' '}\n {formatCurrency(investment.minimumInvestment, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/investor/opportunity/${investment.id}`)}\n className=\"w-full rounded-lg bg-status-success-text py-2 text-xs font-medium text-white hover:bg-status-success-text transition-colors\"\n >\n Fund This Business\n </button>\n </div>\n )}\n </div>\n </div>\n )}\n\n {/* Sticky mobile cart bar (mockup: \"View Cart · N items · ₹X\") */}\n {activeTab === 'menu' && cartCount > 0 && (\n <>\n <div className=\"h-20 lg:hidden\" aria-hidden=\"true\" />\n <div className=\"fixed inset-x-0 bottom-0 z-40 border-t border-border-subtle bg-bg-surface/95 p-3 backdrop-blur-sm shadow-elevation-2 lg:hidden\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/checkout')}\n className=\"flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg py-3 text-sm font-semibold text-action-primary-text hover:bg-action-primary-bg-hover transition-colors\"\n >\n <ShoppingCart className=\"h-4 w-4\" />\n View Cart · {cartCount} {cartCount === 1 ? 'item' : 'items'} ·{' '}\n {formatCurrency(cartTotal, { minimumFractionDigits: 0 })}\n </button>\n </div>\n </>\n )}\n\n {/* Customization Modal */}\n {showCustomization && customization && (\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 max-h-[90vh] overflow-y-auto rounded-lg border border-border-subtle bg-bg-surface\">\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\">\n {customization.product.name}\n </h3>\n <button\n type=\"button\"\n onClick={() => {\n setShowCustomization(false);\n setCustomization(null);\n }}\n className=\"rounded-md p-1 text-text-secondary hover:text-text-primary\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n\n <p className=\"text-sm text-text-secondary mb-4\">\n {customization.product.description}\n </p>\n <p className=\"text-lg font-bold text-text-primary mb-4\">\n {formatCurrency(customization.product.price, { minimumFractionDigits: 0 })}\n </p>\n\n {/* Quantity */}\n <div className=\"mb-4\">\n <label className=\"block text-sm font-medium text-text-primary mb-2\">Quantity</label>\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() =>\n setCustomization((prev) =>\n prev ? { ...prev, quantity: Math.max(1, prev.quantity - 1) } : prev\n )\n }\n className=\"flex h-8 w-8 items-center justify-center rounded-full bg-bg-sunken text-text-primary\"\n >\n <Minus className=\"h-4 w-4\" />\n </button>\n <span className=\"min-w-[2ch] text-center font-medium text-text-primary\">\n {customization.quantity}\n </span>\n <button\n type=\"button\"\n onClick={() =>\n setCustomization((prev) =>\n prev ? { ...prev, quantity: prev.quantity + 1 } : prev\n )\n }\n className=\"flex h-8 w-8 items-center justify-center rounded-full bg-bg-sunken text-text-primary\"\n >\n <Plus className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n\n {/* Special Instructions */}\n <div className=\"mb-4\">\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n Special Instructions\n </label>\n <textarea\n value={customization.specialInstructions}\n onChange={(e) =>\n setCustomization((prev) =>\n prev ? { ...prev, specialInstructions: e.target.value } : prev\n )\n }\n placeholder=\"Any special requests...\"\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface p-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n rows={3}\n />\n </div>\n\n <button\n type=\"button\"\n onClick={confirmAddToCart}\n className=\"w-full rounded-lg bg-foreground py-2.5 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n Add to Cart -{' '}\n {formatCurrency(customization.product.price * customization.quantity, {\n minimumFractionDigits: 0,\n })}\n </button>\n </div>\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -3,9 +3,19 @@
|
|
|
3
3
|
* @module kadaikodi/pages/customer
|
|
4
4
|
*
|
|
5
5
|
* Browse and search service providers (carts) with full filtering:
|
|
6
|
-
* category, rating, price range, sort, search.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* category, rating, price range, open-now, sort, search. Active filters are
|
|
7
|
+
* shown as individually removable chips. Grid view with cart info modal, load
|
|
8
|
+
* more, investment indicators, scheduled stops, direct service links, verified
|
|
9
|
+
* badges, and prep time badges.
|
|
10
|
+
*
|
|
11
|
+
* "Open now" filters on the provider's real trading status (ACTIVE/VERIFIED →
|
|
12
|
+
* `isOpen`) client-side. It deliberately does NOT send the schema's
|
|
13
|
+
* `KadaikodiProviderFilterInput.openOnly`: that argument is accepted by the
|
|
14
|
+
* resolver but never applied to the query, so passing it would look like a
|
|
15
|
+
* server-side filter while changing nothing.
|
|
16
|
+
*
|
|
17
|
+
* There is no distance or "near me" filter because the service exposes no
|
|
18
|
+
* viewer location and provider coordinates alone cannot produce a real distance.
|
|
9
19
|
*/
|
|
10
20
|
export declare function CartDiscoveryPage(): import("react").JSX.Element;
|
|
11
21
|
//# sourceMappingURL=CartDiscoveryPage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CartDiscoveryPage.d.ts","sourceRoot":"","sources":["../../../../src/kadaikodi/pages/customer/CartDiscoveryPage.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"CartDiscoveryPage.d.ts","sourceRoot":"","sources":["../../../../src/kadaikodi/pages/customer/CartDiscoveryPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA2CH,wBAAgB,iBAAiB,gCAmrBhC"}
|