@burdenoff/microfe-subscriberbot 2026.625.1 → 2026.626.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/subscriberbot/pages/HomePage.js +19 -14
- package/dist/subscriberbot/pages/HomePage.js.map +1 -1
- package/dist/subscriberbot/pages/admin/AdminAnalyticsPage.js +66 -60
- package/dist/subscriberbot/pages/admin/AdminAnalyticsPage.js.map +1 -1
- package/dist/subscriberbot/pages/admin/AdminDashboard.js +83 -44
- package/dist/subscriberbot/pages/admin/AdminDashboard.js.map +1 -1
- package/dist/subscriberbot/pages/admin/AdminFinancialPage.js +38 -32
- package/dist/subscriberbot/pages/admin/AdminFinancialPage.js.map +1 -1
- package/dist/subscriberbot/pages/admin/AdminOrdersPage.js +226 -221
- package/dist/subscriberbot/pages/admin/AdminOrdersPage.js.map +1 -1
- package/dist/subscriberbot/pages/admin/AdminProfilePage.js +127 -125
- package/dist/subscriberbot/pages/admin/AdminProfilePage.js.map +1 -1
- package/dist/subscriberbot/pages/admin/AdminSettingsPage.js +235 -230
- package/dist/subscriberbot/pages/admin/AdminSettingsPage.js.map +1 -1
- package/dist/subscriberbot/pages/admin/CartManagementPage.js +267 -262
- package/dist/subscriberbot/pages/admin/CartManagementPage.js.map +1 -1
- package/dist/subscriberbot/pages/admin/UserManagementPage.js +267 -262
- package/dist/subscriberbot/pages/admin/UserManagementPage.js.map +1 -1
- package/dist/subscriberbot/pages/cart-owner/AnalyticsDashboard.js +46 -41
- package/dist/subscriberbot/pages/cart-owner/AnalyticsDashboard.js.map +1 -1
- package/dist/subscriberbot/pages/cart-owner/BusinessSettingsPage.js +257 -252
- package/dist/subscriberbot/pages/cart-owner/BusinessSettingsPage.js.map +1 -1
- package/dist/subscriberbot/pages/cart-owner/CartOwnerDashboard.js +231 -194
- package/dist/subscriberbot/pages/cart-owner/CartOwnerDashboard.js.map +1 -1
- package/dist/subscriberbot/pages/cart-owner/CartOwnerProfilePage.js +167 -162
- package/dist/subscriberbot/pages/cart-owner/CartOwnerProfilePage.js.map +1 -1
- package/dist/subscriberbot/pages/cart-owner/CartServiceConfigPage.js +128 -126
- package/dist/subscriberbot/pages/cart-owner/CartServiceConfigPage.js.map +1 -1
- package/dist/subscriberbot/pages/cart-owner/InventoryManagementPage.js +297 -300
- package/dist/subscriberbot/pages/cart-owner/InventoryManagementPage.js.map +1 -1
- package/dist/subscriberbot/pages/cart-owner/OrderManagementPage.js +220 -223
- package/dist/subscriberbot/pages/cart-owner/OrderManagementPage.js.map +1 -1
- package/dist/subscriberbot/pages/cart-owner/StaffManagementPage.js +250 -245
- package/dist/subscriberbot/pages/cart-owner/StaffManagementPage.js.map +1 -1
- package/dist/subscriberbot/pages/common/HelpSupportPage.js +94 -96
- package/dist/subscriberbot/pages/common/HelpSupportPage.js.map +1 -1
- package/dist/subscriberbot/pages/common/NotificationCenterPage.js +48 -42
- package/dist/subscriberbot/pages/common/NotificationCenterPage.js.map +1 -1
- package/dist/subscriberbot/pages/common/SettingsPage.js +745 -736
- package/dist/subscriberbot/pages/common/SettingsPage.js.map +1 -1
- package/dist/subscriberbot/pages/customer/BookingDetailsPage.js +353 -321
- package/dist/subscriberbot/pages/customer/BookingDetailsPage.js.map +1 -1
- package/dist/subscriberbot/pages/customer/CartDetailPage.js +258 -225
- package/dist/subscriberbot/pages/customer/CartDetailPage.js.map +1 -1
- package/dist/subscriberbot/pages/customer/CartDiscoveryPage.js +82 -76
- package/dist/subscriberbot/pages/customer/CartDiscoveryPage.js.map +1 -1
- package/dist/subscriberbot/pages/customer/CheckoutPage.js +212 -215
- package/dist/subscriberbot/pages/customer/CheckoutPage.js.map +1 -1
- package/dist/subscriberbot/pages/customer/CustomerDashboard.js +416 -381
- package/dist/subscriberbot/pages/customer/CustomerDashboard.js.map +1 -1
- package/dist/subscriberbot/pages/customer/CustomerProfilePage.js +488 -479
- package/dist/subscriberbot/pages/customer/CustomerProfilePage.js.map +1 -1
- package/dist/subscriberbot/pages/customer/DirectServiceBookingPage.js +521 -512
- package/dist/subscriberbot/pages/customer/DirectServiceBookingPage.js.map +1 -1
- package/dist/subscriberbot/pages/customer/FavoritesPage.js +57 -51
- package/dist/subscriberbot/pages/customer/FavoritesPage.js.map +1 -1
- package/dist/subscriberbot/pages/customer/OrderHistoryPage.js +56 -50
- package/dist/subscriberbot/pages/customer/OrderHistoryPage.js.map +1 -1
- package/dist/subscriberbot/pages/customer/OrderTrackingPage.js +65 -60
- package/dist/subscriberbot/pages/customer/OrderTrackingPage.js.map +1 -1
- package/dist/subscriberbot/pages/customer/PaymentMethodsPage.js +79 -73
- package/dist/subscriberbot/pages/customer/PaymentMethodsPage.js.map +1 -1
- package/dist/subscriberbot/pages/customer/ReviewsPage.js +68 -62
- package/dist/subscriberbot/pages/customer/ReviewsPage.js.map +1 -1
- package/dist/subscriberbot/pages/customer/SavedAddressesPage.js +60 -54
- package/dist/subscriberbot/pages/customer/SavedAddressesPage.js.map +1 -1
- package/dist/subscriberbot/pages/investor/InvestmentDetailsPage.js +292 -255
- package/dist/subscriberbot/pages/investor/InvestmentDetailsPage.js.map +1 -1
- package/dist/subscriberbot/pages/investor/InvestmentOpportunitiesPage.js +237 -231
- package/dist/subscriberbot/pages/investor/InvestmentOpportunitiesPage.js.map +1 -1
- package/dist/subscriberbot/pages/investor/InvestorAnalyticsPage.js +60 -54
- package/dist/subscriberbot/pages/investor/InvestorAnalyticsPage.js.map +1 -1
- package/dist/subscriberbot/pages/investor/InvestorDashboard.js +350 -319
- package/dist/subscriberbot/pages/investor/InvestorDashboard.js.map +1 -1
- package/dist/subscriberbot/pages/investor/InvestorInvestmentsPage.js +106 -100
- package/dist/subscriberbot/pages/investor/InvestorInvestmentsPage.js.map +1 -1
- package/dist/subscriberbot/pages/investor/InvestorPortfolioPage.js +51 -45
- package/dist/subscriberbot/pages/investor/InvestorPortfolioPage.js.map +1 -1
- package/dist/subscriberbot/pages/investor/InvestorProfilePage.js +387 -382
- package/dist/subscriberbot/pages/investor/InvestorProfilePage.js.map +1 -1
- package/dist/subscriberbot/pages/worker/TaskDetailsPage.js +320 -282
- package/dist/subscriberbot/pages/worker/TaskDetailsPage.js.map +1 -1
- package/dist/subscriberbot/pages/worker/WorkerDashboard.js +92 -61
- package/dist/subscriberbot/pages/worker/WorkerDashboard.js.map +1 -1
- package/dist/subscriberbot/pages/worker/WorkerOrdersPage.js +82 -77
- package/dist/subscriberbot/pages/worker/WorkerOrdersPage.js.map +1 -1
- package/dist/subscriberbot/pages/worker/WorkerProfilePage.js +82 -77
- package/dist/subscriberbot/pages/worker/WorkerProfilePage.js.map +1 -1
- package/dist/subscriberbot/pages/worker/WorkerSchedulePage.js +348 -340
- package/dist/subscriberbot/pages/worker/WorkerSchedulePage.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DirectServiceBookingPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/customer/DirectServiceBookingPage.tsx"],"sourcesContent":["/**\n * Direct Service Booking Page\n * @module subscriberbot/pages/customer\n *\n * 4-step wizard: Location > Details > Payment > Confirmation.\n * Progress indicator, step validation, geolocation button,\n * address fields, preferred time slot selector (30-min slots),\n * urgent booking checkbox, payment method selection,\n * payment summary, confirmation step with checkmark/IDs/next steps.\n */\n\nimport { useState, useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n ArrowRight,\n MapPin,\n Calendar,\n Clock,\n CreditCard,\n Smartphone,\n Wallet,\n CheckCircle2,\n AlertCircle,\n Navigation,\n Phone,\n Home,\n Loader2,\n} from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { getCartById } from '../../mocks/data';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency } from '../../utils/formatters';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype Step = 'location' | 'details' | 'payment' | 'confirmation';\nconst STEPS: Step[] = ['location', 'details', 'payment', 'confirmation'];\nconst STEP_LABELS: Record<Step, string> = {\n location: 'Location',\n details: 'Details',\n payment: 'Payment',\n confirmation: 'Confirmation',\n};\n\ninterface ServiceLocation {\n address: string;\n landmark: string;\n instructions: string;\n phoneNumber: string;\n}\n\ninterface BookingDetails {\n preferredTime: string;\n specialInstructions: string;\n isUrgent: boolean;\n}\n\ninterface ConfirmationData {\n bookingId: string;\n transactionId: string;\n estimatedArrival: string;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction generateTimeSlots(): { value: string; label: string }[] {\n const slots: { value: string; label: string }[] = [];\n const now = new Date();\n const start = new Date(now.getTime() + 30 * 60000); // 30 min from now\n\n for (let i = 0; i < 8; i++) {\n const time = new Date(start.getTime() + i * 30 * 60000);\n const val = time.toTimeString().slice(0, 5);\n const lbl = time.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n slots.push({ value: val, label: lbl });\n }\n\n return slots;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function DirectServiceBookingPage() {\n const { cartId } = useParams<{ cartId: string }>();\n const { navigateTo } = useSubscriberBot();\n\n const cart = useMemo(() => (cartId ? getCartById(cartId) : undefined), [cartId]);\n\n const [step, setStep] = useState<Step>('location');\n const [submitting, setSubmitting] = useState(false);\n\n // Location step\n const [location, setLocation] = useState<ServiceLocation>({\n address: '',\n landmark: '',\n instructions: '',\n phoneNumber: '',\n });\n\n // Details step\n const [details, setDetails] = useState<BookingDetails>({\n preferredTime: '',\n specialInstructions: '',\n isUrgent: false,\n });\n\n // Payment step\n const [paymentMethod, setPaymentMethod] = useState<'upi' | 'card' | 'wallet'>('upi');\n\n // Confirmation data\n const [confirmation, setConfirmation] = useState<ConfirmationData | null>(null);\n\n // Mock pricing\n const advancePayment = 100;\n const serviceFee = 50;\n const balancePayment = serviceFee;\n const totalAmount = advancePayment + serviceFee;\n\n // --- Not found ---\n if (!cart) {\n return (\n <PageLayout title=\"Cart Not Found\">\n <EmptyState\n illustration=\"empty-generic\"\n icon={<Home className=\"h-12 w-12\" />}\n title=\"Service not available\"\n description=\"Direct service is not available for this cart.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/carts')}\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 const timeSlots = generateTimeSlots();\n const stepIndex = STEPS.indexOf(step);\n\n // --- Geolocation ---\n const handleGetLocation = () => {\n if (!navigator.geolocation) {\n alert('Geolocation is not supported by this browser.');\n return;\n }\n navigator.geolocation.getCurrentPosition(\n () => {\n setLocation((p) => ({ ...p, address: p.address || 'Current location detected' }));\n alert('Location detected successfully!');\n },\n () => {\n alert('Failed to get your location. Please enter address manually.');\n }\n );\n };\n\n // --- Validation ---\n const validateLocation = (): boolean => {\n if (!location.address.trim()) {\n alert('Please enter your address.');\n return false;\n }\n if (!location.phoneNumber.trim()) {\n alert('Please enter your phone number.');\n return false;\n }\n return true;\n };\n\n const validateDetails = (): boolean => {\n if (!details.preferredTime) {\n alert('Please select a preferred time slot.');\n return false;\n }\n return true;\n };\n\n // --- Navigation ---\n const nextStep = () => {\n if (step === 'location' && validateLocation()) setStep('details');\n else if (step === 'details' && validateDetails()) setStep('payment');\n else if (step === 'payment') handleBookingSubmit();\n };\n\n const prevStep = () => {\n if (step === 'details') setStep('location');\n else if (step === 'payment') setStep('details');\n };\n\n // --- Submit ---\n const handleBookingSubmit = () => {\n setSubmitting(true);\n setTimeout(() => {\n const bookingId = `BK-${Date.now()}`;\n const transactionId = `TXN-${Date.now()}`;\n const estimatedArrival = new Date(Date.now() + 30 * 60000).toISOString();\n setConfirmation({ bookingId, transactionId, estimatedArrival });\n setStep('confirmation');\n setSubmitting(false);\n }, 1500);\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/carts/${cart.id}`)}\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 <div>\n <span>Book Direct Service</span>\n <p className=\"text-xs font-normal text-text-secondary\">{cart.name}</p>\n </div>\n </div>\n }\n >\n {/* Progress Indicator */}\n <div className=\"flex items-center justify-between mb-6 px-2\">\n {STEPS.map((s, i) => {\n const isCompleted = i < stepIndex;\n const isCurrent = s === step;\n return (\n <div key={s} className=\"flex items-center\">\n <div className=\"flex flex-col items-center\">\n <div\n className={cn(\n 'flex h-8 w-8 items-center justify-center rounded-full text-xs font-medium',\n isCompleted\n ? 'bg-status-success-bg/20 text-status-success-text'\n : isCurrent\n ? 'bg-foreground text-background'\n : 'bg-bg-sunken text-text-secondary'\n )}\n >\n {isCompleted ? <CheckCircle2 className=\"h-4 w-4\" /> : i + 1}\n </div>\n <span\n className={cn(\n 'mt-1 text-[10px]',\n isCurrent ? 'font-medium text-text-primary' : 'text-text-secondary'\n )}\n >\n {STEP_LABELS[s]}\n </span>\n </div>\n {i < STEPS.length - 1 && (\n <div\n className={cn(\n 'mx-2 h-0.5 w-8 sm:w-16',\n isCompleted ? 'bg-status-success-bg/30' : 'bg-border'\n )}\n />\n )}\n </div>\n );\n })}\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Main Content */}\n <div className=\"lg:col-span-2\">\n {/* Step 1: Location */}\n {step === 'location' && (\n <div className=\"rounded-lg border border-border-seam bg-bg-surface p-5\">\n <h2 className=\"text-base font-semibold text-text-primary mb-1 flex items-center gap-2\">\n <MapPin className=\"h-4 w-4\" />\n Service Location\n </h2>\n <p className=\"text-xs text-text-secondary mb-5\">Where should the cart come?</p>\n\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Your Address <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"flex gap-2\">\n <input\n type=\"text\"\n placeholder=\"Enter your full address\"\n value={location.address}\n onChange={(e) => setLocation((p) => ({ ...p, address: e.target.value }))}\n className=\"flex-1 rounded-lg border border-border-seam 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)]\"\n />\n <button\n type=\"button\"\n onClick={handleGetLocation}\n className=\"flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-xs font-medium text-text-primary hover:bg-accent transition-colors whitespace-nowrap\"\n >\n <Navigation className=\"h-3.5 w-3.5\" />\n Use Current Location\n </button>\n </div>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Nearby Landmark\n </label>\n <input\n type=\"text\"\n placeholder=\"e.g., Near Metro Station, Opposite Mall\"\n value={location.landmark}\n onChange={(e) => setLocation((p) => ({ ...p, landmark: e.target.value }))}\n className=\"w-full rounded-lg border border-border-seam 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)]\"\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Instructions for Cart Owner\n </label>\n <textarea\n rows={3}\n placeholder=\"Any specific instructions to help us find you...\"\n value={location.instructions}\n onChange={(e) => setLocation((p) => ({ ...p, instructions: e.target.value }))}\n className=\"w-full rounded-lg border border-border-seam 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>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Phone Number <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"relative\">\n <Phone className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <input\n type=\"tel\"\n placeholder=\"Enter your phone number\"\n value={location.phoneNumber}\n onChange={(e) => setLocation((p) => ({ ...p, phoneNumber: e.target.value }))}\n className=\"w-full rounded-lg border border-border-seam bg-bg-surface py-2 pl-9 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 </div>\n </div>\n </div>\n )}\n\n {/* Step 2: Details */}\n {step === 'details' && (\n <div className=\"rounded-lg border border-border-seam bg-bg-surface p-5\">\n <h2 className=\"text-base font-semibold text-text-primary mb-1 flex items-center gap-2\">\n <Calendar className=\"h-4 w-4\" />\n Booking Details\n </h2>\n <p className=\"text-xs text-text-secondary mb-5\">Choose your preferred timing</p>\n\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Preferred Time Slot <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"grid grid-cols-4 gap-2\">\n {timeSlots.map((slot) => (\n <button\n key={slot.value}\n type=\"button\"\n onClick={() => setDetails((p) => ({ ...p, preferredTime: slot.value }))}\n className={cn(\n 'rounded-lg border py-2 px-2 text-xs font-medium transition-colors',\n details.preferredTime === slot.value\n ? 'border-foreground bg-accent text-text-primary'\n : 'border-border-seam text-text-secondary hover:bg-accent hover:text-text-primary'\n )}\n >\n {slot.label}\n </button>\n ))}\n </div>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Special Instructions\n </label>\n <textarea\n rows={3}\n placeholder=\"Any special requests or dietary preferences...\"\n value={details.specialInstructions}\n onChange={(e) =>\n setDetails((p) => ({ ...p, specialInstructions: e.target.value }))\n }\n className=\"w-full rounded-lg border border-border-seam 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 <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={details.isUrgent}\n onChange={(e) => setDetails((p) => ({ ...p, isUrgent: e.target.checked }))}\n className=\"h-4 w-4 rounded border-border-seam\"\n />\n <span className=\"text-sm text-text-secondary\">\n This is urgent (additional charges may apply)\n </span>\n </label>\n </div>\n </div>\n )}\n\n {/* Step 3: Payment */}\n {step === 'payment' && (\n <div className=\"rounded-lg border border-border-seam bg-bg-surface p-5\">\n <h2 className=\"text-base font-semibold text-text-primary mb-1 flex items-center gap-2\">\n <CreditCard className=\"h-4 w-4\" />\n Advance Payment\n </h2>\n <p className=\"text-xs text-text-secondary mb-5\">Select your payment method</p>\n\n <div className=\"space-y-4\">\n {/* Info callout */}\n <div className=\"flex items-start gap-2 rounded-lg border border-status-info-border/20 bg-status-info-bg/5 p-3\">\n <AlertCircle className=\"h-4 w-4 text-status-info-text shrink-0 mt-0.5\" />\n <p className=\"text-xs text-status-info-text\">\n You need to pay {formatCurrency(advancePayment, { minimumFractionDigits: 0 })}{' '}\n in advance to confirm your booking. Pay the remaining when the cart arrives.\n </p>\n </div>\n\n {/* Payment methods */}\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-3\">\n {[\n {\n value: 'upi' as const,\n label: 'UPI',\n sub: 'Instant payment',\n Icon: Smartphone,\n },\n {\n value: 'card' as const,\n label: 'Card',\n sub: 'Secure payment',\n Icon: CreditCard,\n },\n {\n value: 'wallet' as const,\n label: 'Wallet',\n sub: 'Quick payment',\n Icon: Wallet,\n },\n ].map(({ value, label, sub, Icon }) => (\n <button\n key={value}\n type=\"button\"\n onClick={() => setPaymentMethod(value)}\n className={cn(\n 'rounded-lg border p-3 text-center transition-colors',\n paymentMethod === value\n ? 'border-foreground bg-accent'\n : 'border-border-seam hover:bg-accent'\n )}\n >\n <Icon className=\"mx-auto h-5 w-5 text-text-secondary mb-1\" />\n <p className=\"text-sm font-medium text-text-primary\">{label}</p>\n <p className=\"text-[10px] text-text-secondary\">{sub}</p>\n </button>\n ))}\n </div>\n\n {/* Payment Summary */}\n <div className=\"rounded-lg bg-bg-sunken p-4\">\n <h3 className=\"text-sm font-medium text-text-primary mb-2\">Payment Summary</h3>\n <div className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Advance Payment:</span>\n <span className=\"text-text-primary\">\n {formatCurrency(advancePayment, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Service Fee:</span>\n <span className=\"text-text-primary\">\n {formatCurrency(serviceFee, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <div className=\"flex justify-between text-text-secondary\">\n <span>Balance Payment (at arrival):</span>\n <span>{formatCurrency(balancePayment, { minimumFractionDigits: 0 })}</span>\n </div>\n <div className=\"flex justify-between border-t border-border-seam pt-2 font-semibold\">\n <span className=\"text-text-primary\">Total Amount:</span>\n <span className=\"text-text-primary\">\n {formatCurrency(totalAmount, { minimumFractionDigits: 0 })}\n </span>\n </div>\n </div>\n </div>\n </div>\n </div>\n )}\n\n {/* Step 4: Confirmation */}\n {step === 'confirmation' && confirmation && (\n <div className=\"rounded-lg border border-border-seam bg-bg-surface p-5\">\n {/* Success header */}\n <div className=\"text-center mb-6\">\n <div className=\"mx-auto mb-3 flex h-14 w-14 items-center justify-center rounded-full bg-status-success-bg/10\">\n <CheckCircle2 className=\"h-7 w-7 text-status-success-text\" />\n </div>\n <h2 className=\"text-lg font-semibold text-text-primary mb-1\">Booking Confirmed!</h2>\n <p className=\"text-sm text-text-secondary\">\n Your direct service booking has been confirmed and payment processed.\n </p>\n </div>\n\n {/* Booking details */}\n <div className=\"rounded-lg bg-bg-sunken p-4 mb-4\">\n <h3 className=\"text-sm font-medium text-text-primary mb-3\">Booking Details</h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm\">\n <div>\n <span className=\"text-xs text-text-secondary\">Booking ID</span>\n <p className=\"font-mono text-xs text-text-primary\">{confirmation.bookingId}</p>\n </div>\n <div>\n <span className=\"text-xs text-text-secondary\">Est. Arrival</span>\n <p className=\"text-text-primary\">\n {new Date(confirmation.estimatedArrival).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n })}\n </p>\n </div>\n <div>\n <span className=\"text-xs text-text-secondary\">Location</span>\n <p className=\"text-text-primary truncate\">{location.address}</p>\n </div>\n <div>\n <span className=\"text-xs text-text-secondary\">Phone</span>\n <p className=\"text-text-primary\">{location.phoneNumber}</p>\n </div>\n </div>\n </div>\n\n {/* Payment details */}\n <div className=\"rounded-lg border border-status-success-border/20 bg-status-success-bg/5 p-4 mb-4\">\n <h3 className=\"text-sm font-medium text-status-success-text mb-2 flex items-center gap-2\">\n <CheckCircle2 className=\"h-4 w-4\" />\n Payment Processed\n </h3>\n <div className=\"grid grid-cols-2 gap-3 text-sm\">\n <div>\n <span className=\"text-xs text-text-secondary\">Transaction ID</span>\n <p className=\"font-mono text-xs text-text-primary\">\n {confirmation.transactionId}\n </p>\n </div>\n <div>\n <span className=\"text-xs text-text-secondary\">Advance Paid</span>\n <p className=\"font-medium text-text-primary\">\n {formatCurrency(advancePayment, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <span className=\"text-xs text-text-secondary\">Method</span>\n <p className=\"capitalize text-text-primary\">{paymentMethod}</p>\n </div>\n <div>\n <span className=\"text-xs text-text-secondary\">Status</span>\n <p className=\"font-medium text-status-success-text\">Paid</p>\n </div>\n </div>\n </div>\n\n {/* Next Steps */}\n <div className=\"rounded-lg border border-status-info-border/20 bg-status-info-bg/5 p-4 mb-6\">\n <h3 className=\"text-sm font-medium text-status-info-text mb-2\">Next Steps</h3>\n <div className=\"space-y-2 text-xs text-status-info-text\">\n <div className=\"flex items-start gap-2\">\n <CheckCircle2 className=\"h-3.5 w-3.5 text-status-success-text mt-0.5 shrink-0\" />\n <span>\n Payment confirmed -{' '}\n {formatCurrency(advancePayment, { minimumFractionDigits: 0 })} paid\n </span>\n </div>\n <div className=\"flex items-start gap-2\">\n <Clock className=\"h-3.5 w-3.5 mt-0.5 shrink-0\" />\n <span>\n Cart will arrive around{' '}\n {new Date(confirmation.estimatedArrival).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n })}\n </span>\n </div>\n <div className=\"flex items-start gap-2\">\n <CreditCard className=\"h-3.5 w-3.5 mt-0.5 shrink-0\" />\n <span>\n Pay remaining {formatCurrency(balancePayment, { minimumFractionDigits: 0 })}{' '}\n when cart arrives\n </span>\n </div>\n </div>\n </div>\n\n {/* Action buttons */}\n <div className=\"flex gap-3\">\n <button\n type=\"button\"\n onClick={() => navigateTo(`/customer/bookings/${confirmation.bookingId}`)}\n className=\"flex-1 rounded-lg bg-foreground px-4 py-2.5 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n View Booking\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/carts')}\n className=\"flex-1 rounded-lg border border-border-seam px-4 py-2.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Browse More\n </button>\n </div>\n </div>\n )}\n\n {/* Navigation Buttons */}\n {step !== 'confirmation' && (\n <div className=\"flex justify-between mt-5\">\n <button\n type=\"button\"\n onClick={prevStep}\n disabled={step === 'location'}\n className={cn(\n 'flex items-center gap-2 rounded-lg border border-border-seam px-4 py-2.5 text-sm font-medium text-text-primary transition-colors',\n step === 'location' ? 'opacity-40 cursor-not-allowed' : 'hover:bg-accent'\n )}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n Previous\n </button>\n <button\n type=\"button\"\n onClick={nextStep}\n disabled={submitting}\n className={cn(\n 'flex items-center gap-2 rounded-lg bg-foreground px-4 py-2.5 text-sm font-medium text-background transition-opacity',\n submitting ? 'opacity-60 cursor-not-allowed' : 'hover:opacity-90'\n )}\n >\n {submitting ? (\n <>\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n {step === 'payment' ? 'Processing Payment...' : 'Processing...'}\n </>\n ) : (\n <>\n {step === 'payment' ? 'Confirm & Pay' : 'Next'}\n <ArrowRight className=\"h-4 w-4\" />\n </>\n )}\n </button>\n </div>\n )}\n </div>\n\n {/* Sidebar: Service Summary */}\n <div className=\"lg:col-span-1\">\n <div className=\"sticky top-6 rounded-lg border border-border-seam bg-bg-surface p-5\">\n <h3 className=\"text-base font-semibold text-text-primary mb-4\">Service Summary</h3>\n\n <div className=\"flex items-center gap-3 mb-4\">\n <img src={cart.image} alt={cart.name} className=\"h-12 w-12 rounded-lg object-cover\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">{cart.name}</p>\n <p className=\"text-xs text-text-secondary\">{cart.category}</p>\n </div>\n </div>\n\n <div className=\"space-y-2 text-sm border-t border-border-seam pt-3\">\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Service Fee:</span>\n <span className=\"text-text-primary\">\n {formatCurrency(serviceFee, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Advance Payment:</span>\n <span className=\"font-medium text-text-primary\">\n {formatCurrency(advancePayment, { minimumFractionDigits: 0 })}\n </span>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2 mt-3 pt-3 border-t border-border-seam text-status-success-text\">\n <CheckCircle2 className=\"h-3.5 w-3.5\" />\n <span className=\"text-xs\">Pay remaining amount at cart</span>\n </div>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DirectServiceBookingPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/customer/DirectServiceBookingPage.tsx"],"sourcesContent":["/**\n * Direct Service Booking Page\n * @module subscriberbot/pages/customer\n *\n * 4-step wizard: Location > Details > Payment > Confirmation.\n * Progress indicator, step validation, geolocation button,\n * address fields, preferred time slot selector (30-min slots),\n * urgent booking checkbox, payment method selection,\n * payment summary, confirmation step with checkmark/IDs/next steps.\n */\n\nimport { useState, useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n ArrowRight,\n MapPin,\n Calendar,\n Clock,\n CreditCard,\n Smartphone,\n Wallet,\n CheckCircle2,\n AlertCircle,\n Navigation,\n Phone,\n Home,\n Loader2,\n} from 'lucide-react';\nimport { PagePurpose, EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { getCartById } from '../../mocks/data';\nimport { cn } from '../../utils/cn';\nimport { formatCurrency } from '../../utils/formatters';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype Step = 'location' | 'details' | 'payment' | 'confirmation';\nconst STEPS: Step[] = ['location', 'details', 'payment', 'confirmation'];\nconst STEP_LABELS: Record<Step, string> = {\n location: 'Location',\n details: 'Details',\n payment: 'Payment',\n confirmation: 'Confirmation',\n};\n\ninterface ServiceLocation {\n address: string;\n landmark: string;\n instructions: string;\n phoneNumber: string;\n}\n\ninterface BookingDetails {\n preferredTime: string;\n specialInstructions: string;\n isUrgent: boolean;\n}\n\ninterface ConfirmationData {\n bookingId: string;\n transactionId: string;\n estimatedArrival: string;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction generateTimeSlots(): { value: string; label: string }[] {\n const slots: { value: string; label: string }[] = [];\n const now = new Date();\n const start = new Date(now.getTime() + 30 * 60000); // 30 min from now\n\n for (let i = 0; i < 8; i++) {\n const time = new Date(start.getTime() + i * 30 * 60000);\n const val = time.toTimeString().slice(0, 5);\n const lbl = time.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n slots.push({ value: val, label: lbl });\n }\n\n return slots;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function DirectServiceBookingPage() {\n const { cartId } = useParams<{ cartId: string }>();\n const { navigateTo } = useSubscriberBot();\n\n const cart = useMemo(() => (cartId ? getCartById(cartId) : undefined), [cartId]);\n\n const [step, setStep] = useState<Step>('location');\n const [submitting, setSubmitting] = useState(false);\n\n // Location step\n const [location, setLocation] = useState<ServiceLocation>({\n address: '',\n landmark: '',\n instructions: '',\n phoneNumber: '',\n });\n\n // Details step\n const [details, setDetails] = useState<BookingDetails>({\n preferredTime: '',\n specialInstructions: '',\n isUrgent: false,\n });\n\n // Payment step\n const [paymentMethod, setPaymentMethod] = useState<'upi' | 'card' | 'wallet'>('upi');\n\n // Confirmation data\n const [confirmation, setConfirmation] = useState<ConfirmationData | null>(null);\n\n // Mock pricing\n const advancePayment = 100;\n const serviceFee = 50;\n const balancePayment = serviceFee;\n const totalAmount = advancePayment + serviceFee;\n\n // --- Not found ---\n if (!cart) {\n return (\n <PageLayout title=\"Cart Not Found\">\n <EmptyState\n illustration=\"empty-generic\"\n icon={<Home className=\"h-12 w-12\" />}\n title=\"Service not available\"\n description=\"Direct service is not available for this cart.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/carts')}\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 const timeSlots = generateTimeSlots();\n const stepIndex = STEPS.indexOf(step);\n\n // --- Geolocation ---\n const handleGetLocation = () => {\n if (!navigator.geolocation) {\n alert('Geolocation is not supported by this browser.');\n return;\n }\n navigator.geolocation.getCurrentPosition(\n () => {\n setLocation((p) => ({ ...p, address: p.address || 'Current location detected' }));\n alert('Location detected successfully!');\n },\n () => {\n alert('Failed to get your location. Please enter address manually.');\n }\n );\n };\n\n // --- Validation ---\n const validateLocation = (): boolean => {\n if (!location.address.trim()) {\n alert('Please enter your address.');\n return false;\n }\n if (!location.phoneNumber.trim()) {\n alert('Please enter your phone number.');\n return false;\n }\n return true;\n };\n\n const validateDetails = (): boolean => {\n if (!details.preferredTime) {\n alert('Please select a preferred time slot.');\n return false;\n }\n return true;\n };\n\n // --- Navigation ---\n const nextStep = () => {\n if (step === 'location' && validateLocation()) setStep('details');\n else if (step === 'details' && validateDetails()) setStep('payment');\n else if (step === 'payment') handleBookingSubmit();\n };\n\n const prevStep = () => {\n if (step === 'details') setStep('location');\n else if (step === 'payment') setStep('details');\n };\n\n // --- Submit ---\n const handleBookingSubmit = () => {\n setSubmitting(true);\n setTimeout(() => {\n const bookingId = `BK-${Date.now()}`;\n const transactionId = `TXN-${Date.now()}`;\n const estimatedArrival = new Date(Date.now() + 30 * 60000).toISOString();\n setConfirmation({ bookingId, transactionId, estimatedArrival });\n setStep('confirmation');\n setSubmitting(false);\n }, 1500);\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/carts/${cart.id}`)}\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 <div>\n <span>Book Direct Service</span>\n <p className=\"text-xs font-normal text-text-secondary\">{cart.name}</p>\n </div>\n </div>\n }\n >\n <PagePurpose icon={<Calendar className=\"h-4 w-4\" />} className=\"mb-6\">\n Book a service from this cart directly, on your terms. Walk through choosing where\n and when, describing exactly what you need, and confirming the details — then pay a\n small advance to lock it in and settle the rest at the cart. Use this when a\n standard menu item isn't quite what you're after.\n </PagePurpose>\n\n {/* Progress Indicator */}\n <div className=\"flex items-center justify-between mb-6 px-2\">\n {STEPS.map((s, i) => {\n const isCompleted = i < stepIndex;\n const isCurrent = s === step;\n return (\n <div key={s} className=\"flex items-center\">\n <div className=\"flex flex-col items-center\">\n <div\n className={cn(\n 'flex h-8 w-8 items-center justify-center rounded-full text-xs font-medium',\n isCompleted\n ? 'bg-status-success-bg/20 text-status-success-text'\n : isCurrent\n ? 'bg-foreground text-background'\n : 'bg-bg-sunken text-text-secondary'\n )}\n >\n {isCompleted ? <CheckCircle2 className=\"h-4 w-4\" /> : i + 1}\n </div>\n <span\n className={cn(\n 'mt-1 text-[10px]',\n isCurrent ? 'font-medium text-text-primary' : 'text-text-secondary'\n )}\n >\n {STEP_LABELS[s]}\n </span>\n </div>\n {i < STEPS.length - 1 && (\n <div\n className={cn(\n 'mx-2 h-0.5 w-8 sm:w-16',\n isCompleted ? 'bg-status-success-bg/30' : 'bg-border'\n )}\n />\n )}\n </div>\n );\n })}\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Main Content */}\n <div className=\"lg:col-span-2\">\n {/* Step 1: Location */}\n {step === 'location' && (\n <div className=\"rounded-lg border border-border-seam bg-bg-surface p-5\">\n <h2 className=\"text-base font-semibold text-text-primary mb-1 flex items-center gap-2\">\n <MapPin className=\"h-4 w-4\" />\n Service Location\n </h2>\n <p className=\"text-xs text-text-secondary mb-5\">Where should the cart come?</p>\n\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Your Address <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"flex gap-2\">\n <input\n type=\"text\"\n placeholder=\"Enter your full address\"\n value={location.address}\n onChange={(e) => setLocation((p) => ({ ...p, address: e.target.value }))}\n className=\"flex-1 rounded-lg border border-border-seam 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)]\"\n />\n <button\n type=\"button\"\n onClick={handleGetLocation}\n className=\"flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-xs font-medium text-text-primary hover:bg-accent transition-colors whitespace-nowrap\"\n >\n <Navigation className=\"h-3.5 w-3.5\" />\n Use Current Location\n </button>\n </div>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Nearby Landmark\n </label>\n <input\n type=\"text\"\n placeholder=\"e.g., Near Metro Station, Opposite Mall\"\n value={location.landmark}\n onChange={(e) => setLocation((p) => ({ ...p, landmark: e.target.value }))}\n className=\"w-full rounded-lg border border-border-seam 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)]\"\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Instructions for Cart Owner\n </label>\n <textarea\n rows={3}\n placeholder=\"Any specific instructions to help us find you...\"\n value={location.instructions}\n onChange={(e) => setLocation((p) => ({ ...p, instructions: e.target.value }))}\n className=\"w-full rounded-lg border border-border-seam 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>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Phone Number <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"relative\">\n <Phone className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <input\n type=\"tel\"\n placeholder=\"Enter your phone number\"\n value={location.phoneNumber}\n onChange={(e) => setLocation((p) => ({ ...p, phoneNumber: e.target.value }))}\n className=\"w-full rounded-lg border border-border-seam bg-bg-surface py-2 pl-9 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 </div>\n </div>\n </div>\n )}\n\n {/* Step 2: Details */}\n {step === 'details' && (\n <div className=\"rounded-lg border border-border-seam bg-bg-surface p-5\">\n <h2 className=\"text-base font-semibold text-text-primary mb-1 flex items-center gap-2\">\n <Calendar className=\"h-4 w-4\" />\n Booking Details\n </h2>\n <p className=\"text-xs text-text-secondary mb-5\">Choose your preferred timing</p>\n\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Preferred Time Slot <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"grid grid-cols-4 gap-2\">\n {timeSlots.map((slot) => (\n <button\n key={slot.value}\n type=\"button\"\n onClick={() => setDetails((p) => ({ ...p, preferredTime: slot.value }))}\n className={cn(\n 'rounded-lg border py-2 px-2 text-xs font-medium transition-colors',\n details.preferredTime === slot.value\n ? 'border-foreground bg-accent text-text-primary'\n : 'border-border-seam text-text-secondary hover:bg-accent hover:text-text-primary'\n )}\n >\n {slot.label}\n </button>\n ))}\n </div>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Special Instructions\n </label>\n <textarea\n rows={3}\n placeholder=\"Any special requests or dietary preferences...\"\n value={details.specialInstructions}\n onChange={(e) =>\n setDetails((p) => ({ ...p, specialInstructions: e.target.value }))\n }\n className=\"w-full rounded-lg border border-border-seam 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 <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={details.isUrgent}\n onChange={(e) => setDetails((p) => ({ ...p, isUrgent: e.target.checked }))}\n className=\"h-4 w-4 rounded border-border-seam\"\n />\n <span className=\"text-sm text-text-secondary\">\n This is urgent (additional charges may apply)\n </span>\n </label>\n </div>\n </div>\n )}\n\n {/* Step 3: Payment */}\n {step === 'payment' && (\n <div className=\"rounded-lg border border-border-seam bg-bg-surface p-5\">\n <h2 className=\"text-base font-semibold text-text-primary mb-1 flex items-center gap-2\">\n <CreditCard className=\"h-4 w-4\" />\n Advance Payment\n </h2>\n <p className=\"text-xs text-text-secondary mb-5\">Select your payment method</p>\n\n <div className=\"space-y-4\">\n {/* Info callout */}\n <div className=\"flex items-start gap-2 rounded-lg border border-status-info-border/20 bg-status-info-bg/5 p-3\">\n <AlertCircle className=\"h-4 w-4 text-status-info-text shrink-0 mt-0.5\" />\n <p className=\"text-xs text-status-info-text\">\n You need to pay {formatCurrency(advancePayment, { minimumFractionDigits: 0 })}{' '}\n in advance to confirm your booking. Pay the remaining when the cart arrives.\n </p>\n </div>\n\n {/* Payment methods */}\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-3\">\n {[\n {\n value: 'upi' as const,\n label: 'UPI',\n sub: 'Instant payment',\n Icon: Smartphone,\n },\n {\n value: 'card' as const,\n label: 'Card',\n sub: 'Secure payment',\n Icon: CreditCard,\n },\n {\n value: 'wallet' as const,\n label: 'Wallet',\n sub: 'Quick payment',\n Icon: Wallet,\n },\n ].map(({ value, label, sub, Icon }) => (\n <button\n key={value}\n type=\"button\"\n onClick={() => setPaymentMethod(value)}\n className={cn(\n 'rounded-lg border p-3 text-center transition-colors',\n paymentMethod === value\n ? 'border-foreground bg-accent'\n : 'border-border-seam hover:bg-accent'\n )}\n >\n <Icon className=\"mx-auto h-5 w-5 text-text-secondary mb-1\" />\n <p className=\"text-sm font-medium text-text-primary\">{label}</p>\n <p className=\"text-[10px] text-text-secondary\">{sub}</p>\n </button>\n ))}\n </div>\n\n {/* Payment Summary */}\n <div className=\"rounded-lg bg-bg-sunken p-4\">\n <h3 className=\"text-sm font-medium text-text-primary mb-2\">Payment Summary</h3>\n <div className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Advance Payment:</span>\n <span className=\"text-text-primary\">\n {formatCurrency(advancePayment, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Service Fee:</span>\n <span className=\"text-text-primary\">\n {formatCurrency(serviceFee, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <div className=\"flex justify-between text-text-secondary\">\n <span>Balance Payment (at arrival):</span>\n <span>{formatCurrency(balancePayment, { minimumFractionDigits: 0 })}</span>\n </div>\n <div className=\"flex justify-between border-t border-border-seam pt-2 font-semibold\">\n <span className=\"text-text-primary\">Total Amount:</span>\n <span className=\"text-text-primary\">\n {formatCurrency(totalAmount, { minimumFractionDigits: 0 })}\n </span>\n </div>\n </div>\n </div>\n </div>\n </div>\n )}\n\n {/* Step 4: Confirmation */}\n {step === 'confirmation' && confirmation && (\n <div className=\"rounded-lg border border-border-seam bg-bg-surface p-5\">\n {/* Success header */}\n <div className=\"text-center mb-6\">\n <div className=\"mx-auto mb-3 flex h-14 w-14 items-center justify-center rounded-full bg-status-success-bg/10\">\n <CheckCircle2 className=\"h-7 w-7 text-status-success-text\" />\n </div>\n <h2 className=\"text-lg font-semibold text-text-primary mb-1\">Booking Confirmed!</h2>\n <p className=\"text-sm text-text-secondary\">\n Your direct service booking has been confirmed and payment processed.\n </p>\n </div>\n\n {/* Booking details */}\n <div className=\"rounded-lg bg-bg-sunken p-4 mb-4\">\n <h3 className=\"text-sm font-medium text-text-primary mb-3\">Booking Details</h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm\">\n <div>\n <span className=\"text-xs text-text-secondary\">Booking ID</span>\n <p className=\"font-mono text-xs text-text-primary\">{confirmation.bookingId}</p>\n </div>\n <div>\n <span className=\"text-xs text-text-secondary\">Est. Arrival</span>\n <p className=\"text-text-primary\">\n {new Date(confirmation.estimatedArrival).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n })}\n </p>\n </div>\n <div>\n <span className=\"text-xs text-text-secondary\">Location</span>\n <p className=\"text-text-primary truncate\">{location.address}</p>\n </div>\n <div>\n <span className=\"text-xs text-text-secondary\">Phone</span>\n <p className=\"text-text-primary\">{location.phoneNumber}</p>\n </div>\n </div>\n </div>\n\n {/* Payment details */}\n <div className=\"rounded-lg border border-status-success-border/20 bg-status-success-bg/5 p-4 mb-4\">\n <h3 className=\"text-sm font-medium text-status-success-text mb-2 flex items-center gap-2\">\n <CheckCircle2 className=\"h-4 w-4\" />\n Payment Processed\n </h3>\n <div className=\"grid grid-cols-2 gap-3 text-sm\">\n <div>\n <span className=\"text-xs text-text-secondary\">Transaction ID</span>\n <p className=\"font-mono text-xs text-text-primary\">\n {confirmation.transactionId}\n </p>\n </div>\n <div>\n <span className=\"text-xs text-text-secondary\">Advance Paid</span>\n <p className=\"font-medium text-text-primary\">\n {formatCurrency(advancePayment, { minimumFractionDigits: 0 })}\n </p>\n </div>\n <div>\n <span className=\"text-xs text-text-secondary\">Method</span>\n <p className=\"capitalize text-text-primary\">{paymentMethod}</p>\n </div>\n <div>\n <span className=\"text-xs text-text-secondary\">Status</span>\n <p className=\"font-medium text-status-success-text\">Paid</p>\n </div>\n </div>\n </div>\n\n {/* Next Steps */}\n <div className=\"rounded-lg border border-status-info-border/20 bg-status-info-bg/5 p-4 mb-6\">\n <h3 className=\"text-sm font-medium text-status-info-text mb-2\">Next Steps</h3>\n <div className=\"space-y-2 text-xs text-status-info-text\">\n <div className=\"flex items-start gap-2\">\n <CheckCircle2 className=\"h-3.5 w-3.5 text-status-success-text mt-0.5 shrink-0\" />\n <span>\n Payment confirmed -{' '}\n {formatCurrency(advancePayment, { minimumFractionDigits: 0 })} paid\n </span>\n </div>\n <div className=\"flex items-start gap-2\">\n <Clock className=\"h-3.5 w-3.5 mt-0.5 shrink-0\" />\n <span>\n Cart will arrive around{' '}\n {new Date(confirmation.estimatedArrival).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n })}\n </span>\n </div>\n <div className=\"flex items-start gap-2\">\n <CreditCard className=\"h-3.5 w-3.5 mt-0.5 shrink-0\" />\n <span>\n Pay remaining {formatCurrency(balancePayment, { minimumFractionDigits: 0 })}{' '}\n when cart arrives\n </span>\n </div>\n </div>\n </div>\n\n {/* Action buttons */}\n <div className=\"flex gap-3\">\n <button\n type=\"button\"\n onClick={() => navigateTo(`/customer/bookings/${confirmation.bookingId}`)}\n className=\"flex-1 rounded-lg bg-foreground px-4 py-2.5 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n View Booking\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/carts')}\n className=\"flex-1 rounded-lg border border-border-seam px-4 py-2.5 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Browse More\n </button>\n </div>\n </div>\n )}\n\n {/* Navigation Buttons */}\n {step !== 'confirmation' && (\n <div className=\"flex justify-between mt-5\">\n <button\n type=\"button\"\n onClick={prevStep}\n disabled={step === 'location'}\n className={cn(\n 'flex items-center gap-2 rounded-lg border border-border-seam px-4 py-2.5 text-sm font-medium text-text-primary transition-colors',\n step === 'location' ? 'opacity-40 cursor-not-allowed' : 'hover:bg-accent'\n )}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n Previous\n </button>\n <button\n type=\"button\"\n onClick={nextStep}\n disabled={submitting}\n className={cn(\n 'flex items-center gap-2 rounded-lg bg-foreground px-4 py-2.5 text-sm font-medium text-background transition-opacity',\n submitting ? 'opacity-60 cursor-not-allowed' : 'hover:opacity-90'\n )}\n >\n {submitting ? (\n <>\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n {step === 'payment' ? 'Processing Payment...' : 'Processing...'}\n </>\n ) : (\n <>\n {step === 'payment' ? 'Confirm & Pay' : 'Next'}\n <ArrowRight className=\"h-4 w-4\" />\n </>\n )}\n </button>\n </div>\n )}\n </div>\n\n {/* Sidebar: Service Summary — the ONE emphasis zone */}\n <div className=\"lg:col-span-1\">\n <EmphasisPanel className=\"sticky top-6 p-5\">\n <h3 className=\"text-base font-semibold text-text-primary mb-4\">Service Summary</h3>\n\n <div className=\"flex items-center gap-3 mb-4\">\n <img src={cart.image} alt={cart.name} className=\"h-12 w-12 rounded-lg object-cover\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">{cart.name}</p>\n <p className=\"text-xs text-text-secondary\">{cart.category}</p>\n </div>\n </div>\n\n <div className=\"space-y-2 text-sm border-t border-border-seam pt-3\">\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Service Fee:</span>\n <span className=\"text-text-primary\">\n {formatCurrency(serviceFee, { minimumFractionDigits: 0 })}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Advance Payment:</span>\n <span className=\"font-medium text-text-primary\">\n {formatCurrency(advancePayment, { minimumFractionDigits: 0 })}\n </span>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2 mt-3 pt-3 border-t border-border-seam text-status-success-text\">\n <CheckCircle2 className=\"h-3.5 w-3.5\" />\n <span className=\"text-xs\">Pay remaining amount at cart</span>\n </div>\n </EmphasisPanel>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -7,9 +7,10 @@ import { formatCurrency as o, formatDate as s } from "../../utils/formatters.js"
|
|
|
7
7
|
import { useCallback as c, useState as l } from "react";
|
|
8
8
|
import { Clock as u, Heart as d, Leaf as f, RotateCcw as p, Search as m, ShoppingCart as h, Star as g, Utensils as _, X as v } from "lucide-react";
|
|
9
9
|
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
10
|
+
import { EmphasisPanel as x, PagePurpose as S } from "@burdenoff/fe-libs/ui";
|
|
10
11
|
//#region src/subscriberbot/pages/customer/FavoritesPage.tsx
|
|
11
|
-
function
|
|
12
|
-
let { navigateTo:
|
|
12
|
+
function C() {
|
|
13
|
+
let { navigateTo: C, currentUser: w } = e(), { data: T = [], isLoading: E } = a(), { data: D = [], isLoading: O } = i({ customerId: w?.id }), k = T.slice(0, 2).map((e) => ({
|
|
13
14
|
id: e.id,
|
|
14
15
|
name: e.name,
|
|
15
16
|
description: "Authentic services from SubscriberBot",
|
|
@@ -22,35 +23,35 @@ function x() {
|
|
|
22
23
|
distance: e.distance,
|
|
23
24
|
estimatedTime: e.estimatedTime,
|
|
24
25
|
addedToFavorites: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25
|
-
totalOrders:
|
|
26
|
-
totalSpent:
|
|
27
|
-
})),
|
|
26
|
+
totalOrders: D.filter((t) => t.cartId === e.id).length,
|
|
27
|
+
totalSpent: D.filter((t) => t.cartId === e.id).reduce((e, t) => e + t.total, 0)
|
|
28
|
+
})), A = [{
|
|
28
29
|
id: "prod-001",
|
|
29
30
|
name: "Masala Dosa",
|
|
30
31
|
description: "Crispy rice crepe with spiced potato filling",
|
|
31
32
|
price: 120,
|
|
32
33
|
category: "South Indian",
|
|
33
34
|
image: "https://images.unsplash.com/photo-1630383249896-424e482df921?w=300",
|
|
34
|
-
cartId:
|
|
35
|
-
cartName:
|
|
35
|
+
cartId: T[0]?.id || "FOOD-001",
|
|
36
|
+
cartName: T[0]?.name || "Dosa Express",
|
|
36
37
|
isVegetarian: !0,
|
|
37
38
|
isVegan: !1,
|
|
38
39
|
preparationTime: 15,
|
|
39
40
|
rating: 4.7,
|
|
40
41
|
addedToFavorites: "2024-02-20T12:30:00Z",
|
|
41
42
|
orderCount: 8
|
|
42
|
-
}], [
|
|
43
|
+
}], [j, M] = l({
|
|
43
44
|
searchQuery: "",
|
|
44
45
|
type: "all",
|
|
45
46
|
category: "",
|
|
46
47
|
sortBy: "recent"
|
|
47
|
-
}),
|
|
48
|
-
let e = [...
|
|
49
|
-
if (
|
|
50
|
-
let n =
|
|
48
|
+
}), N = E || O, { carts: P, products: F } = c(() => {
|
|
49
|
+
let e = [...k], t = [...A];
|
|
50
|
+
if (j.searchQuery) {
|
|
51
|
+
let n = j.searchQuery.toLowerCase();
|
|
51
52
|
e = e.filter((e) => e.name.toLowerCase().includes(n) || e.description.toLowerCase().includes(n) || e.category.toLowerCase().includes(n)), t = t.filter((e) => e.name.toLowerCase().includes(n) || e.description.toLowerCase().includes(n) || e.category.toLowerCase().includes(n) || e.cartName.toLowerCase().includes(n));
|
|
52
53
|
}
|
|
53
|
-
switch (
|
|
54
|
+
switch (j.category && (e = e.filter((e) => e.category === j.category), t = t.filter((e) => e.category === j.category)), j.sortBy) {
|
|
54
55
|
case "recent":
|
|
55
56
|
e.sort((e, t) => new Date(t.addedToFavorites).getTime() - new Date(e.addedToFavorites).getTime()), t.sort((e, t) => new Date(t.addedToFavorites).getTime() - new Date(e.addedToFavorites).getTime());
|
|
56
57
|
break;
|
|
@@ -64,10 +65,10 @@ function x() {
|
|
|
64
65
|
e.sort((e, t) => t.totalOrders - e.totalOrders), t.sort((e, t) => t.orderCount - e.orderCount);
|
|
65
66
|
break;
|
|
66
67
|
}
|
|
67
|
-
return
|
|
68
|
+
return j.type === "carts" ? {
|
|
68
69
|
carts: e,
|
|
69
70
|
products: []
|
|
70
|
-
} :
|
|
71
|
+
} : j.type === "products" ? {
|
|
71
72
|
carts: [],
|
|
72
73
|
products: t
|
|
73
74
|
} : {
|
|
@@ -75,15 +76,15 @@ function x() {
|
|
|
75
76
|
products: t
|
|
76
77
|
};
|
|
77
78
|
}, [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
])(),
|
|
79
|
+
k,
|
|
80
|
+
A,
|
|
81
|
+
j
|
|
82
|
+
])(), I = (e) => {
|
|
82
83
|
console.log("Remove cart:", e);
|
|
83
|
-
},
|
|
84
|
+
}, L = (e) => {
|
|
84
85
|
console.log("Remove product:", e);
|
|
85
|
-
},
|
|
86
|
-
return
|
|
86
|
+
}, R = k.reduce((e, t) => e + t.totalSpent, 0) + A.reduce((e, t) => e + t.price * t.orderCount, 0);
|
|
87
|
+
return N ? /* @__PURE__ */ y(n, {
|
|
87
88
|
title: "My Favorites",
|
|
88
89
|
children: /* @__PURE__ */ y("div", {
|
|
89
90
|
className: "flex items-center justify-center py-20",
|
|
@@ -91,16 +92,21 @@ function x() {
|
|
|
91
92
|
})
|
|
92
93
|
}) : /* @__PURE__ */ b(n, {
|
|
93
94
|
title: "My Favorites",
|
|
94
|
-
description: `${
|
|
95
|
+
description: `${k.length} carts, ${A.length} products`,
|
|
95
96
|
children: [
|
|
96
|
-
/* @__PURE__ */
|
|
97
|
+
/* @__PURE__ */ y(S, {
|
|
98
|
+
icon: /* @__PURE__ */ y(d, { className: "h-4 w-4" }),
|
|
99
|
+
className: "mb-6",
|
|
100
|
+
children: "Your shortlist of carts and items worth coming back to. Save anything you love so you can reorder in seconds instead of searching again, and see at a glance how much you've saved with favourites. Filter by carts or products to find exactly what you're craving."
|
|
101
|
+
}),
|
|
102
|
+
/* @__PURE__ */ b(x, {
|
|
97
103
|
className: "flex flex-wrap items-center gap-4 text-sm text-text-secondary mb-6",
|
|
98
104
|
children: [
|
|
99
105
|
/* @__PURE__ */ b("span", {
|
|
100
106
|
className: "flex items-center gap-1.5",
|
|
101
107
|
children: [
|
|
102
108
|
/* @__PURE__ */ y(h, { className: "h-3.5 w-3.5" }),
|
|
103
|
-
|
|
109
|
+
k.length,
|
|
104
110
|
" carts"
|
|
105
111
|
]
|
|
106
112
|
}),
|
|
@@ -108,7 +114,7 @@ function x() {
|
|
|
108
114
|
className: "flex items-center gap-1.5",
|
|
109
115
|
children: [
|
|
110
116
|
/* @__PURE__ */ y(_, { className: "h-3.5 w-3.5" }),
|
|
111
|
-
|
|
117
|
+
A.length,
|
|
112
118
|
" products"
|
|
113
119
|
]
|
|
114
120
|
}),
|
|
@@ -117,7 +123,7 @@ function x() {
|
|
|
117
123
|
children: [
|
|
118
124
|
/* @__PURE__ */ y(g, { className: "h-3.5 w-3.5" }),
|
|
119
125
|
"Total saved: ",
|
|
120
|
-
o(
|
|
126
|
+
o(R, { minimumFractionDigits: 0 })
|
|
121
127
|
]
|
|
122
128
|
})
|
|
123
129
|
]
|
|
@@ -132,8 +138,8 @@ function x() {
|
|
|
132
138
|
children: [/* @__PURE__ */ y(m, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ y("input", {
|
|
133
139
|
type: "text",
|
|
134
140
|
placeholder: "Search favorites...",
|
|
135
|
-
value:
|
|
136
|
-
onChange: (e) =>
|
|
141
|
+
value: j.searchQuery,
|
|
142
|
+
onChange: (e) => M((t) => ({
|
|
137
143
|
...t,
|
|
138
144
|
searchQuery: e.target.value
|
|
139
145
|
})),
|
|
@@ -141,8 +147,8 @@ function x() {
|
|
|
141
147
|
})]
|
|
142
148
|
}),
|
|
143
149
|
/* @__PURE__ */ b("select", {
|
|
144
|
-
value:
|
|
145
|
-
onChange: (e) =>
|
|
150
|
+
value: j.type,
|
|
151
|
+
onChange: (e) => M((t) => ({
|
|
146
152
|
...t,
|
|
147
153
|
type: e.target.value
|
|
148
154
|
})),
|
|
@@ -163,8 +169,8 @@ function x() {
|
|
|
163
169
|
]
|
|
164
170
|
}),
|
|
165
171
|
/* @__PURE__ */ b("select", {
|
|
166
|
-
value:
|
|
167
|
-
onChange: (e) =>
|
|
172
|
+
value: j.category,
|
|
173
|
+
onChange: (e) => M((t) => ({
|
|
168
174
|
...t,
|
|
169
175
|
category: e.target.value
|
|
170
176
|
})),
|
|
@@ -193,8 +199,8 @@ function x() {
|
|
|
193
199
|
]
|
|
194
200
|
}),
|
|
195
201
|
/* @__PURE__ */ b("select", {
|
|
196
|
-
value:
|
|
197
|
-
onChange: (e) =>
|
|
202
|
+
value: j.sortBy,
|
|
203
|
+
onChange: (e) => M((t) => ({
|
|
198
204
|
...t,
|
|
199
205
|
sortBy: e.target.value
|
|
200
206
|
})),
|
|
@@ -221,37 +227,37 @@ function x() {
|
|
|
221
227
|
]
|
|
222
228
|
})
|
|
223
229
|
}),
|
|
224
|
-
|
|
230
|
+
P.length === 0 && F.length === 0 ? /* @__PURE__ */ y(r, {
|
|
225
231
|
illustration: "empty-data",
|
|
226
232
|
icon: /* @__PURE__ */ y(d, { className: "h-12 w-12" }),
|
|
227
233
|
title: "No favorites yet",
|
|
228
234
|
description: "Browse carts and tap the heart icon to add them to your favorites.",
|
|
229
235
|
action: /* @__PURE__ */ y("button", {
|
|
230
236
|
type: "button",
|
|
231
|
-
onClick: () =>
|
|
237
|
+
onClick: () => C("/customer/carts"),
|
|
232
238
|
className: "rounded-lg bg-foreground px-4 py-2 text-sm font-medium text-background hover:opacity-90 transition-opacity",
|
|
233
239
|
children: "Discover Carts"
|
|
234
240
|
})
|
|
235
241
|
}) : /* @__PURE__ */ b("div", {
|
|
236
242
|
className: "space-y-8",
|
|
237
|
-
children: [
|
|
243
|
+
children: [P.length > 0 && /* @__PURE__ */ b("section", { children: [/* @__PURE__ */ b("h3", {
|
|
238
244
|
className: "text-base font-semibold text-text-primary mb-4 flex items-center gap-2",
|
|
239
245
|
children: [
|
|
240
246
|
/* @__PURE__ */ y(h, { className: "h-4 w-4 text-text-secondary" }),
|
|
241
247
|
"Favorite Carts (",
|
|
242
|
-
|
|
248
|
+
P.length,
|
|
243
249
|
")"
|
|
244
250
|
]
|
|
245
251
|
}), /* @__PURE__ */ y("div", {
|
|
246
252
|
className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4",
|
|
247
|
-
children:
|
|
253
|
+
children: P.map((e) => /* @__PURE__ */ b("div", {
|
|
248
254
|
className: "rounded-lg border border-border-seam bg-bg-surface shadow-sm overflow-hidden",
|
|
249
255
|
children: [/* @__PURE__ */ b("div", {
|
|
250
256
|
className: "relative h-36 bg-bg-sunken",
|
|
251
257
|
children: [
|
|
252
258
|
/* @__PURE__ */ y("button", {
|
|
253
259
|
type: "button",
|
|
254
|
-
onClick: () =>
|
|
260
|
+
onClick: () => C(`/customer/carts/${e.id}`),
|
|
255
261
|
className: "block h-full w-full",
|
|
256
262
|
children: /* @__PURE__ */ y("img", {
|
|
257
263
|
src: e.image,
|
|
@@ -261,7 +267,7 @@ function x() {
|
|
|
261
267
|
}),
|
|
262
268
|
/* @__PURE__ */ y("button", {
|
|
263
269
|
type: "button",
|
|
264
|
-
onClick: () =>
|
|
270
|
+
onClick: () => I(e.id),
|
|
265
271
|
title: "Remove from favorites",
|
|
266
272
|
className: "absolute top-2 right-2 flex h-8 w-8 items-center justify-center rounded-full bg-bg-surface/80 backdrop-blur-sm text-status-error-text hover:bg-bg-surface transition-colors",
|
|
267
273
|
children: /* @__PURE__ */ y(d, { className: "h-4 w-4 fill-current" })
|
|
@@ -341,12 +347,12 @@ function x() {
|
|
|
341
347
|
className: "flex gap-2 mt-4",
|
|
342
348
|
children: [/* @__PURE__ */ b("button", {
|
|
343
349
|
type: "button",
|
|
344
|
-
onClick: () =>
|
|
350
|
+
onClick: () => C(`/customer/carts/${e.id}`),
|
|
345
351
|
className: "flex-1 flex items-center justify-center gap-1.5 rounded-lg bg-foreground px-3 py-2 text-xs font-medium text-background hover:opacity-90 transition-opacity",
|
|
346
352
|
children: [/* @__PURE__ */ y(p, { className: "h-3 w-3" }), "Order Again"]
|
|
347
353
|
}), /* @__PURE__ */ y("button", {
|
|
348
354
|
type: "button",
|
|
349
|
-
onClick: () =>
|
|
355
|
+
onClick: () => C(`/customer/carts/${e.id}`),
|
|
350
356
|
className: "flex-1 rounded-lg border border-border-seam px-3 py-2 text-xs font-medium text-text-primary hover:bg-accent transition-colors",
|
|
351
357
|
children: "View Menu"
|
|
352
358
|
})]
|
|
@@ -354,17 +360,17 @@ function x() {
|
|
|
354
360
|
]
|
|
355
361
|
})]
|
|
356
362
|
}, e.id))
|
|
357
|
-
})] }),
|
|
363
|
+
})] }), F.length > 0 && /* @__PURE__ */ b("section", { children: [/* @__PURE__ */ b("h3", {
|
|
358
364
|
className: "text-base font-semibold text-text-primary mb-4 flex items-center gap-2",
|
|
359
365
|
children: [
|
|
360
366
|
/* @__PURE__ */ y(_, { className: "h-4 w-4 text-text-secondary" }),
|
|
361
367
|
"Favorite Products (",
|
|
362
|
-
|
|
368
|
+
F.length,
|
|
363
369
|
")"
|
|
364
370
|
]
|
|
365
371
|
}), /* @__PURE__ */ y("div", {
|
|
366
372
|
className: "space-y-3",
|
|
367
|
-
children:
|
|
373
|
+
children: F.map((e) => /* @__PURE__ */ y("div", {
|
|
368
374
|
className: "rounded-lg border border-border-seam bg-bg-surface p-4",
|
|
369
375
|
children: /* @__PURE__ */ b("div", {
|
|
370
376
|
className: "flex flex-col sm:flex-row sm:items-center gap-4",
|
|
@@ -389,7 +395,7 @@ function x() {
|
|
|
389
395
|
children: o(e.price, { minimumFractionDigits: 0 })
|
|
390
396
|
}), /* @__PURE__ */ y("button", {
|
|
391
397
|
type: "button",
|
|
392
|
-
onClick: () =>
|
|
398
|
+
onClick: () => L(e.id),
|
|
393
399
|
title: "Remove from favorites",
|
|
394
400
|
className: "rounded-md p-1 text-status-error-text hover:bg-status-error-bg/10 transition-colors",
|
|
395
401
|
children: /* @__PURE__ */ y(v, { className: "h-4 w-4" })
|
|
@@ -454,12 +460,12 @@ function x() {
|
|
|
454
460
|
className: "flex sm:flex-col gap-2 shrink-0",
|
|
455
461
|
children: [/* @__PURE__ */ y("button", {
|
|
456
462
|
type: "button",
|
|
457
|
-
onClick: () =>
|
|
463
|
+
onClick: () => C(`/customer/carts/${e.cartId}`),
|
|
458
464
|
className: "flex-1 sm:flex-none rounded-lg bg-foreground px-4 py-2 text-xs font-medium text-background hover:opacity-90 transition-opacity whitespace-nowrap",
|
|
459
465
|
children: "Add to Cart"
|
|
460
466
|
}), /* @__PURE__ */ y("button", {
|
|
461
467
|
type: "button",
|
|
462
|
-
onClick: () =>
|
|
468
|
+
onClick: () => C(`/customer/carts/${e.cartId}`),
|
|
463
469
|
className: "flex-1 sm:flex-none rounded-lg border border-border-seam px-4 py-2 text-xs font-medium text-text-primary hover:bg-accent transition-colors whitespace-nowrap",
|
|
464
470
|
children: "View Cart"
|
|
465
471
|
})]
|
|
@@ -473,6 +479,6 @@ function x() {
|
|
|
473
479
|
});
|
|
474
480
|
}
|
|
475
481
|
//#endregion
|
|
476
|
-
export {
|
|
482
|
+
export { C as FavoritesPage };
|
|
477
483
|
|
|
478
484
|
//# sourceMappingURL=FavoritesPage.js.map
|