@mohasinac/appkit 2.7.27 → 2.7.31
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/_internal/client/features/filters/filter-load-options.d.ts +29 -0
- package/dist/_internal/client/features/filters/filter-load-options.js +98 -0
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +1 -1
- package/dist/_internal/server/features/checkout/actions.js +42 -35
- package/dist/_internal/server/features/classified/adapters.d.ts +21 -0
- package/dist/_internal/server/features/classified/adapters.js +24 -0
- package/dist/_internal/server/features/classified/index.d.ts +3 -0
- package/dist/_internal/server/features/classified/index.js +3 -0
- package/dist/_internal/server/features/classified/metadata.d.ts +8 -0
- package/dist/_internal/server/features/classified/metadata.js +43 -0
- package/dist/_internal/server/features/classified/og.d.ts +30 -0
- package/dist/_internal/server/features/classified/og.js +76 -0
- package/dist/_internal/server/features/digital-code/adapters.d.ts +21 -0
- package/dist/_internal/server/features/digital-code/adapters.js +29 -0
- package/dist/_internal/server/features/digital-code/index.d.ts +3 -0
- package/dist/_internal/server/features/digital-code/index.js +3 -0
- package/dist/_internal/server/features/digital-code/metadata.d.ts +8 -0
- package/dist/_internal/server/features/digital-code/metadata.js +36 -0
- package/dist/_internal/server/features/digital-code/og.d.ts +27 -0
- package/dist/_internal/server/features/digital-code/og.js +77 -0
- package/dist/_internal/server/features/live/adapters.d.ts +21 -0
- package/dist/_internal/server/features/live/adapters.js +34 -0
- package/dist/_internal/server/features/live/index.d.ts +3 -0
- package/dist/_internal/server/features/live/index.js +3 -0
- package/dist/_internal/server/features/live/metadata.d.ts +8 -0
- package/dist/_internal/server/features/live/metadata.js +39 -0
- package/dist/_internal/server/features/live/og.d.ts +27 -0
- package/dist/_internal/server/features/live/og.js +72 -0
- package/dist/_internal/server/features/promotions/actions.js +4 -3
- package/dist/_internal/server/jobs/core/onOrderCreate.js +19 -16
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +25 -22
- package/dist/_internal/server/jobs/core/onProductWrite.js +48 -58
- package/dist/_internal/shared/actions/action-registry.js +504 -9
- package/dist/_internal/shared/features/blog/schema.d.ts +4 -4
- package/dist/_internal/shared/features/brands/schema.d.ts +5 -5
- package/dist/_internal/shared/features/cart/schema.d.ts +18 -18
- package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +38 -38
- package/dist/_internal/shared/features/events/schema.d.ts +8 -8
- package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
- package/dist/_internal/shared/features/products/schema.d.ts +42 -42
- package/dist/_internal/shared/features/promotions/schema.d.ts +4 -4
- package/dist/_internal/shared/features/reviews/schema.d.ts +1 -1
- package/dist/_internal/shared/media/limits.js +4 -3
- package/dist/client.d.ts +4 -0
- package/dist/client.js +2 -0
- package/dist/configs/next.js +4 -0
- package/dist/constants/api-endpoints.d.ts +6 -0
- package/dist/constants/api-endpoints.js +2 -0
- package/dist/constants/field-names.d.ts +1 -0
- package/dist/constants/field-names.js +1 -0
- package/dist/constants/table-keys.d.ts +6 -0
- package/dist/constants/table-keys.js +9 -0
- package/dist/core/hooks/useSyncManager.js +9 -8
- package/dist/features/about/components/FeesView.js +10 -7
- package/dist/features/about/components/HelpPageView.js +10 -1
- package/dist/features/about/components/HowAuctionsWorkView.js +10 -1
- package/dist/features/about/components/HowCheckoutWorksView.js +10 -1
- package/dist/features/about/components/HowOffersWorkView.js +10 -1
- package/dist/features/about/components/HowOrdersWorkView.js +10 -1
- package/dist/features/about/components/HowPayoutsWorkView.js +10 -1
- package/dist/features/about/components/HowPreOrdersWorkView.js +10 -1
- package/dist/features/about/components/HowReviewsWorkView.js +10 -1
- package/dist/features/about/components/PublicProfileView.js +46 -16
- package/dist/features/about/components/SecurityPrivacyView.js +7 -1
- package/dist/features/account/components/AddressesIndexListing.js +2 -2
- package/dist/features/account/components/NotificationBell.js +27 -16
- package/dist/features/account/components/NotificationPreferencesPanel.d.ts +9 -0
- package/dist/features/account/components/NotificationPreferencesPanel.js +91 -0
- package/dist/features/account/components/UserSidebar.js +4 -4
- package/dist/features/account/components/UserSupportView.js +16 -6
- package/dist/features/account/components/index.d.ts +2 -0
- package/dist/features/account/components/index.js +1 -0
- package/dist/features/account/schemas/index.d.ts +4 -4
- package/dist/features/account/types/index.d.ts +34 -0
- package/dist/features/admin/actions/admin-actions.js +4 -3
- package/dist/features/admin/actions/notification-actions.d.ts +24 -22
- package/dist/features/admin/actions/notification-actions.js +122 -22
- package/dist/features/admin/components/AdminAdEditorView.js +29 -15
- package/dist/features/admin/components/AdminAddressEditorView.d.ts +7 -0
- package/dist/features/admin/components/AdminAddressEditorView.js +117 -0
- package/dist/features/admin/components/AdminAdsView.js +22 -28
- package/dist/features/admin/components/AdminAllEventEntriesView.js +6 -1
- package/dist/features/admin/components/AdminBidsView.js +10 -3
- package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
- package/dist/features/admin/components/AdminBlogView.js +8 -3
- package/dist/features/admin/components/AdminBrandsView.js +7 -2
- package/dist/features/admin/components/AdminBundleEditorView.js +5 -2
- package/dist/features/admin/components/AdminCarouselEditorView.js +6 -3
- package/dist/features/admin/components/AdminCarouselView.js +13 -7
- package/dist/features/admin/components/AdminCategoriesView.js +8 -3
- package/dist/features/admin/components/AdminCategoryEditorView.js +12 -9
- package/dist/features/admin/components/AdminContactView.js +6 -1
- package/dist/features/admin/components/AdminCouponEditorView.js +8 -2
- package/dist/features/admin/components/AdminCouponsView.js +6 -1
- package/dist/features/admin/components/AdminEmployeeEditorView.js +12 -9
- package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
- package/dist/features/admin/components/AdminFaqsView.js +7 -2
- package/dist/features/admin/components/AdminFeatureFlagsView.js +58 -13
- package/dist/features/admin/components/AdminFeaturesView.js +4 -3
- package/dist/features/admin/components/AdminMediaView.js +9 -8
- package/dist/features/admin/components/AdminNavigationView.js +10 -17
- package/dist/features/admin/components/AdminNewsletterView.js +6 -1
- package/dist/features/admin/components/AdminNotificationsView.js +11 -3
- package/dist/features/admin/components/AdminOrdersView.js +6 -1
- package/dist/features/admin/components/AdminPayoutsView.js +10 -3
- package/dist/features/admin/components/AdminPrizeDrawsView.js +10 -3
- package/dist/features/admin/components/AdminProductEditorView.d.ts +3 -1
- package/dist/features/admin/components/AdminProductEditorView.js +12 -9
- package/dist/features/admin/components/AdminProductsView.js +18 -12
- package/dist/features/admin/components/AdminReturnRequestsView.js +5 -4
- package/dist/features/admin/components/AdminReviewsView.js +36 -26
- package/dist/features/admin/components/AdminScammerEditorView.js +3 -2
- package/dist/features/admin/components/AdminScammersView.js +28 -26
- package/dist/features/admin/components/AdminSectionsView.js +112 -99
- package/dist/features/admin/components/AdminSessionsView.js +10 -3
- package/dist/features/admin/components/AdminSidebar.js +4 -4
- package/dist/features/admin/components/AdminSiteSettingsView.js +45 -4
- package/dist/features/admin/components/AdminStoresView.js +6 -1
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +0 -1
- package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
- package/dist/features/admin/components/AdminSupportTicketsView.js +32 -34
- package/dist/features/admin/components/AdminTeamView.js +6 -1
- package/dist/features/admin/components/AdminUserEditorView.js +8 -15
- package/dist/features/admin/components/AdminUsersView.js +6 -1
- package/dist/features/admin/components/AdminViewCards.js +4 -3
- package/dist/features/admin/components/DashboardStats.js +2 -2
- package/dist/features/admin/components/DataTable.js +2 -2
- package/dist/features/admin/components/index.d.ts +2 -0
- package/dist/features/admin/components/index.js +1 -0
- package/dist/features/admin/components/sections/adminSectionsTypes.js +4 -3
- package/dist/features/admin/repository/chat.repository.js +8 -8
- package/dist/features/admin/repository/site-settings.repository.d.ts +1 -0
- package/dist/features/admin/repository/site-settings.repository.js +11 -9
- package/dist/features/admin/schemas/firestore.d.ts +38 -0
- package/dist/features/admin/schemas/firestore.js +15 -0
- package/dist/features/auctions/components/AuctionBidsTable.d.ts +13 -0
- package/dist/features/auctions/components/AuctionBidsTable.js +62 -0
- package/dist/features/auctions/components/AuctionDetailPageView.js +15 -21
- package/dist/features/auctions/components/AuctionFilters.d.ts +7 -1
- package/dist/features/auctions/components/AuctionFilters.js +3 -2
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +18 -9
- package/dist/features/auctions/components/MarketplaceAuctionGrid.js +3 -2
- package/dist/features/auctions/components/index.d.ts +2 -1
- package/dist/features/auctions/components/index.js +1 -1
- package/dist/features/auctions/schemas/index.d.ts +14 -14
- package/dist/features/auth/actions/realtime-token-actions.js +19 -4
- package/dist/features/auth/components/RegisterForm.js +8 -4
- package/dist/features/auth/consent-otp.d.ts +2 -0
- package/dist/features/auth/consent-otp.js +8 -0
- package/dist/features/auth/schemas/firestore.d.ts +2 -0
- package/dist/features/auth/schemas/firestore.js +18 -25
- package/dist/features/auth/schemas/index.d.ts +2 -2
- package/dist/features/before-after/api/[id]/route.js +8 -6
- package/dist/features/before-after/schemas/index.d.ts +2 -2
- package/dist/features/blog/actions/blog-actions.d.ts +3 -3
- package/dist/features/blog/components/BlogIndexListing.js +21 -2
- package/dist/features/blog/components/BlogPostForm.js +11 -5
- package/dist/features/blog/components/BlogPostView.js +10 -2
- package/dist/features/blog/schemas/index.d.ts +18 -18
- package/dist/features/cart/components/CartDrawer.js +3 -2
- package/dist/features/cart/components/CartView.js +2 -1
- package/dist/features/cart/components/CheckoutView.js +2 -1
- package/dist/features/cart/repository/cart.repository.js +4 -3
- package/dist/features/cart/utils/pending-ops.d.ts +1 -1
- package/dist/features/categories/api/[id]/route.js +4 -3
- package/dist/features/categories/api/route.js +4 -3
- package/dist/features/categories/components/BrandDetailPageView.js +2 -2
- package/dist/features/categories/components/BrandDetailTabs.d.ts +5 -1
- package/dist/features/categories/components/BrandDetailTabs.js +30 -16
- package/dist/features/categories/components/BundleCollage.d.ts +8 -0
- package/dist/features/categories/components/BundleCollage.js +50 -0
- package/dist/features/categories/components/BundleDetailView.js +2 -10
- package/dist/features/categories/components/BundleItemsPicker.js +20 -13
- package/dist/features/categories/components/CategoriesIndexListing.js +28 -9
- package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
- package/dist/features/categories/components/CategoryDetailTabs.d.ts +5 -1
- package/dist/features/categories/components/CategoryDetailTabs.js +31 -16
- package/dist/features/categories/components/CategoryProductsListing.js +52 -13
- package/dist/features/categories/components/index.d.ts +2 -0
- package/dist/features/categories/components/index.js +1 -0
- package/dist/features/categories/schemas/index.d.ts +6 -6
- package/dist/features/checkout/actions/checkout-actions.js +4 -3
- package/dist/features/checkout/hooks/usePaymentCheckout.js +31 -22
- package/dist/features/classified/components/ClassifiedFilters.d.ts +12 -0
- package/dist/features/classified/components/ClassifiedFilters.js +20 -0
- package/dist/features/classified/components/ClassifiedIndexListing.d.ts +4 -0
- package/dist/features/classified/components/ClassifiedIndexListing.js +110 -0
- package/dist/features/classified/components/ClassifiedListView.d.ts +6 -0
- package/dist/features/classified/components/ClassifiedListView.js +43 -0
- package/dist/features/classified/components/index.d.ts +6 -0
- package/dist/features/classified/components/index.js +3 -0
- package/dist/features/collections/api/[slug]/route.js +16 -12
- package/dist/features/collections/schemas/index.d.ts +5 -5
- package/dist/features/consultation/api/[id]/route.js +12 -9
- package/dist/features/consultation/components/ConsultationForm.js +3 -2
- package/dist/features/consultation/schemas/index.d.ts +6 -6
- package/dist/features/contact/email.js +77 -116
- package/dist/features/copilot/components/AdminCopilotView.js +12 -2
- package/dist/features/corporate/api/[id]/route.js +12 -9
- package/dist/features/corporate/components/CorporateInquiryForm.js +2 -1
- package/dist/features/digital-codes/components/DigitalCodeFilters.d.ts +12 -0
- package/dist/features/digital-codes/components/DigitalCodeFilters.js +17 -0
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +4 -0
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +107 -0
- package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +6 -0
- package/dist/features/digital-codes/components/DigitalCodesListView.js +37 -0
- package/dist/features/digital-codes/components/index.d.ts +6 -0
- package/dist/features/digital-codes/components/index.js +3 -0
- package/dist/features/events/actions/event-actions.js +4 -3
- package/dist/features/events/components/AdminEventEditorView.js +3 -2
- package/dist/features/events/components/AdminEventsView.js +4 -2
- package/dist/features/events/components/EventPollWidget.js +5 -5
- package/dist/features/events/components/EventsIndexListing.js +2 -2
- package/dist/features/events/repository/event-entry.repository.d.ts +1 -0
- package/dist/features/events/repository/event-entry.repository.js +5 -0
- package/dist/features/events/schemas/index.d.ts +20 -20
- package/dist/features/faq/actions/faq-actions.d.ts +8 -8
- package/dist/features/faq/components/ContactCTA.js +3 -1
- package/dist/features/faq/components/FAQAccordion.js +1 -1
- package/dist/features/faq/schemas/index.d.ts +4 -4
- package/dist/features/filters/AsyncFacetSection.d.ts +18 -0
- package/dist/features/filters/AsyncFacetSection.js +65 -0
- package/dist/features/filters/index.d.ts +2 -0
- package/dist/features/filters/index.js +1 -0
- package/dist/features/forms/Checkbox.js +2 -2
- package/dist/features/forms/Input.js +2 -2
- package/dist/features/forms/Radio.js +5 -5
- package/dist/features/forms/Select.js +2 -2
- package/dist/features/forms/Slider.js +2 -2
- package/dist/features/forms/Textarea.js +2 -2
- package/dist/features/homepage/api/[id]/route.js +4 -3
- package/dist/features/homepage/api/sections/[id]/route.js +12 -9
- package/dist/features/homepage/components/AdSlot.js +2 -1
- package/dist/features/homepage/components/AdvertisementBanner.js +5 -3
- package/dist/features/homepage/components/BrandsSection.js +2 -2
- package/dist/features/homepage/components/CTABannerSection.js +2 -2
- package/dist/features/homepage/components/CharacterHotspot.d.ts +2 -2
- package/dist/features/homepage/components/CharacterHotspot.js +119 -157
- package/dist/features/homepage/components/CharacterHotspotForm.js +25 -20
- package/dist/features/homepage/components/CustomCardsSection.js +8 -6
- package/dist/features/homepage/components/FeaturedProductsSection.js +2 -2
- package/dist/features/homepage/components/GoogleReviewsSection.js +3 -3
- package/dist/features/homepage/components/HeroBanner.js +5 -4
- package/dist/features/homepage/components/HeroCarousel.js +13 -26
- package/dist/features/homepage/components/HowItWorksSection.js +4 -2
- package/dist/features/homepage/components/SocialFeedSection.js +2 -2
- package/dist/features/homepage/components/SocialPostCard.js +3 -2
- package/dist/features/homepage/lib/social-feed-fetcher.js +6 -3
- package/dist/features/layout/AppLayoutShell.d.ts +8 -2
- package/dist/features/layout/AppLayoutShell.js +54 -78
- package/dist/features/layout/BottomActions.js +43 -48
- package/dist/features/live/components/LiveItemFilters.d.ts +12 -0
- package/dist/features/live/components/LiveItemFilters.js +24 -0
- package/dist/features/live/components/LiveItemsIndexListing.d.ts +4 -0
- package/dist/features/live/components/LiveItemsIndexListing.js +108 -0
- package/dist/features/live/components/LiveItemsListView.d.ts +6 -0
- package/dist/features/live/components/LiveItemsListView.js +43 -0
- package/dist/features/live/components/index.d.ts +6 -0
- package/dist/features/live/components/index.js +3 -0
- package/dist/features/media/MediaLightbox.js +8 -14
- package/dist/features/media/types/index.d.ts +2 -2
- package/dist/features/media/upload/CameraCapture.js +2 -2
- package/dist/features/media/upload/ImageUpload.js +4 -2
- package/dist/features/media/upload/MediaUploadField.js +24 -8
- package/dist/features/media/upload/MediaUploadList.js +1 -1
- package/dist/features/orders/actions/order-actions.js +4 -3
- package/dist/features/orders/components/MarketplaceOrderCard.js +2 -1
- package/dist/features/orders/components/OrderFilters.js +12 -9
- package/dist/features/orders/schemas/index.d.ts +6 -6
- package/dist/features/pre-orders/api/[id]/route.js +12 -9
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +5 -4
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +29 -22
- package/dist/features/pre-orders/components/PreOrderFilters.d.ts +7 -1
- package/dist/features/pre-orders/components/PreOrderFilters.js +3 -2
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +17 -52
- package/dist/features/pre-orders/components/PreorderCard.d.ts +0 -9
- package/dist/features/pre-orders/components/PreorderCard.js +2 -13
- package/dist/features/pre-orders/components/index.d.ts +1 -1
- package/dist/features/pre-orders/components/index.js +1 -1
- package/dist/features/pre-orders/schemas/index.d.ts +10 -10
- package/dist/features/products/api/[id]/route.js +9 -7
- package/dist/features/products/api/route.js +1 -1
- package/dist/features/products/columns/productTableColumns.js +3 -3
- package/dist/features/products/components/AuctionsIndexListing.js +15 -51
- package/dist/features/products/components/BidHistory.js +2 -2
- package/dist/features/products/components/CompareOverlay.d.ts +2 -0
- package/dist/features/products/components/CompareOverlay.js +3 -2
- package/dist/features/products/components/MakeOfferButton.js +20 -14
- package/dist/features/products/components/MarketplacePrizeDrawCard.js +2 -1
- package/dist/features/products/components/PrizeDrawCollage.d.ts +1 -15
- package/dist/features/products/components/PrizeDrawCollage.js +54 -14
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
- package/dist/features/products/components/PrizeDrawEntryActions.js +2 -1
- package/dist/features/products/components/PrizeDrawItemsEditor.js +9 -7
- package/dist/features/products/components/PrizeDrawsIndexListing.js +18 -51
- package/dist/features/products/components/PrizeRevealModal.js +24 -14
- package/dist/features/products/components/ProductDetailPageView.js +2 -1
- package/dist/features/products/components/ProductFilters.d.ts +7 -1
- package/dist/features/products/components/ProductFilters.js +11 -8
- package/dist/features/products/components/ProductForm.js +18 -16
- package/dist/features/products/components/ProductGalleryClient.js +2 -1
- package/dist/features/products/components/ProductGrid.js +12 -15
- package/dist/features/products/components/ProductsIndexListing.js +16 -52
- package/dist/features/products/components/ProductsIndexPageView.js +2 -2
- package/dist/features/products/repository/products.repository.d.ts +4 -0
- package/dist/features/products/repository/products.repository.js +22 -3
- package/dist/features/products/schemas/firestore.d.ts +7 -1
- package/dist/features/products/schemas/index.d.ts +56 -56
- package/dist/features/products/schemas/product-features.validators.d.ts +14 -14
- package/dist/features/products/types/index.d.ts +4 -0
- package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
- package/dist/features/promotions/schemas/index.d.ts +6 -6
- package/dist/features/reviews/actions/review-actions.js +6 -5
- package/dist/features/reviews/api/[id]/route.js +4 -3
- package/dist/features/reviews/components/ReviewDetailPageView.js +2 -2
- package/dist/features/reviews/components/ReviewDetailShell.js +6 -3
- package/dist/features/reviews/components/ReviewsIndexListing.js +2 -2
- package/dist/features/reviews/schemas/index.d.ts +6 -6
- package/dist/features/scams/components/ScamProfileView.js +19 -10
- package/dist/features/scams/components/ScamRegistryView.js +2 -1
- package/dist/features/search/components/Search.d.ts +1 -1
- package/dist/features/search/components/Search.js +56 -49
- package/dist/features/search/schemas/index.d.ts +5 -5
- package/dist/features/seller/actions/offer-actions.js +11 -9
- package/dist/features/seller/components/SellerAddressesView.js +6 -4
- package/dist/features/seller/components/SellerBidsView.js +2 -2
- package/dist/features/seller/components/SellerCouponsView.js +1 -1
- package/dist/features/seller/components/SellerOffersPanel.js +6 -1
- package/dist/features/seller/components/SellerOrdersView.js +1 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +3 -3
- package/dist/features/seller/components/SellerPreOrdersView.js +5 -4
- package/dist/features/seller/components/SellerPrizeDrawsView.js +5 -4
- package/dist/features/seller/components/SellerProductShell.d.ts +19 -1
- package/dist/features/seller/components/SellerProductShell.js +75 -9
- package/dist/features/seller/components/SellerProductsView.js +10 -11
- package/dist/features/seller/components/SellerShippingView.js +3 -3
- package/dist/features/seller/components/SellerSidebar.js +10 -7
- package/dist/features/seller/components/SellerStorefrontView.js +3 -3
- package/dist/features/seller/schemas/index.d.ts +4 -4
- package/dist/features/shell/FormShell.js +2 -1
- package/dist/features/shell/QuickFormDrawer.js +4 -3
- package/dist/features/shell/StepForm.js +4 -3
- package/dist/features/stores/actions/store-query-actions.js +4 -3
- package/dist/features/stores/components/StoreAboutView.js +2 -1
- package/dist/features/stores/components/StoreAuctionsListing.js +43 -64
- package/dist/features/stores/components/StoreDetailLayoutView.js +18 -4
- package/dist/features/stores/components/StorePreOrdersListing.js +33 -57
- package/dist/features/stores/components/StoreProductsListing.js +16 -49
- package/dist/features/stores/components/StoresIndexListing.js +2 -2
- package/dist/features/stores/schemas/index.d.ts +2 -2
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +8 -7
- package/dist/features/wishlist/hooks/useGuestWishlist.d.ts +5 -5
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +6 -6
- package/dist/features/wishlist/utils/guest-wishlist.d.ts +5 -5
- package/dist/index.d.ts +27 -3
- package/dist/index.js +1743 -1725
- package/dist/monitoring/server-logger.js +5 -9
- package/dist/next/api/apiHandler.js +56 -37
- package/dist/next/components/GlobalError.js +2 -1
- package/dist/next/routing/route-map.d.ts +41 -0
- package/dist/next/routing/route-map.js +17 -0
- package/dist/react/ErrorBoundary.js +2 -1
- package/dist/react/contexts/SessionContext.js +38 -28
- package/dist/react/hooks/useCamera.d.ts +1 -1
- package/dist/react/hooks/useCamera.js +8 -7
- package/dist/seed/products-auctions-seed-data.js +40 -40
- package/dist/seed/products-preorders-seed-data.js +16 -16
- package/dist/seed/products-prize-draws-seed-data.js +4 -4
- package/dist/seed/products-standard-seed-data.js +202 -202
- package/dist/seed/site-settings-seed-data.js +6 -0
- package/dist/server-entry.d.ts +3 -0
- package/dist/server-entry.js +3 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.js +15 -0
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/DataTable.js +28 -7
- package/dist/ui/components/Button.d.ts +8 -1
- package/dist/ui/components/Button.js +47 -8
- package/dist/ui/components/CollageLightbox.d.ts +18 -0
- package/dist/ui/components/CollageLightbox.js +41 -0
- package/dist/ui/components/Dropdown.js +7 -6
- package/dist/ui/components/ImageLightbox.d.ts +7 -1
- package/dist/ui/components/ImageLightbox.js +15 -5
- package/dist/ui/components/PageLoader.js +4 -3
- package/dist/ui/components/PaginatedMultiSelect.d.ts +28 -0
- package/dist/ui/components/PaginatedMultiSelect.js +141 -0
- package/dist/ui/components/PaginatedMultiSelect.style.css +272 -0
- package/dist/ui/components/Semantic.js +1 -1
- package/dist/ui/components/SideDrawer.js +17 -15
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1 -0
- package/dist/utils/number.formatter.js +5 -13
- package/dist/utils/string.formatter.js +21 -18
- package/dist/validation/schemas.d.ts +2 -2
- package/package.json +1 -1
|
@@ -33,9 +33,9 @@ export declare const consultationBookingSchema: z.ZodObject<{
|
|
|
33
33
|
createdAt?: string | undefined;
|
|
34
34
|
adminNote?: string | undefined;
|
|
35
35
|
message?: string | undefined;
|
|
36
|
-
mode?: "online" | "phone" | "in_person" | undefined;
|
|
37
|
-
userId?: string | undefined;
|
|
38
36
|
phone?: string | undefined;
|
|
37
|
+
mode?: "phone" | "online" | "in_person" | undefined;
|
|
38
|
+
userId?: string | undefined;
|
|
39
39
|
concern?: string[] | undefined;
|
|
40
40
|
preferredDate?: string | undefined;
|
|
41
41
|
preferredTime?: string | undefined;
|
|
@@ -47,9 +47,9 @@ export declare const consultationBookingSchema: z.ZodObject<{
|
|
|
47
47
|
status?: "pending" | "completed" | "confirmed" | "cancelled" | "no_show" | undefined;
|
|
48
48
|
adminNote?: string | undefined;
|
|
49
49
|
message?: string | undefined;
|
|
50
|
-
mode?: "online" | "phone" | "in_person" | undefined;
|
|
51
|
-
userId?: string | undefined;
|
|
52
50
|
phone?: string | undefined;
|
|
51
|
+
mode?: "phone" | "online" | "in_person" | undefined;
|
|
52
|
+
userId?: string | undefined;
|
|
53
53
|
concern?: string[] | undefined;
|
|
54
54
|
preferredDate?: string | undefined;
|
|
55
55
|
preferredTime?: string | undefined;
|
|
@@ -71,8 +71,8 @@ export declare const bookConsultationSchema: z.ZodObject<{
|
|
|
71
71
|
name: string;
|
|
72
72
|
concern: string[];
|
|
73
73
|
message?: string | undefined;
|
|
74
|
-
mode?: "online" | "phone" | "in_person" | undefined;
|
|
75
74
|
phone?: string | undefined;
|
|
75
|
+
mode?: "phone" | "online" | "in_person" | undefined;
|
|
76
76
|
preferredDate?: string | undefined;
|
|
77
77
|
preferredTime?: string | undefined;
|
|
78
78
|
}, {
|
|
@@ -80,8 +80,8 @@ export declare const bookConsultationSchema: z.ZodObject<{
|
|
|
80
80
|
name: string;
|
|
81
81
|
concern: string[];
|
|
82
82
|
message?: string | undefined;
|
|
83
|
-
mode?: "online" | "phone" | "in_person" | undefined;
|
|
84
83
|
phone?: string | undefined;
|
|
84
|
+
mode?: "phone" | "online" | "in_person" | undefined;
|
|
85
85
|
preferredDate?: string | undefined;
|
|
86
86
|
preferredTime?: string | undefined;
|
|
87
87
|
}>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getProviders } from "../../contracts";
|
|
2
2
|
import { serverLogger } from "../../monitoring";
|
|
3
3
|
import { currentYear, formatCurrency, formatDateTime, nowMs, } from "../../utils";
|
|
4
|
+
const EMAIL_STYLE_MUTED = "color: #666; font-size: 14px;";
|
|
5
|
+
const EMAIL_STYLE_BODY = "color: #333; font-size: 14px;";
|
|
4
6
|
function getSiteName() {
|
|
5
7
|
return process.env.NEXT_PUBLIC_SITE_NAME?.trim() || "App";
|
|
6
8
|
}
|
|
@@ -74,134 +76,93 @@ export async function sendPasswordResetEmailWithLink(email, resetLink) {
|
|
|
74
76
|
throw error;
|
|
75
77
|
}
|
|
76
78
|
}
|
|
79
|
+
function buildOrderItemsHtml(items, productTitle, quantity, currency) {
|
|
80
|
+
if (items && items.length > 1) {
|
|
81
|
+
return `
|
|
82
|
+
<table width="100%" cellpadding="8" cellspacing="0" border="0" style="border-collapse: collapse; margin-bottom: 8px;">
|
|
83
|
+
<thead>
|
|
84
|
+
<tr style="background-color: #e9ecef;">
|
|
85
|
+
<th style="text-align: left; font-size: 12px; font-weight: 600; color: #666; text-transform: uppercase; letter-spacing: 0.05em; padding: 8px 12px;">Product</th>
|
|
86
|
+
<th style="text-align: center; font-size: 12px; font-weight: 600; color: #666; text-transform: uppercase; letter-spacing: 0.05em; padding: 8px 12px;">Qty</th>
|
|
87
|
+
<th style="text-align: right; font-size: 12px; font-weight: 600; color: #666; text-transform: uppercase; letter-spacing: 0.05em; padding: 8px 12px;">Amount</th>
|
|
88
|
+
</tr>
|
|
89
|
+
</thead>
|
|
90
|
+
<tbody>
|
|
91
|
+
${items.map((item, index) => `
|
|
92
|
+
<tr style="background-color: ${index % 2 === 0 ? "#ffffff" : "#f8f9fa"}; border-top: 1px solid #e9ecef;">
|
|
93
|
+
<td style="font-size: 14px; color: #333; padding: 8px 12px;">${item.productTitle}</td>
|
|
94
|
+
<td style="font-size: 14px; color: #333; text-align: center; padding: 8px 12px;">${item.quantity}</td>
|
|
95
|
+
<td style="font-size: 14px; color: #333; text-align: right; padding: 8px 12px;">${formatCurrency(item.totalPrice, currency)}</td>
|
|
96
|
+
</tr>`).join("")}
|
|
97
|
+
</tbody>
|
|
98
|
+
</table>`;
|
|
99
|
+
}
|
|
100
|
+
return `
|
|
101
|
+
<tr>
|
|
102
|
+
<td style="${EMAIL_STYLE_MUTED}">Product</td>
|
|
103
|
+
<td style="${EMAIL_STYLE_BODY}">${productTitle}</td>
|
|
104
|
+
</tr>
|
|
105
|
+
<tr>
|
|
106
|
+
<td style="${EMAIL_STYLE_MUTED}">Quantity</td>
|
|
107
|
+
<td style="${EMAIL_STYLE_BODY}">${quantity}</td>
|
|
108
|
+
</tr>`;
|
|
109
|
+
}
|
|
110
|
+
function buildOrderConfirmationHtml(params) {
|
|
111
|
+
const { userName, orderId, formattedTotal, shippingAddress, paymentMethod, orderUrl, itemsHtml, siteName, items } = params;
|
|
112
|
+
return `
|
|
113
|
+
<!DOCTYPE html><html>
|
|
114
|
+
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Order Confirmation</title></head>
|
|
115
|
+
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;">
|
|
116
|
+
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color: #f5f5f5; padding: 40px 0;">
|
|
117
|
+
<tr><td align="center">
|
|
118
|
+
<table width="600" cellpadding="0" cellspacing="0" border="0" style="background-color: #ffffff; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
|
|
119
|
+
<tr><td style="background: linear-gradient(135deg, #10b981 0%, #059669 100%); padding: 40px; text-align: center;">
|
|
120
|
+
<p style="font-size: 48px; margin: 0 0 12px;">✅</p>
|
|
121
|
+
<h1 style="color: #ffffff; margin: 0; font-size: 28px; font-weight: 600;">Order Confirmed!</h1>
|
|
122
|
+
</td></tr>
|
|
123
|
+
<tr><td style="padding: 40px;">
|
|
124
|
+
<p style="color: #333; font-size: 16px; line-height: 1.6; margin: 0 0 20px;">Hi ${userName},</p>
|
|
125
|
+
<p style="color: #333; font-size: 16px; line-height: 1.6; margin: 0 0 24px;">Thank you for your order! We've received it and will process it shortly.</p>
|
|
126
|
+
<table width="100%" cellpadding="12" cellspacing="0" border="0" style="background-color: #f8f9fa; border-radius: 8px; margin-bottom: 24px;">
|
|
127
|
+
<tr><td style="color: #666; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; border-bottom: 1px solid #e9ecef;" colspan="2">Order Details</td></tr>
|
|
128
|
+
<tr><td style="color: #666; font-size: 14px; width: 40%;">Order ID</td><td style="color: #333; font-size: 14px; font-weight: 600;">${orderId}</td></tr>
|
|
129
|
+
${items && items.length > 1
|
|
130
|
+
? `<tr><td style="color: #666; font-size: 14px; vertical-align: top;" colspan="2"><div style="font-weight: 600; margin-bottom: 8px;">Items (${items.length})</div>${itemsHtml}</td></tr>`
|
|
131
|
+
: itemsHtml}
|
|
132
|
+
<tr><td style="${EMAIL_STYLE_MUTED}">Total</td><td style="color: #333; font-size: 14px; font-weight: 700;">${formattedTotal}</td></tr>
|
|
133
|
+
<tr><td style="${EMAIL_STYLE_MUTED}">Payment</td><td style="${EMAIL_STYLE_BODY}">${paymentMethod === "cod" ? "Cash on Delivery" : "Online Payment"}</td></tr>
|
|
134
|
+
<tr><td style="color: #666; font-size: 14px; vertical-align: top;">Ship to</td><td style="${EMAIL_STYLE_BODY}">${shippingAddress}</td></tr>
|
|
135
|
+
</table>
|
|
136
|
+
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="margin: 30px 0;">
|
|
137
|
+
<tr><td align="center">
|
|
138
|
+
<a href="${orderUrl}" style="display: inline-block; padding: 14px 40px; background: linear-gradient(135deg, #10b981 0%, #059669 100%); color: #ffffff; text-decoration: none; border-radius: 6px; font-size: 16px; font-weight: 600;">View Order</a>
|
|
139
|
+
</td></tr>
|
|
140
|
+
</table>
|
|
141
|
+
<p style="color: #999; font-size: 13px; line-height: 1.6; margin: 0;">We'll send you another email when your order is shipped.</p>
|
|
142
|
+
</td></tr>
|
|
143
|
+
<tr><td style="background-color: #f8f9fa; padding: 24px; text-align: center; border-top: 1px solid #eee;">
|
|
144
|
+
<p style="color: #999; font-size: 12px; margin: 0;">© ${currentYear()} ${siteName}. All rights reserved.</p>
|
|
145
|
+
</td></tr>
|
|
146
|
+
</table>
|
|
147
|
+
</td></tr>
|
|
148
|
+
</table>
|
|
149
|
+
</body></html>`;
|
|
150
|
+
}
|
|
77
151
|
export async function sendOrderConfirmationEmail(params) {
|
|
78
152
|
const siteName = getSiteName();
|
|
79
153
|
const siteUrl = getSiteUrl();
|
|
80
154
|
const { to, userName, orderId, productTitle, quantity, totalPrice, currency, shippingAddress, paymentMethod, items, } = params;
|
|
81
155
|
const orderUrl = `${siteUrl}/user/orders/view/${orderId}`;
|
|
82
156
|
const formattedTotal = formatCurrency(totalPrice, currency);
|
|
83
|
-
const itemsHtml = items
|
|
84
|
-
? `
|
|
85
|
-
<table width="100%" cellpadding="8" cellspacing="0" border="0" style="border-collapse: collapse; margin-bottom: 8px;">
|
|
86
|
-
<thead>
|
|
87
|
-
<tr style="background-color: #e9ecef;">
|
|
88
|
-
<th style="text-align: left; font-size: 12px; font-weight: 600; color: #666; text-transform: uppercase; letter-spacing: 0.05em; padding: 8px 12px;">Product</th>
|
|
89
|
-
<th style="text-align: center; font-size: 12px; font-weight: 600; color: #666; text-transform: uppercase; letter-spacing: 0.05em; padding: 8px 12px;">Qty</th>
|
|
90
|
-
<th style="text-align: right; font-size: 12px; font-weight: 600; color: #666; text-transform: uppercase; letter-spacing: 0.05em; padding: 8px 12px;">Amount</th>
|
|
91
|
-
</tr>
|
|
92
|
-
</thead>
|
|
93
|
-
<tbody>
|
|
94
|
-
${items
|
|
95
|
-
.map((item, index) => `
|
|
96
|
-
<tr style="background-color: ${index % 2 === 0 ? "#ffffff" : "#f8f9fa"}; border-top: 1px solid #e9ecef;">
|
|
97
|
-
<td style="font-size: 14px; color: #333; padding: 8px 12px;">${item.productTitle}</td>
|
|
98
|
-
<td style="font-size: 14px; color: #333; text-align: center; padding: 8px 12px;">${item.quantity}</td>
|
|
99
|
-
<td style="font-size: 14px; color: #333; text-align: right; padding: 8px 12px;">${formatCurrency(item.totalPrice, currency)}</td>
|
|
100
|
-
</tr>`)
|
|
101
|
-
.join("")}
|
|
102
|
-
</tbody>
|
|
103
|
-
</table>`
|
|
104
|
-
: `
|
|
105
|
-
<tr>
|
|
106
|
-
<td style="color: #666; font-size: 14px;">Product</td>
|
|
107
|
-
<td style="color: #333; font-size: 14px;">${productTitle}</td>
|
|
108
|
-
</tr>
|
|
109
|
-
<tr>
|
|
110
|
-
<td style="color: #666; font-size: 14px;">Quantity</td>
|
|
111
|
-
<td style="color: #333; font-size: 14px;">${quantity}</td>
|
|
112
|
-
</tr>`;
|
|
157
|
+
const itemsHtml = buildOrderItemsHtml(items, productTitle, quantity, currency);
|
|
113
158
|
const itemsText = items && items.length > 1
|
|
114
|
-
? items
|
|
115
|
-
.map((item) => ` • ${item.productTitle} × ${item.quantity} — ${formatCurrency(item.totalPrice, currency)}`)
|
|
116
|
-
.join("\n")
|
|
159
|
+
? items.map((item) => ` • ${item.productTitle} × ${item.quantity} — ${formatCurrency(item.totalPrice, currency)}`).join("\n")
|
|
117
160
|
: ` Product: ${productTitle}\n Quantity: ${quantity}`;
|
|
118
161
|
try {
|
|
119
162
|
const { data, error } = await sendConfiguredEmail({
|
|
120
163
|
to,
|
|
121
164
|
subject: `Order Confirmed — ${orderId}`,
|
|
122
|
-
html:
|
|
123
|
-
<!DOCTYPE html>
|
|
124
|
-
<html>
|
|
125
|
-
<head>
|
|
126
|
-
<meta charset="utf-8">
|
|
127
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
128
|
-
<title>Order Confirmation</title>
|
|
129
|
-
</head>
|
|
130
|
-
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;">
|
|
131
|
-
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color: #f5f5f5; padding: 40px 0;">
|
|
132
|
-
<tr>
|
|
133
|
-
<td align="center">
|
|
134
|
-
<table width="600" cellpadding="0" cellspacing="0" border="0" style="background-color: #ffffff; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
|
|
135
|
-
<tr>
|
|
136
|
-
<td style="background: linear-gradient(135deg, #10b981 0%, #059669 100%); padding: 40px; text-align: center;">
|
|
137
|
-
<p style="font-size: 48px; margin: 0 0 12px;">✅</p>
|
|
138
|
-
<h1 style="color: #ffffff; margin: 0; font-size: 28px; font-weight: 600;">Order Confirmed!</h1>
|
|
139
|
-
</td>
|
|
140
|
-
</tr>
|
|
141
|
-
<tr>
|
|
142
|
-
<td style="padding: 40px;">
|
|
143
|
-
<p style="color: #333; font-size: 16px; line-height: 1.6; margin: 0 0 20px;">Hi ${userName},</p>
|
|
144
|
-
<p style="color: #333; font-size: 16px; line-height: 1.6; margin: 0 0 24px;">
|
|
145
|
-
Thank you for your order! We've received it and will process it shortly.
|
|
146
|
-
</p>
|
|
147
|
-
<table width="100%" cellpadding="12" cellspacing="0" border="0" style="background-color: #f8f9fa; border-radius: 8px; margin-bottom: 24px;">
|
|
148
|
-
<tr>
|
|
149
|
-
<td style="color: #666; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; border-bottom: 1px solid #e9ecef;" colspan="2">Order Details</td>
|
|
150
|
-
</tr>
|
|
151
|
-
<tr>
|
|
152
|
-
<td style="color: #666; font-size: 14px; width: 40%;">Order ID</td>
|
|
153
|
-
<td style="color: #333; font-size: 14px; font-weight: 600;">${orderId}</td>
|
|
154
|
-
</tr>
|
|
155
|
-
${items && items.length > 1
|
|
156
|
-
? `
|
|
157
|
-
<tr>
|
|
158
|
-
<td style="color: #666; font-size: 14px; vertical-align: top;" colspan="2">
|
|
159
|
-
<div style="font-weight: 600; margin-bottom: 8px;">Items (${items.length})</div>
|
|
160
|
-
${itemsHtml}
|
|
161
|
-
</td>
|
|
162
|
-
</tr>`
|
|
163
|
-
: itemsHtml}
|
|
164
|
-
<tr>
|
|
165
|
-
<td style="color: #666; font-size: 14px;">Total</td>
|
|
166
|
-
<td style="color: #333; font-size: 14px; font-weight: 700;">${formattedTotal}</td>
|
|
167
|
-
</tr>
|
|
168
|
-
<tr>
|
|
169
|
-
<td style="color: #666; font-size: 14px;">Payment</td>
|
|
170
|
-
<td style="color: #333; font-size: 14px;">${paymentMethod === "cod" ? "Cash on Delivery" : "Online Payment"}</td>
|
|
171
|
-
</tr>
|
|
172
|
-
<tr>
|
|
173
|
-
<td style="color: #666; font-size: 14px; vertical-align: top;">Ship to</td>
|
|
174
|
-
<td style="color: #333; font-size: 14px;">${shippingAddress}</td>
|
|
175
|
-
</tr>
|
|
176
|
-
</table>
|
|
177
|
-
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="margin: 30px 0;">
|
|
178
|
-
<tr>
|
|
179
|
-
<td align="center">
|
|
180
|
-
<a href="${orderUrl}" style="display: inline-block; padding: 14px 40px; background: linear-gradient(135deg, #10b981 0%, #059669 100%); color: #ffffff; text-decoration: none; border-radius: 6px; font-size: 16px; font-weight: 600;">
|
|
181
|
-
View Order
|
|
182
|
-
</a>
|
|
183
|
-
</td>
|
|
184
|
-
</tr>
|
|
185
|
-
</table>
|
|
186
|
-
<p style="color: #999; font-size: 13px; line-height: 1.6; margin: 0;">
|
|
187
|
-
We'll send you another email when your order is shipped.
|
|
188
|
-
</p>
|
|
189
|
-
</td>
|
|
190
|
-
</tr>
|
|
191
|
-
<tr>
|
|
192
|
-
<td style="background-color: #f8f9fa; padding: 24px; text-align: center; border-top: 1px solid #eee;">
|
|
193
|
-
<p style="color: #999; font-size: 12px; margin: 0;">
|
|
194
|
-
© ${currentYear()} ${siteName}. All rights reserved.
|
|
195
|
-
</p>
|
|
196
|
-
</td>
|
|
197
|
-
</tr>
|
|
198
|
-
</table>
|
|
199
|
-
</td>
|
|
200
|
-
</tr>
|
|
201
|
-
</table>
|
|
202
|
-
</body>
|
|
203
|
-
</html>
|
|
204
|
-
`,
|
|
165
|
+
html: buildOrderConfirmationHtml({ userName, orderId, formattedTotal, shippingAddress, paymentMethod, orderUrl, itemsHtml, siteName, items }),
|
|
205
166
|
text: `Hi ${userName},\n\nYour order ${orderId} has been confirmed!\n\n${itemsText}\nTotal: ${formattedTotal}\nPayment: ${paymentMethod === "cod" ? "Cash on Delivery" : "Online Payment"}\nShip to: ${shippingAddress}\n\nView your order: ${orderUrl}\n\n© ${currentYear()} ${siteName}`,
|
|
206
167
|
});
|
|
207
168
|
if (error) {
|
|
@@ -6,12 +6,22 @@ import { Alert, Button, Div, Heading, Input, Span, StackedViewShell, Text, } fro
|
|
|
6
6
|
import { apiClient } from "../../../http";
|
|
7
7
|
import { useCopilotChat } from "../hooks/useCopilotChat";
|
|
8
8
|
import { THEME_CONSTANTS } from "../../../tokens";
|
|
9
|
+
const LBL_CONVERSATION_ID = "Conversation ID";
|
|
9
10
|
function MessageBubble({ msg }) {
|
|
10
11
|
const isUser = msg.role === "user";
|
|
11
12
|
return (_jsx(Div, { className: `flex ${isUser ? "justify-end" : "justify-start"}`, children: _jsxs(Div, { className: `max-w-[80%] rounded-2xl px-4 py-2.5 text-sm ${isUser
|
|
12
13
|
? "bg-primary text-white rounded-tr-sm"
|
|
13
14
|
: "bg-neutral-100 dark:bg-slate-700 text-neutral-900 dark:text-neutral-100 rounded-tl-sm"}`, children: [_jsx(Text, { className: "whitespace-pre-wrap text-sm leading-relaxed", children: msg.content }), msg.durationMs ? (_jsxs(Span, { className: "mt-1 block text-xs opacity-60", children: [(msg.durationMs / 1000).toFixed(1), "s"] })) : null] }) }));
|
|
14
15
|
}
|
|
16
|
+
function renderCopilotChatPanel(props) {
|
|
17
|
+
const { messages, conversationId, isLoading, error, input, setInput, labels, messagesEndRef, handleSubmit } = props;
|
|
18
|
+
return (_jsxs(Div, { className: "flex flex-col rounded-xl border border-neutral-200 dark:border-slate-700 bg-white dark:bg-slate-800/60 h-[calc(100vh-300px)]", children: [_jsx(Div, { className: "border-b border-neutral-200 dark:border-slate-700 p-3", children: _jsxs(Text, { className: "text-xs font-medium text-neutral-500 dark:text-zinc-400", children: [labels?.conversationId ?? LBL_CONVERSATION_ID, ": ", conversationId] }) }), _jsxs(Div, { className: "flex-1 overflow-y-auto p-4 space-y-4", children: [messages.length === 0 ? (_jsxs(Div, { className: "flex flex-col items-center justify-center h-full text-center", children: [_jsx(Text, { className: "font-medium", children: labels?.noMessages ?? "No messages yet" }), _jsx(Text, { variant: "secondary", className: "text-sm mt-1", children: labels?.noMessagesDesc ?? "Ask anything to get started" })] })) : null, messages.map((msg) => _jsx(MessageBubble, { msg: msg }, msg.id)), isLoading ? (_jsx(Div, { className: "flex justify-start", children: _jsx(Div, { className: "rounded-2xl rounded-tl-sm bg-neutral-100 dark:bg-slate-700 px-4 py-2.5", children: _jsx(Span, { className: "text-sm opacity-60 animate-pulse", children: "Thinking..." }) }) })) : null, error ? _jsx(Text, { className: "text-center text-sm text-red-500", children: labels?.errorLabel ?? "An error occurred. Please try again." }) : null, _jsx("div", { ref: messagesEndRef })] }), _jsx(Div, { className: "border-t border-neutral-200 dark:border-slate-700 p-3", children: _jsxs("form", { onSubmit: handleSubmit, className: "flex gap-2", children: [_jsx("input", { type: "text", value: input, onChange: (e) => setInput(e.target.value), placeholder: labels?.inputPlaceholder ?? "Ask anything...", disabled: isLoading, className: "flex-1 h-10 rounded-lg border border-neutral-200 dark:border-slate-600 bg-white dark:bg-slate-800 px-3 text-sm outline-none focus:ring-2 ring-primary/20 transition disabled:opacity-60" }), _jsx(Button, { type: "submit", variant: "primary", disabled: isLoading || !input.trim(), className: "shrink-0", children: isLoading ? labels?.sendingButton ?? "Sending..." : labels?.sendButton ?? "Send" })] }) })] }));
|
|
19
|
+
}
|
|
20
|
+
function renderCopilotHistoryPanel(props) {
|
|
21
|
+
const { historyQuery, conversationInput, setConversationInput, loadConversation, labels } = props;
|
|
22
|
+
return (_jsxs(Div, { className: "rounded-xl border border-neutral-200 dark:border-slate-700 bg-white dark:bg-slate-900 p-4 space-y-3", children: [_jsx(Heading, { level: 3, className: "text-sm font-semibold", children: labels?.historyTitle ?? "Conversation History" }), _jsxs("form", { className: "space-y-2", onSubmit: (e) => { e.preventDefault(); if (!conversationInput.trim())
|
|
23
|
+
return; loadConversation(conversationInput.trim()); }, children: [_jsx(Input, { label: labels?.conversationId ?? LBL_CONVERSATION_ID, value: conversationInput, onChange: (e) => setConversationInput(e.target.value), placeholder: "conv_..." }), _jsx(Button, { type: "submit", variant: "secondary", size: "sm", className: "w-full", children: labels?.loadConversation ?? "Load conversation" })] }), historyQuery.error ? (_jsx(Alert, { variant: "warning", title: "History unavailable", children: historyQuery.error instanceof Error ? historyQuery.error.message : "Could not load history" })) : null, _jsxs(Div, { className: "max-h-72 overflow-y-auto space-y-2", children: [(historyQuery.data?.messages ?? []).map((log, index) => (_jsxs(Div, { className: "rounded-lg border border-neutral-200 dark:border-slate-700 p-2", children: [_jsx(Text, { className: "text-xs font-medium text-neutral-500 dark:text-zinc-400", children: new Date(log.createdAt).toLocaleString() }), _jsxs(Text, { className: `text-sm mt-1 ${THEME_CONSTANTS.utilities.textClamp3}`, children: ["Q: ", log.prompt] }), _jsxs(Text, { className: `text-sm mt-1 ${THEME_CONSTANTS.utilities.textClamp3} text-neutral-600 dark:text-zinc-300`, children: ["A: ", log.response] })] }, `${log.createdAt}-${index}`))), !historyQuery.isLoading && (historyQuery.data?.messages?.length ?? 0) === 0 ? (_jsx(Text, { variant: "secondary", className: "text-sm", children: "No server history found for this conversation yet." })) : null] })] }));
|
|
24
|
+
}
|
|
15
25
|
export function AdminCopilotView({ endpoint, historyEndpoint = "/api/copilot/history", renderHeader, labels = {}, className = "", }) {
|
|
16
26
|
const [input, setInput] = useState("");
|
|
17
27
|
const [conversationInput, setConversationInput] = useState("");
|
|
@@ -34,11 +44,11 @@ export function AdminCopilotView({ endpoint, historyEndpoint = "/api/copilot/his
|
|
|
34
44
|
};
|
|
35
45
|
return (_jsx(StackedViewShell, { portal: "admin", title: labels.title ?? "AI Copilot", className: className, sections: [
|
|
36
46
|
renderHeader ? (renderHeader(startNewConversation)) : (_jsxs(Div, { className: "flex items-center justify-between gap-3", children: [_jsx(Heading, { level: 2, children: labels.title ?? "AI Copilot" }), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: startNewConversation, children: labels.newConversation ?? "New Conversation" })] })),
|
|
37
|
-
_jsxs(Div, { className: "grid grid-cols-1 lg:grid-cols-[2fr,1fr] gap-4", children: [_jsxs(Div, { className: "flex flex-col rounded-xl border border-neutral-200 dark:border-slate-700 bg-white dark:bg-slate-800/60 h-[calc(100vh-300px)]", children: [_jsx(Div, { className: "border-b border-neutral-200 dark:border-slate-700 p-3", children: _jsxs(Text, { className: "text-xs font-medium text-neutral-500 dark:text-zinc-400", children: [labels.conversationId ??
|
|
47
|
+
_jsxs(Div, { className: "grid grid-cols-1 lg:grid-cols-[2fr,1fr] gap-4", children: [_jsxs(Div, { className: "flex flex-col rounded-xl border border-neutral-200 dark:border-slate-700 bg-white dark:bg-slate-800/60 h-[calc(100vh-300px)]", children: [_jsx(Div, { className: "border-b border-neutral-200 dark:border-slate-700 p-3", children: _jsxs(Text, { className: "text-xs font-medium text-neutral-500 dark:text-zinc-400", children: [labels.conversationId ?? LBL_CONVERSATION_ID, ": ", conversationId] }) }), _jsxs(Div, { className: "flex-1 overflow-y-auto p-4 space-y-4", children: [messages.length === 0 ? (_jsxs(Div, { className: "flex flex-col items-center justify-center h-full text-center", children: [_jsx(Text, { className: "font-medium", children: labels.noMessages ?? "No messages yet" }), _jsx(Text, { variant: "secondary", className: "text-sm mt-1", children: labels.noMessagesDesc ?? "Ask anything to get started" })] })) : null, messages.map((msg) => (_jsx(MessageBubble, { msg: msg }, msg.id))), isLoading ? (_jsx(Div, { className: "flex justify-start", children: _jsx(Div, { className: "rounded-2xl rounded-tl-sm bg-neutral-100 dark:bg-slate-700 px-4 py-2.5", children: _jsx(Span, { className: "text-sm opacity-60 animate-pulse", children: "Thinking..." }) }) })) : null, error ? (_jsx(Text, { className: "text-center text-sm text-red-500", children: labels.errorLabel ?? "An error occurred. Please try again." })) : null, _jsx("div", { ref: messagesEndRef })] }), _jsx(Div, { className: "border-t border-neutral-200 dark:border-slate-700 p-3", children: _jsxs("form", { onSubmit: handleSubmit, className: "flex gap-2", children: [_jsx("input", { type: "text", value: input, onChange: (event) => setInput(event.target.value), placeholder: labels.inputPlaceholder ?? "Ask anything...", disabled: isLoading, className: "flex-1 h-10 rounded-lg border border-neutral-200 dark:border-slate-600 bg-white dark:bg-slate-800 px-3 text-sm outline-none focus:ring-2 ring-primary/20 transition disabled:opacity-60" }), _jsx(Button, { type: "submit", variant: "primary", disabled: isLoading || !input.trim(), className: "shrink-0", children: isLoading ? labels.sendingButton ?? "Sending..." : labels.sendButton ?? "Send" })] }) })] }), _jsxs(Div, { className: "rounded-xl border border-neutral-200 dark:border-slate-700 bg-white dark:bg-slate-900 p-4 space-y-3", children: [_jsx(Heading, { level: 3, className: "text-sm font-semibold", children: labels.historyTitle ?? "Conversation History" }), _jsxs("form", { className: "space-y-2", onSubmit: (event) => {
|
|
38
48
|
event.preventDefault();
|
|
39
49
|
if (!conversationInput.trim())
|
|
40
50
|
return;
|
|
41
51
|
loadConversation(conversationInput.trim());
|
|
42
|
-
}, children: [_jsx(Input, { label: labels.conversationId ??
|
|
52
|
+
}, children: [_jsx(Input, { label: labels.conversationId ?? LBL_CONVERSATION_ID, value: conversationInput, onChange: (event) => setConversationInput(event.target.value), placeholder: "conv_..." }), _jsx(Button, { type: "submit", variant: "secondary", size: "sm", className: "w-full", children: labels.loadConversation ?? "Load conversation" })] }), historyQuery.error ? (_jsx(Alert, { variant: "warning", title: "History unavailable", children: historyQuery.error instanceof Error ? historyQuery.error.message : "Could not load history" })) : null, _jsxs(Div, { className: "max-h-72 overflow-y-auto space-y-2", children: [(historyQuery.data?.messages ?? []).map((log, index) => (_jsxs(Div, { className: "rounded-lg border border-neutral-200 dark:border-slate-700 p-2", children: [_jsx(Text, { className: "text-xs font-medium text-neutral-500 dark:text-zinc-400", children: new Date(log.createdAt).toLocaleString() }), _jsxs(Text, { className: `text-sm mt-1 ${THEME_CONSTANTS.utilities.textClamp3}`, children: ["Q: ", log.prompt] }), _jsxs(Text, { className: `text-sm mt-1 ${THEME_CONSTANTS.utilities.textClamp3} text-neutral-600 dark:text-zinc-300`, children: ["A: ", log.response] })] }, `${log.createdAt}-${index}`))), !historyQuery.isLoading && (historyQuery.data?.messages?.length ?? 0) === 0 ? (_jsx(Text, { variant: "secondary", className: "text-sm", children: "No server history found for this conversation yet." })) : null] })] })] }),
|
|
43
53
|
] }));
|
|
44
54
|
}
|
|
@@ -10,15 +10,18 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { NextResponse } from "next/server.js";
|
|
12
12
|
import { getProviders } from "../../../../contracts";
|
|
13
|
+
const ERR_INQUIRY_ID_REQUIRED = "Inquiry ID is required";
|
|
14
|
+
const ERR_DB_NOT_CONFIGURED = "Database provider not configured";
|
|
15
|
+
const ERR_INTERNAL_SERVER_ERROR = "Internal server error";
|
|
13
16
|
export async function GET(request, { params }) {
|
|
14
17
|
try {
|
|
15
18
|
const { id } = await params;
|
|
16
19
|
if (!id) {
|
|
17
|
-
return NextResponse.json({ success: false, error:
|
|
20
|
+
return NextResponse.json({ success: false, error: ERR_INQUIRY_ID_REQUIRED }, { status: 400 });
|
|
18
21
|
}
|
|
19
22
|
const { db } = getProviders();
|
|
20
23
|
if (!db)
|
|
21
|
-
return NextResponse.json({ success: false, error:
|
|
24
|
+
return NextResponse.json({ success: false, error: ERR_DB_NOT_CONFIGURED }, { status: 503 });
|
|
22
25
|
const repo = db.getRepository("corporate_inquiries");
|
|
23
26
|
const inquiry = await repo.findById(id);
|
|
24
27
|
if (!inquiry) {
|
|
@@ -32,7 +35,7 @@ export async function GET(request, { params }) {
|
|
|
32
35
|
catch (error) {
|
|
33
36
|
return NextResponse.json({
|
|
34
37
|
success: false,
|
|
35
|
-
error: error instanceof Error ? error.message :
|
|
38
|
+
error: error instanceof Error ? error.message : ERR_INTERNAL_SERVER_ERROR,
|
|
36
39
|
}, { status: 500 });
|
|
37
40
|
}
|
|
38
41
|
}
|
|
@@ -40,12 +43,12 @@ export async function PATCH(request, { params }) {
|
|
|
40
43
|
try {
|
|
41
44
|
const { id } = await params;
|
|
42
45
|
if (!id) {
|
|
43
|
-
return NextResponse.json({ success: false, error:
|
|
46
|
+
return NextResponse.json({ success: false, error: ERR_INQUIRY_ID_REQUIRED }, { status: 400 });
|
|
44
47
|
}
|
|
45
48
|
const body = await request.json();
|
|
46
49
|
const { db } = getProviders();
|
|
47
50
|
if (!db)
|
|
48
|
-
return NextResponse.json({ success: false, error:
|
|
51
|
+
return NextResponse.json({ success: false, error: ERR_DB_NOT_CONFIGURED }, { status: 503 });
|
|
49
52
|
const repo = db.getRepository("corporate_inquiries");
|
|
50
53
|
const updated = await repo.update(id, body);
|
|
51
54
|
if (!updated) {
|
|
@@ -59,7 +62,7 @@ export async function PATCH(request, { params }) {
|
|
|
59
62
|
catch (error) {
|
|
60
63
|
return NextResponse.json({
|
|
61
64
|
success: false,
|
|
62
|
-
error: error instanceof Error ? error.message :
|
|
65
|
+
error: error instanceof Error ? error.message : ERR_INTERNAL_SERVER_ERROR,
|
|
63
66
|
}, { status: 500 });
|
|
64
67
|
}
|
|
65
68
|
}
|
|
@@ -67,11 +70,11 @@ export async function DELETE(request, { params }) {
|
|
|
67
70
|
try {
|
|
68
71
|
const { id } = await params;
|
|
69
72
|
if (!id) {
|
|
70
|
-
return NextResponse.json({ success: false, error:
|
|
73
|
+
return NextResponse.json({ success: false, error: ERR_INQUIRY_ID_REQUIRED }, { status: 400 });
|
|
71
74
|
}
|
|
72
75
|
const { db } = getProviders();
|
|
73
76
|
if (!db)
|
|
74
|
-
return NextResponse.json({ success: false, error:
|
|
77
|
+
return NextResponse.json({ success: false, error: ERR_DB_NOT_CONFIGURED }, { status: 503 });
|
|
75
78
|
const repo = db.getRepository("corporate_inquiries");
|
|
76
79
|
await repo.delete(id);
|
|
77
80
|
return NextResponse.json({
|
|
@@ -82,7 +85,7 @@ export async function DELETE(request, { params }) {
|
|
|
82
85
|
catch (error) {
|
|
83
86
|
return NextResponse.json({
|
|
84
87
|
success: false,
|
|
85
|
-
error: error instanceof Error ? error.message :
|
|
88
|
+
error: error instanceof Error ? error.message : ERR_INTERNAL_SERVER_ERROR,
|
|
86
89
|
}, { status: 500 });
|
|
87
90
|
}
|
|
88
91
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import { Button, Div, Input, Text, Textarea } from "../../../ui";
|
|
5
|
+
const CLS_INPUT = "w-full rounded-md border border-neutral-300 px-3 py-2 text-sm";
|
|
5
6
|
export function CorporateInquiryForm({ onSubmit, isPending, }) {
|
|
6
7
|
const [form, setForm] = React.useState({
|
|
7
8
|
companyName: "",
|
|
@@ -32,5 +33,5 @@ export function CorporateInquiryForm({ onSubmit, isPending, }) {
|
|
|
32
33
|
e.preventDefault();
|
|
33
34
|
await onSubmit(form);
|
|
34
35
|
}
|
|
35
|
-
return (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsxs(Div, { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [_jsx(Input, { name: "companyName", type: "text", placeholder: "Company name", value: form.companyName, onChange: handleChange, required: true, className:
|
|
36
|
+
return (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsxs(Div, { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [_jsx(Input, { name: "companyName", type: "text", placeholder: "Company name", value: form.companyName, onChange: handleChange, required: true, className: CLS_INPUT }), _jsx(Input, { name: "contactPerson", type: "text", placeholder: "Contact person", value: form.contactPerson, onChange: handleChange, required: true, className: CLS_INPUT }), _jsx(Input, { name: "designation", type: "text", placeholder: "Designation (optional)", value: form.designation ?? "", onChange: handleChange, className: CLS_INPUT }), _jsx(Input, { name: "email", type: "email", placeholder: "Business email", value: form.email, onChange: handleChange, required: true, className: CLS_INPUT }), _jsx(Input, { name: "phone", type: "tel", placeholder: "Phone number", value: form.phone, onChange: handleChange, required: true, className: CLS_INPUT }), _jsx(Input, { name: "units", type: "number", placeholder: "Number of units", value: form.units, onChange: handleChange, min: 1, required: true, className: CLS_INPUT }), _jsx(Input, { name: "budgetPerUnit", type: "number", placeholder: "Budget per unit (optional)", value: form.budgetPerUnit ?? "", onChange: handleChange, min: 0, className: CLS_INPUT }), _jsx(Input, { name: "deliveryDateRequired", type: "date", placeholder: "Required by (optional)", value: form.deliveryDateRequired ?? "", onChange: handleChange, className: CLS_INPUT })] }), _jsxs(Div, { className: "flex items-center gap-2 text-sm text-neutral-700", children: [_jsx("input", { name: "customBranding", type: "checkbox", checked: form.customBranding, onChange: handleChange, className: "h-4 w-4 rounded border-neutral-300" }), _jsx(Text, { className: "text-sm text-neutral-700", children: "Custom branding required" })] }), _jsx(Textarea, { name: "message", placeholder: "Additional requirements (optional)", value: form.message ?? "", onChange: handleChange, rows: 4, className: CLS_INPUT }), _jsx(Button, { type: "submit", disabled: isPending, variant: "primary", className: "w-full rounded-md bg-primary px-4 py-2 text-sm font-medium text-white transition hover:bg-primary/90 disabled:opacity-60", children: isPending ? "Submitting..." : "Submit Inquiry" })] }));
|
|
36
37
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FacetOption } from "../../filters/FilterFacetSection";
|
|
2
|
+
import type { UrlTable } from "../../filters/FilterPanel";
|
|
3
|
+
import type { AsyncFacetSectionProps } from "../../filters/AsyncFacetSection";
|
|
4
|
+
type LoadOptionsFn = AsyncFacetSectionProps["loadOptions"];
|
|
5
|
+
export interface DigitalCodeFiltersProps {
|
|
6
|
+
table: UrlTable;
|
|
7
|
+
categoryOptions?: FacetOption[];
|
|
8
|
+
loadCategoryOptions?: LoadOptionsFn;
|
|
9
|
+
currencyPrefix?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function DigitalCodeFilters({ table, categoryOptions, loadCategoryOptions, currencyPrefix, }: DigitalCodeFiltersProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { FilterFacetSection } from "../../filters/FilterFacetSection";
|
|
4
|
+
import { AsyncFacetSection } from "../../filters/AsyncFacetSection";
|
|
5
|
+
import { RangeFilter } from "../../filters/RangeFilter";
|
|
6
|
+
import { Div } from "../../../ui";
|
|
7
|
+
const DELIVERY_OPTIONS = [
|
|
8
|
+
{ value: "auto-claim", label: "Instant (auto-claim)" },
|
|
9
|
+
{ value: "manual-email", label: "Manual (sent by seller)" },
|
|
10
|
+
];
|
|
11
|
+
export function DigitalCodeFilters({ table, categoryOptions = [], loadCategoryOptions, currencyPrefix = "₹", }) {
|
|
12
|
+
const selectedCategories = table.get("category")
|
|
13
|
+
? table.get("category").split("|").filter(Boolean)
|
|
14
|
+
: [];
|
|
15
|
+
const selectedDelivery = table.get("deliveryMethod") ? [table.get("deliveryMethod")] : [];
|
|
16
|
+
return (_jsxs(Div, { children: [loadCategoryOptions ? (_jsx(AsyncFacetSection, { title: "Category", loadOptions: loadCategoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), defaultCollapsed: false })) : categoryOptions.length > 0 ? (_jsx(FilterFacetSection, { title: "Category", options: categoryOptions, selected: selectedCategories, onChange: (vals) => table.set("category", vals.join("|")), searchable: true, defaultCollapsed: categoryOptions.length > 6 })) : null, _jsx(FilterFacetSection, { title: "Delivery Method", options: DELIVERY_OPTIONS, selected: selectedDelivery, onChange: (vals) => table.set("deliveryMethod", vals[0] ?? ""), searchable: false, selectionMode: "single", defaultCollapsed: false }), _jsx(RangeFilter, { title: "Price per Code", minValue: table.get("minPrice"), maxValue: table.get("maxPrice"), onMinChange: (v) => table.set("minPrice", v), onMaxChange: (v) => table.set("maxPrice", v), prefix: currencyPrefix, showSlider: true, minBound: 0, maxBound: 50000, step: 50, minPlaceholder: "Min price", maxPlaceholder: "Max price", defaultCollapsed: false })] }));
|
|
17
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useCallback } from "react";
|
|
4
|
+
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
5
|
+
import { useProducts } from "../../products/hooks/useProducts";
|
|
6
|
+
import { BulkActionBar, FilterDrawer, ListingToolbar, LoginRequiredModal, Pagination, Text, useToast } from "../../../ui";
|
|
7
|
+
import { usePendingTable } from "../../../react/hooks/usePendingTable";
|
|
8
|
+
import { useAuthGate } from "../../../react/hooks/useAuthGate";
|
|
9
|
+
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
10
|
+
import { useGuestWishlist } from "../../wishlist/hooks/useGuestWishlist";
|
|
11
|
+
import { pushWishlistOp } from "../../cart/utils/pending-ops";
|
|
12
|
+
import { useCategoryTree, categoriesToFacetOptions } from "../../categories/hooks/useCategoryTree";
|
|
13
|
+
import { TABLE_KEYS, VIEW_MODE } from "../../../constants/table-keys";
|
|
14
|
+
import { sortBy } from "../../../constants/sort";
|
|
15
|
+
import { PRODUCT_FIELDS } from "../../../constants/field-names";
|
|
16
|
+
import { ROUTES } from "../../../next";
|
|
17
|
+
import { InteractiveProductCard } from "../../products/components/InteractiveProductCard";
|
|
18
|
+
import { DigitalCodeFilters } from "./DigitalCodeFilters";
|
|
19
|
+
import { ACTION_ID } from "../../products/constants/action-defs";
|
|
20
|
+
const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
|
|
21
|
+
const SORT_OPTIONS = [
|
|
22
|
+
{ value: sortBy(PRODUCT_FIELDS.CREATED_AT), label: "Newest First" },
|
|
23
|
+
{ value: sortBy(PRODUCT_FIELDS.CREATED_AT, "ASC"), label: "Oldest First" },
|
|
24
|
+
{ value: sortBy(PRODUCT_FIELDS.PRICE, "ASC"), label: "Price: Low to High" },
|
|
25
|
+
{ value: sortBy(PRODUCT_FIELDS.PRICE), label: "Price: High to Low" },
|
|
26
|
+
];
|
|
27
|
+
const FILTER_KEYS = [
|
|
28
|
+
TABLE_KEYS.CATEGORY,
|
|
29
|
+
TABLE_KEYS.DELIVERY_METHOD,
|
|
30
|
+
TABLE_KEYS.MIN_PRICE,
|
|
31
|
+
TABLE_KEYS.MAX_PRICE,
|
|
32
|
+
];
|
|
33
|
+
export function DigitalCodesIndexListing({ initialData }) {
|
|
34
|
+
const table = useUrlTable({ defaults: { pageSize: "24", sort: DEFAULT_SORT } });
|
|
35
|
+
const { showToast } = useToast();
|
|
36
|
+
const { requireAuth, modalOpen, modalMessage, closeModal } = useAuthGate();
|
|
37
|
+
const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
|
|
38
|
+
const [filterOpen, setFilterOpen] = useState(false);
|
|
39
|
+
const [view, setView] = useState(table.get(TABLE_KEYS.VIEW) || VIEW_MODE.GRID);
|
|
40
|
+
const localWishlist = useGuestWishlist();
|
|
41
|
+
const { categories } = useCategoryTree();
|
|
42
|
+
const categoryOptions = categoriesToFacetOptions(categories);
|
|
43
|
+
const wishlistedIds = new Set(localWishlist.items.filter((i) => i.type === "digital-code").map((i) => i.itemId));
|
|
44
|
+
const { pendingTable, filterActiveCount, onFilterApply, onFilterClear, onFilterReset } = usePendingTable(table, FILTER_KEYS);
|
|
45
|
+
const openFilters = useCallback(() => {
|
|
46
|
+
onFilterReset();
|
|
47
|
+
setFilterOpen(true);
|
|
48
|
+
}, [onFilterReset]);
|
|
49
|
+
const applyFilters = useCallback(() => {
|
|
50
|
+
onFilterApply();
|
|
51
|
+
setFilterOpen(false);
|
|
52
|
+
}, [onFilterApply]);
|
|
53
|
+
const resetAll = useCallback(() => {
|
|
54
|
+
table.setMany({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "" });
|
|
55
|
+
onFilterClear();
|
|
56
|
+
setSearchInput("");
|
|
57
|
+
}, [table, onFilterClear]);
|
|
58
|
+
const hasActiveState = !!table.get(TABLE_KEYS.QUERY) ||
|
|
59
|
+
table.get(TABLE_KEYS.SORT) !== DEFAULT_SORT ||
|
|
60
|
+
filterActiveCount > 0;
|
|
61
|
+
const params = {
|
|
62
|
+
q: table.get(TABLE_KEYS.QUERY) || undefined,
|
|
63
|
+
category: table.get(TABLE_KEYS.CATEGORY) || undefined,
|
|
64
|
+
minPrice: table.get(TABLE_KEYS.MIN_PRICE) ? Number(table.get(TABLE_KEYS.MIN_PRICE)) : undefined,
|
|
65
|
+
maxPrice: table.get(TABLE_KEYS.MAX_PRICE) ? Number(table.get(TABLE_KEYS.MAX_PRICE)) : undefined,
|
|
66
|
+
sort: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT,
|
|
67
|
+
page: table.getNumber(TABLE_KEYS.PAGE, 1),
|
|
68
|
+
perPage: table.getNumber(TABLE_KEYS.PAGE_SIZE, 24),
|
|
69
|
+
listingType: "digital-code",
|
|
70
|
+
};
|
|
71
|
+
const { products, totalPages, page, isLoading } = useProducts(params, { initialData });
|
|
72
|
+
const commitSearch = useCallback(() => {
|
|
73
|
+
table.set(TABLE_KEYS.QUERY, searchInput.trim());
|
|
74
|
+
}, [searchInput, table]);
|
|
75
|
+
const selection = useBulkSelection({ items: products, keyExtractor: (p) => p.id });
|
|
76
|
+
const gridClass = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4";
|
|
77
|
+
const wishlistActions = {
|
|
78
|
+
addToWishlist: (productId) => {
|
|
79
|
+
requireAuth(ACTION_ID.ADD_TO_WISHLIST, () => {
|
|
80
|
+
localWishlist.add(productId, "digital-code");
|
|
81
|
+
pushWishlistOp({ op: "add", itemId: productId, type: "digital-code" });
|
|
82
|
+
showToast("Added to wishlist", "success");
|
|
83
|
+
});
|
|
84
|
+
return Promise.resolve();
|
|
85
|
+
},
|
|
86
|
+
removeFromWishlist: (productId) => {
|
|
87
|
+
requireAuth(ACTION_ID.REMOVE_FROM_WISHLIST, () => {
|
|
88
|
+
localWishlist.remove(productId, "digital-code");
|
|
89
|
+
pushWishlistOp({ op: "remove", itemId: productId, type: "digital-code" });
|
|
90
|
+
showToast("Removed from wishlist", "info");
|
|
91
|
+
});
|
|
92
|
+
return Promise.resolve();
|
|
93
|
+
},
|
|
94
|
+
isWishlisted: (productId) => wishlistedIds.has(productId),
|
|
95
|
+
};
|
|
96
|
+
function handleToggleWishlist(id) {
|
|
97
|
+
if (wishlistActions.isWishlisted(id)) {
|
|
98
|
+
wishlistActions.removeFromWishlist(id);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
wishlistActions.addToWishlist(id);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search digital codes\u2026", onSearchChange: setSearchInput, onSearchCommit: commitSearch, onSearchKeyDown: (e) => { if (e.key === "Enter")
|
|
105
|
+
commitSearch(); }, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: (v) => { if (v !== "table")
|
|
106
|
+
setView(v); }, onResetAll: resetAll, hasActiveState: hasActiveState, bulkMode: selection.isSelecting, bulkSelectedCount: selection.selectedCount, bulkTotalCount: products.length, onBulkSelectAll: selection.toggleAll, onBulkClear: selection.clearSelection }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [] }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6", children: isLoading ? (_jsx("div", { className: gridClass, children: Array.from({ length: 10 }).map((_, i) => (_jsxs("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: [_jsx("div", { className: "aspect-square bg-zinc-200 dark:bg-slate-700" }), _jsxs("div", { className: "p-3 space-y-2", children: [_jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-1/3" })] })] }, i))) })) : products.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No digital code listings found." })) : (_jsx("div", { className: view === "list" ? "flex flex-col divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800" : gridClass, children: products.map((product) => (_jsx(InteractiveProductCard, { product: product, href: String(ROUTES.PUBLIC.DIGITAL_CODE_DETAIL(product.id)), variant: view === "list" ? "list" : "grid", isWishlisted: wishlistActions.isWishlisted(product.id), onToggleWishlist: handleToggleWishlist, selectable: selection.isSelecting, isSelected: selection.isSelected(product.id), onSelect: (id) => selection.toggle(id) }, product.id))) })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: onFilterClear, activeCount: filterActiveCount, hideTrigger: true, children: _jsx(DigitalCodeFilters, { table: pendingTable, categoryOptions: categoryOptions }) }), _jsx(LoginRequiredModal, { isOpen: modalOpen, onClose: closeModal, message: modalMessage })] }));
|
|
107
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
type SearchParams = Record<string, string | string[]>;
|
|
2
|
+
export interface DigitalCodesListViewProps {
|
|
3
|
+
searchParams?: SearchParams;
|
|
4
|
+
}
|
|
5
|
+
export declare function DigitalCodesListView({ searchParams }: DigitalCodesListViewProps): Promise<import("react/jsx-runtime").JSX.Element>;
|
|
6
|
+
export {};
|