@burdenoff/microfe-kadaikodi 2026.723.1 → 2026.730.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/KadaikodiRoutes.d.ts.map +1 -1
- package/dist/kadaikodi/KadaikodiRoutes.js +33 -29
- package/dist/kadaikodi/KadaikodiRoutes.js.map +1 -1
- package/dist/kadaikodi/hooks/useKadaikodiApi.d.ts +42 -0
- package/dist/kadaikodi/hooks/useKadaikodiApi.d.ts.map +1 -1
- package/dist/kadaikodi/hooks/useKadaikodiApi.js +133 -65
- package/dist/kadaikodi/hooks/useKadaikodiApi.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/BusinessSettingsPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/BusinessSettingsPage.js +180 -162
- package/dist/kadaikodi/pages/cart-owner/BusinessSettingsPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/LoyaltyManagementPage.d.ts +12 -0
- package/dist/kadaikodi/pages/cart-owner/LoyaltyManagementPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/LoyaltyManagementPage.js +198 -0
- package/dist/kadaikodi/pages/cart-owner/LoyaltyManagementPage.js.map +1 -0
- package/dist/kadaikodi/pages/customer/CustomerProfilePage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/customer/CustomerProfilePage.js +256 -97
- package/dist/kadaikodi/pages/customer/CustomerProfilePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BusinessSettingsPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/cart-owner/BusinessSettingsPage.tsx"],"sourcesContent":["/**\n * Business Settings Page\n *\n * Tabbed interface (general/contact/location/operating/policies/notifications/integrations),\n * all form fields per tab including social media, coordinates, delivery charges,\n * payment methods, policy textareas, notification toggles, payment gateway config.\n *\n * @module kadaikodi/pages/cart-owner\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport {\n Store,\n Save,\n AlertCircle,\n MapPin,\n Clock,\n Shield,\n Bell,\n Link2,\n CheckCircle2,\n Phone,\n} from 'lucide-react';\nimport { EmphasisPanel, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport { useProviders, useUpdateProvider } from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype TabId =\n | 'general'\n | 'contact'\n | 'location'\n | 'operating'\n | 'policies'\n | 'notifications'\n | 'integration';\n\ninterface Tab {\n id: TabId;\n label: string;\n icon: typeof Store;\n}\n\ninterface GeneralSettings {\n businessName: string;\n description: string;\n category: string;\n gstNumber: string;\n panNumber: string;\n fssaiLicense: string;\n establishedYear: string;\n}\n\ninterface ContactSettings {\n phone: string;\n email: string;\n website: string;\n whatsapp: string;\n instagram: string;\n twitter: string;\n facebook: string;\n}\n\ninterface LocationSettings {\n address: string;\n city: string;\n state: string;\n pincode: string;\n latitude: string;\n longitude: string;\n deliveryRadius: number;\n deliveryCharge: number;\n freeDeliveryAbove: number;\n}\n\ninterface OperatingSettings {\n autoAcceptOrders: boolean;\n preparationTime: number;\n maxConcurrentOrders: number;\n advanceBookingDays: number;\n}\n\ninterface PolicySettings {\n returnPolicy: string;\n cancellationPolicy: string;\n privacyPolicy: string;\n termsOfService: string;\n}\n\ninterface NotificationSettings {\n newOrderEmail: boolean;\n newOrderSms: boolean;\n newOrderPush: boolean;\n orderUpdateEmail: boolean;\n orderUpdatePush: boolean;\n dailySummaryEmail: boolean;\n weeklySummaryEmail: boolean;\n lowStockAlert: boolean;\n reviewNotification: boolean;\n marketingEmails: boolean;\n}\n\ninterface IntegrationSettings {\n paymentGateway: string;\n paymentGatewayKey: string;\n smsProvider: string;\n smsApiKey: string;\n analyticsId: string;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst tabs: Tab[] = [\n { id: 'general', label: 'General', icon: Store },\n { id: 'contact', label: 'Contact', icon: Phone },\n { id: 'location', label: 'Location', icon: MapPin },\n { id: 'operating', label: 'Operating', icon: Clock },\n { id: 'policies', label: 'Policies', icon: Shield },\n { id: 'notifications', label: 'Notifications', icon: Bell },\n { id: 'integration', label: 'Integrations', icon: Link2 },\n];\n\nconst categories = [\n 'Food & Beverage',\n 'Personal Care & Beauty',\n 'Repair & Maintenance',\n 'Home Services',\n 'Clothing & Fashion',\n 'Health & Wellness',\n 'Education & Skills',\n 'Retail & Merchandise',\n 'Grocery & Essentials',\n];\n\n// ============================================================================\n// Form Field Component\n// ============================================================================\n\ninterface FormFieldProps {\n label: string;\n value: string | number;\n onChange: (value: string) => void;\n type?: 'text' | 'email' | 'tel' | 'url' | 'number' | 'textarea' | 'select';\n options?: string[];\n placeholder?: string;\n hint?: string;\n rows?: number;\n disabled?: boolean;\n}\n\nconst FormField = ({\n label,\n value,\n onChange,\n type = 'text',\n options,\n placeholder,\n hint,\n rows = 3,\n disabled = false,\n}: FormFieldProps) => {\n const id = label.toLowerCase().replace(/\\s+/g, '-');\n return (\n <div>\n <label htmlFor={id} className=\"block text-sm font-medium text-text-primary mb-1.5\">\n {label}\n </label>\n {type === 'textarea' ? (\n <textarea\n id={id}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n rows={rows}\n placeholder={placeholder}\n disabled={disabled}\n className={cn(\n 'w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none',\n disabled && 'bg-bg-sunken/50 cursor-not-allowed'\n )}\n />\n ) : type === 'select' ? (\n <select\n id={id}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n disabled={disabled}\n className={cn(\n 'w-full rounded-md 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 disabled && 'bg-bg-sunken/50 cursor-not-allowed'\n )}\n >\n {options?.map((opt) => (\n <option key={opt} value={opt}>\n {opt}\n </option>\n ))}\n </select>\n ) : (\n <input\n id={id}\n type={type}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n placeholder={placeholder}\n disabled={disabled}\n className={cn(\n 'w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]',\n disabled && 'bg-bg-sunken/50 cursor-not-allowed'\n )}\n />\n )}\n {hint && <p className=\"mt-1 text-xs text-text-secondary\">{hint}</p>}\n </div>\n );\n};\n\n// ============================================================================\n// Toggle Component\n// ============================================================================\n\nconst Toggle = ({\n label,\n description,\n checked,\n onChange,\n}: {\n label: string;\n description?: string;\n checked: boolean;\n onChange: (v: boolean) => void;\n}) => (\n <div className=\"flex items-center justify-between py-3\">\n <div>\n <p className=\"text-sm font-medium text-text-primary\">{label}</p>\n {description && <p className=\"text-xs text-text-secondary mt-0.5\">{description}</p>}\n </div>\n <button\n type=\"button\"\n onClick={() => onChange(!checked)}\n className={cn(\n 'h-6 w-11 rounded-full transition-colors relative',\n checked ? 'bg-action-primary-bg' : 'bg-muted-foreground/30'\n )}\n >\n <div\n className={cn(\n 'absolute top-0.5 h-5 w-5 rounded-full bg-white transition-transform',\n checked ? 'translate-x-5' : 'translate-x-0.5'\n )}\n />\n </button>\n </div>\n);\n\n// ============================================================================\n// Component\n// ============================================================================\n\nconst CATEGORY_LABELS: Record<string, string> = {\n FOOD_BEVERAGE: 'Food & Beverage',\n PERSONAL_CARE_BEAUTY: 'Personal Care & Beauty',\n CLOTHING_FASHION: 'Clothing & Fashion',\n REPAIR_MAINTENANCE: 'Repair & Maintenance',\n HOME_SERVICES: 'Home Services',\n HEALTH_WELLNESS: 'Health & Wellness',\n EDUCATION_SKILLS: 'Education & Skills',\n RETAIL_MERCHANDISE: 'Retail & Merchandise',\n GROCERY_ESSENTIALS: 'Grocery & Essentials',\n};\n\nexport const BusinessSettingsPage = () => {\n const { navigateTo, currentUser } = useKadaikodi();\n const [activeTab, setActiveTab] = useState<TabId>('general');\n const updateProvider = useUpdateProvider();\n const saving = updateProvider.isPending;\n const [saved, setSaved] = useState(false);\n const [saveError, setSaveError] = useState(false);\n\n // Resolve the signed-in owner's provider (\"my cart\") to seed the form.\n const { data: providers = [], isLoading: providersLoading } = useProviders();\n const myProvider = useMemo(\n () => providers.find((p) => p.ownerId === currentUser?.id) ?? providers[0],\n [providers, currentUser?.id]\n );\n\n // Form state — seeded blank; real provider values are applied once loaded.\n // Fields with no backend source stay empty (placeholders only), never fabricated.\n const [general, setGeneral] = useState<GeneralSettings>({\n businessName: '',\n description: '',\n category: 'Food & Beverage',\n gstNumber: '',\n panNumber: '',\n fssaiLicense: '',\n establishedYear: '',\n });\n\n const [contact, setContact] = useState<ContactSettings>({\n phone: '',\n email: '',\n website: '',\n whatsapp: '',\n instagram: '',\n twitter: '',\n facebook: '',\n });\n\n const [location, setLocation] = useState<LocationSettings>({\n address: '',\n city: '',\n state: '',\n pincode: '',\n latitude: '',\n longitude: '',\n deliveryRadius: 5,\n deliveryCharge: 30,\n freeDeliveryAbove: 300,\n });\n\n const [operating, setOperating] = useState<OperatingSettings>({\n autoAcceptOrders: true,\n preparationTime: 15,\n maxConcurrentOrders: 10,\n advanceBookingDays: 3,\n });\n\n const [policies, setPolicies] = useState<PolicySettings>({\n returnPolicy: '',\n cancellationPolicy: '',\n privacyPolicy: '',\n termsOfService: '',\n });\n\n const [notifications, setNotifications] = useState<NotificationSettings>({\n newOrderEmail: true,\n newOrderSms: true,\n newOrderPush: true,\n orderUpdateEmail: true,\n orderUpdatePush: true,\n dailySummaryEmail: true,\n weeklySummaryEmail: false,\n lowStockAlert: true,\n reviewNotification: true,\n marketingEmails: false,\n });\n\n const [integration, setIntegration] = useState<IntegrationSettings>({\n paymentGateway: 'razorpay',\n paymentGatewayKey: '',\n smsProvider: 'twilio',\n smsApiKey: '',\n analyticsId: '',\n });\n\n // Seed general/location from the provider's real data once it loads.\n const [seeded, setSeeded] = useState(false);\n useEffect(() => {\n if (!myProvider || seeded) return;\n const categoryLabel = CATEGORY_LABELS[myProvider.category] ?? myProvider.category;\n setGeneral((p) => ({\n ...p,\n businessName: myProvider.name,\n category: categories.includes(categoryLabel) ? categoryLabel : p.category,\n }));\n const coords = myProvider.location?.coordinates;\n setLocation((p) => ({\n ...p,\n address: myProvider.location?.address ?? '',\n latitude: coords?.lat ? String(coords.lat) : '',\n longitude: coords?.lng ? String(coords.lng) : '',\n }));\n setSeeded(true);\n }, [myProvider, seeded]);\n\n const handleSave = () => {\n if (!myProvider) return;\n setSaveError(false);\n\n // Only the fields the provider record supports are persisted: business name,\n // description, and location (address + coordinates). Category is fixed at cart\n // creation and cannot be edited here; contact / policy / notification /\n // integration settings have no backend field yet and stay in this browser.\n const lat = parseFloat(location.latitude);\n const lng = parseFloat(location.longitude);\n const input: Record<string, unknown> = {\n name: general.businessName,\n description: general.description || undefined,\n location: {\n address: location.address,\n latitude: Number.isFinite(lat) ? lat : undefined,\n longitude: Number.isFinite(lng) ? lng : undefined,\n coordinates: {\n lat: Number.isFinite(lat) ? lat : 0,\n lng: Number.isFinite(lng) ? lng : 0,\n },\n },\n };\n\n updateProvider.mutate(\n { id: myProvider.id, input },\n {\n onSuccess: () => {\n setSaved(true);\n setTimeout(() => setSaved(false), 3000);\n },\n onError: () => setSaveError(true),\n }\n );\n };\n\n const updateGeneral = (field: keyof GeneralSettings) => (value: string) =>\n setGeneral((p) => ({ ...p, [field]: value }));\n const updateContact = (field: keyof ContactSettings) => (value: string) =>\n setContact((p) => ({ ...p, [field]: value }));\n const updateLocation = (field: keyof LocationSettings) => (value: string) =>\n setLocation((p) => ({\n ...p,\n [field]:\n field === 'deliveryRadius' || field === 'deliveryCharge' || field === 'freeDeliveryAbove'\n ? parseInt(value) || 0\n : value,\n }));\n const updatePolicies = (field: keyof PolicySettings) => (value: string) =>\n setPolicies((p) => ({ ...p, [field]: value }));\n const updateNotification = (field: keyof NotificationSettings) => (value: boolean) =>\n setNotifications((p) => ({ ...p, [field]: value }));\n const updateIntegration = (field: keyof IntegrationSettings) => (value: string) =>\n setIntegration((p) => ({ ...p, [field]: value }));\n\n // ---- Tab content renderers ----\n\n const renderGeneralTab = () => (\n <div className=\"space-y-5\">\n <FormField\n label=\"Business Name\"\n value={general.businessName}\n onChange={updateGeneral('businessName')}\n />\n <FormField\n label=\"Description\"\n value={general.description}\n onChange={updateGeneral('description')}\n type=\"textarea\"\n />\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-5\">\n <FormField\n label=\"Category\"\n value={general.category}\n onChange={updateGeneral('category')}\n type=\"select\"\n options={categories}\n disabled\n hint=\"Set when your cart was created and can't be changed here.\"\n />\n <FormField\n label=\"Established Year\"\n value={general.establishedYear}\n onChange={updateGeneral('establishedYear')}\n />\n </div>\n <div className=\"flex items-start gap-3 rounded-md bg-[var(--color-accent-soft)] border border-border-focus/20 p-3\">\n <AlertCircle className=\"h-4 w-4 text-text-primary shrink-0 mt-0.5\" />\n <p className=\"text-xs text-text-primary\">\n GST, PAN, and FSSAI details are used for invoicing and compliance. Changes require\n verification.\n </p>\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-5\">\n <FormField\n label=\"GST Number\"\n value={general.gstNumber}\n onChange={updateGeneral('gstNumber')}\n hint=\"15-digit GST ID\"\n />\n <FormField\n label=\"PAN Number\"\n value={general.panNumber}\n onChange={updateGeneral('panNumber')}\n hint=\"10-digit PAN\"\n />\n <FormField\n label=\"FSSAI License\"\n value={general.fssaiLicense}\n onChange={updateGeneral('fssaiLicense')}\n hint=\"FSSAI license number\"\n />\n </div>\n </div>\n );\n\n const renderContactTab = () => (\n <div className=\"space-y-5\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-5\">\n <FormField\n label=\"Phone\"\n value={contact.phone}\n onChange={updateContact('phone')}\n type=\"tel\"\n />\n <FormField\n label=\"Email\"\n value={contact.email}\n onChange={updateContact('email')}\n type=\"email\"\n />\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-5\">\n <FormField\n label=\"Website\"\n value={contact.website}\n onChange={updateContact('website')}\n type=\"url\"\n placeholder=\"https://\"\n />\n <FormField\n label=\"WhatsApp\"\n value={contact.whatsapp}\n onChange={updateContact('whatsapp')}\n type=\"tel\"\n />\n </div>\n <h3 className=\"text-sm font-semibold text-text-primary pt-2\">Social Media</h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-5\">\n <FormField\n label=\"Instagram\"\n value={contact.instagram}\n onChange={updateContact('instagram')}\n placeholder=\"@handle\"\n />\n <FormField\n label=\"Twitter / X\"\n value={contact.twitter}\n onChange={updateContact('twitter')}\n placeholder=\"@handle\"\n />\n <FormField\n label=\"Facebook\"\n value={contact.facebook}\n onChange={updateContact('facebook')}\n placeholder=\"Page name\"\n />\n </div>\n </div>\n );\n\n const renderLocationTab = () => (\n <div className=\"space-y-5\">\n <FormField\n label=\"Address\"\n value={location.address}\n onChange={updateLocation('address')}\n type=\"textarea\"\n rows={2}\n />\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-5\">\n <FormField label=\"City\" value={location.city} onChange={updateLocation('city')} />\n <FormField label=\"State\" value={location.state} onChange={updateLocation('state')} />\n <FormField label=\"Pincode\" value={location.pincode} onChange={updateLocation('pincode')} />\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-5\">\n <FormField\n label=\"Latitude\"\n value={location.latitude}\n onChange={updateLocation('latitude')}\n hint=\"e.g., 12.9352\"\n />\n <FormField\n label=\"Longitude\"\n value={location.longitude}\n onChange={updateLocation('longitude')}\n hint=\"e.g., 77.6245\"\n />\n </div>\n <h3 className=\"text-sm font-semibold text-text-primary pt-2\">Delivery Settings</h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-5\">\n <FormField\n label=\"Delivery Radius (km)\"\n value={location.deliveryRadius}\n onChange={updateLocation('deliveryRadius')}\n type=\"number\"\n />\n <FormField\n label=\"Delivery Charge (₹)\"\n value={location.deliveryCharge}\n onChange={updateLocation('deliveryCharge')}\n type=\"number\"\n />\n <FormField\n label=\"Free Delivery Above (₹)\"\n value={location.freeDeliveryAbove}\n onChange={updateLocation('freeDeliveryAbove')}\n type=\"number\"\n />\n </div>\n </div>\n );\n\n const renderOperatingTab = () => (\n <div className=\"space-y-5\">\n <Toggle\n label=\"Auto-Accept Orders\"\n description=\"Automatically accept incoming orders without manual confirmation\"\n checked={operating.autoAcceptOrders}\n onChange={(v) => setOperating((p) => ({ ...p, autoAcceptOrders: v }))}\n />\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-5\">\n <FormField\n label=\"Default Preparation Time (min)\"\n value={operating.preparationTime}\n onChange={(v) => setOperating((p) => ({ ...p, preparationTime: parseInt(v) || 0 }))}\n type=\"number\"\n />\n <FormField\n label=\"Max Concurrent Orders\"\n value={operating.maxConcurrentOrders}\n onChange={(v) => setOperating((p) => ({ ...p, maxConcurrentOrders: parseInt(v) || 0 }))}\n type=\"number\"\n />\n <FormField\n label=\"Advance Booking (days)\"\n value={operating.advanceBookingDays}\n onChange={(v) => setOperating((p) => ({ ...p, advanceBookingDays: parseInt(v) || 0 }))}\n type=\"number\"\n />\n </div>\n </div>\n );\n\n const renderPoliciesTab = () => (\n <div className=\"space-y-5\">\n <FormField\n label=\"Return Policy\"\n value={policies.returnPolicy}\n onChange={updatePolicies('returnPolicy')}\n type=\"textarea\"\n rows={4}\n />\n <FormField\n label=\"Cancellation Policy\"\n value={policies.cancellationPolicy}\n onChange={updatePolicies('cancellationPolicy')}\n type=\"textarea\"\n rows={4}\n />\n <FormField\n label=\"Privacy Policy\"\n value={policies.privacyPolicy}\n onChange={updatePolicies('privacyPolicy')}\n type=\"textarea\"\n rows={4}\n />\n <FormField\n label=\"Terms of Service\"\n value={policies.termsOfService}\n onChange={updatePolicies('termsOfService')}\n type=\"textarea\"\n rows={4}\n />\n </div>\n );\n\n const renderNotificationsTab = () => (\n <div className=\"space-y-1 divide-y divide-border\">\n <h3 className=\"text-sm font-semibold text-text-primary pb-2\">New Orders</h3>\n <Toggle\n label=\"Email Notification\"\n description=\"Receive email for new orders\"\n checked={notifications.newOrderEmail}\n onChange={updateNotification('newOrderEmail')}\n />\n <Toggle\n label=\"SMS Notification\"\n description=\"Receive SMS for new orders\"\n checked={notifications.newOrderSms}\n onChange={updateNotification('newOrderSms')}\n />\n <Toggle\n label=\"Push Notification\"\n description=\"Receive push notifications for new orders\"\n checked={notifications.newOrderPush}\n onChange={updateNotification('newOrderPush')}\n />\n <h3 className=\"text-sm font-semibold text-text-primary pt-4 pb-2\">Order Updates</h3>\n <Toggle\n label=\"Email Updates\"\n description=\"Get email when order status changes\"\n checked={notifications.orderUpdateEmail}\n onChange={updateNotification('orderUpdateEmail')}\n />\n <Toggle\n label=\"Push Updates\"\n description=\"Get push notifications for order updates\"\n checked={notifications.orderUpdatePush}\n onChange={updateNotification('orderUpdatePush')}\n />\n <h3 className=\"text-sm font-semibold text-text-primary pt-4 pb-2\">Reports & Alerts</h3>\n <Toggle\n label=\"Daily Summary\"\n description=\"Receive daily business summary email\"\n checked={notifications.dailySummaryEmail}\n onChange={updateNotification('dailySummaryEmail')}\n />\n <Toggle\n label=\"Weekly Summary\"\n description=\"Receive weekly performance report\"\n checked={notifications.weeklySummaryEmail}\n onChange={updateNotification('weeklySummaryEmail')}\n />\n <Toggle\n label=\"Low Stock Alert\"\n description=\"Get alerted when items are low on stock\"\n checked={notifications.lowStockAlert}\n onChange={updateNotification('lowStockAlert')}\n />\n <Toggle\n label=\"Review Notifications\"\n description=\"Get notified for new customer reviews\"\n checked={notifications.reviewNotification}\n onChange={updateNotification('reviewNotification')}\n />\n <Toggle\n label=\"Marketing Emails\"\n description=\"Receive tips and promotional content\"\n checked={notifications.marketingEmails}\n onChange={updateNotification('marketingEmails')}\n />\n </div>\n );\n\n const renderIntegrationTab = () => (\n <div className=\"space-y-5\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Payment Gateway</h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-5\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">Provider</label>\n <select\n value={integration.paymentGateway}\n onChange={(e) => updateIntegration('paymentGateway')(e.target.value)}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n <option value=\"razorpay\">Razorpay</option>\n <option value=\"paytm\">Paytm</option>\n <option value=\"stripe\">Stripe</option>\n <option value=\"phonepe\">PhonePe</option>\n </select>\n </div>\n <FormField\n label=\"API Key\"\n value={integration.paymentGatewayKey}\n onChange={updateIntegration('paymentGatewayKey')}\n placeholder=\"Enter API key\"\n hint=\"Keep this secret\"\n />\n </div>\n <h3 className=\"text-sm font-semibold text-text-primary pt-2\">SMS Provider</h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-5\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">Provider</label>\n <select\n value={integration.smsProvider}\n onChange={(e) => updateIntegration('smsProvider')(e.target.value)}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n <option value=\"twilio\">Twilio</option>\n <option value=\"msg91\">MSG91</option>\n <option value=\"textlocal\">Textlocal</option>\n </select>\n </div>\n <FormField\n label=\"SMS API Key\"\n value={integration.smsApiKey}\n onChange={updateIntegration('smsApiKey')}\n placeholder=\"Enter SMS API key\"\n />\n </div>\n <h3 className=\"text-sm font-semibold text-text-primary pt-2\">Analytics</h3>\n <FormField\n label=\"Google Analytics ID\"\n value={integration.analyticsId}\n onChange={updateIntegration('analyticsId')}\n placeholder=\"GA-XXXXXXXXX\"\n />\n </div>\n );\n\n if (providersLoading) {\n return (\n <PageLayout\n title=\"Business Settings\"\n description=\"Manage your business profile and configuration\"\n >\n <div className=\"flex items-center justify-center py-24\">\n <div className=\"h-10 w-10 animate-spin rounded-full border-b-2 border-foreground\" />\n </div>\n </PageLayout>\n );\n }\n\n if (!myProvider) {\n return (\n <PageLayout\n title=\"Business Settings\"\n description=\"Manage your business profile and configuration\"\n >\n <EmptyState\n illustration=\"empty-generic\"\n title=\"Create your cart first\"\n description=\"You don't have a service provider yet. Set up your cart before configuring its business settings.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/cart-owner/service-config')}\n className=\"inline-flex items-center gap-2 rounded-md bg-accent px-4 py-2 text-sm font-medium text-text-primary hover:bg-accent/80\"\n >\n Set up your cart\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Business Settings\"\n description=\"Manage your business profile and configuration\"\n actions={\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={saving}\n className={cn(\n 'inline-flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors',\n saved\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : saving\n ? 'bg-bg-sunken text-text-secondary cursor-not-allowed'\n : 'bg-accent text-text-primary hover:bg-accent/80'\n )}\n >\n {saving ? (\n <>\n <div className=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n Saving...\n </>\n ) : saved ? (\n <>\n <CheckCircle2 className=\"h-4 w-4\" />\n Saved!\n </>\n ) : (\n <>\n <Save className=\"h-4 w-4\" />\n Save Settings\n </>\n )}\n </button>\n }\n >\n <PagePurpose className=\"mb-6\">\n Your business's public identity and ground rules. Use this page to set your business\n name and branding, contact details and location, operating hours, and the policies (refunds,\n delivery radius, taxes) customers agree to — plus the alerts you receive and any\n integrations you connect. These details shape how customers find and trust your cart.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"kadaikodi-owner-business-settings\"\n className=\"mb-6\"\n steps={[\n {\n id: 'location',\n label: 'Confirm your location & hours',\n description: 'So customers know where and when to find you.',\n onClick: () => setActiveTab('location'),\n },\n {\n id: 'policies',\n label: 'Set your policies',\n description: 'Refunds, delivery radius and taxes.',\n onClick: () => setActiveTab('policies'),\n },\n {\n id: 'config',\n label: 'Configure your service types',\n description: 'Pickup, delivery and scheduled stops.',\n onClick: () => navigateTo('/cart-owner/service-config'),\n },\n ]}\n />\n\n <div className=\"mb-6 flex items-start gap-3 rounded-md border border-border-subtle bg-bg-sunken/50 p-3\">\n <AlertCircle className=\"h-4 w-4 text-text-secondary shrink-0 mt-0.5\" />\n <p className=\"text-xs text-text-secondary\">\n Business name, description and location save to your cart record. Category is fixed at\n cart creation. Contact, policy, notification and integration settings are kept in this\n browser for now.\n </p>\n </div>\n\n {saveError && (\n <div className=\"mb-6 flex items-start gap-3 rounded-md border border-status-error-text/30 bg-status-error-bg-subtle p-3\">\n <AlertCircle className=\"h-4 w-4 text-status-error-text shrink-0 mt-0.5\" />\n <p className=\"text-xs text-status-error-text\">\n We couldn't save your changes just now. Please check your connection and try again.\n </p>\n </div>\n )}\n\n <div className=\"flex flex-col lg:flex-row gap-6\">\n {/* Mobile Tab Navigation */}\n <div className=\"lg:hidden\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3 shadow-sm\">\n <div className=\"grid grid-cols-4 gap-2\">\n {tabs.map((tab) => {\n const Icon = tab.icon;\n return (\n <button\n key={tab.id}\n type=\"button\"\n onClick={() => setActiveTab(tab.id)}\n className={cn(\n 'flex flex-col items-center gap-1 rounded-md px-2 py-2 text-xs font-medium transition-colors',\n activeTab === tab.id\n ? 'bg-accent text-text-primary'\n : 'text-text-secondary hover:bg-bg-sunken'\n )}\n >\n <Icon className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">{tab.label}</span>\n </button>\n );\n })}\n </div>\n </div>\n </div>\n\n {/* Desktop Sidebar */}\n <div className=\"hidden lg:block lg:w-56 shrink-0\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface shadow-sm sticky top-24\">\n <div className=\"p-4 border-b border-border-subtle\">\n <h2 className=\"font-semibold text-text-primary text-sm\">Settings</h2>\n </div>\n <nav className=\"p-2\">\n {tabs.map((tab) => {\n const Icon = tab.icon;\n return (\n <button\n key={tab.id}\n type=\"button\"\n onClick={() => setActiveTab(tab.id)}\n className={cn(\n 'w-full text-left px-3 py-2 rounded-md mb-1 flex items-center gap-3 text-sm transition-colors',\n activeTab === tab.id\n ? 'bg-accent text-text-primary font-medium'\n : 'text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n <Icon className=\"h-4 w-4\" />\n {tab.label}\n </button>\n );\n })}\n </nav>\n </div>\n </div>\n\n {/* Content — the one emphasis zone for this page */}\n <div className=\"flex-1 min-w-0\">\n <EmphasisPanel className=\"p-5 sm:p-6\">\n {activeTab === 'general' && renderGeneralTab()}\n {activeTab === 'contact' && renderContactTab()}\n {activeTab === 'location' && renderLocationTab()}\n {activeTab === 'operating' && renderOperatingTab()}\n {activeTab === 'policies' && renderPoliciesTab()}\n {activeTab === 'notifications' && renderNotificationsTab()}\n {activeTab === 'integration' && renderIntegrationTab()}\n\n {/* Save Button (bottom) */}\n <div className=\"flex justify-end mt-8 pt-6 border-t border-border-subtle\">\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={saving}\n className={cn(\n 'inline-flex items-center gap-2 rounded-md px-6 py-2 text-sm font-medium transition-colors',\n saved\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : saving\n ? 'bg-bg-sunken text-text-secondary cursor-not-allowed'\n : 'bg-accent text-text-primary hover:bg-accent/80'\n )}\n >\n {saving ? (\n <>\n <div className=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n Saving...\n </>\n ) : saved ? (\n <>\n <CheckCircle2 className=\"h-4 w-4\" />\n Saved!\n </>\n ) : (\n <>\n <Save className=\"h-4 w-4\" />\n Save Settings\n </>\n )}\n </button>\n </div>\n </EmphasisPanel>\n </div>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BusinessSettingsPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/cart-owner/BusinessSettingsPage.tsx"],"sourcesContent":["/**\n * Business Settings Page\n *\n * Tabbed interface (general/contact/location/operating/policies/notifications/integrations),\n * all form fields per tab including social media, coordinates, delivery charges,\n * payment methods, policy textareas, notification toggles, payment gateway config.\n *\n * @module kadaikodi/pages/cart-owner\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport {\n Store,\n Save,\n AlertCircle,\n MapPin,\n Clock,\n Shield,\n Bell,\n Link2,\n CheckCircle2,\n Phone,\n Gift,\n ChevronRight,\n} from 'lucide-react';\nimport { EmphasisPanel, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport { useProviders, useUpdateProvider } from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype TabId =\n 'general' | 'contact' | 'location' | 'operating' | 'policies' | 'notifications' | 'integration';\n\ninterface Tab {\n id: TabId;\n label: string;\n icon: typeof Store;\n}\n\ninterface GeneralSettings {\n businessName: string;\n description: string;\n category: string;\n gstNumber: string;\n panNumber: string;\n fssaiLicense: string;\n establishedYear: string;\n}\n\ninterface ContactSettings {\n phone: string;\n email: string;\n website: string;\n whatsapp: string;\n instagram: string;\n twitter: string;\n facebook: string;\n}\n\ninterface LocationSettings {\n address: string;\n city: string;\n state: string;\n pincode: string;\n latitude: string;\n longitude: string;\n deliveryRadius: number;\n deliveryCharge: number;\n freeDeliveryAbove: number;\n}\n\ninterface OperatingSettings {\n autoAcceptOrders: boolean;\n preparationTime: number;\n maxConcurrentOrders: number;\n advanceBookingDays: number;\n}\n\ninterface PolicySettings {\n returnPolicy: string;\n cancellationPolicy: string;\n privacyPolicy: string;\n termsOfService: string;\n}\n\ninterface NotificationSettings {\n newOrderEmail: boolean;\n newOrderSms: boolean;\n newOrderPush: boolean;\n orderUpdateEmail: boolean;\n orderUpdatePush: boolean;\n dailySummaryEmail: boolean;\n weeklySummaryEmail: boolean;\n lowStockAlert: boolean;\n reviewNotification: boolean;\n marketingEmails: boolean;\n}\n\ninterface IntegrationSettings {\n paymentGateway: string;\n paymentGatewayKey: string;\n smsProvider: string;\n smsApiKey: string;\n analyticsId: string;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst tabs: Tab[] = [\n { id: 'general', label: 'General', icon: Store },\n { id: 'contact', label: 'Contact', icon: Phone },\n { id: 'location', label: 'Location', icon: MapPin },\n { id: 'operating', label: 'Operating', icon: Clock },\n { id: 'policies', label: 'Policies', icon: Shield },\n { id: 'notifications', label: 'Notifications', icon: Bell },\n { id: 'integration', label: 'Integrations', icon: Link2 },\n];\n\nconst categories = [\n 'Food & Beverage',\n 'Personal Care & Beauty',\n 'Repair & Maintenance',\n 'Home Services',\n 'Clothing & Fashion',\n 'Health & Wellness',\n 'Education & Skills',\n 'Retail & Merchandise',\n 'Grocery & Essentials',\n];\n\n// ============================================================================\n// Form Field Component\n// ============================================================================\n\ninterface FormFieldProps {\n label: string;\n value: string | number;\n onChange: (value: string) => void;\n type?: 'text' | 'email' | 'tel' | 'url' | 'number' | 'textarea' | 'select';\n options?: string[];\n placeholder?: string;\n hint?: string;\n rows?: number;\n disabled?: boolean;\n}\n\nconst FormField = ({\n label,\n value,\n onChange,\n type = 'text',\n options,\n placeholder,\n hint,\n rows = 3,\n disabled = false,\n}: FormFieldProps) => {\n const id = label.toLowerCase().replace(/\\s+/g, '-');\n return (\n <div>\n <label htmlFor={id} className=\"block text-sm font-medium text-text-primary mb-1.5\">\n {label}\n </label>\n {type === 'textarea' ? (\n <textarea\n id={id}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n rows={rows}\n placeholder={placeholder}\n disabled={disabled}\n className={cn(\n 'w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none',\n disabled && 'bg-bg-sunken/50 cursor-not-allowed'\n )}\n />\n ) : type === 'select' ? (\n <select\n id={id}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n disabled={disabled}\n className={cn(\n 'w-full rounded-md 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 disabled && 'bg-bg-sunken/50 cursor-not-allowed'\n )}\n >\n {options?.map((opt) => (\n <option key={opt} value={opt}>\n {opt}\n </option>\n ))}\n </select>\n ) : (\n <input\n id={id}\n type={type}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n placeholder={placeholder}\n disabled={disabled}\n className={cn(\n 'w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]',\n disabled && 'bg-bg-sunken/50 cursor-not-allowed'\n )}\n />\n )}\n {hint && <p className=\"mt-1 text-xs text-text-secondary\">{hint}</p>}\n </div>\n );\n};\n\n// ============================================================================\n// Toggle Component\n// ============================================================================\n\nconst Toggle = ({\n label,\n description,\n checked,\n onChange,\n}: {\n label: string;\n description?: string;\n checked: boolean;\n onChange: (v: boolean) => void;\n}) => (\n <div className=\"flex items-center justify-between py-3\">\n <div>\n <p className=\"text-sm font-medium text-text-primary\">{label}</p>\n {description && <p className=\"text-xs text-text-secondary mt-0.5\">{description}</p>}\n </div>\n <button\n type=\"button\"\n onClick={() => onChange(!checked)}\n className={cn(\n 'h-6 w-11 rounded-full transition-colors relative',\n checked ? 'bg-action-primary-bg' : 'bg-muted-foreground/30'\n )}\n >\n <div\n className={cn(\n 'absolute top-0.5 h-5 w-5 rounded-full bg-white transition-transform',\n checked ? 'translate-x-5' : 'translate-x-0.5'\n )}\n />\n </button>\n </div>\n);\n\n// ============================================================================\n// Component\n// ============================================================================\n\nconst CATEGORY_LABELS: Record<string, string> = {\n FOOD_BEVERAGE: 'Food & Beverage',\n PERSONAL_CARE_BEAUTY: 'Personal Care & Beauty',\n CLOTHING_FASHION: 'Clothing & Fashion',\n REPAIR_MAINTENANCE: 'Repair & Maintenance',\n HOME_SERVICES: 'Home Services',\n HEALTH_WELLNESS: 'Health & Wellness',\n EDUCATION_SKILLS: 'Education & Skills',\n RETAIL_MERCHANDISE: 'Retail & Merchandise',\n GROCERY_ESSENTIALS: 'Grocery & Essentials',\n};\n\nexport const BusinessSettingsPage = () => {\n const { navigateTo, currentUser } = useKadaikodi();\n const [activeTab, setActiveTab] = useState<TabId>('general');\n const updateProvider = useUpdateProvider();\n const saving = updateProvider.isPending;\n const [saved, setSaved] = useState(false);\n const [saveError, setSaveError] = useState(false);\n\n // Resolve the signed-in owner's provider (\"my cart\") to seed the form.\n const { data: providers = [], isLoading: providersLoading } = useProviders();\n const myProvider = useMemo(\n () => providers.find((p) => p.ownerId === currentUser?.id) ?? providers[0],\n [providers, currentUser?.id]\n );\n\n // Form state — seeded blank; real provider values are applied once loaded.\n // Fields with no backend source stay empty (placeholders only), never fabricated.\n const [general, setGeneral] = useState<GeneralSettings>({\n businessName: '',\n description: '',\n category: 'Food & Beverage',\n gstNumber: '',\n panNumber: '',\n fssaiLicense: '',\n establishedYear: '',\n });\n\n const [contact, setContact] = useState<ContactSettings>({\n phone: '',\n email: '',\n website: '',\n whatsapp: '',\n instagram: '',\n twitter: '',\n facebook: '',\n });\n\n const [location, setLocation] = useState<LocationSettings>({\n address: '',\n city: '',\n state: '',\n pincode: '',\n latitude: '',\n longitude: '',\n deliveryRadius: 5,\n deliveryCharge: 30,\n freeDeliveryAbove: 300,\n });\n\n const [operating, setOperating] = useState<OperatingSettings>({\n autoAcceptOrders: true,\n preparationTime: 15,\n maxConcurrentOrders: 10,\n advanceBookingDays: 3,\n });\n\n const [policies, setPolicies] = useState<PolicySettings>({\n returnPolicy: '',\n cancellationPolicy: '',\n privacyPolicy: '',\n termsOfService: '',\n });\n\n const [notifications, setNotifications] = useState<NotificationSettings>({\n newOrderEmail: true,\n newOrderSms: true,\n newOrderPush: true,\n orderUpdateEmail: true,\n orderUpdatePush: true,\n dailySummaryEmail: true,\n weeklySummaryEmail: false,\n lowStockAlert: true,\n reviewNotification: true,\n marketingEmails: false,\n });\n\n const [integration, setIntegration] = useState<IntegrationSettings>({\n paymentGateway: 'razorpay',\n paymentGatewayKey: '',\n smsProvider: 'twilio',\n smsApiKey: '',\n analyticsId: '',\n });\n\n // Seed general/location from the provider's real data once it loads.\n const [seeded, setSeeded] = useState(false);\n useEffect(() => {\n if (!myProvider || seeded) return;\n const categoryLabel = CATEGORY_LABELS[myProvider.category] ?? myProvider.category;\n setGeneral((p) => ({\n ...p,\n businessName: myProvider.name,\n category: categories.includes(categoryLabel) ? categoryLabel : p.category,\n }));\n const coords = myProvider.location?.coordinates;\n setLocation((p) => ({\n ...p,\n address: myProvider.location?.address ?? '',\n latitude: coords?.lat ? String(coords.lat) : '',\n longitude: coords?.lng ? String(coords.lng) : '',\n }));\n setSeeded(true);\n }, [myProvider, seeded]);\n\n const handleSave = () => {\n if (!myProvider) return;\n setSaveError(false);\n\n // Only the fields the provider record supports are persisted: business name,\n // description, and location (address + coordinates). Category is fixed at cart\n // creation and cannot be edited here; contact / policy / notification /\n // integration settings have no backend field yet and stay in this browser.\n const lat = parseFloat(location.latitude);\n const lng = parseFloat(location.longitude);\n const input: Record<string, unknown> = {\n name: general.businessName,\n description: general.description || undefined,\n location: {\n address: location.address,\n latitude: Number.isFinite(lat) ? lat : undefined,\n longitude: Number.isFinite(lng) ? lng : undefined,\n coordinates: {\n lat: Number.isFinite(lat) ? lat : 0,\n lng: Number.isFinite(lng) ? lng : 0,\n },\n },\n };\n\n updateProvider.mutate(\n { id: myProvider.id, input },\n {\n onSuccess: () => {\n setSaved(true);\n setTimeout(() => setSaved(false), 3000);\n },\n onError: () => setSaveError(true),\n }\n );\n };\n\n const updateGeneral = (field: keyof GeneralSettings) => (value: string) =>\n setGeneral((p) => ({ ...p, [field]: value }));\n const updateContact = (field: keyof ContactSettings) => (value: string) =>\n setContact((p) => ({ ...p, [field]: value }));\n const updateLocation = (field: keyof LocationSettings) => (value: string) =>\n setLocation((p) => ({\n ...p,\n [field]:\n field === 'deliveryRadius' || field === 'deliveryCharge' || field === 'freeDeliveryAbove'\n ? parseInt(value) || 0\n : value,\n }));\n const updatePolicies = (field: keyof PolicySettings) => (value: string) =>\n setPolicies((p) => ({ ...p, [field]: value }));\n const updateNotification = (field: keyof NotificationSettings) => (value: boolean) =>\n setNotifications((p) => ({ ...p, [field]: value }));\n const updateIntegration = (field: keyof IntegrationSettings) => (value: string) =>\n setIntegration((p) => ({ ...p, [field]: value }));\n\n // ---- Tab content renderers ----\n\n const renderGeneralTab = () => (\n <div className=\"space-y-5\">\n <FormField\n label=\"Business Name\"\n value={general.businessName}\n onChange={updateGeneral('businessName')}\n />\n <FormField\n label=\"Description\"\n value={general.description}\n onChange={updateGeneral('description')}\n type=\"textarea\"\n />\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-5\">\n <FormField\n label=\"Category\"\n value={general.category}\n onChange={updateGeneral('category')}\n type=\"select\"\n options={categories}\n disabled\n hint=\"Set when your cart was created and can't be changed here.\"\n />\n <FormField\n label=\"Established Year\"\n value={general.establishedYear}\n onChange={updateGeneral('establishedYear')}\n />\n </div>\n <div className=\"flex items-start gap-3 rounded-md bg-[var(--color-accent-soft)] border border-border-focus/20 p-3\">\n <AlertCircle className=\"h-4 w-4 text-text-primary shrink-0 mt-0.5\" />\n <p className=\"text-xs text-text-primary\">\n GST, PAN, and FSSAI details are used for invoicing and compliance. Changes require\n verification.\n </p>\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-5\">\n <FormField\n label=\"GST Number\"\n value={general.gstNumber}\n onChange={updateGeneral('gstNumber')}\n hint=\"15-digit GST ID\"\n />\n <FormField\n label=\"PAN Number\"\n value={general.panNumber}\n onChange={updateGeneral('panNumber')}\n hint=\"10-digit PAN\"\n />\n <FormField\n label=\"FSSAI License\"\n value={general.fssaiLicense}\n onChange={updateGeneral('fssaiLicense')}\n hint=\"FSSAI license number\"\n />\n </div>\n </div>\n );\n\n const renderContactTab = () => (\n <div className=\"space-y-5\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-5\">\n <FormField\n label=\"Phone\"\n value={contact.phone}\n onChange={updateContact('phone')}\n type=\"tel\"\n />\n <FormField\n label=\"Email\"\n value={contact.email}\n onChange={updateContact('email')}\n type=\"email\"\n />\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-5\">\n <FormField\n label=\"Website\"\n value={contact.website}\n onChange={updateContact('website')}\n type=\"url\"\n placeholder=\"https://\"\n />\n <FormField\n label=\"WhatsApp\"\n value={contact.whatsapp}\n onChange={updateContact('whatsapp')}\n type=\"tel\"\n />\n </div>\n <h3 className=\"text-sm font-semibold text-text-primary pt-2\">Social Media</h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-5\">\n <FormField\n label=\"Instagram\"\n value={contact.instagram}\n onChange={updateContact('instagram')}\n placeholder=\"@handle\"\n />\n <FormField\n label=\"Twitter / X\"\n value={contact.twitter}\n onChange={updateContact('twitter')}\n placeholder=\"@handle\"\n />\n <FormField\n label=\"Facebook\"\n value={contact.facebook}\n onChange={updateContact('facebook')}\n placeholder=\"Page name\"\n />\n </div>\n </div>\n );\n\n const renderLocationTab = () => (\n <div className=\"space-y-5\">\n <FormField\n label=\"Address\"\n value={location.address}\n onChange={updateLocation('address')}\n type=\"textarea\"\n rows={2}\n />\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-5\">\n <FormField label=\"City\" value={location.city} onChange={updateLocation('city')} />\n <FormField label=\"State\" value={location.state} onChange={updateLocation('state')} />\n <FormField label=\"Pincode\" value={location.pincode} onChange={updateLocation('pincode')} />\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-5\">\n <FormField\n label=\"Latitude\"\n value={location.latitude}\n onChange={updateLocation('latitude')}\n hint=\"e.g., 12.9352\"\n />\n <FormField\n label=\"Longitude\"\n value={location.longitude}\n onChange={updateLocation('longitude')}\n hint=\"e.g., 77.6245\"\n />\n </div>\n <h3 className=\"text-sm font-semibold text-text-primary pt-2\">Delivery Settings</h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-5\">\n <FormField\n label=\"Delivery Radius (km)\"\n value={location.deliveryRadius}\n onChange={updateLocation('deliveryRadius')}\n type=\"number\"\n />\n <FormField\n label=\"Delivery Charge (₹)\"\n value={location.deliveryCharge}\n onChange={updateLocation('deliveryCharge')}\n type=\"number\"\n />\n <FormField\n label=\"Free Delivery Above (₹)\"\n value={location.freeDeliveryAbove}\n onChange={updateLocation('freeDeliveryAbove')}\n type=\"number\"\n />\n </div>\n </div>\n );\n\n const renderOperatingTab = () => (\n <div className=\"space-y-5\">\n <Toggle\n label=\"Auto-Accept Orders\"\n description=\"Automatically accept incoming orders without manual confirmation\"\n checked={operating.autoAcceptOrders}\n onChange={(v) => setOperating((p) => ({ ...p, autoAcceptOrders: v }))}\n />\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-5\">\n <FormField\n label=\"Default Preparation Time (min)\"\n value={operating.preparationTime}\n onChange={(v) => setOperating((p) => ({ ...p, preparationTime: parseInt(v) || 0 }))}\n type=\"number\"\n />\n <FormField\n label=\"Max Concurrent Orders\"\n value={operating.maxConcurrentOrders}\n onChange={(v) => setOperating((p) => ({ ...p, maxConcurrentOrders: parseInt(v) || 0 }))}\n type=\"number\"\n />\n <FormField\n label=\"Advance Booking (days)\"\n value={operating.advanceBookingDays}\n onChange={(v) => setOperating((p) => ({ ...p, advanceBookingDays: parseInt(v) || 0 }))}\n type=\"number\"\n />\n </div>\n </div>\n );\n\n const renderPoliciesTab = () => (\n <div className=\"space-y-5\">\n <FormField\n label=\"Return Policy\"\n value={policies.returnPolicy}\n onChange={updatePolicies('returnPolicy')}\n type=\"textarea\"\n rows={4}\n />\n <FormField\n label=\"Cancellation Policy\"\n value={policies.cancellationPolicy}\n onChange={updatePolicies('cancellationPolicy')}\n type=\"textarea\"\n rows={4}\n />\n <FormField\n label=\"Privacy Policy\"\n value={policies.privacyPolicy}\n onChange={updatePolicies('privacyPolicy')}\n type=\"textarea\"\n rows={4}\n />\n <FormField\n label=\"Terms of Service\"\n value={policies.termsOfService}\n onChange={updatePolicies('termsOfService')}\n type=\"textarea\"\n rows={4}\n />\n </div>\n );\n\n const renderNotificationsTab = () => (\n <div className=\"space-y-1 divide-y divide-border\">\n <h3 className=\"text-sm font-semibold text-text-primary pb-2\">New Orders</h3>\n <Toggle\n label=\"Email Notification\"\n description=\"Receive email for new orders\"\n checked={notifications.newOrderEmail}\n onChange={updateNotification('newOrderEmail')}\n />\n <Toggle\n label=\"SMS Notification\"\n description=\"Receive SMS for new orders\"\n checked={notifications.newOrderSms}\n onChange={updateNotification('newOrderSms')}\n />\n <Toggle\n label=\"Push Notification\"\n description=\"Receive push notifications for new orders\"\n checked={notifications.newOrderPush}\n onChange={updateNotification('newOrderPush')}\n />\n <h3 className=\"text-sm font-semibold text-text-primary pt-4 pb-2\">Order Updates</h3>\n <Toggle\n label=\"Email Updates\"\n description=\"Get email when order status changes\"\n checked={notifications.orderUpdateEmail}\n onChange={updateNotification('orderUpdateEmail')}\n />\n <Toggle\n label=\"Push Updates\"\n description=\"Get push notifications for order updates\"\n checked={notifications.orderUpdatePush}\n onChange={updateNotification('orderUpdatePush')}\n />\n <h3 className=\"text-sm font-semibold text-text-primary pt-4 pb-2\">Reports & Alerts</h3>\n <Toggle\n label=\"Daily Summary\"\n description=\"Receive daily business summary email\"\n checked={notifications.dailySummaryEmail}\n onChange={updateNotification('dailySummaryEmail')}\n />\n <Toggle\n label=\"Weekly Summary\"\n description=\"Receive weekly performance report\"\n checked={notifications.weeklySummaryEmail}\n onChange={updateNotification('weeklySummaryEmail')}\n />\n <Toggle\n label=\"Low Stock Alert\"\n description=\"Get alerted when items are low on stock\"\n checked={notifications.lowStockAlert}\n onChange={updateNotification('lowStockAlert')}\n />\n <Toggle\n label=\"Review Notifications\"\n description=\"Get notified for new customer reviews\"\n checked={notifications.reviewNotification}\n onChange={updateNotification('reviewNotification')}\n />\n <Toggle\n label=\"Marketing Emails\"\n description=\"Receive tips and promotional content\"\n checked={notifications.marketingEmails}\n onChange={updateNotification('marketingEmails')}\n />\n </div>\n );\n\n const renderIntegrationTab = () => (\n <div className=\"space-y-5\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Payment Gateway</h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-5\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">Provider</label>\n <select\n value={integration.paymentGateway}\n onChange={(e) => updateIntegration('paymentGateway')(e.target.value)}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n <option value=\"razorpay\">Razorpay</option>\n <option value=\"paytm\">Paytm</option>\n <option value=\"stripe\">Stripe</option>\n <option value=\"phonepe\">PhonePe</option>\n </select>\n </div>\n <FormField\n label=\"API Key\"\n value={integration.paymentGatewayKey}\n onChange={updateIntegration('paymentGatewayKey')}\n placeholder=\"Enter API key\"\n hint=\"Keep this secret\"\n />\n </div>\n <h3 className=\"text-sm font-semibold text-text-primary pt-2\">SMS Provider</h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-5\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">Provider</label>\n <select\n value={integration.smsProvider}\n onChange={(e) => updateIntegration('smsProvider')(e.target.value)}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n <option value=\"twilio\">Twilio</option>\n <option value=\"msg91\">MSG91</option>\n <option value=\"textlocal\">Textlocal</option>\n </select>\n </div>\n <FormField\n label=\"SMS API Key\"\n value={integration.smsApiKey}\n onChange={updateIntegration('smsApiKey')}\n placeholder=\"Enter SMS API key\"\n />\n </div>\n <h3 className=\"text-sm font-semibold text-text-primary pt-2\">Analytics</h3>\n <FormField\n label=\"Google Analytics ID\"\n value={integration.analyticsId}\n onChange={updateIntegration('analyticsId')}\n placeholder=\"GA-XXXXXXXXX\"\n />\n </div>\n );\n\n if (providersLoading) {\n return (\n <PageLayout\n title=\"Business Settings\"\n description=\"Manage your business profile and configuration\"\n >\n <div className=\"flex items-center justify-center py-24\">\n <div className=\"h-10 w-10 animate-spin rounded-full border-b-2 border-foreground\" />\n </div>\n </PageLayout>\n );\n }\n\n if (!myProvider) {\n return (\n <PageLayout\n title=\"Business Settings\"\n description=\"Manage your business profile and configuration\"\n >\n <EmptyState\n illustration=\"empty-generic\"\n title=\"Create your cart first\"\n description=\"You don't have a service provider yet. Set up your cart before configuring its business settings.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/cart-owner/service-config')}\n className=\"inline-flex items-center gap-2 rounded-md bg-accent px-4 py-2 text-sm font-medium text-text-primary hover:bg-accent/80\"\n >\n Set up your cart\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Business Settings\"\n description=\"Manage your business profile and configuration\"\n actions={\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={saving}\n className={cn(\n 'inline-flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors',\n saved\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : saving\n ? 'bg-bg-sunken text-text-secondary cursor-not-allowed'\n : 'bg-accent text-text-primary hover:bg-accent/80'\n )}\n >\n {saving ? (\n <>\n <div className=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n Saving...\n </>\n ) : saved ? (\n <>\n <CheckCircle2 className=\"h-4 w-4\" />\n Saved!\n </>\n ) : (\n <>\n <Save className=\"h-4 w-4\" />\n Save Settings\n </>\n )}\n </button>\n }\n >\n <PagePurpose className=\"mb-6\">\n Your business's public identity and ground rules. Use this page to set your business\n name and branding, contact details and location, operating hours, and the policies (refunds,\n delivery radius, taxes) customers agree to — plus the alerts you receive and any\n integrations you connect. These details shape how customers find and trust your cart.\n </PagePurpose>\n\n {/* Loyalty program — marketplace-wide, managed on its own page (BOFF-4290) */}\n <button\n type=\"button\"\n onClick={() => navigateTo('/cart-owner/loyalty')}\n className=\"mb-6 flex w-full items-center justify-between rounded-lg border border-border-subtle bg-bg-surface p-4 text-left hover:bg-accent transition-colors\"\n >\n <span className=\"flex items-center gap-3\">\n <span className=\"flex h-10 w-10 items-center justify-center rounded-lg bg-[var(--color-accent-soft)]\">\n <Gift className=\"h-5 w-5 text-text-primary\" />\n </span>\n <span>\n <span className=\"block text-sm font-semibold text-text-primary\">Loyalty Program</span>\n <span className=\"block text-xs text-text-secondary\">\n Look up customer point balances, award goodwill points, and review the ledger\n </span>\n </span>\n </span>\n <ChevronRight className=\"h-4 w-4 text-text-secondary shrink-0\" />\n </button>\n\n <NextSteps\n storageKey=\"kadaikodi-owner-business-settings\"\n className=\"mb-6\"\n steps={[\n {\n id: 'location',\n label: 'Confirm your location & hours',\n description: 'So customers know where and when to find you.',\n onClick: () => setActiveTab('location'),\n },\n {\n id: 'policies',\n label: 'Set your policies',\n description: 'Refunds, delivery radius and taxes.',\n onClick: () => setActiveTab('policies'),\n },\n {\n id: 'config',\n label: 'Configure your service types',\n description: 'Pickup, delivery and scheduled stops.',\n onClick: () => navigateTo('/cart-owner/service-config'),\n },\n ]}\n />\n\n <div className=\"mb-6 flex items-start gap-3 rounded-md border border-border-subtle bg-bg-sunken/50 p-3\">\n <AlertCircle className=\"h-4 w-4 text-text-secondary shrink-0 mt-0.5\" />\n <p className=\"text-xs text-text-secondary\">\n Business name, description and location save to your cart record. Category is fixed at\n cart creation. Contact, policy, notification and integration settings are kept in this\n browser for now.\n </p>\n </div>\n\n {saveError && (\n <div className=\"mb-6 flex items-start gap-3 rounded-md border border-status-error-text/30 bg-status-error-bg-subtle p-3\">\n <AlertCircle className=\"h-4 w-4 text-status-error-text shrink-0 mt-0.5\" />\n <p className=\"text-xs text-status-error-text\">\n We couldn't save your changes just now. Please check your connection and try again.\n </p>\n </div>\n )}\n\n <div className=\"flex flex-col lg:flex-row gap-6\">\n {/* Mobile Tab Navigation */}\n <div className=\"lg:hidden\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-3 shadow-sm\">\n <div className=\"grid grid-cols-4 gap-2\">\n {tabs.map((tab) => {\n const Icon = tab.icon;\n return (\n <button\n key={tab.id}\n type=\"button\"\n onClick={() => setActiveTab(tab.id)}\n className={cn(\n 'flex flex-col items-center gap-1 rounded-md px-2 py-2 text-xs font-medium transition-colors',\n activeTab === tab.id\n ? 'bg-accent text-text-primary'\n : 'text-text-secondary hover:bg-bg-sunken'\n )}\n >\n <Icon className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">{tab.label}</span>\n </button>\n );\n })}\n </div>\n </div>\n </div>\n\n {/* Desktop Sidebar */}\n <div className=\"hidden lg:block lg:w-56 shrink-0\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface shadow-sm sticky top-24\">\n <div className=\"p-4 border-b border-border-subtle\">\n <h2 className=\"font-semibold text-text-primary text-sm\">Settings</h2>\n </div>\n <nav className=\"p-2\">\n {tabs.map((tab) => {\n const Icon = tab.icon;\n return (\n <button\n key={tab.id}\n type=\"button\"\n onClick={() => setActiveTab(tab.id)}\n className={cn(\n 'w-full text-left px-3 py-2 rounded-md mb-1 flex items-center gap-3 text-sm transition-colors',\n activeTab === tab.id\n ? 'bg-accent text-text-primary font-medium'\n : 'text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n <Icon className=\"h-4 w-4\" />\n {tab.label}\n </button>\n );\n })}\n </nav>\n </div>\n </div>\n\n {/* Content — the one emphasis zone for this page */}\n <div className=\"flex-1 min-w-0\">\n <EmphasisPanel className=\"p-5 sm:p-6\">\n {activeTab === 'general' && renderGeneralTab()}\n {activeTab === 'contact' && renderContactTab()}\n {activeTab === 'location' && renderLocationTab()}\n {activeTab === 'operating' && renderOperatingTab()}\n {activeTab === 'policies' && renderPoliciesTab()}\n {activeTab === 'notifications' && renderNotificationsTab()}\n {activeTab === 'integration' && renderIntegrationTab()}\n\n {/* Save Button (bottom) */}\n <div className=\"flex justify-end mt-8 pt-6 border-t border-border-subtle\">\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={saving}\n className={cn(\n 'inline-flex items-center gap-2 rounded-md px-6 py-2 text-sm font-medium transition-colors',\n saved\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : saving\n ? 'bg-bg-sunken text-text-secondary cursor-not-allowed'\n : 'bg-accent text-text-primary hover:bg-accent/80'\n )}\n >\n {saving ? (\n <>\n <div className=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n Saving...\n </>\n ) : saved ? (\n <>\n <CheckCircle2 className=\"h-4 w-4\" />\n Saved!\n </>\n ) : (\n <>\n <Save className=\"h-4 w-4\" />\n Save Settings\n </>\n )}\n </button>\n </div>\n </EmphasisPanel>\n </div>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loyalty Management Page
|
|
3
|
+
* @module kadaikodi/pages/cart-owner
|
|
4
|
+
*
|
|
5
|
+
* Merchant/admin view of the marketplace-wide loyalty program (BOFF-4290):
|
|
6
|
+
* look up a customer's points balance, manually award goodwill/compensation
|
|
7
|
+
* points, and browse the recent points ledger. Backed by real server
|
|
8
|
+
* persistence (kadaikodiLoyaltyAccount / kadaikodiListLoyaltyTransactions /
|
|
9
|
+
* kadaikodiAwardLoyaltyPoints) — no client-only state.
|
|
10
|
+
*/
|
|
11
|
+
export declare function LoyaltyManagementPage(): import("react").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=LoyaltyManagementPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoyaltyManagementPage.d.ts","sourceRoot":"","sources":["../../../../src/kadaikodi/pages/cart-owner/LoyaltyManagementPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAcH,wBAAgB,qBAAqB,gCAuNpC"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { cn as e } from "../../utils/cn.js";
|
|
2
|
+
import { PageLayout as t } from "../../components/PageLayout.js";
|
|
3
|
+
import { EmptyState as n } from "../../components/EmptyState.js";
|
|
4
|
+
import { useAwardLoyaltyPoints as r, useListLoyaltyTransactions as i, useLoyaltyAccountByCustomerId as a } from "../../hooks/useKadaikodiApi.js";
|
|
5
|
+
import { useState as o } from "react";
|
|
6
|
+
import { CheckCircle2 as s, Gift as c, History as l, Loader2 as u, Search as d } from "lucide-react";
|
|
7
|
+
import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
8
|
+
import { EmphasisPanel as h, PagePurpose as g } from "@burdenoff/fe-libs/ui";
|
|
9
|
+
//#region src/kadaikodi/pages/cart-owner/LoyaltyManagementPage.tsx
|
|
10
|
+
function _() {
|
|
11
|
+
let [_, v] = o(""), [y, b] = o(""), [x, S] = o("100"), [C, w] = o(""), [T, E] = o(null), [D, O] = o(null), { data: k, isLoading: A } = a(y), { data: j = [], isLoading: M } = i(y || void 0), N = r(), P = (e) => {
|
|
12
|
+
E(e), setTimeout(() => E(null), 4e3);
|
|
13
|
+
}, F = () => {
|
|
14
|
+
b(_.trim());
|
|
15
|
+
};
|
|
16
|
+
return /* @__PURE__ */ m(t, {
|
|
17
|
+
title: "Loyalty Program",
|
|
18
|
+
description: "Look up customer balances, award goodwill points, and review the recent ledger",
|
|
19
|
+
children: [
|
|
20
|
+
/* @__PURE__ */ p(g, {
|
|
21
|
+
className: "mb-6",
|
|
22
|
+
children: "Kadaikodi's loyalty program is marketplace-wide: customers earn 1 point per ₹100 spent on every completed order (across any cart), and can redeem points for a discount on a future order. Use this page to support a specific customer — check their balance, credit a goodwill/compensation award, and review recent activity."
|
|
23
|
+
}),
|
|
24
|
+
/* @__PURE__ */ m("div", {
|
|
25
|
+
className: "rounded-lg border border-border-subtle bg-bg-surface p-5 mb-6",
|
|
26
|
+
children: [/* @__PURE__ */ p("h3", {
|
|
27
|
+
className: "text-base font-semibold text-text-primary mb-3",
|
|
28
|
+
children: "Look up a customer"
|
|
29
|
+
}), /* @__PURE__ */ m("div", {
|
|
30
|
+
className: "flex flex-col sm:flex-row gap-3",
|
|
31
|
+
children: [/* @__PURE__ */ p("input", {
|
|
32
|
+
type: "text",
|
|
33
|
+
placeholder: "Customer id (actor id)",
|
|
34
|
+
value: _,
|
|
35
|
+
onChange: (e) => v(e.target.value),
|
|
36
|
+
onKeyDown: (e) => e.key === "Enter" && F(),
|
|
37
|
+
className: "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]"
|
|
38
|
+
}), /* @__PURE__ */ m("button", {
|
|
39
|
+
type: "button",
|
|
40
|
+
onClick: F,
|
|
41
|
+
disabled: !_.trim(),
|
|
42
|
+
className: "flex items-center justify-center gap-2 rounded-lg bg-foreground px-4 py-2.5 text-sm font-medium text-background hover:opacity-90 transition-opacity disabled:opacity-50 disabled:cursor-not-allowed",
|
|
43
|
+
children: [/* @__PURE__ */ p(d, { className: "h-4 w-4" }), "Look up"]
|
|
44
|
+
})]
|
|
45
|
+
})]
|
|
46
|
+
}),
|
|
47
|
+
T && /* @__PURE__ */ m("div", {
|
|
48
|
+
className: "mb-4 rounded-lg border border-status-success-text/30 bg-status-success-bg-subtle p-3 flex items-center gap-2",
|
|
49
|
+
children: [/* @__PURE__ */ p(s, { className: "h-4 w-4 text-status-success-text shrink-0" }), /* @__PURE__ */ p("p", {
|
|
50
|
+
className: "text-sm text-status-success-text",
|
|
51
|
+
children: T
|
|
52
|
+
})]
|
|
53
|
+
}),
|
|
54
|
+
D && /* @__PURE__ */ p("div", {
|
|
55
|
+
className: "mb-4 rounded-lg border border-status-error-text/30 bg-status-error-bg/10 p-3",
|
|
56
|
+
children: /* @__PURE__ */ p("p", {
|
|
57
|
+
className: "text-sm text-status-error-text",
|
|
58
|
+
children: D
|
|
59
|
+
})
|
|
60
|
+
}),
|
|
61
|
+
y && /* @__PURE__ */ m(f, { children: [
|
|
62
|
+
A ? /* @__PURE__ */ p("div", {
|
|
63
|
+
className: "flex h-24 items-center justify-center mb-6",
|
|
64
|
+
children: /* @__PURE__ */ p(u, { className: "h-6 w-6 animate-spin text-text-secondary" })
|
|
65
|
+
}) : /* @__PURE__ */ p(h, {
|
|
66
|
+
className: "mb-6",
|
|
67
|
+
children: /* @__PURE__ */ m("div", {
|
|
68
|
+
className: "flex items-center gap-2 text-sm text-text-secondary",
|
|
69
|
+
children: [/* @__PURE__ */ p(c, { className: "h-4 w-4" }), k ? /* @__PURE__ */ m("span", { children: [
|
|
70
|
+
"Customer",
|
|
71
|
+
" ",
|
|
72
|
+
/* @__PURE__ */ p("span", {
|
|
73
|
+
className: "font-medium text-text-primary",
|
|
74
|
+
children: y
|
|
75
|
+
}),
|
|
76
|
+
" has",
|
|
77
|
+
" ",
|
|
78
|
+
/* @__PURE__ */ p("span", {
|
|
79
|
+
className: "font-semibold text-text-primary",
|
|
80
|
+
children: k.pointsBalance
|
|
81
|
+
}),
|
|
82
|
+
" ",
|
|
83
|
+
"points (lifetime earned ",
|
|
84
|
+
k.lifetimePointsEarned,
|
|
85
|
+
", lifetime redeemed",
|
|
86
|
+
" ",
|
|
87
|
+
k.lifetimePointsRedeemed,
|
|
88
|
+
")."
|
|
89
|
+
] }) : /* @__PURE__ */ m("span", { children: [
|
|
90
|
+
"No loyalty account yet for",
|
|
91
|
+
" ",
|
|
92
|
+
/* @__PURE__ */ p("span", {
|
|
93
|
+
className: "font-medium text-text-primary",
|
|
94
|
+
children: y
|
|
95
|
+
}),
|
|
96
|
+
" — one will be created automatically when points are earned or awarded."
|
|
97
|
+
] })]
|
|
98
|
+
})
|
|
99
|
+
}),
|
|
100
|
+
/* @__PURE__ */ m("div", {
|
|
101
|
+
className: "rounded-lg border border-border-subtle bg-bg-surface p-5 mb-6",
|
|
102
|
+
children: [
|
|
103
|
+
/* @__PURE__ */ p("h3", {
|
|
104
|
+
className: "text-base font-semibold text-text-primary mb-1",
|
|
105
|
+
children: "Award Points"
|
|
106
|
+
}),
|
|
107
|
+
/* @__PURE__ */ p("p", {
|
|
108
|
+
className: "text-xs text-text-secondary mb-4",
|
|
109
|
+
children: "Manual credit for goodwill, compensation, or a promotion — separate from automatic accrual on completed orders."
|
|
110
|
+
}),
|
|
111
|
+
/* @__PURE__ */ m("div", {
|
|
112
|
+
className: "grid grid-cols-1 sm:grid-cols-[140px_1fr_auto] gap-3",
|
|
113
|
+
children: [
|
|
114
|
+
/* @__PURE__ */ p("input", {
|
|
115
|
+
type: "number",
|
|
116
|
+
min: 1,
|
|
117
|
+
step: 1,
|
|
118
|
+
value: x,
|
|
119
|
+
onChange: (e) => S(e.target.value),
|
|
120
|
+
className: "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]"
|
|
121
|
+
}),
|
|
122
|
+
/* @__PURE__ */ p("input", {
|
|
123
|
+
type: "text",
|
|
124
|
+
placeholder: "Reason (optional)",
|
|
125
|
+
value: C,
|
|
126
|
+
onChange: (e) => w(e.target.value),
|
|
127
|
+
className: "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]"
|
|
128
|
+
}),
|
|
129
|
+
/* @__PURE__ */ m("button", {
|
|
130
|
+
type: "button",
|
|
131
|
+
onClick: async () => {
|
|
132
|
+
O(null);
|
|
133
|
+
let e = parseInt(x, 10);
|
|
134
|
+
if (!y.trim()) {
|
|
135
|
+
O("Look up a customer id first.");
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (!Number.isFinite(e) || e <= 0) {
|
|
139
|
+
O("Enter a positive number of points to award.");
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
await N.mutateAsync({
|
|
144
|
+
customerId: y.trim(),
|
|
145
|
+
points: e,
|
|
146
|
+
reason: C.trim() || void 0
|
|
147
|
+
}), P(`Awarded ${e} points to customer ${y.trim()}.`), w("");
|
|
148
|
+
} catch (e) {
|
|
149
|
+
O(e instanceof Error ? e.message : "Failed to award points.");
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
disabled: N.isPending,
|
|
153
|
+
className: "flex items-center justify-center gap-2 rounded-lg bg-foreground px-4 py-2.5 text-sm font-medium text-background hover:opacity-90 transition-opacity disabled:opacity-50 disabled:cursor-not-allowed",
|
|
154
|
+
children: [N.isPending ? /* @__PURE__ */ p(u, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ p(c, { className: "h-4 w-4" }), "Award"]
|
|
155
|
+
})
|
|
156
|
+
]
|
|
157
|
+
})
|
|
158
|
+
]
|
|
159
|
+
}),
|
|
160
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ m("h3", {
|
|
161
|
+
className: "text-base font-semibold text-text-primary mb-3 flex items-center gap-2",
|
|
162
|
+
children: [/* @__PURE__ */ p(l, { className: "h-4 w-4 text-text-secondary" }), "Recent Activity"]
|
|
163
|
+
}), M ? /* @__PURE__ */ p("div", {
|
|
164
|
+
className: "flex h-24 items-center justify-center",
|
|
165
|
+
children: /* @__PURE__ */ p(u, { className: "h-5 w-5 animate-spin text-text-secondary" })
|
|
166
|
+
}) : j.length > 0 ? /* @__PURE__ */ p("div", {
|
|
167
|
+
className: "space-y-2",
|
|
168
|
+
children: j.map((t) => /* @__PURE__ */ m("div", {
|
|
169
|
+
className: "flex items-center justify-between rounded-lg border border-border-subtle bg-bg-surface p-3",
|
|
170
|
+
children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
|
|
171
|
+
className: "text-sm font-medium text-text-primary",
|
|
172
|
+
children: t.description || t.type
|
|
173
|
+
}), /* @__PURE__ */ p("p", {
|
|
174
|
+
className: "text-xs text-text-secondary",
|
|
175
|
+
children: new Date(t.createdAt).toLocaleDateString()
|
|
176
|
+
})] }), /* @__PURE__ */ m("p", {
|
|
177
|
+
className: e("text-sm font-semibold", t.points >= 0 ? "text-status-success-text" : "text-status-error-text"),
|
|
178
|
+
children: [
|
|
179
|
+
t.points >= 0 ? "+" : "",
|
|
180
|
+
t.points,
|
|
181
|
+
" pts"
|
|
182
|
+
]
|
|
183
|
+
})]
|
|
184
|
+
}, t.id))
|
|
185
|
+
}) : /* @__PURE__ */ p(n, {
|
|
186
|
+
illustration: "empty-data",
|
|
187
|
+
icon: /* @__PURE__ */ p(c, { className: "h-12 w-12" }),
|
|
188
|
+
title: "No activity yet",
|
|
189
|
+
description: "This customer hasn't earned, redeemed, or been awarded any points yet."
|
|
190
|
+
})] })
|
|
191
|
+
] })
|
|
192
|
+
]
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
//#endregion
|
|
196
|
+
export { _ as LoyaltyManagementPage };
|
|
197
|
+
|
|
198
|
+
//# sourceMappingURL=LoyaltyManagementPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoyaltyManagementPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/cart-owner/LoyaltyManagementPage.tsx"],"sourcesContent":["/**\n * Loyalty Management Page\n * @module kadaikodi/pages/cart-owner\n *\n * Merchant/admin view of the marketplace-wide loyalty program (BOFF-4290):\n * look up a customer's points balance, manually award goodwill/compensation\n * points, and browse the recent points ledger. Backed by real server\n * persistence (kadaikodiLoyaltyAccount / kadaikodiListLoyaltyTransactions /\n * kadaikodiAwardLoyaltyPoints) — no client-only state.\n */\n\nimport { useState } from 'react';\nimport { Gift, Search, Loader2, CheckCircle2, History } from 'lucide-react';\nimport { PagePurpose, EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport {\n useLoyaltyAccountByCustomerId,\n useListLoyaltyTransactions,\n useAwardLoyaltyPoints,\n} from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\n\nexport function LoyaltyManagementPage() {\n const [lookupCustomerId, setLookupCustomerId] = useState('');\n const [searchedCustomerId, setSearchedCustomerId] = useState('');\n const [awardPoints, setAwardPoints] = useState('100');\n const [awardReason, setAwardReason] = useState('');\n const [statusMessage, setStatusMessage] = useState<string | null>(null);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n\n const { data: account, isLoading: isLoadingAccount } =\n useLoyaltyAccountByCustomerId(searchedCustomerId);\n const { data: transactions = [], isLoading: isLoadingTransactions } = useListLoyaltyTransactions(\n searchedCustomerId || undefined\n );\n const awardLoyaltyPoints = useAwardLoyaltyPoints();\n\n const showStatus = (msg: string) => {\n setStatusMessage(msg);\n setTimeout(() => setStatusMessage(null), 4000);\n };\n\n const handleSearch = () => {\n setSearchedCustomerId(lookupCustomerId.trim());\n };\n\n const handleAward = async () => {\n setErrorMessage(null);\n const points = parseInt(awardPoints, 10);\n if (!searchedCustomerId.trim()) {\n setErrorMessage('Look up a customer id first.');\n return;\n }\n if (!Number.isFinite(points) || points <= 0) {\n setErrorMessage('Enter a positive number of points to award.');\n return;\n }\n try {\n await awardLoyaltyPoints.mutateAsync({\n customerId: searchedCustomerId.trim(),\n points,\n reason: awardReason.trim() || undefined,\n });\n showStatus(`Awarded ${points} points to customer ${searchedCustomerId.trim()}.`);\n setAwardReason('');\n } catch (err) {\n setErrorMessage(err instanceof Error ? err.message : 'Failed to award points.');\n }\n };\n\n return (\n <PageLayout\n title=\"Loyalty Program\"\n description=\"Look up customer balances, award goodwill points, and review the recent ledger\"\n >\n <PagePurpose className=\"mb-6\">\n Kadaikodi's loyalty program is marketplace-wide: customers earn 1 point per ₹100 spent on\n every completed order (across any cart), and can redeem points for a discount on a future\n order. Use this page to support a specific customer — check their balance, credit a\n goodwill/compensation award, and review recent activity.\n </PagePurpose>\n\n {/* Customer lookup */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5 mb-6\">\n <h3 className=\"text-base font-semibold text-text-primary mb-3\">Look up a customer</h3>\n <div className=\"flex flex-col sm:flex-row gap-3\">\n <input\n type=\"text\"\n placeholder=\"Customer id (actor id)\"\n value={lookupCustomerId}\n onChange={(e) => setLookupCustomerId(e.target.value)}\n onKeyDown={(e) => e.key === 'Enter' && handleSearch()}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 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={handleSearch}\n disabled={!lookupCustomerId.trim()}\n className=\"flex items-center justify-center gap-2 rounded-lg bg-foreground px-4 py-2.5 text-sm font-medium text-background hover:opacity-90 transition-opacity disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <Search className=\"h-4 w-4\" />\n Look up\n </button>\n </div>\n </div>\n\n {statusMessage && (\n <div className=\"mb-4 rounded-lg border border-status-success-text/30 bg-status-success-bg-subtle p-3 flex items-center gap-2\">\n <CheckCircle2 className=\"h-4 w-4 text-status-success-text shrink-0\" />\n <p className=\"text-sm text-status-success-text\">{statusMessage}</p>\n </div>\n )}\n {errorMessage && (\n <div className=\"mb-4 rounded-lg border border-status-error-text/30 bg-status-error-bg/10 p-3\">\n <p className=\"text-sm text-status-error-text\">{errorMessage}</p>\n </div>\n )}\n\n {searchedCustomerId && (\n <>\n {/* Balance summary */}\n {isLoadingAccount ? (\n <div className=\"flex h-24 items-center justify-center mb-6\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : (\n <EmphasisPanel className=\"mb-6\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Gift className=\"h-4 w-4\" />\n {account ? (\n <span>\n Customer{' '}\n <span className=\"font-medium text-text-primary\">{searchedCustomerId}</span> has{' '}\n <span className=\"font-semibold text-text-primary\">{account.pointsBalance}</span>{' '}\n points (lifetime earned {account.lifetimePointsEarned}, lifetime redeemed{' '}\n {account.lifetimePointsRedeemed}).\n </span>\n ) : (\n <span>\n No loyalty account yet for{' '}\n <span className=\"font-medium text-text-primary\">{searchedCustomerId}</span> —\n one will be created automatically when points are earned or awarded.\n </span>\n )}\n </div>\n </EmphasisPanel>\n )}\n\n {/* Award points form */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5 mb-6\">\n <h3 className=\"text-base font-semibold text-text-primary mb-1\">Award Points</h3>\n <p className=\"text-xs text-text-secondary mb-4\">\n Manual credit for goodwill, compensation, or a promotion — separate from automatic\n accrual on completed orders.\n </p>\n <div className=\"grid grid-cols-1 sm:grid-cols-[140px_1fr_auto] gap-3\">\n <input\n type=\"number\"\n min={1}\n step={1}\n value={awardPoints}\n onChange={(e) => setAwardPoints(e.target.value)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n <input\n type=\"text\"\n placeholder=\"Reason (optional)\"\n value={awardReason}\n onChange={(e) => setAwardReason(e.target.value)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 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={handleAward}\n disabled={awardLoyaltyPoints.isPending}\n className=\"flex items-center justify-center gap-2 rounded-lg bg-foreground px-4 py-2.5 text-sm font-medium text-background hover:opacity-90 transition-opacity disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {awardLoyaltyPoints.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Gift className=\"h-4 w-4\" />\n )}\n Award\n </button>\n </div>\n </div>\n\n {/* Transaction history for this customer */}\n <div>\n <h3 className=\"text-base font-semibold text-text-primary mb-3 flex items-center gap-2\">\n <History className=\"h-4 w-4 text-text-secondary\" />\n Recent Activity\n </h3>\n {isLoadingTransactions ? (\n <div className=\"flex h-24 items-center justify-center\">\n <Loader2 className=\"h-5 w-5 animate-spin text-text-secondary\" />\n </div>\n ) : transactions.length > 0 ? (\n <div className=\"space-y-2\">\n {transactions.map((txn) => (\n <div\n key={txn.id}\n className=\"flex items-center justify-between rounded-lg border border-border-subtle bg-bg-surface p-3\"\n >\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {txn.description || txn.type}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {new Date(txn.createdAt).toLocaleDateString()}\n </p>\n </div>\n <p\n className={cn(\n 'text-sm font-semibold',\n txn.points >= 0 ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n {txn.points >= 0 ? '+' : ''}\n {txn.points} pts\n </p>\n </div>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Gift className=\"h-12 w-12\" />}\n title=\"No activity yet\"\n description=\"This customer hasn't earned, redeemed, or been awarded any points yet.\"\n />\n )}\n </div>\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomerProfilePage.d.ts","sourceRoot":"","sources":["../../../../src/kadaikodi/pages/customer/CustomerProfilePage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"CustomerProfilePage.d.ts","sourceRoot":"","sources":["../../../../src/kadaikodi/pages/customer/CustomerProfilePage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA+DH,wBAAgB,mBAAmB,gCA2oBlC"}
|