@burdenoff/microfe-kadaikodi 2026.704.4 → 2026.710.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/generated/global-operations.d.ts +2 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-types.d.ts +23527 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +2 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-types.d.ts +57851 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -1
- package/dist/kadaikodi/KadaikodiRoot.d.ts +5 -0
- package/dist/kadaikodi/KadaikodiRoot.d.ts.map +1 -0
- package/dist/kadaikodi/KadaikodiRoutes.d.ts +4 -0
- package/dist/kadaikodi/KadaikodiRoutes.d.ts.map +1 -0
- package/dist/kadaikodi/KadaikodiRoutes.js +30 -26
- package/dist/kadaikodi/KadaikodiRoutes.js.map +1 -1
- package/dist/kadaikodi/components/CartCard.d.ts +18 -0
- package/dist/kadaikodi/components/CartCard.d.ts.map +1 -0
- package/dist/kadaikodi/components/EmptyState.d.ts +17 -0
- package/dist/kadaikodi/components/EmptyState.d.ts.map +1 -0
- package/dist/kadaikodi/components/InvestmentCard.d.ts +18 -0
- package/dist/kadaikodi/components/InvestmentCard.d.ts.map +1 -0
- package/dist/kadaikodi/components/MetricsCard.d.ts +16 -0
- package/dist/kadaikodi/components/MetricsCard.d.ts.map +1 -0
- package/dist/kadaikodi/components/OrderCard.d.ts +18 -0
- package/dist/kadaikodi/components/OrderCard.d.ts.map +1 -0
- package/dist/kadaikodi/components/PageLayout.d.ts +12 -0
- package/dist/kadaikodi/components/PageLayout.d.ts.map +1 -0
- package/dist/kadaikodi/components/RatingDisplay.d.ts +12 -0
- package/dist/kadaikodi/components/RatingDisplay.d.ts.map +1 -0
- package/dist/kadaikodi/components/StatusBadge.d.ts +9 -0
- package/dist/kadaikodi/components/StatusBadge.d.ts.map +1 -0
- package/dist/kadaikodi/components/index.d.ts +13 -0
- package/dist/kadaikodi/components/index.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/AllocationBar.d.ts +21 -0
- package/dist/kadaikodi/components/viz/AllocationBar.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/AllocationBar.js +68 -0
- package/dist/kadaikodi/components/viz/AllocationBar.js.map +1 -0
- package/dist/kadaikodi/components/viz/AreaChart.d.ts +18 -0
- package/dist/kadaikodi/components/viz/AreaChart.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/AreaChart.js +102 -0
- package/dist/kadaikodi/components/viz/AreaChart.js.map +1 -0
- package/dist/kadaikodi/components/viz/AvatarStack.d.ts +13 -0
- package/dist/kadaikodi/components/viz/AvatarStack.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/AvatarStack.js +36 -0
- package/dist/kadaikodi/components/viz/AvatarStack.js.map +1 -0
- package/dist/kadaikodi/components/viz/BarChart.d.ts +17 -0
- package/dist/kadaikodi/components/viz/BarChart.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/BarChart.js +83 -0
- package/dist/kadaikodi/components/viz/BarChart.js.map +1 -0
- package/dist/kadaikodi/components/viz/CertificateCard.d.ts +14 -0
- package/dist/kadaikodi/components/viz/CertificateCard.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/CertificateCard.js +4 -0
- package/dist/kadaikodi/components/viz/DonutChart.d.ts +20 -0
- package/dist/kadaikodi/components/viz/DonutChart.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/DonutChart.js +109 -0
- package/dist/kadaikodi/components/viz/DonutChart.js.map +1 -0
- package/dist/kadaikodi/components/viz/HBarFunnel.d.ts +17 -0
- package/dist/kadaikodi/components/viz/HBarFunnel.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/HBarFunnel.js +54 -0
- package/dist/kadaikodi/components/viz/HBarFunnel.js.map +1 -0
- package/dist/kadaikodi/components/viz/Heatmap.d.ts +26 -0
- package/dist/kadaikodi/components/viz/Heatmap.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/Heatmap.js +3 -0
- package/dist/kadaikodi/components/viz/KanbanBoard.d.ts +17 -0
- package/dist/kadaikodi/components/viz/KanbanBoard.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/KanbanBoard.js +50 -0
- package/dist/kadaikodi/components/viz/KanbanBoard.js.map +1 -0
- package/dist/kadaikodi/components/viz/LineChart.d.ts +20 -0
- package/dist/kadaikodi/components/viz/LineChart.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/LineChart.js +4 -0
- package/dist/kadaikodi/components/viz/OrgTree.d.ts +14 -0
- package/dist/kadaikodi/components/viz/OrgTree.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/OrgTree.js +2 -0
- package/dist/kadaikodi/components/viz/PathSteps.d.ts +17 -0
- package/dist/kadaikodi/components/viz/PathSteps.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/PathSteps.js +3 -0
- package/dist/kadaikodi/components/viz/ProgressRing.d.ts +20 -0
- package/dist/kadaikodi/components/viz/ProgressRing.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/ProgressRing.js +68 -0
- package/dist/kadaikodi/components/viz/ProgressRing.js.map +1 -0
- package/dist/kadaikodi/components/viz/RatingStars.d.ts +14 -0
- package/dist/kadaikodi/components/viz/RatingStars.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/RatingStars.js +51 -0
- package/dist/kadaikodi/components/viz/RatingStars.js.map +1 -0
- package/dist/kadaikodi/components/viz/SegmentedTabs.d.ts +26 -0
- package/dist/kadaikodi/components/viz/SegmentedTabs.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/SegmentedTabs.js +69 -0
- package/dist/kadaikodi/components/viz/SegmentedTabs.js.map +1 -0
- package/dist/kadaikodi/components/viz/SkillBar.d.ts +17 -0
- package/dist/kadaikodi/components/viz/SkillBar.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/SkillBar.js +3 -0
- package/dist/kadaikodi/components/viz/Sparkline.d.ts +16 -0
- package/dist/kadaikodi/components/viz/Sparkline.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/Sparkline.js +74 -0
- package/dist/kadaikodi/components/viz/Sparkline.js.map +1 -0
- package/dist/kadaikodi/components/viz/StatCard.d.ts +22 -0
- package/dist/kadaikodi/components/viz/StatCard.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/StatCard.js +60 -0
- package/dist/kadaikodi/components/viz/StatCard.js.map +1 -0
- package/dist/kadaikodi/components/viz/StepProgress.d.ts +17 -0
- package/dist/kadaikodi/components/viz/StepProgress.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/StepProgress.js +64 -0
- package/dist/kadaikodi/components/viz/StepProgress.js.map +1 -0
- package/dist/kadaikodi/components/viz/Timeline.d.ts +21 -0
- package/dist/kadaikodi/components/viz/Timeline.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/Timeline.js +66 -0
- package/dist/kadaikodi/components/viz/Timeline.js.map +1 -0
- package/dist/kadaikodi/components/viz/index.d.ts +35 -0
- package/dist/kadaikodi/components/viz/index.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/index.js +23 -0
- package/dist/kadaikodi/components/viz/lib/Avatar.d.ts +15 -0
- package/dist/kadaikodi/components/viz/lib/Avatar.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/lib/Avatar.js +30 -0
- package/dist/kadaikodi/components/viz/lib/Avatar.js.map +1 -0
- package/dist/kadaikodi/components/viz/lib/CartesianFrame.d.ts +44 -0
- package/dist/kadaikodi/components/viz/lib/CartesianFrame.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/lib/CartesianFrame.js +119 -0
- package/dist/kadaikodi/components/viz/lib/CartesianFrame.js.map +1 -0
- package/dist/kadaikodi/components/viz/lib/ResponsiveSvg.d.ts +27 -0
- package/dist/kadaikodi/components/viz/lib/ResponsiveSvg.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/lib/ResponsiveSvg.js +35 -0
- package/dist/kadaikodi/components/viz/lib/ResponsiveSvg.js.map +1 -0
- package/dist/kadaikodi/components/viz/lib/format.d.ts +10 -0
- package/dist/kadaikodi/components/viz/lib/format.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/lib/format.js +21 -0
- package/dist/kadaikodi/components/viz/lib/format.js.map +1 -0
- package/dist/kadaikodi/components/viz/lib/geometry.d.ts +41 -0
- package/dist/kadaikodi/components/viz/lib/geometry.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/lib/geometry.js +61 -0
- package/dist/kadaikodi/components/viz/lib/geometry.js.map +1 -0
- package/dist/kadaikodi/components/viz/lib/hooks.d.ts +18 -0
- package/dist/kadaikodi/components/viz/lib/hooks.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/lib/hooks.js +39 -0
- package/dist/kadaikodi/components/viz/lib/hooks.js.map +1 -0
- package/dist/kadaikodi/components/viz/lib/palette.d.ts +31 -0
- package/dist/kadaikodi/components/viz/lib/palette.d.ts.map +1 -0
- package/dist/kadaikodi/components/viz/lib/palette.js +27 -0
- package/dist/kadaikodi/components/viz/lib/palette.js.map +1 -0
- package/dist/kadaikodi/components/viz/lib/types.d.ts +27 -0
- package/dist/kadaikodi/components/viz/lib/types.d.ts.map +1 -0
- package/dist/kadaikodi/context/KadaikodiContext.d.ts +16 -0
- package/dist/kadaikodi/context/KadaikodiContext.d.ts.map +1 -0
- package/dist/kadaikodi/context/index.d.ts +6 -0
- package/dist/kadaikodi/context/index.d.ts.map +1 -0
- package/dist/kadaikodi/hooks/index.d.ts +2 -0
- package/dist/kadaikodi/hooks/index.d.ts.map +1 -0
- package/dist/kadaikodi/hooks/useKadaikodiApi.d.ts +169 -0
- package/dist/kadaikodi/hooks/useKadaikodiApi.d.ts.map +1 -0
- package/dist/kadaikodi/hooks/useKadaikodiApi.js +18 -10
- package/dist/kadaikodi/hooks/useKadaikodiApi.js.map +1 -1
- package/dist/kadaikodi/index.d.ts +11 -0
- package/dist/kadaikodi/index.d.ts.map +1 -0
- package/dist/kadaikodi/pages/HomePage.d.ts +14 -0
- package/dist/kadaikodi/pages/HomePage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/HomePage.js +373 -631
- package/dist/kadaikodi/pages/HomePage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.d.ts +13 -0
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.js +304 -169
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminDashboard.d.ts +13 -0
- package/dist/kadaikodi/pages/admin/AdminDashboard.d.ts.map +1 -0
- package/dist/kadaikodi/pages/admin/AdminDashboard.js +255 -271
- package/dist/kadaikodi/pages/admin/AdminDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminFinancialPage.d.ts +12 -0
- package/dist/kadaikodi/pages/admin/AdminFinancialPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/admin/AdminFinancialPage.js +185 -125
- package/dist/kadaikodi/pages/admin/AdminFinancialPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminOrdersPage.d.ts +11 -0
- package/dist/kadaikodi/pages/admin/AdminOrdersPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/admin/AdminOrdersPage.js +141 -102
- package/dist/kadaikodi/pages/admin/AdminOrdersPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminProfilePage.d.ts +11 -0
- package/dist/kadaikodi/pages/admin/AdminProfilePage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/admin/AdminSettingsPage.d.ts +10 -0
- package/dist/kadaikodi/pages/admin/AdminSettingsPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/admin/CartManagementPage.d.ts +13 -0
- package/dist/kadaikodi/pages/admin/CartManagementPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/admin/CartManagementPage.js +558 -718
- package/dist/kadaikodi/pages/admin/CartManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/UserManagementPage.d.ts +10 -0
- package/dist/kadaikodi/pages/admin/UserManagementPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/admin/UserManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/AnalyticsDashboard.d.ts +13 -0
- package/dist/kadaikodi/pages/cart-owner/AnalyticsDashboard.d.ts.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/AnalyticsDashboard.js +142 -55
- package/dist/kadaikodi/pages/cart-owner/AnalyticsDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/BusinessSettingsPage.d.ts +11 -0
- package/dist/kadaikodi/pages/cart-owner/BusinessSettingsPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/CartOwnerDashboard.d.ts +12 -0
- package/dist/kadaikodi/pages/cart-owner/CartOwnerDashboard.d.ts.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/CartOwnerDashboard.js +129 -164
- package/dist/kadaikodi/pages/cart-owner/CartOwnerDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/CartOwnerProfilePage.d.ts +12 -0
- package/dist/kadaikodi/pages/cart-owner/CartOwnerProfilePage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/CartServiceConfigPage.d.ts +11 -0
- package/dist/kadaikodi/pages/cart-owner/CartServiceConfigPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/InventoryManagementPage.d.ts +11 -0
- package/dist/kadaikodi/pages/cart-owner/InventoryManagementPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/InventoryManagementPage.js +379 -361
- package/dist/kadaikodi/pages/cart-owner/InventoryManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/InvestmentListingPage.d.ts +2 -0
- package/dist/kadaikodi/pages/cart-owner/InvestmentListingPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/InvestmentListingPage.js +266 -166
- package/dist/kadaikodi/pages/cart-owner/InvestmentListingPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/MerchantOnboardingPage.d.ts +2 -0
- package/dist/kadaikodi/pages/cart-owner/MerchantOnboardingPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/MerchantOnboardingPage.js +373 -0
- package/dist/kadaikodi/pages/cart-owner/MerchantOnboardingPage.js.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/OrderManagementPage.d.ts +10 -0
- package/dist/kadaikodi/pages/cart-owner/OrderManagementPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/OrderManagementPage.js +288 -161
- package/dist/kadaikodi/pages/cart-owner/OrderManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.d.ts +12 -0
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.js +180 -181
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/common/HelpSupportPage.d.ts +11 -0
- package/dist/kadaikodi/pages/common/HelpSupportPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/common/HelpSupportPage.js.map +1 -1
- package/dist/kadaikodi/pages/common/NotificationCenterPage.d.ts +10 -0
- package/dist/kadaikodi/pages/common/NotificationCenterPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/common/SettingsPage.d.ts +19 -0
- package/dist/kadaikodi/pages/common/SettingsPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/common/SettingsPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/BookingDetailsPage.d.ts +12 -0
- package/dist/kadaikodi/pages/customer/BookingDetailsPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/BookingDetailsPage.js +17 -34
- package/dist/kadaikodi/pages/customer/BookingDetailsPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDetailPage.d.ts +13 -0
- package/dist/kadaikodi/pages/customer/CartDetailPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/CartDetailPage.js +405 -248
- package/dist/kadaikodi/pages/customer/CartDetailPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.d.ts +11 -0
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.js +258 -232
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CheckoutPage.d.ts +9 -0
- package/dist/kadaikodi/pages/customer/CheckoutPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/CheckoutPage.js +254 -205
- package/dist/kadaikodi/pages/customer/CheckoutPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CustomerDashboard.d.ts +10 -0
- package/dist/kadaikodi/pages/customer/CustomerDashboard.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/CustomerProfilePage.d.ts +10 -0
- package/dist/kadaikodi/pages/customer/CustomerProfilePage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/DirectServiceBookingPage.d.ts +12 -0
- package/dist/kadaikodi/pages/customer/DirectServiceBookingPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/DirectServiceBookingPage.js +270 -230
- package/dist/kadaikodi/pages/customer/DirectServiceBookingPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/FavoritesPage.d.ts +11 -0
- package/dist/kadaikodi/pages/customer/FavoritesPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/FavoritesPage.js +149 -412
- package/dist/kadaikodi/pages/customer/FavoritesPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/OrderHistoryPage.d.ts +9 -0
- package/dist/kadaikodi/pages/customer/OrderHistoryPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/OrderHistoryPage.js +173 -134
- package/dist/kadaikodi/pages/customer/OrderHistoryPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.d.ts +9 -0
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.js +176 -175
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/PaymentMethodsPage.d.ts +11 -0
- package/dist/kadaikodi/pages/customer/PaymentMethodsPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/ReviewsPage.d.ts +12 -0
- package/dist/kadaikodi/pages/customer/ReviewsPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/ReviewsPage.js +295 -438
- package/dist/kadaikodi/pages/customer/ReviewsPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/SavedAddressesPage.d.ts +10 -0
- package/dist/kadaikodi/pages/customer/SavedAddressesPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/shared.d.ts +41 -0
- package/dist/kadaikodi/pages/customer/shared.d.ts.map +1 -0
- package/dist/kadaikodi/pages/customer/shared.js +181 -0
- package/dist/kadaikodi/pages/customer/shared.js.map +1 -0
- package/dist/kadaikodi/pages/investor/InvestmentDetailsPage.d.ts +13 -0
- package/dist/kadaikodi/pages/investor/InvestmentDetailsPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/investor/InvestmentDetailsPage.js +438 -311
- package/dist/kadaikodi/pages/investor/InvestmentDetailsPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestmentOpportunitiesPage.d.ts +10 -0
- package/dist/kadaikodi/pages/investor/InvestmentOpportunitiesPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/investor/InvestmentOpportunitiesPage.js +320 -293
- package/dist/kadaikodi/pages/investor/InvestmentOpportunitiesPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestorAnalyticsPage.d.ts +11 -0
- package/dist/kadaikodi/pages/investor/InvestorAnalyticsPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/investor/InvestorAnalyticsPage.js +159 -91
- package/dist/kadaikodi/pages/investor/InvestorAnalyticsPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestorDashboard.d.ts +10 -0
- package/dist/kadaikodi/pages/investor/InvestorDashboard.d.ts.map +1 -0
- package/dist/kadaikodi/pages/investor/InvestorDashboard.js +137 -107
- package/dist/kadaikodi/pages/investor/InvestorDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestorInvestmentsPage.d.ts +10 -0
- package/dist/kadaikodi/pages/investor/InvestorInvestmentsPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/investor/InvestorInvestmentsPage.js +157 -135
- package/dist/kadaikodi/pages/investor/InvestorInvestmentsPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestorPortfolioPage.d.ts +11 -0
- package/dist/kadaikodi/pages/investor/InvestorPortfolioPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/investor/InvestorPortfolioPage.js +280 -206
- package/dist/kadaikodi/pages/investor/InvestorPortfolioPage.js.map +1 -1
- package/dist/kadaikodi/pages/investor/InvestorProfilePage.d.ts +20 -0
- package/dist/kadaikodi/pages/investor/InvestorProfilePage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/investor/InvestorProfilePage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.d.ts +18 -0
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.js +424 -448
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/WorkerDashboard.d.ts +14 -0
- package/dist/kadaikodi/pages/worker/WorkerDashboard.d.ts.map +1 -0
- package/dist/kadaikodi/pages/worker/WorkerDashboard.js +328 -445
- package/dist/kadaikodi/pages/worker/WorkerDashboard.js.map +1 -1
- package/dist/kadaikodi/pages/worker/WorkerOrdersPage.d.ts +18 -0
- package/dist/kadaikodi/pages/worker/WorkerOrdersPage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/worker/WorkerOrdersPage.js +141 -164
- package/dist/kadaikodi/pages/worker/WorkerOrdersPage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/WorkerProfilePage.d.ts +18 -0
- package/dist/kadaikodi/pages/worker/WorkerProfilePage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/worker/WorkerProfilePage.js +300 -296
- package/dist/kadaikodi/pages/worker/WorkerProfilePage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/WorkerSchedulePage.d.ts +16 -0
- package/dist/kadaikodi/pages/worker/WorkerSchedulePage.d.ts.map +1 -0
- package/dist/kadaikodi/pages/worker/WorkerSchedulePage.js +284 -309
- package/dist/kadaikodi/pages/worker/WorkerSchedulePage.js.map +1 -1
- package/dist/kadaikodi/store/index.d.ts +6 -0
- package/dist/kadaikodi/store/index.d.ts.map +1 -0
- package/dist/kadaikodi/store/kadaikodiStore.d.ts +60 -0
- package/dist/kadaikodi/store/kadaikodiStore.d.ts.map +1 -0
- package/dist/kadaikodi/types/index.d.ts +464 -0
- package/dist/kadaikodi/types/index.d.ts.map +1 -0
- package/dist/kadaikodi/utils/cn.d.ts +4 -0
- package/dist/kadaikodi/utils/cn.d.ts.map +1 -0
- package/dist/kadaikodi/utils/formatters.d.ts +78 -0
- package/dist/kadaikodi/utils/formatters.d.ts.map +1 -0
- package/dist/kadaikodi/utils/index.d.ts +8 -0
- package/dist/kadaikodi/utils/index.d.ts.map +1 -0
- package/dist/kadaikodi/utils/navigation.d.ts +20 -0
- package/dist/kadaikodi/utils/navigation.d.ts.map +1 -0
- package/dist/services/createSandboxAssistantTransport.d.ts +43 -0
- package/dist/services/createSandboxAssistantTransport.d.ts.map +1 -0
- package/dist/services/createSandboxAssistantTransport.js +15 -0
- package/dist/services/createSandboxAssistantTransport.js.map +1 -0
- package/package.json +5 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReviewsPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/customer/ReviewsPage.tsx"],"sourcesContent":["/**\n * Reviews Page\n * @module kadaikodi/pages/customer\n *\n * Full-featured reviews: Write Review modal (interactive star rating with\n * text labels, title, comment, guidelines), Owner Response callout,\n * review images, verified badge, Mark as Helpful toggle, 4 filters\n * (search, type, rating, sort), Your Review label, 5 mock reviews.\n */\n\nimport { useState, useCallback } from 'react';\nimport {\n Star,\n MessageSquare,\n ThumbsUp,\n PenSquare,\n X,\n CheckCircle2,\n Image,\n MessageCircle,\n Info,\n Search,\n} from 'lucide-react';\nimport { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { RatingDisplay } from '../../components/RatingDisplay';\nimport { EmptyState } from '../../components/EmptyState';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport { useOrders, useCreateReview } from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatDate } from '../../utils/formatters';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface Review {\n id: string;\n userId: string;\n userName: string;\n userAvatar: string;\n itemId: string;\n itemName: string;\n itemType: 'cart' | 'product';\n cartId: string;\n cartName: string;\n orderId: string;\n rating: number;\n title: string;\n comment: string;\n images?: string[];\n helpfulCount: number;\n isHelpful: boolean;\n isVerified: boolean;\n createdAt: string;\n response?: {\n message: string;\n respondedBy: string;\n respondedAt: string;\n };\n}\n\ninterface ReviewFormData {\n rating: number;\n title: string;\n comment: string;\n}\n\ninterface ReviewFilters {\n searchQuery: string;\n type: 'all' | 'cart' | 'product' | 'my-reviews';\n rating: string;\n sortBy: 'recent' | 'helpful' | 'rating-high' | 'rating-low';\n}\n\nconst ratingLabels: Record<number, string> = {\n 1: 'Terrible',\n 2: 'Poor',\n 3: 'Average',\n 4: 'Good',\n 5: 'Excellent',\n};\n\n// ============================================================================\n// Star Rating Interactive Component\n// ============================================================================\n\nfunction InteractiveStarRating({\n value,\n onChange,\n}: {\n value: number;\n onChange: (v: number) => void;\n}) {\n const [hoverValue, setHoverValue] = useState(0);\n const displayValue = hoverValue || value;\n\n return (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex items-center gap-0.5\">\n {[1, 2, 3, 4, 5].map((star) => (\n <button\n key={star}\n type=\"button\"\n onClick={() => onChange(star)}\n onMouseEnter={() => setHoverValue(star)}\n onMouseLeave={() => setHoverValue(0)}\n className=\"p-0.5 transition-transform\"\n >\n <Star\n className={cn(\n 'h-6 w-6',\n star <= displayValue\n ? 'fill-status-warning-text text-status-warning-text'\n : 'fill-none text-text-secondary/40'\n )}\n />\n </button>\n ))}\n </div>\n <span className=\"text-sm font-medium text-text-secondary\">\n {ratingLabels[displayValue] ?? ''}\n </span>\n </div>\n );\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function ReviewsPage() {\n const { navigateTo, currentUser } = useKadaikodi();\n // There is no cross-cart \"my reviews\" endpoint; reviews are listed per provider\n // via useReviews(providerId). This customer-level view has no provider context,\n // so we never fabricate reviews — the list stays empty until a real source exists.\n const currentUserId = currentUser?.id ?? '';\n const { data: myOrders = [] } = useOrders({ customerId: currentUser?.id });\n const createReview = useCreateReview();\n // Reviews are attached to a delivered order + its provider. Only delivered\n // orders can be reviewed, so those are the options the customer picks from.\n const reviewableOrders = myOrders.filter((o) => o.status === 'delivered');\n const [reviews, setReviews] = useState<Review[]>([]);\n const [showWriteReview, setShowWriteReview] = useState(false);\n const [selectedOrderId, setSelectedOrderId] = useState('');\n const [reviewForm, setReviewForm] = useState<ReviewFormData>({\n rating: 5,\n title: '',\n comment: '',\n });\n const [filters, setFilters] = useState<ReviewFilters>({\n searchQuery: '',\n type: 'all',\n rating: '',\n sortBy: 'recent',\n });\n const [statusMessage, setStatusMessage] = useState<string | null>(null);\n\n const showStatus = (msg: string) => {\n setStatusMessage(msg);\n setTimeout(() => setStatusMessage(null), 3000);\n };\n\n // --- Filtered reviews ---\n const filteredReviews = useCallback(() => {\n let result = [...reviews];\n\n // Type filter\n if (filters.type === 'my-reviews') {\n result = result.filter((r) => r.userId === currentUserId);\n } else if (filters.type !== 'all') {\n result = result.filter((r) => r.itemType === filters.type);\n }\n\n // Rating filter\n if (filters.rating) {\n const ratingVal = parseInt(filters.rating, 10);\n result = result.filter((r) => r.rating === ratingVal);\n }\n\n // Search\n if (filters.searchQuery) {\n const q = filters.searchQuery.toLowerCase();\n result = result.filter(\n (r) =>\n r.itemName.toLowerCase().includes(q) ||\n r.title.toLowerCase().includes(q) ||\n r.comment.toLowerCase().includes(q) ||\n r.cartName.toLowerCase().includes(q)\n );\n }\n\n // Sort\n switch (filters.sortBy) {\n case 'recent':\n result.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());\n break;\n case 'helpful':\n result.sort((a, b) => b.helpfulCount - a.helpfulCount);\n break;\n case 'rating-high':\n result.sort((a, b) => b.rating - a.rating);\n break;\n case 'rating-low':\n result.sort((a, b) => a.rating - b.rating);\n break;\n }\n\n return result;\n }, [reviews, filters])();\n\n // --- Stats ---\n const myReviewCount = reviews.filter((r) => r.userId === currentUserId).length;\n const avgRating =\n reviews.length > 0\n ? (reviews.reduce((s, r) => s + r.rating, 0) / reviews.length).toFixed(1)\n : '0';\n\n // --- Handlers ---\n const handleSubmitReview = () => {\n if (!selectedOrderId) {\n showStatus('Please choose which delivered order you want to review.');\n return;\n }\n if (!reviewForm.title.trim() || !reviewForm.comment.trim()) {\n showStatus('Please fill in the Review Title and Comment.');\n return;\n }\n const targetOrder = reviewableOrders.find((o) => o.id === selectedOrderId);\n if (!targetOrder || !currentUser?.id) {\n showStatus('Could not find that order. Please try again.');\n return;\n }\n\n // Reviews attach to a specific provider + delivered order — persist via the\n // real createReview mutation.\n createReview.mutate(\n {\n providerId: targetOrder.cartId,\n orderId: targetOrder.id,\n customerId: currentUser.id,\n rating: reviewForm.rating,\n review: `${reviewForm.title.trim()} — ${reviewForm.comment.trim()}`,\n },\n {\n onSuccess: () => {\n setReviewForm({ rating: 5, title: '', comment: '' });\n setSelectedOrderId('');\n setShowWriteReview(false);\n showStatus('Thanks! Your review has been posted to the cart.');\n },\n onError: () => showStatus('Could not post your review. Please try again.'),\n }\n );\n };\n\n const handleMarkHelpful = (reviewId: string) => {\n setReviews((prev) =>\n prev.map((r) =>\n r.id === reviewId\n ? {\n ...r,\n isHelpful: !r.isHelpful,\n helpfulCount: r.isHelpful ? r.helpfulCount - 1 : r.helpfulCount + 1,\n }\n : r\n )\n );\n };\n\n return (\n <PageLayout\n title=\"Reviews & Ratings\"\n description={`${filteredReviews.length} reviews found`}\n actions={\n <button\n type=\"button\"\n onClick={() => setShowWriteReview(true)}\n className={cn(\n 'flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-opacity',\n 'bg-foreground text-background hover:opacity-90'\n )}\n >\n <PenSquare className=\"h-4 w-4\" />\n Write Review\n </button>\n }\n >\n {/* Status message */}\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\n <PagePurpose className=\"mb-6\">\n Your voice on the carts you've tried — write honest reviews to help other customers and give\n vendors feedback they can act on. Browse what others said, then add your own rating for a\n recent order.\n </PagePurpose>\n\n {/* Stats — the one emphasis zone */}\n <EmphasisPanel className=\"mb-6\">\n <div className=\"flex flex-wrap items-center gap-4 text-sm text-text-secondary\">\n <span>{reviews.length} total reviews</span>\n <span>{myReviewCount} your reviews</span>\n <span className=\"flex items-center gap-1\">\n Average: {avgRating}\n <Star className=\"h-3.5 w-3.5 fill-status-warning-text text-status-warning-text\" />\n </span>\n </div>\n </EmphasisPanel>\n\n {/* Filters */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 mb-6\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3\">\n {/* Search */}\n <div className=\"relative\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <input\n type=\"text\"\n placeholder=\"Search reviews...\"\n value={filters.searchQuery}\n onChange={(e) => setFilters((p) => ({ ...p, searchQuery: e.target.value }))}\n className=\"w-full rounded-lg border border-border-subtle 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\n {/* Type */}\n <select\n value={filters.type}\n onChange={(e) =>\n setFilters((p) => ({ ...p, type: e.target.value as ReviewFilters['type'] }))\n }\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"all\">All Reviews</option>\n <option value=\"cart\">Cart Reviews</option>\n <option value=\"product\">Product Reviews</option>\n <option value=\"my-reviews\">My Reviews</option>\n </select>\n\n {/* Rating */}\n <select\n value={filters.rating}\n onChange={(e) => setFilters((p) => ({ ...p, rating: e.target.value }))}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Ratings</option>\n <option value=\"5\">5 Stars</option>\n <option value=\"4\">4 Stars</option>\n <option value=\"3\">3 Stars</option>\n <option value=\"2\">2 Stars</option>\n <option value=\"1\">1 Star</option>\n </select>\n\n {/* Sort */}\n <select\n value={filters.sortBy}\n onChange={(e) =>\n setFilters((p) => ({ ...p, sortBy: e.target.value as ReviewFilters['sortBy'] }))\n }\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"recent\">Most Recent</option>\n <option value=\"helpful\">Most Helpful</option>\n <option value=\"rating-high\">Highest Rating</option>\n <option value=\"rating-low\">Lowest Rating</option>\n </select>\n </div>\n </div>\n\n {/* Reviews List */}\n {filteredReviews.length === 0 ? (\n <EmptyState\n icon={<MessageSquare className=\"h-12 w-12\" />}\n title=\"No reviews found\"\n description=\"Be the first to write a review!\"\n action={\n <button\n type=\"button\"\n onClick={() => setShowWriteReview(true)}\n className=\"rounded-lg bg-foreground px-4 py-2 text-sm font-medium text-background hover:opacity-90 transition-opacity\"\n >\n Write a Review\n </button>\n }\n />\n ) : (\n <div className=\"space-y-4\">\n {filteredReviews.map((review) => {\n const isMyReview = review.userId === currentUserId;\n return (\n <div\n key={review.id}\n className={cn(\n 'rounded-lg border bg-bg-surface p-5',\n isMyReview ? 'border-foreground/20' : 'border-border-subtle'\n )}\n >\n {/* Header */}\n <div className=\"flex items-start gap-3 mb-3\">\n <img\n src={review.userAvatar}\n alt={review.userName}\n className=\"h-10 w-10 rounded-full object-cover shrink-0\"\n />\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span className=\"text-sm font-semibold text-text-primary\">\n {review.userName}\n </span>\n {review.isVerified && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-[10px] font-medium text-status-success-text\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Verified\n </span>\n )}\n {isMyReview && (\n <span className=\"inline-flex items-center rounded-full bg-[var(--color-accent-soft)] px-2 py-0.5 text-[10px] font-medium text-text-primary\">\n Your Review\n </span>\n )}\n </div>\n <div className=\"flex flex-wrap items-center gap-2 text-xs text-text-secondary mt-0.5\">\n <span>\n {review.itemType === 'cart' ? (\n <MessageSquare className=\"inline h-3 w-3 mr-0.5\" />\n ) : (\n <Star className=\"inline h-3 w-3 mr-0.5\" />\n )}\n {review.itemName}\n </span>\n <span>\n {formatDate(review.createdAt, {\n hour: undefined,\n minute: undefined,\n hour12: undefined,\n })}\n </span>\n </div>\n </div>\n <div className=\"shrink-0\">\n <RatingDisplay value={review.rating} size=\"sm\" />\n <p className=\"text-xs text-text-secondary mt-0.5 text-right\">\n From: {review.cartName}\n </p>\n </div>\n </div>\n\n {/* Content */}\n <div className=\"mb-3\">\n <h4 className=\"text-sm font-semibold text-text-primary mb-1\">{review.title}</h4>\n <p className=\"text-sm text-text-primary leading-relaxed\">{review.comment}</p>\n </div>\n\n {/* Review Images */}\n {review.images && review.images.length > 0 && (\n <div className=\"mb-3 flex gap-2 overflow-x-auto pb-1\">\n {review.images.map((img, idx) => (\n <img\n key={idx}\n src={img}\n alt={`Review image ${idx + 1}`}\n className=\"h-20 w-20 rounded-lg object-cover shrink-0\"\n />\n ))}\n </div>\n )}\n\n {/* Owner Response */}\n {review.response && (\n <div className=\"mb-3 rounded-lg border border-border-focus/20 bg-[var(--color-accent-soft)] p-3\">\n <div className=\"flex flex-wrap items-center gap-2 mb-1.5\">\n <MessageCircle className=\"h-3.5 w-3.5 text-text-primary\" />\n <span className=\"text-xs font-medium text-text-primary\">\n Response from {review.response.respondedBy}\n </span>\n <span className=\"text-[10px] text-text-primary/70\">\n {formatDate(review.response.respondedAt, {\n hour: undefined,\n minute: undefined,\n hour12: undefined,\n })}\n </span>\n </div>\n <p className=\"text-xs text-text-primary leading-relaxed\">\n {review.response.message}\n </p>\n </div>\n )}\n\n {/* Footer */}\n <div className=\"flex items-center justify-between pt-3 border-t border-border-subtle\">\n <button\n type=\"button\"\n onClick={() => handleMarkHelpful(review.id)}\n className={cn(\n 'flex items-center gap-1.5 text-xs transition-colors',\n review.isHelpful\n ? 'text-text-primary font-medium'\n : 'text-text-secondary hover:text-text-primary'\n )}\n >\n <ThumbsUp className={cn('h-3.5 w-3.5', review.isHelpful && 'fill-current')} />\n Helpful ({review.helpfulCount})\n </button>\n\n <div className=\"flex items-center gap-3 text-xs text-text-secondary\">\n <span>Order: {review.orderId}</span>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/customer/cart/${review.cartId}`)}\n className=\"font-medium hover:text-text-primary transition-colors\"\n >\n View Cart\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {/* Write Review Modal */}\n {showWriteReview && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\">\n <div className=\"w-full max-w-2xl max-h-[90vh] overflow-y-auto rounded-lg border border-border-subtle bg-bg-surface shadow-lg\">\n <div className=\"p-5\">\n {/* Header */}\n <div className=\"flex items-center justify-between mb-5\">\n <h3 className=\"text-lg font-semibold text-text-primary\">Write a Review</h3>\n <button\n type=\"button\"\n onClick={() => setShowWriteReview(false)}\n className=\"rounded-md p-2 text-text-secondary hover:bg-accent hover:text-text-primary transition-colors\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n\n <div className=\"space-y-4\">\n {/* Order selection — reviews attach to a delivered order */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Which order? <span className=\"text-status-error-text\">*</span>\n </label>\n {reviewableOrders.length > 0 ? (\n <select\n value={selectedOrderId}\n onChange={(e) => setSelectedOrderId(e.target.value)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">Select a delivered order…</option>\n {reviewableOrders.map((o) => (\n <option key={o.id} value={o.id}>\n {o.cartName} · {formatDate(o.orderDate)}\n </option>\n ))}\n </select>\n ) : (\n <p className=\"rounded-lg bg-bg-sunken p-3 text-xs text-text-secondary\">\n You can review a cart once one of your orders has been delivered. Place an order\n and come back after it arrives.\n </p>\n )}\n </div>\n\n {/* Rating */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n Rating <span className=\"text-status-error-text\">*</span>\n </label>\n <InteractiveStarRating\n value={reviewForm.rating}\n onChange={(v) => setReviewForm((p) => ({ ...p, rating: v }))}\n />\n </div>\n\n {/* Title */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Review Title <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"text\"\n placeholder=\"Summarize your experience\"\n value={reviewForm.title}\n onChange={(e) => setReviewForm((p) => ({ ...p, title: e.target.value }))}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n\n {/* Comment */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1.5\">\n Your Review <span className=\"text-status-error-text\">*</span>\n </label>\n <textarea\n rows={5}\n placeholder=\"Share your experience with others...\"\n value={reviewForm.comment}\n onChange={(e) => setReviewForm((p) => ({ ...p, comment: e.target.value }))}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none\"\n />\n </div>\n\n {/* Guidelines */}\n <div className=\"rounded-lg bg-bg-sunken p-4\">\n <div className=\"flex items-center gap-2 mb-2\">\n <Info className=\"h-4 w-4 text-text-secondary\" />\n <h4 className=\"text-sm font-medium text-text-primary\">Review Guidelines</h4>\n </div>\n <ul className=\"text-xs text-text-secondary space-y-1\">\n <li>- Be honest and helpful to other customers</li>\n <li>- Focus on your experience with the food and service</li>\n <li>- Avoid personal information or inappropriate content</li>\n <li>- Reviews are public and cannot be deleted once submitted</li>\n </ul>\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center gap-3 pt-5\">\n <button\n type=\"button\"\n onClick={handleSubmitReview}\n disabled={createReview.isPending || reviewableOrders.length === 0}\n className={cn(\n 'rounded-lg bg-foreground px-4 py-2 text-sm font-medium text-background transition-opacity',\n createReview.isPending || reviewableOrders.length === 0\n ? 'opacity-60 cursor-not-allowed'\n : 'hover:opacity-90'\n )}\n >\n {createReview.isPending ? 'Posting…' : 'Submit Review'}\n </button>\n <button\n type=\"button\"\n onClick={() => setShowWriteReview(false)}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-accent transition-colors\"\n >\n Cancel\n </button>\n </div>\n </div>\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ReviewsPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/customer/ReviewsPage.tsx"],"sourcesContent":["/**\n * Reviews Page\n * @module kadaikodi/pages/customer\n *\n * Per-cart reviews on REAL data: pick a cart (defaults to one you've ordered\n * from), see its aggregate rating + a 5→1 rating-distribution, read every\n * review with the owner's public response, and write your own review for a\n * delivered order (persisted via useCreateReview). Nothing here is fabricated —\n * when a cart has no reviews yet, an honest empty state is shown.\n */\n\nimport { useMemo, useState } from 'react';\nimport {\n Star,\n MessageSquare,\n MessageCircle,\n Search,\n Loader2,\n CheckCircle2,\n PenSquare,\n} from 'lucide-react';\nimport { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { RatingStars } from '../../components/viz';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport {\n useProviders,\n useOrders,\n useReviews,\n useCreateReview,\n} from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\nimport { formatRelativeTime } from '../../utils/formatters';\nimport { ProviderImage } from './shared';\n\nconst ratingLabels: Record<number, string> = {\n 1: 'Terrible',\n 2: 'Poor',\n 3: 'Average',\n 4: 'Good',\n 5: 'Excellent',\n};\n\ntype SortBy = 'recent' | 'rating-high' | 'rating-low';\n\nfunction InteractiveStarRating({\n value,\n onChange,\n}: {\n value: number;\n onChange: (v: number) => void;\n}) {\n const [hoverValue, setHoverValue] = useState(0);\n const displayValue = hoverValue || value;\n return (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex items-center gap-0.5\">\n {[1, 2, 3, 4, 5].map((star) => (\n <button\n key={star}\n type=\"button\"\n onClick={() => onChange(star)}\n onMouseEnter={() => setHoverValue(star)}\n onMouseLeave={() => setHoverValue(0)}\n className=\"p-0.5 transition-transform hover:scale-110\"\n aria-label={`${star} star${star > 1 ? 's' : ''}`}\n >\n <Star\n className={cn(\n 'h-7 w-7',\n star <= displayValue\n ? 'fill-status-warning-text text-status-warning-text'\n : 'fill-none text-text-secondary/40'\n )}\n />\n </button>\n ))}\n </div>\n <span className=\"text-sm font-medium text-text-secondary\">\n {ratingLabels[displayValue] ?? ''}\n </span>\n </div>\n );\n}\n\nexport function ReviewsPage() {\n const { navigateTo, currentUser } = useKadaikodi();\n const { data: providers = [], isLoading: providersLoading } = useProviders();\n const { data: myOrders = [] } = useOrders({ customerId: currentUser?.id });\n const createReview = useCreateReview();\n\n // Delivered orders are the only reviewable ones. The providers behind them\n // are the carts the customer can write about.\n const reviewableOrders = useMemo(\n () => myOrders.filter((o) => o.status === 'delivered'),\n [myOrders]\n );\n const reviewableProviderIds = useMemo(\n () => new Set(reviewableOrders.map((o) => o.cartId)),\n [reviewableOrders]\n );\n\n const [selectedProviderId, setSelectedProviderId] = useState('');\n const effectiveProviderId =\n selectedProviderId ||\n reviewableOrders[0]?.cartId ||\n providers[0]?.id ||\n '';\n\n const provider = useMemo(\n () => providers.find((p) => p.id === effectiveProviderId),\n [providers, effectiveProviderId]\n );\n\n const { data: reviews = [], isLoading: reviewsLoading } = useReviews(effectiveProviderId);\n\n const [searchQuery, setSearchQuery] = useState('');\n const [ratingFilter, setRatingFilter] = useState('');\n const [sortBy, setSortBy] = useState<SortBy>('recent');\n\n const [formRating, setFormRating] = useState(5);\n const [formComment, setFormComment] = useState('');\n const [statusMessage, setStatusMessage] = useState<string | null>(null);\n\n const showStatus = (msg: string): void => {\n setStatusMessage(msg);\n setTimeout(() => setStatusMessage(null), 3000);\n };\n\n // Rating distribution 5→1 from the real review list.\n const distribution = useMemo(() => {\n const counts: Record<number, number> = { 5: 0, 4: 0, 3: 0, 2: 0, 1: 0 };\n for (const r of reviews) {\n const bucket = Math.min(5, Math.max(1, Math.round(r.rating)));\n counts[bucket] += 1;\n }\n return counts;\n }, [reviews]);\n\n const filteredReviews = useMemo(() => {\n let list = [...reviews];\n if (ratingFilter) {\n const val = parseInt(ratingFilter, 10);\n list = list.filter((r) => Math.round(r.rating) === val);\n }\n if (searchQuery.trim()) {\n const q = searchQuery.toLowerCase();\n list = list.filter(\n (r) => (r.review ?? '').toLowerCase().includes(q) || (r.response ?? '').toLowerCase().includes(q)\n );\n }\n switch (sortBy) {\n case 'recent':\n list.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());\n break;\n case 'rating-high':\n list.sort((a, b) => b.rating - a.rating);\n break;\n case 'rating-low':\n list.sort((a, b) => a.rating - b.rating);\n break;\n }\n return list;\n }, [reviews, ratingFilter, searchQuery, sortBy]);\n\n // The delivered order for this provider that anchors a new review.\n const orderForReview = useMemo(\n () => reviewableOrders.find((o) => o.cartId === effectiveProviderId),\n [reviewableOrders, effectiveProviderId]\n );\n const canWrite = Boolean(orderForReview && currentUser?.id);\n\n const handleSubmit = (): void => {\n if (!orderForReview || !currentUser?.id) {\n showStatus('Order from this cart and wait for delivery to leave a review.');\n return;\n }\n createReview.mutate(\n {\n providerId: effectiveProviderId,\n orderId: orderForReview.id,\n customerId: currentUser.id,\n rating: formRating,\n review: formComment.trim() || undefined,\n },\n {\n onSuccess: () => {\n setFormComment('');\n setFormRating(5);\n showStatus('Thanks! Your review has been posted.');\n },\n onError: () => showStatus('Could not post your review. Please try again.'),\n }\n );\n };\n\n if (providersLoading) {\n return (\n <PageLayout title=\"Reviews & Ratings\">\n <div className=\"flex h-[60vh] items-center justify-center\">\n <Loader2 className=\"h-8 w-8 animate-spin text-accent-primary\" />\n </div>\n </PageLayout>\n );\n }\n\n if (!provider) {\n return (\n <PageLayout title=\"Reviews & Ratings\">\n <EmptyState\n icon={<MessageSquare className=\"h-12 w-12\" />}\n title=\"No carts to review yet\"\n description=\"Browse carts and place an order — once it's delivered you can rate and review it.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/customer/discover')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-semibold text-action-primary-text hover:bg-action-primary-bg-hover transition-colors\"\n >\n Discover Carts\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title=\"Reviews & Ratings\" description={`${reviews.length} reviews`}>\n {statusMessage && (\n <div className=\"mb-4 flex items-center gap-2 rounded-lg border border-status-success-text/30 bg-status-success-bg-subtle p-3\">\n <CheckCircle2 className=\"h-4 w-4 text-status-success-text shrink-0\" />\n <p className=\"text-sm text-status-success-text\">{statusMessage}</p>\n </div>\n )}\n\n <PagePurpose className=\"mb-6\">\n Honest ratings for the carts on Kadaikodi — pick a cart to see its aggregate score and every\n review, then add your own for an order you've had delivered.\n </PagePurpose>\n\n {/* Cart picker */}\n <div className=\"mb-6\">\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Viewing reviews for\n </label>\n <select\n value={effectiveProviderId}\n onChange={(e) => setSelectedProviderId(e.target.value)}\n className=\"w-full max-w-sm 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 {providers.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n {reviewableProviderIds.has(p.id) ? ' • ordered' : ''}\n </option>\n ))}\n </select>\n </div>\n\n {/* Aggregate — the one emphasis zone */}\n <EmphasisPanel className=\"mb-6\">\n <div className=\"flex flex-col gap-5 sm:flex-row sm:items-center\">\n <div className=\"flex items-center gap-4\">\n <div className=\"h-16 w-16 shrink-0 overflow-hidden rounded-xl\">\n <ProviderImage src={provider.image} alt={provider.name} seed={provider.name} />\n </div>\n <div>\n <p className=\"text-4xl font-bold leading-none text-text-primary\">\n {provider.rating.toFixed(1)}\n </p>\n <div className=\"mt-1.5\">\n <RatingStars value={provider.rating} size={16} />\n </div>\n <p className=\"mt-1 text-xs text-text-secondary\">{provider.totalRatings} ratings</p>\n </div>\n </div>\n\n {/* Distribution 5→1 */}\n <div className=\"flex-1 space-y-1.5\">\n {[5, 4, 3, 2, 1].map((star) => {\n const count = distribution[star];\n const pct = reviews.length ? (count / reviews.length) * 100 : 0;\n return (\n <div key={star} className=\"flex items-center gap-2 text-xs\">\n <span className=\"flex w-7 items-center gap-0.5 text-text-secondary\">\n {star}\n <Star className=\"h-3 w-3 fill-status-warning-text text-status-warning-text\" />\n </span>\n <div className=\"h-2 flex-1 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-accent-primary transition-all\"\n style={{ width: `${pct}%` }}\n />\n </div>\n <span className=\"w-6 text-right tabular-nums text-text-muted\">{count}</span>\n </div>\n );\n })}\n </div>\n </div>\n </EmphasisPanel>\n\n {/* Write a review */}\n <div className=\"mb-6 rounded-xl border border-border-subtle bg-bg-surface p-5\">\n <h2 className=\"mb-3 flex items-center gap-2 text-base font-semibold text-text-primary\">\n <PenSquare className=\"h-4 w-4 text-text-secondary\" />\n Write a review\n </h2>\n {canWrite ? (\n <div className=\"space-y-3\">\n <InteractiveStarRating value={formRating} onChange={setFormRating} />\n <textarea\n rows={3}\n value={formComment}\n onChange={(e) => setFormComment(e.target.value)}\n placeholder=\"Share your experience…\"\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)] resize-none\"\n />\n <div className=\"flex justify-end\">\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={createReview.isPending}\n className={cn(\n 'inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-semibold text-action-primary-text transition-colors',\n createReview.isPending\n ? 'opacity-60 cursor-not-allowed'\n : 'hover:bg-action-primary-bg-hover'\n )}\n >\n {createReview.isPending && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n Submit Review\n </button>\n </div>\n </div>\n ) : (\n <p className=\"rounded-lg bg-bg-sunken p-3 text-xs text-text-secondary\">\n You can review <span className=\"font-medium text-text-primary\">{provider.name}</span>{' '}\n once one of your orders from it has been delivered.{' '}\n <button\n type=\"button\"\n onClick={() => navigateTo(`/customer/cart/${provider.id}`)}\n className=\"font-medium text-accent-primary hover:underline\"\n >\n Order now\n </button>\n </p>\n )}\n </div>\n\n {/* Filters */}\n <div className=\"mb-6 grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <div className=\"relative sm:col-span-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"text\"\n placeholder=\"Search reviews…\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-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 <select\n value={ratingFilter}\n onChange={(e) => setRatingFilter(e.target.value)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All ratings</option>\n <option value=\"5\">5 stars</option>\n <option value=\"4\">4 stars</option>\n <option value=\"3\">3 stars</option>\n <option value=\"2\">2 stars</option>\n <option value=\"1\">1 star</option>\n </select>\n <select\n value={sortBy}\n onChange={(e) => setSortBy(e.target.value as SortBy)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"recent\">Most recent</option>\n <option value=\"rating-high\">Highest rating</option>\n <option value=\"rating-low\">Lowest rating</option>\n </select>\n </div>\n\n {/* Review list */}\n {reviewsLoading ? (\n <div className=\"flex h-40 items-center justify-center\">\n <Loader2 className=\"h-6 w-6 animate-spin text-accent-primary\" />\n </div>\n ) : filteredReviews.length === 0 ? (\n <EmptyState\n icon={<MessageSquare className=\"h-12 w-12\" />}\n title=\"No reviews yet\"\n description={`Be the first to review ${provider.name}.`}\n />\n ) : (\n <div className=\"space-y-3\">\n {filteredReviews.map((review) => {\n const isMine = review.customerId === currentUser?.id;\n return (\n <div\n key={review.id}\n className={cn(\n 'rounded-xl border bg-bg-surface p-4',\n isMine ? 'border-action-primary-bg/40' : 'border-border-subtle'\n )}\n >\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"flex items-center gap-2\">\n <RatingStars value={review.rating} size={14} />\n {isMine && (\n <span className=\"rounded-full bg-[var(--color-accent-soft)] px-2 py-0.5 text-[10px] font-medium text-accent-primary\">\n Your review\n </span>\n )}\n </div>\n <span className=\"text-xs text-text-muted\">\n {formatRelativeTime(review.createdAt)}\n </span>\n </div>\n {review.review && (\n <p className=\"mt-2 text-sm leading-relaxed text-text-primary\">{review.review}</p>\n )}\n {review.response && (\n <div className=\"mt-3 rounded-lg border-l-2 border-accent-primary bg-[var(--color-accent-soft)] p-3\">\n <p className=\"mb-1 flex items-center gap-1.5 text-xs font-medium text-text-primary\">\n <MessageCircle className=\"h-3.5 w-3.5\" />\n Owner response\n </p>\n <p className=\"text-xs leading-relaxed text-text-primary\">{review.response}</p>\n </div>\n )}\n </div>\n );\n })}\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Saved Addresses Page
|
|
3
|
+
* @module kadaikodi/pages/customer
|
|
4
|
+
*
|
|
5
|
+
* Manage delivery addresses: list, add (inline expandable), edit (modal),
|
|
6
|
+
* delete (with default protection), set default, usage count, last used date,
|
|
7
|
+
* address nickname support. 4 mock addresses.
|
|
8
|
+
*/
|
|
9
|
+
export declare function SavedAddressesPage(): import("react").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=SavedAddressesPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SavedAddressesPage.d.ts","sourceRoot":"","sources":["../../../../src/kadaikodi/pages/customer/SavedAddressesPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA8MH,wBAAgB,kBAAkB,gCA2SjC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
interface ImageWithFallbackProps {
|
|
4
|
+
src?: string | null;
|
|
5
|
+
alt: string;
|
|
6
|
+
/** Seed text for the placeholder initial (usually the name). */
|
|
7
|
+
seed?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
/** Icon shown in the placeholder (defaults to a storefront). */
|
|
10
|
+
icon?: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Renders `src` when present and loadable; otherwise a tokenized accent-gradient
|
|
14
|
+
* placeholder with the seed's initial. Fills its positioned parent.
|
|
15
|
+
*/
|
|
16
|
+
export declare function ImageWithFallback({ src, alt, seed, className, icon }: ImageWithFallbackProps): import("react").JSX.Element;
|
|
17
|
+
/** Convenience wrapper for provider/cart imagery. */
|
|
18
|
+
export declare function ProviderImage(props: Omit<ImageWithFallbackProps, 'icon'>): import("react").JSX.Element;
|
|
19
|
+
/** Toggle a provider id in the favorites store and notify subscribers. */
|
|
20
|
+
export declare function toggleFavorite(id: string): void;
|
|
21
|
+
/** Reactive access to the customer's saved-provider ids. */
|
|
22
|
+
export declare function useFavorites(): {
|
|
23
|
+
ids: string[];
|
|
24
|
+
has: (id: string) => boolean;
|
|
25
|
+
toggle: (id: string) => void;
|
|
26
|
+
};
|
|
27
|
+
interface StylizedRouteMapProps {
|
|
28
|
+
/** 0–1 progress of the courier along the illustrative route. */
|
|
29
|
+
progress?: number;
|
|
30
|
+
originLabel?: string;
|
|
31
|
+
destinationLabel?: string;
|
|
32
|
+
className?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A tokenized, animated-dashed SVG "route" between the cart and the delivery
|
|
36
|
+
* address. It is explicitly labelled as illustrative — Kadaikodi has no live-GPS
|
|
37
|
+
* feed, so this never pretends to show a real courier position.
|
|
38
|
+
*/
|
|
39
|
+
export declare function StylizedRouteMap({ progress, originLabel, destinationLabel, className, }: StylizedRouteMapProps): import("react").JSX.Element;
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../../src/kadaikodi/pages/customer/shared.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAQf,UAAU,sBAAsB;IAC9B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,sBAAsB,+BAgC5F;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,+BAExE;AAuBD,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAM/C;AAcD,4DAA4D;AAC5D,wBAAgB,YAAY,IAAI;IAC9B,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7B,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B,CAKA;AAMD,UAAU,qBAAqB;IAC7B,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,QAAc,EACd,WAAoB,EACpB,gBAAwB,EACxB,SAAS,GACV,EAAE,qBAAqB,+BAoEvB"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { cn as e } from "../../utils/cn.js";
|
|
2
|
+
import { useCallback as t, useMemo as n, useState as r, useSyncExternalStore as i } from "react";
|
|
3
|
+
import { Home as a, MapPin as o, Navigation as s, Store as c } from "lucide-react";
|
|
4
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
5
|
+
//#region src/kadaikodi/pages/customer/shared.tsx
|
|
6
|
+
function d({ src: t, alt: n, seed: i, className: a, icon: o }) {
|
|
7
|
+
let [s, d] = r(!1);
|
|
8
|
+
if (t && !s) return /* @__PURE__ */ l("img", {
|
|
9
|
+
src: t,
|
|
10
|
+
alt: n,
|
|
11
|
+
loading: "lazy",
|
|
12
|
+
onError: () => d(!0),
|
|
13
|
+
className: e("h-full w-full object-cover", a)
|
|
14
|
+
});
|
|
15
|
+
let f = (i ?? n).trim().charAt(0).toUpperCase() || "?";
|
|
16
|
+
return /* @__PURE__ */ l("div", {
|
|
17
|
+
"aria-label": n,
|
|
18
|
+
role: "img",
|
|
19
|
+
className: e("flex h-full w-full items-center justify-center bg-gradient-to-br from-accent-primary/25 via-accent-primary/10 to-bg-sunken", a),
|
|
20
|
+
children: /* @__PURE__ */ u("div", {
|
|
21
|
+
className: "flex flex-col items-center gap-1 text-accent-primary/70",
|
|
22
|
+
children: [o ?? /* @__PURE__ */ l(c, {
|
|
23
|
+
className: "h-6 w-6",
|
|
24
|
+
"aria-hidden": "true"
|
|
25
|
+
}), /* @__PURE__ */ l("span", {
|
|
26
|
+
className: "text-lg font-bold leading-none",
|
|
27
|
+
children: f
|
|
28
|
+
})]
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function f(e) {
|
|
33
|
+
return /* @__PURE__ */ l(d, {
|
|
34
|
+
...e,
|
|
35
|
+
icon: /* @__PURE__ */ l(c, {
|
|
36
|
+
className: "h-6 w-6",
|
|
37
|
+
"aria-hidden": "true"
|
|
38
|
+
})
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
var p = "kadaikodi:favorites:providers", m = /* @__PURE__ */ new Set();
|
|
42
|
+
function h() {
|
|
43
|
+
return typeof localStorage > "u" ? "[]" : localStorage.getItem(p) ?? "[]";
|
|
44
|
+
}
|
|
45
|
+
function g(e) {
|
|
46
|
+
try {
|
|
47
|
+
let t = JSON.parse(e);
|
|
48
|
+
return Array.isArray(t) ? t.filter((e) => typeof e == "string") : [];
|
|
49
|
+
} catch {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function _(e) {
|
|
54
|
+
if (typeof localStorage > "u") return;
|
|
55
|
+
let t = g(h()), n = t.includes(e) ? t.filter((t) => t !== e) : [...t, e];
|
|
56
|
+
localStorage.setItem(p, JSON.stringify(n)), m.forEach((e) => e());
|
|
57
|
+
}
|
|
58
|
+
var v = (e) => {
|
|
59
|
+
m.add(e);
|
|
60
|
+
let t = (t) => {
|
|
61
|
+
t.key === p && e();
|
|
62
|
+
};
|
|
63
|
+
return typeof window < "u" && window.addEventListener("storage", t), () => {
|
|
64
|
+
m.delete(e), typeof window < "u" && window.removeEventListener("storage", t);
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
function y() {
|
|
68
|
+
let e = i(v, h, () => "[]"), r = n(() => g(e), [e]);
|
|
69
|
+
return {
|
|
70
|
+
ids: r,
|
|
71
|
+
has: t((e) => r.includes(e), [r]),
|
|
72
|
+
toggle: _
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function b({ progress: t = .5, originLabel: n = "Cart", destinationLabel: r = "You", className: i }) {
|
|
76
|
+
let c = Math.min(1, Math.max(0, t)), d = {
|
|
77
|
+
x: 60,
|
|
78
|
+
y: 168
|
|
79
|
+
}, f = {
|
|
80
|
+
x: 340,
|
|
81
|
+
y: 56
|
|
82
|
+
}, p = {
|
|
83
|
+
x: 150,
|
|
84
|
+
y: 60
|
|
85
|
+
}, m = {
|
|
86
|
+
x: 250,
|
|
87
|
+
y: 200
|
|
88
|
+
}, h = c, g = 1 - h, _ = g * g * g * d.x + 3 * g * g * h * p.x + 3 * g * h * h * m.x + h * h * h * f.x, v = g * g * g * d.y + 3 * g * g * h * p.y + 3 * g * h * h * m.y + h * h * h * f.y;
|
|
89
|
+
return /* @__PURE__ */ u("div", {
|
|
90
|
+
className: e("relative overflow-hidden rounded-xl border border-border-subtle bg-bg-sunken", i),
|
|
91
|
+
children: [
|
|
92
|
+
/* @__PURE__ */ u("svg", {
|
|
93
|
+
viewBox: "0 0 400 220",
|
|
94
|
+
className: "h-full w-full",
|
|
95
|
+
role: "img",
|
|
96
|
+
"aria-label": "Illustrative delivery route",
|
|
97
|
+
children: [
|
|
98
|
+
/* @__PURE__ */ u("g", {
|
|
99
|
+
stroke: "var(--color-border-subtle)",
|
|
100
|
+
strokeWidth: "1",
|
|
101
|
+
opacity: "0.6",
|
|
102
|
+
children: [/* @__PURE__ */ l("path", { d: "M0 40 H400 M0 90 H400 M0 140 H400 M0 190 H400" }), /* @__PURE__ */ l("path", { d: "M70 0 V220 M150 0 V220 M230 0 V220 M310 0 V220" })]
|
|
103
|
+
}),
|
|
104
|
+
/* @__PURE__ */ l("path", {
|
|
105
|
+
d: `M${d.x} ${d.y} C ${p.x} ${p.y}, ${m.x} ${m.y}, ${f.x} ${f.y}`,
|
|
106
|
+
fill: "none",
|
|
107
|
+
stroke: "var(--color-accent-primary)",
|
|
108
|
+
strokeWidth: "3",
|
|
109
|
+
strokeLinecap: "round",
|
|
110
|
+
strokeDasharray: "2 8",
|
|
111
|
+
opacity: "0.9"
|
|
112
|
+
}),
|
|
113
|
+
/* @__PURE__ */ l("circle", {
|
|
114
|
+
cx: d.x,
|
|
115
|
+
cy: d.y,
|
|
116
|
+
r: "16",
|
|
117
|
+
fill: "var(--color-accent-primary)",
|
|
118
|
+
opacity: "0.12"
|
|
119
|
+
}),
|
|
120
|
+
/* @__PURE__ */ l("circle", {
|
|
121
|
+
cx: d.x,
|
|
122
|
+
cy: d.y,
|
|
123
|
+
r: "6",
|
|
124
|
+
fill: "var(--color-accent-primary)"
|
|
125
|
+
}),
|
|
126
|
+
/* @__PURE__ */ l("circle", {
|
|
127
|
+
cx: f.x,
|
|
128
|
+
cy: f.y,
|
|
129
|
+
r: "9",
|
|
130
|
+
fill: "var(--color-status-success-text)"
|
|
131
|
+
}),
|
|
132
|
+
/* @__PURE__ */ l("circle", {
|
|
133
|
+
cx: _,
|
|
134
|
+
cy: v,
|
|
135
|
+
r: "12",
|
|
136
|
+
fill: "var(--color-accent-primary)",
|
|
137
|
+
opacity: "0.18",
|
|
138
|
+
children: /* @__PURE__ */ l("animate", {
|
|
139
|
+
attributeName: "r",
|
|
140
|
+
values: "10;16;10",
|
|
141
|
+
dur: "2.4s",
|
|
142
|
+
repeatCount: "indefinite"
|
|
143
|
+
})
|
|
144
|
+
}),
|
|
145
|
+
/* @__PURE__ */ l("circle", {
|
|
146
|
+
cx: _,
|
|
147
|
+
cy: v,
|
|
148
|
+
r: "6",
|
|
149
|
+
fill: "var(--color-accent-primary)",
|
|
150
|
+
stroke: "var(--color-bg-surface)",
|
|
151
|
+
strokeWidth: "2"
|
|
152
|
+
})
|
|
153
|
+
]
|
|
154
|
+
}),
|
|
155
|
+
/* @__PURE__ */ u("span", {
|
|
156
|
+
className: "absolute bottom-2 left-2 inline-flex items-center gap-1 rounded-full bg-bg-surface/80 px-2 py-0.5 text-[10px] font-medium text-text-secondary backdrop-blur-sm",
|
|
157
|
+
children: [
|
|
158
|
+
/* @__PURE__ */ l(o, { className: "h-3 w-3 text-accent-primary" }),
|
|
159
|
+
" ",
|
|
160
|
+
n
|
|
161
|
+
]
|
|
162
|
+
}),
|
|
163
|
+
/* @__PURE__ */ u("span", {
|
|
164
|
+
className: "absolute right-2 top-2 inline-flex items-center gap-1 rounded-full bg-bg-surface/80 px-2 py-0.5 text-[10px] font-medium text-text-secondary backdrop-blur-sm",
|
|
165
|
+
children: [
|
|
166
|
+
/* @__PURE__ */ l(a, { className: "h-3 w-3 text-status-success-text" }),
|
|
167
|
+
" ",
|
|
168
|
+
r
|
|
169
|
+
]
|
|
170
|
+
}),
|
|
171
|
+
/* @__PURE__ */ u("span", {
|
|
172
|
+
className: "absolute right-2 bottom-2 inline-flex items-center gap-1 rounded-full bg-bg-surface/70 px-2 py-0.5 text-[10px] text-text-muted backdrop-blur-sm",
|
|
173
|
+
children: [/* @__PURE__ */ l(s, { className: "h-3 w-3" }), " Illustrative route"]
|
|
174
|
+
})
|
|
175
|
+
]
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
//#endregion
|
|
179
|
+
export { f as ProviderImage, b as StylizedRouteMap, y as useFavorites };
|
|
180
|
+
|
|
181
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","names":[],"sources":["../../../../src/kadaikodi/pages/customer/shared.tsx"],"sourcesContent":["/**\n * Shared presentational helpers for the customer pages.\n * @module kadaikodi/pages/customer\n *\n * - `ProviderImage` / `OfferingImage`: render a real media image when the\n * backend supplies one, otherwise a tokenized, themeable placeholder (never a\n * broken <img> and never a fabricated stock photo).\n * - `useFavorites`: a real, user-owned favorites store persisted in\n * localStorage and shared reactively across the customer pages (Discover adds,\n * Favorites reads). This is genuine user data — nothing is fabricated.\n * - `StylizedRouteMap`: an honest, clearly-labelled illustrative route panel for\n * order tracking (there is no live-GPS backend, so we never fake live coords).\n */\n\nimport {\n useCallback,\n useMemo,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from 'react';\nimport { Store, MapPin, Navigation, Home } from 'lucide-react';\nimport { cn } from '../../utils/cn';\n\n// ============================================================================\n// Media with graceful, tokenized fallback\n// ============================================================================\n\ninterface ImageWithFallbackProps {\n src?: string | null;\n alt: string;\n /** Seed text for the placeholder initial (usually the name). */\n seed?: string;\n className?: string;\n /** Icon shown in the placeholder (defaults to a storefront). */\n icon?: ReactNode;\n}\n\n/**\n * Renders `src` when present and loadable; otherwise a tokenized accent-gradient\n * placeholder with the seed's initial. Fills its positioned parent.\n */\nexport function ImageWithFallback({ src, alt, seed, className, icon }: ImageWithFallbackProps) {\n const [failed, setFailed] = useState(false);\n const showImage = Boolean(src) && !failed;\n\n if (showImage) {\n return (\n <img\n src={src as string}\n alt={alt}\n loading=\"lazy\"\n onError={() => setFailed(true)}\n className={cn('h-full w-full object-cover', className)}\n />\n );\n }\n\n const initial = (seed ?? alt).trim().charAt(0).toUpperCase() || '?';\n return (\n <div\n aria-label={alt}\n role=\"img\"\n className={cn(\n 'flex h-full w-full items-center justify-center bg-gradient-to-br from-accent-primary/25 via-accent-primary/10 to-bg-sunken',\n className\n )}\n >\n <div className=\"flex flex-col items-center gap-1 text-accent-primary/70\">\n {icon ?? <Store className=\"h-6 w-6\" aria-hidden=\"true\" />}\n <span className=\"text-lg font-bold leading-none\">{initial}</span>\n </div>\n </div>\n );\n}\n\n/** Convenience wrapper for provider/cart imagery. */\nexport function ProviderImage(props: Omit<ImageWithFallbackProps, 'icon'>) {\n return <ImageWithFallback {...props} icon={<Store className=\"h-6 w-6\" aria-hidden=\"true\" />} />;\n}\n\n// ============================================================================\n// Favorites — real localStorage-backed store, reactive across pages\n// ============================================================================\n\nconst FAVORITES_KEY = 'kadaikodi:favorites:providers';\nconst listeners = new Set<() => void>();\n\nfunction readRaw(): string {\n if (typeof localStorage === 'undefined') return '[]';\n return localStorage.getItem(FAVORITES_KEY) ?? '[]';\n}\n\nfunction parse(raw: string): string[] {\n try {\n const parsed: unknown = JSON.parse(raw);\n return Array.isArray(parsed) ? parsed.filter((x): x is string => typeof x === 'string') : [];\n } catch {\n return [];\n }\n}\n\n/** Toggle a provider id in the favorites store and notify subscribers. */\nexport function toggleFavorite(id: string): void {\n if (typeof localStorage === 'undefined') return;\n const current = parse(readRaw());\n const next = current.includes(id) ? current.filter((x) => x !== id) : [...current, id];\n localStorage.setItem(FAVORITES_KEY, JSON.stringify(next));\n listeners.forEach((l) => l());\n}\n\nconst subscribe = (cb: () => void): (() => void) => {\n listeners.add(cb);\n const onStorage = (e: StorageEvent): void => {\n if (e.key === FAVORITES_KEY) cb();\n };\n if (typeof window !== 'undefined') window.addEventListener('storage', onStorage);\n return () => {\n listeners.delete(cb);\n if (typeof window !== 'undefined') window.removeEventListener('storage', onStorage);\n };\n};\n\n/** Reactive access to the customer's saved-provider ids. */\nexport function useFavorites(): {\n ids: string[];\n has: (id: string) => boolean;\n toggle: (id: string) => void;\n} {\n const raw = useSyncExternalStore(subscribe, readRaw, () => '[]');\n const ids = useMemo(() => parse(raw), [raw]);\n const has = useCallback((id: string) => ids.includes(id), [ids]);\n return { ids, has, toggle: toggleFavorite };\n}\n\n// ============================================================================\n// Stylised route map (honest illustration — no live GPS backend)\n// ============================================================================\n\ninterface StylizedRouteMapProps {\n /** 0–1 progress of the courier along the illustrative route. */\n progress?: number;\n originLabel?: string;\n destinationLabel?: string;\n className?: string;\n}\n\n/**\n * A tokenized, animated-dashed SVG \"route\" between the cart and the delivery\n * address. It is explicitly labelled as illustrative — Kadaikodi has no live-GPS\n * feed, so this never pretends to show a real courier position.\n */\nexport function StylizedRouteMap({\n progress = 0.5,\n originLabel = 'Cart',\n destinationLabel = 'You',\n className,\n}: StylizedRouteMapProps) {\n const clamped = Math.min(1, Math.max(0, progress));\n // Path points in the 0..400 x 0..220 viewBox.\n const start = { x: 60, y: 168 };\n const end = { x: 340, y: 56 };\n const c1 = { x: 150, y: 60 };\n const c2 = { x: 250, y: 200 };\n const t = clamped;\n const mt = 1 - t;\n // Cubic bezier point at t for the courier marker.\n const cx =\n mt * mt * mt * start.x +\n 3 * mt * mt * t * c1.x +\n 3 * mt * t * t * c2.x +\n t * t * t * end.x;\n const cy =\n mt * mt * mt * start.y +\n 3 * mt * mt * t * c1.y +\n 3 * mt * t * t * c2.y +\n t * t * t * end.y;\n\n return (\n <div\n className={cn(\n 'relative overflow-hidden rounded-xl border border-border-subtle bg-bg-sunken',\n className\n )}\n >\n <svg viewBox=\"0 0 400 220\" className=\"h-full w-full\" role=\"img\" aria-label=\"Illustrative delivery route\">\n {/* Faint \"streets\" grid */}\n <g stroke=\"var(--color-border-subtle)\" strokeWidth=\"1\" opacity=\"0.6\">\n <path d=\"M0 40 H400 M0 90 H400 M0 140 H400 M0 190 H400\" />\n <path d=\"M70 0 V220 M150 0 V220 M230 0 V220 M310 0 V220\" />\n </g>\n {/* Route */}\n <path\n d={`M${start.x} ${start.y} C ${c1.x} ${c1.y}, ${c2.x} ${c2.y}, ${end.x} ${end.y}`}\n fill=\"none\"\n stroke=\"var(--color-accent-primary)\"\n strokeWidth=\"3\"\n strokeLinecap=\"round\"\n strokeDasharray=\"2 8\"\n opacity=\"0.9\"\n />\n {/* Origin (cart) */}\n <circle cx={start.x} cy={start.y} r=\"16\" fill=\"var(--color-accent-primary)\" opacity=\"0.12\" />\n <circle cx={start.x} cy={start.y} r=\"6\" fill=\"var(--color-accent-primary)\" />\n {/* Destination (home) */}\n <circle cx={end.x} cy={end.y} r=\"9\" fill=\"var(--color-status-success-text)\" />\n {/* Courier marker */}\n <circle cx={cx} cy={cy} r=\"12\" fill=\"var(--color-accent-primary)\" opacity=\"0.18\">\n <animate attributeName=\"r\" values=\"10;16;10\" dur=\"2.4s\" repeatCount=\"indefinite\" />\n </circle>\n <circle cx={cx} cy={cy} r=\"6\" fill=\"var(--color-accent-primary)\" stroke=\"var(--color-bg-surface)\" strokeWidth=\"2\" />\n </svg>\n\n {/* Corner labels */}\n <span className=\"absolute bottom-2 left-2 inline-flex items-center gap-1 rounded-full bg-bg-surface/80 px-2 py-0.5 text-[10px] font-medium text-text-secondary backdrop-blur-sm\">\n <MapPin className=\"h-3 w-3 text-accent-primary\" /> {originLabel}\n </span>\n <span className=\"absolute right-2 top-2 inline-flex items-center gap-1 rounded-full bg-bg-surface/80 px-2 py-0.5 text-[10px] font-medium text-text-secondary backdrop-blur-sm\">\n <Home className=\"h-3 w-3 text-status-success-text\" /> {destinationLabel}\n </span>\n <span className=\"absolute right-2 bottom-2 inline-flex items-center gap-1 rounded-full bg-bg-surface/70 px-2 py-0.5 text-[10px] text-text-muted backdrop-blur-sm\">\n <Navigation className=\"h-3 w-3\" /> Illustrative route\n </span>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Investment Details Page
|
|
3
|
+
* @module kadaikodi/pages/investor
|
|
4
|
+
*
|
|
5
|
+
* Serves both /investor/opportunity/:id and /investor/investments/:id. Resolves
|
|
6
|
+
* the opportunity (and the investor's holding, if any) from the live backend by
|
|
7
|
+
* route id. Business metrics are read from the real service-provider record
|
|
8
|
+
* (useProvider by cartId) — never fabricated. The invest panel is wired to the
|
|
9
|
+
* live useInvest mutation; the projected-returns curve is a transparent forecast
|
|
10
|
+
* computed from the stated expected return, not invented performance data.
|
|
11
|
+
*/
|
|
12
|
+
export declare function InvestmentDetailsPage(): import("react").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=InvestmentDetailsPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvestmentDetailsPage.d.ts","sourceRoot":"","sources":["../../../../src/kadaikodi/pages/investor/InvestmentDetailsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAsEH,wBAAgB,qBAAqB,gCA+dpC"}
|