@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
|
@@ -24,14 +24,14 @@ export declare const preorderItemSchema: z.ZodObject<{
|
|
|
24
24
|
}, "strip", z.ZodTypeAny, {
|
|
25
25
|
type: "video" | "image" | "file";
|
|
26
26
|
url: string;
|
|
27
|
-
source?: "
|
|
27
|
+
source?: "upload" | "youtube" | "external" | undefined;
|
|
28
28
|
alt?: string | undefined;
|
|
29
29
|
thumbnailUrl?: string | undefined;
|
|
30
30
|
youtubeId?: string | undefined;
|
|
31
31
|
}, {
|
|
32
32
|
type: "video" | "image" | "file";
|
|
33
33
|
url: string;
|
|
34
|
-
source?: "
|
|
34
|
+
source?: "upload" | "youtube" | "external" | undefined;
|
|
35
35
|
alt?: string | undefined;
|
|
36
36
|
thumbnailUrl?: string | undefined;
|
|
37
37
|
youtubeId?: string | undefined;
|
|
@@ -46,44 +46,44 @@ export declare const preorderItemSchema: z.ZodObject<{
|
|
|
46
46
|
createdAt: z.ZodOptional<z.ZodString>;
|
|
47
47
|
}, "strip", z.ZodTypeAny, {
|
|
48
48
|
id: string;
|
|
49
|
+
slug: string;
|
|
49
50
|
name: string;
|
|
50
51
|
active: boolean;
|
|
51
52
|
isFeatured: boolean;
|
|
52
|
-
slug: string;
|
|
53
53
|
salePrice: number;
|
|
54
54
|
regularPrice: number;
|
|
55
55
|
createdAt?: string | undefined;
|
|
56
|
+
brand?: string | undefined;
|
|
57
|
+
images?: string[] | undefined;
|
|
56
58
|
media?: {
|
|
57
59
|
type: "video" | "image" | "file";
|
|
58
60
|
url: string;
|
|
59
|
-
source?: "
|
|
61
|
+
source?: "upload" | "youtube" | "external" | undefined;
|
|
60
62
|
alt?: string | undefined;
|
|
61
63
|
thumbnailUrl?: string | undefined;
|
|
62
64
|
youtubeId?: string | undefined;
|
|
63
65
|
}[] | undefined;
|
|
64
|
-
brand?: string | undefined;
|
|
65
|
-
images?: string[] | undefined;
|
|
66
66
|
franchise?: string | undefined;
|
|
67
67
|
preorderShipDate?: string | undefined;
|
|
68
68
|
}, {
|
|
69
69
|
id: string;
|
|
70
|
-
name: string;
|
|
71
70
|
slug: string;
|
|
71
|
+
name: string;
|
|
72
72
|
salePrice: number;
|
|
73
73
|
regularPrice: number;
|
|
74
74
|
createdAt?: string | undefined;
|
|
75
|
+
brand?: string | undefined;
|
|
76
|
+
images?: string[] | undefined;
|
|
75
77
|
media?: {
|
|
76
78
|
type: "video" | "image" | "file";
|
|
77
79
|
url: string;
|
|
78
|
-
source?: "
|
|
80
|
+
source?: "upload" | "youtube" | "external" | undefined;
|
|
79
81
|
alt?: string | undefined;
|
|
80
82
|
thumbnailUrl?: string | undefined;
|
|
81
83
|
youtubeId?: string | undefined;
|
|
82
84
|
}[] | undefined;
|
|
83
85
|
active?: boolean | undefined;
|
|
84
|
-
brand?: string | undefined;
|
|
85
86
|
isFeatured?: boolean | undefined;
|
|
86
|
-
images?: string[] | undefined;
|
|
87
87
|
franchise?: string | undefined;
|
|
88
88
|
preorderShipDate?: string | undefined;
|
|
89
89
|
}>;
|
|
@@ -18,6 +18,8 @@ import { storeRepository } from "../../../stores/repository/store.repository";
|
|
|
18
18
|
// SB-UNI-V — bundlesRepository deleted; bundle stock-sync moves to the
|
|
19
19
|
// `onProductStockChange` Firebase Function (see functions/src/bundle-stock-sync.ts).
|
|
20
20
|
import { sanitizeProductForPublic } from "../../utils/sanitize";
|
|
21
|
+
const ERR_DB_NOT_REGISTERED = "Database provider not registered";
|
|
22
|
+
const ERR_PRODUCT_NOT_FOUND = "Product not found";
|
|
21
23
|
const UNAVAILABLE_PRODUCT_STATUSES = new Set([
|
|
22
24
|
"sold",
|
|
23
25
|
"out_of_stock",
|
|
@@ -53,7 +55,7 @@ const productUpdateSchema = z
|
|
|
53
55
|
featured: z.boolean().optional(),
|
|
54
56
|
isPromoted: z.boolean().optional(),
|
|
55
57
|
listingType: z
|
|
56
|
-
.enum(["standard", "auction", "pre-order", "prize-draw", "bundle"])
|
|
58
|
+
.enum(["standard", "auction", "pre-order", "prize-draw", "bundle", "classified", "digital-code", "live"])
|
|
57
59
|
.optional(),
|
|
58
60
|
media: z.array(mediaFieldSchema).optional(),
|
|
59
61
|
})
|
|
@@ -64,7 +66,7 @@ export async function GET(_request, context) {
|
|
|
64
66
|
const { id } = await context.params;
|
|
65
67
|
const repo = getRepo();
|
|
66
68
|
if (!repo) {
|
|
67
|
-
return NextResponse.json({ success: false, error:
|
|
69
|
+
return NextResponse.json({ success: false, error: ERR_DB_NOT_REGISTERED }, { status: 503 });
|
|
68
70
|
}
|
|
69
71
|
// Support both Firestore document ID and URL slug
|
|
70
72
|
let item = await repo.findById(id);
|
|
@@ -77,7 +79,7 @@ export async function GET(_request, context) {
|
|
|
77
79
|
item = slugResult.data[0] ?? null;
|
|
78
80
|
}
|
|
79
81
|
if (!item) {
|
|
80
|
-
return NextResponse.json({ success: false, error:
|
|
82
|
+
return NextResponse.json({ success: false, error: ERR_PRODUCT_NOT_FOUND }, { status: 404 });
|
|
81
83
|
}
|
|
82
84
|
const sanitized = sanitizeProductForPublic(item);
|
|
83
85
|
return NextResponse.json({ success: true, data: sanitized });
|
|
@@ -96,11 +98,11 @@ export const PATCH = createRouteHandler({
|
|
|
96
98
|
const { id } = params;
|
|
97
99
|
const repo = getRepo();
|
|
98
100
|
if (!repo) {
|
|
99
|
-
return NextResponse.json({ success: false, error:
|
|
101
|
+
return NextResponse.json({ success: false, error: ERR_DB_NOT_REGISTERED }, { status: 503 });
|
|
100
102
|
}
|
|
101
103
|
const product = await repo.findById(id);
|
|
102
104
|
if (!product) {
|
|
103
|
-
return NextResponse.json({ success: false, error:
|
|
105
|
+
return NextResponse.json({ success: false, error: ERR_PRODUCT_NOT_FOUND }, { status: 404 });
|
|
104
106
|
}
|
|
105
107
|
const ownerStore = product.storeId ? await storeRepository.findByOwnerId(user?.uid ?? "") : null;
|
|
106
108
|
const isOwner = !!ownerStore && ownerStore.id === product.storeId;
|
|
@@ -150,11 +152,11 @@ export const DELETE = createRouteHandler({
|
|
|
150
152
|
const { id } = params;
|
|
151
153
|
const repo = getRepo();
|
|
152
154
|
if (!repo) {
|
|
153
|
-
return NextResponse.json({ success: false, error:
|
|
155
|
+
return NextResponse.json({ success: false, error: ERR_DB_NOT_REGISTERED }, { status: 503 });
|
|
154
156
|
}
|
|
155
157
|
const product = await repo.findById(id);
|
|
156
158
|
if (!product) {
|
|
157
|
-
return NextResponse.json({ success: false, error:
|
|
159
|
+
return NextResponse.json({ success: false, error: ERR_PRODUCT_NOT_FOUND }, { status: 404 });
|
|
158
160
|
}
|
|
159
161
|
const ownerStore = product.storeId ? await storeRepository.findByOwnerId(user?.uid ?? "") : null;
|
|
160
162
|
const isOwner = !!ownerStore && ownerStore.id === product.storeId;
|
|
@@ -48,7 +48,7 @@ const productMutateSchema = z
|
|
|
48
48
|
sellerEmail: z.string().email().optional(),
|
|
49
49
|
slug: z.string().optional(),
|
|
50
50
|
listingType: z
|
|
51
|
-
.enum(["standard", "auction", "pre-order", "prize-draw", "bundle"])
|
|
51
|
+
.enum(["standard", "auction", "pre-order", "prize-draw", "bundle", "classified", "digital-code", "live"])
|
|
52
52
|
.optional(),
|
|
53
53
|
media: z.array(mediaFieldSchema).optional(),
|
|
54
54
|
})
|
|
@@ -23,7 +23,7 @@ export function getProductTableColumns({ labels, onEdit, onDelete, currencyCode,
|
|
|
23
23
|
header: labels.category,
|
|
24
24
|
sortable: true,
|
|
25
25
|
width: "12%",
|
|
26
|
-
render: (product) => _jsx(Span, { children: product.category ?? "-" }),
|
|
26
|
+
render: (product) => _jsx(Span, { children: (Array.isArray(product.categorySlugs) ? product.categorySlugs[0] : product.category) ?? "-" }),
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
key: "price",
|
|
@@ -76,10 +76,10 @@ export function getProductTableColumns({ labels, onEdit, onDelete, currencyCode,
|
|
|
76
76
|
},
|
|
77
77
|
},
|
|
78
78
|
];
|
|
79
|
-
const actions = (product) => (_jsxs(Div, { className: "flex gap-2", children: [_jsx(Button, { type: "button", onClick: (e) => {
|
|
79
|
+
const actions = (product) => (_jsxs(Div, { className: "flex gap-2", children: [_jsx(Button, { variant: "ghost", type: "button", onClick: (e) => {
|
|
80
80
|
e.stopPropagation();
|
|
81
81
|
onEdit(product);
|
|
82
|
-
}, className: "text-primary hover:text-primary/80", children: labels.edit }), _jsx(Button, { type: "button", onClick: (e) => {
|
|
82
|
+
}, className: "text-primary hover:text-primary/80", children: labels.edit }), _jsx(Button, { variant: "ghost", type: "button", onClick: (e) => {
|
|
83
83
|
e.stopPropagation();
|
|
84
84
|
onDelete(product);
|
|
85
85
|
}, className: "text-red-600 hover:text-red-800 dark:text-red-400", children: labels.delete })] }));
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
3
|
-
import { useState, useCallback
|
|
4
|
-
import { SlidersHorizontal, X } from "lucide-react";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useCallback } from "react";
|
|
5
4
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
5
|
import { useProducts } from "../hooks/useProducts";
|
|
7
|
-
import { Pagination, useToast, ListingToolbar, BulkActionBar, LoginRequiredModal } from "../../../ui";
|
|
6
|
+
import { Pagination, useToast, ListingToolbar, BulkActionBar, LoginRequiredModal, FilterDrawer } from "../../../ui";
|
|
7
|
+
import { usePendingTable } from "../../../react/hooks/usePendingTable";
|
|
8
8
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
9
9
|
import { MarketplaceAuctionGrid } from "../../auctions/components/MarketplaceAuctionGrid";
|
|
10
10
|
import { AuctionFilters } from "../../auctions/components/AuctionFilters";
|
|
@@ -40,60 +40,24 @@ export function AuctionsIndexListing({ initialData, categorySlug, brandName }) {
|
|
|
40
40
|
const { categories } = useCategoryTree();
|
|
41
41
|
const categoryOptions = categoriesToFacetOptions(categories);
|
|
42
42
|
const { brandOptions } = useBrands();
|
|
43
|
-
|
|
44
|
-
const [pendingFilters, setPendingFilters] = useState(() => Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
|
|
45
|
-
const pendingTable = useMemo(() => ({
|
|
46
|
-
get: (key) => pendingFilters[key] ?? "",
|
|
47
|
-
getNumber: (key, fallback = 0) => {
|
|
48
|
-
const v = pendingFilters[key];
|
|
49
|
-
if (!v)
|
|
50
|
-
return fallback;
|
|
51
|
-
const n = Number(v);
|
|
52
|
-
return isNaN(n) ? fallback : n;
|
|
53
|
-
},
|
|
54
|
-
set: (key, value) => setPendingFilters((p) => ({ ...p, [key]: value })),
|
|
55
|
-
setMany: (updates) => setPendingFilters((p) => ({ ...p, ...updates })),
|
|
56
|
-
clear: (keys) => {
|
|
57
|
-
const ks = keys ?? FILTER_KEYS;
|
|
58
|
-
setPendingFilters((p) => ({
|
|
59
|
-
...p,
|
|
60
|
-
...Object.fromEntries(ks.map((k) => [k, ""])),
|
|
61
|
-
}));
|
|
62
|
-
},
|
|
63
|
-
setPage: (_) => { },
|
|
64
|
-
setPageSize: (_) => { },
|
|
65
|
-
setSort: (_) => { },
|
|
66
|
-
buildSieveParams: () => "",
|
|
67
|
-
buildSearchParams: () => "",
|
|
68
|
-
params: new URLSearchParams(),
|
|
69
|
-
}), [pendingFilters]);
|
|
43
|
+
const { pendingTable, filterActiveCount, onFilterApply, onFilterClear, onFilterReset } = usePendingTable(table, FILTER_KEYS);
|
|
70
44
|
const openFilters = useCallback(() => {
|
|
71
|
-
|
|
45
|
+
onFilterReset();
|
|
72
46
|
setFilterOpen(true);
|
|
73
|
-
}, [
|
|
47
|
+
}, [onFilterReset]);
|
|
74
48
|
const applyFilters = useCallback(() => {
|
|
75
|
-
|
|
76
|
-
for (const k of FILTER_KEYS)
|
|
77
|
-
updates[k] = pendingFilters[k] ?? "";
|
|
78
|
-
table.setMany(updates);
|
|
49
|
+
onFilterApply();
|
|
79
50
|
setFilterOpen(false);
|
|
80
|
-
}, [
|
|
81
|
-
const clearFilters = useCallback(() => {
|
|
82
|
-
setPendingFilters(Object.fromEntries(FILTER_KEYS.map((k) => [k, ""])));
|
|
83
|
-
}, []);
|
|
51
|
+
}, [onFilterApply]);
|
|
84
52
|
const resetAll = useCallback(() => {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
updates[k] = "";
|
|
88
|
-
table.setMany(updates);
|
|
53
|
+
table.setMany({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "", [TABLE_KEYS.SHOW_ENDED]: "" });
|
|
54
|
+
onFilterClear();
|
|
89
55
|
setSearchInput("");
|
|
90
|
-
}, [table]);
|
|
91
|
-
const activeFilterCount = FILTER_KEYS.filter((k) => !!table.get(k)).length;
|
|
92
|
-
const pendingFilterCount = FILTER_KEYS.filter((k) => !!pendingFilters[k]).length;
|
|
56
|
+
}, [table, onFilterClear]);
|
|
93
57
|
const hasActiveState = !!table.get(TABLE_KEYS.QUERY) ||
|
|
94
58
|
table.get(TABLE_KEYS.SHOW_ENDED) === "true" ||
|
|
95
59
|
table.get(TABLE_KEYS.SORT) !== DEFAULT_SORT ||
|
|
96
|
-
|
|
60
|
+
filterActiveCount > 0;
|
|
97
61
|
const params = {
|
|
98
62
|
q: table.get(TABLE_KEYS.QUERY) || undefined,
|
|
99
63
|
category: table.get(TABLE_KEYS.CATEGORY) || undefined,
|
|
@@ -148,7 +112,7 @@ export function AuctionsIndexListing({ initialData, categorySlug, brandName }) {
|
|
|
148
112
|
isWishlisted: (productId) => wishlistedIds.has(productId),
|
|
149
113
|
};
|
|
150
114
|
const gridClass = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-3 gap-4";
|
|
151
|
-
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount:
|
|
115
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search auctions...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, onSearchKeyDown: handleSearchKeyDown, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: AUCTION_SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState, bulkMode: selection.isSelecting, bulkSelectedCount: selection.selectedCount, bulkTotalCount: auctions.length, onBulkSelectAll: selection.toggleAll, onBulkClear: selection.clearSelection, extra: _jsxs("label", { className: "flex items-center gap-1.5 cursor-pointer select-none shrink-0", children: [_jsx("span", { className: "hidden sm:inline text-xs text-zinc-600 dark:text-zinc-300 whitespace-nowrap", children: "Show ended" }), _jsx("button", { type: "button", role: "switch", "aria-checked": showEnded, onClick: () => table.set(TABLE_KEYS.SHOW_ENDED, showEnded ? "" : "true"), className: `relative inline-flex h-5 w-9 flex-shrink-0 items-center rounded-full transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1 ${showEnded ? "bg-primary" : "bg-zinc-300 dark:bg-slate-600"}`, children: _jsx("span", { className: `inline-block h-3.5 w-3.5 transform rounded-full bg-white shadow-sm transition-transform duration-200 ${showEnded ? "translate-x-[19px]" : "translate-x-[3px]"}` }) })] }) }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
|
|
152
116
|
{
|
|
153
117
|
id: ACTION_ID.WATCH_AUCTION,
|
|
154
118
|
label: "Add to Watchlist",
|
|
@@ -169,5 +133,5 @@ export function AuctionsIndexListing({ initialData, categorySlug, brandName }) {
|
|
|
169
133
|
selection.clearSelection();
|
|
170
134
|
},
|
|
171
135
|
},
|
|
172
|
-
] }), 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: 8 }).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/2" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx("div", { className: "h-8 bg-zinc-200 dark:bg-slate-700 rounded" })] })] }, i))) })) : (_jsx(MarketplaceAuctionGrid, { auctions: auctions, variant: view === "list" ? "list" : "grid", gridClassName: view === "list" ? "flex flex-col gap-4" : gridClass, wishlistActions: wishlistActions })) }),
|
|
136
|
+
] }), 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: 8 }).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/2" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx("div", { className: "h-8 bg-zinc-200 dark:bg-slate-700 rounded" })] })] }, i))) })) : (_jsx(MarketplaceAuctionGrid, { auctions: auctions, variant: view === "list" ? "list" : "grid", gridClassName: view === "list" ? "flex flex-col gap-4" : gridClass, wishlistActions: wishlistActions })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: onFilterClear, activeCount: filterActiveCount, hideTrigger: true, children: _jsx(AuctionFilters, { table: pendingTable, currencyPrefix: "\u20B9", categoryOptions: categoryOptions, brandOptions: brandOptions }) }), _jsx(LoginRequiredModal, { isOpen: modalOpen, onClose: closeModal, message: modalMessage })] }));
|
|
173
137
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import { Span, Text } from "../../../ui";
|
|
3
|
+
import { Heading, Span, Text } from "../../../ui";
|
|
4
4
|
import { formatCurrency } from "../../../utils/number.formatter";
|
|
5
5
|
function formatBidDate(raw) {
|
|
6
6
|
if (!raw)
|
|
@@ -30,5 +30,5 @@ export function BidHistory({ isLoading = false, isEmpty = false, renderList, ren
|
|
|
30
30
|
}
|
|
31
31
|
if (renderList)
|
|
32
32
|
return _jsx("div", { className: className, "data-section": "bidhistory-div-420", children: renderList() });
|
|
33
|
-
return (_jsxs("div", { className: className, "data-section": "bidhistory-div-421", children: [labels.title && (_jsx(
|
|
33
|
+
return (_jsxs("div", { className: className, "data-section": "bidhistory-div-421", children: [labels.title && (_jsx(Heading, { level: 3, className: "mb-3 text-sm font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: labels.title })), _jsx("div", { className: "space-y-2", children: bids.map((bid, i) => renderBid ? (_jsx(React.Fragment, { children: renderBid(bid, i) }, bid.id)) : (_jsxs("div", { className: "flex items-center justify-between rounded-lg border border-zinc-100 dark:border-zinc-800 bg-white dark:bg-zinc-900 p-3 text-sm", "data-section": "bidhistory-div-422", children: [_jsx(Span, { className: "font-bold text-primary-600 dark:text-primary-400", children: currency ? formatCurrency(bid.amount, currency) : bid.amount.toLocaleString() }), _jsx(Span, { className: "text-xs text-zinc-400 dark:text-zinc-500", children: formatBidDate(bid.placedAt) })] }, bid.id))) })] }));
|
|
34
34
|
}
|
|
@@ -17,6 +17,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
17
17
|
* `GET /api/products?ids=<csv>` (BK3 listByIds endpoint).
|
|
18
18
|
*/
|
|
19
19
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
20
|
+
const REL_NOOPENER = "noopener noreferrer";
|
|
20
21
|
import Link from "next/link";
|
|
21
22
|
import { X } from "lucide-react";
|
|
22
23
|
import { Button, Div, Heading, Row, Stack, Text } from "../../../ui";
|
|
@@ -67,9 +68,9 @@ function FieldRow({ label, children }) {
|
|
|
67
68
|
function CompareColumn({ item, productType, labels, onRemove, onClose }) {
|
|
68
69
|
const href = detailHref(item, productType);
|
|
69
70
|
const img = item.mainImage ?? item.images?.[0];
|
|
70
|
-
return (_jsxs(Stack, { gap: "md", className: COLUMN_CARD_CLASS, children: [_jsxs(Row, { justify: "between", align: "start", gap: "sm", children: [_jsx(Link, { href: href, target: "_blank", rel:
|
|
71
|
+
return (_jsxs(Stack, { gap: "md", className: COLUMN_CARD_CLASS, children: [_jsxs(Row, { justify: "between", align: "start", gap: "sm", children: [_jsx(Link, { href: href, target: "_blank", rel: REL_NOOPENER, className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100 hover:underline line-clamp-2", children: item.title ?? item.id }), onRemove && (_jsx("button", { type: "button", onClick: () => onRemove(item.id), "aria-label": `${labels.remove} ${item.title ?? item.id}`, className: "shrink-0 rounded-full p-1 text-zinc-400 hover:bg-zinc-100 hover:text-rose-500 dark:hover:bg-zinc-800", children: _jsx(X, { className: "h-4 w-4" }) }))] }), _jsx(FieldRow, { label: labels.field.image, children: _jsx(Link, { href: href, target: "_blank", rel: REL_NOOPENER, children: _jsx(Div, { className: "relative aspect-square overflow-hidden rounded-lg bg-zinc-100 dark:bg-zinc-800", children: img ? (
|
|
71
72
|
// eslint-disable-next-line @next/next/no-img-element
|
|
72
|
-
_jsx("img", { src: img, alt: item.title ?? item.id, className: "h-full w-full object-cover" })) : null }) }) }), _jsx(FieldRow, { label: labels.field.price, children: _jsx(Text, { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: priceLabel(item) }) }), _jsx(FieldRow, { label: labels.field.condition, children: _jsx(Text, { children: item.condition ? _jsx("span", { className: CHIP_CLASS, children: item.condition }) : "—" }) }), _jsx(FieldRow, { label: labels.field.brand, children: _jsx(Text, { children: item.brand ? _jsx("span", { className: CHIP_CLASS, children: item.brand }) : "—" }) }), _jsx(FieldRow, { label: labels.field.category, children: _jsx(Text, { children: item.categoryName || item.category ? (_jsx("span", { className: CHIP_CLASS, children: item.categoryName ?? item.category })) : ("—") }) }), _jsx(FieldRow, { label: labels.field.store, children: _jsx(Text, { className: "text-sm text-zinc-700 dark:text-zinc-300", children: item.storeName ?? "—" }) }), _jsx(Button, { asChild: true, variant: "primary", size: "sm", className: "mt-auto", children: _jsx(Link, { href: href, target: "_blank", rel:
|
|
73
|
+
_jsx("img", { src: img, alt: item.title ?? item.id, className: "h-full w-full object-cover" })) : null }) }) }), _jsx(FieldRow, { label: labels.field.price, children: _jsx(Text, { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: priceLabel(item) }) }), _jsx(FieldRow, { label: labels.field.condition, children: _jsx(Text, { children: item.condition ? _jsx("span", { className: CHIP_CLASS, children: item.condition }) : "—" }) }), _jsx(FieldRow, { label: labels.field.brand, children: _jsx(Text, { children: item.brand ? _jsx("span", { className: CHIP_CLASS, children: item.brand }) : "—" }) }), _jsx(FieldRow, { label: labels.field.category, children: _jsx(Text, { children: (Array.isArray(item.categoryNames) ? item.categoryNames[0] : item.categoryName) || (Array.isArray(item.categorySlugs) ? item.categorySlugs[0] : item.category) ? (_jsx("span", { className: CHIP_CLASS, children: (Array.isArray(item.categoryNames) ? item.categoryNames[0] : item.categoryName) ?? (Array.isArray(item.categorySlugs) ? item.categorySlugs[0] : item.category) })) : ("—") }) }), _jsx(FieldRow, { label: labels.field.store, children: _jsx(Text, { className: "text-sm text-zinc-700 dark:text-zinc-300", children: item.storeName ?? "—" }) }), _jsx(Button, { asChild: true, variant: "primary", size: "sm", className: "mt-auto", children: _jsx(Link, { href: href, target: "_blank", rel: REL_NOOPENER, onClick: onClose, children: labels.view }) })] }));
|
|
73
74
|
}
|
|
74
75
|
function useFetchedProducts(productIds, passedItems, isOpen) {
|
|
75
76
|
const [fetched, setFetched] = useState([]);
|
|
@@ -4,6 +4,9 @@ import { useState, useTransition } from "react";
|
|
|
4
4
|
import { Button, Div, Input, LoginRequiredModal, Span, Text } from "../../../ui";
|
|
5
5
|
import { isAuthError } from "../../../utils/auth-error";
|
|
6
6
|
import { formatCurrency } from "../../../utils/number.formatter";
|
|
7
|
+
function isActiveOfferError(msg) {
|
|
8
|
+
return msg.includes("active offer") || msg.includes("ACTIVE_OFFER");
|
|
9
|
+
}
|
|
7
10
|
export function MakeOfferButton({ productId, listedPrice, currency, minOfferPercent = 70, onMakeOffer, className = "", }) {
|
|
8
11
|
const [state, setState] = useState("idle");
|
|
9
12
|
const [errorMsg, setErrorMsg] = useState("");
|
|
@@ -25,6 +28,22 @@ export function MakeOfferButton({ productId, listedPrice, currency, minOfferPerc
|
|
|
25
28
|
if (!isNaN(parsed))
|
|
26
29
|
setOfferAmount(parsed);
|
|
27
30
|
}
|
|
31
|
+
function handleOfferError(err) {
|
|
32
|
+
if (isAuthError(err)) {
|
|
33
|
+
setState("idle");
|
|
34
|
+
setShowLoginModal(true);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
38
|
+
if (isActiveOfferError(msg)) {
|
|
39
|
+
setState("pending");
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
setErrorMsg(msg || "Could not send offer. Please try again.");
|
|
43
|
+
setState("error");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
28
47
|
function handleSubmit() {
|
|
29
48
|
if (offerAmount < minOffer) {
|
|
30
49
|
setErrorMsg(`Minimum offer is ${fmt(minOffer)}`);
|
|
@@ -43,20 +62,7 @@ export function MakeOfferButton({ productId, listedPrice, currency, minOfferPerc
|
|
|
43
62
|
setState("success");
|
|
44
63
|
}
|
|
45
64
|
catch (err) {
|
|
46
|
-
|
|
47
|
-
setState("idle");
|
|
48
|
-
setShowLoginModal(true);
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
52
|
-
if (msg.includes("active offer") || msg.includes("ACTIVE_OFFER")) {
|
|
53
|
-
setState("pending");
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
setErrorMsg(msg || "Could not send offer. Please try again.");
|
|
57
|
-
setState("error");
|
|
58
|
-
}
|
|
59
|
-
}
|
|
65
|
+
handleOfferError(err);
|
|
60
66
|
}
|
|
61
67
|
});
|
|
62
68
|
}
|
|
@@ -4,6 +4,7 @@ import { useCallback } from "react";
|
|
|
4
4
|
import { useRouter } from "next/navigation";
|
|
5
5
|
import { useLongPress } from "../../../react/hooks/useLongPress";
|
|
6
6
|
import { ROUTES } from "../../../next";
|
|
7
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
7
8
|
import { formatCurrency } from "../../../utils";
|
|
8
9
|
import { getDefaultCurrency } from "../../../core/baseline-resolver";
|
|
9
10
|
import { BaseListingCard, Button, Div, Row, Span, Text, TextLink, } from "../../../ui";
|
|
@@ -15,7 +16,7 @@ const DEFAULT_LABELS = {
|
|
|
15
16
|
closedBadge: "Draw closed",
|
|
16
17
|
entriesRemainingLabel: (remaining, max) => `${remaining}/${max} entries left`,
|
|
17
18
|
pricePerEntryLabel: "per entry",
|
|
18
|
-
enterDraw: "
|
|
19
|
+
enterDraw: ACTIONS.PRIZE_DRAW["enter-draw"].label,
|
|
19
20
|
};
|
|
20
21
|
function statusVariant(status) {
|
|
21
22
|
switch (status) {
|
|
@@ -1,19 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PrizeDrawCollage (SB4-B)
|
|
3
|
-
*
|
|
4
|
-
* Read-only display of a prize-draw's full prize pool. Each cell shows the
|
|
5
|
-
* primary image, item-number badge, and title. Items with `isWon === true`
|
|
6
|
-
* are dimmed under a diagonal overlay with a "Won" label so the public
|
|
7
|
-
* collage truthfully reflects what's still up for grabs.
|
|
8
|
-
*
|
|
9
|
-
* Optional `highlightItemNumber` (passed by the reveal modal during animation)
|
|
10
|
-
* adds an emphasis ring to the cell that just won.
|
|
11
|
-
*/
|
|
12
1
|
import type { PrizeDrawItem } from "../schemas/firestore";
|
|
13
2
|
export interface PrizeDrawCollageProps {
|
|
14
3
|
items: PrizeDrawItem[];
|
|
15
4
|
highlightItemNumber?: number;
|
|
16
|
-
/** Custom click handler —
|
|
5
|
+
/** Custom click handler — overrides the built-in lightbox. */
|
|
17
6
|
onItemClick?: (item: PrizeDrawItem) => void;
|
|
18
7
|
/** Defaults to "Won". Use for localisation. */
|
|
19
8
|
wonLabel?: string;
|
|
@@ -22,9 +11,6 @@ export interface PrizeDrawCollageProps {
|
|
|
22
11
|
* renders — otherwise potential buyers would see their favorite prize is
|
|
23
12
|
* already gone and drop out. The seller / admin / winner views leave this
|
|
24
13
|
* `false` (default) to show real pool state.
|
|
25
|
-
*
|
|
26
|
-
* The product adapter for public reads should ALSO strip `isWon` before
|
|
27
|
-
* sending the items array client-side; this prop is the visual fallback.
|
|
28
14
|
*/
|
|
29
15
|
hideWonState?: boolean;
|
|
30
16
|
}
|
|
@@ -1,22 +1,62 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* PrizeDrawCollage (SB4-B)
|
|
5
|
+
*
|
|
6
|
+
* Read-only display of a prize-draw's full prize pool. Each cell shows the
|
|
7
|
+
* primary image, item-number badge, and title. Items with `isWon === true`
|
|
8
|
+
* are dimmed under a diagonal overlay with a "Won" label so the public
|
|
9
|
+
* collage truthfully reflects what's still up for grabs.
|
|
10
|
+
*
|
|
11
|
+
* Clicking any cell opens a full-screen lightbox starting at that item and
|
|
12
|
+
* cycling circularly through all items in itemNumber order.
|
|
13
|
+
*
|
|
14
|
+
* Optional `highlightItemNumber` (passed by the reveal modal during animation)
|
|
15
|
+
* adds an emphasis ring to the cell that just won.
|
|
16
|
+
*/
|
|
17
|
+
import { useState } from "react";
|
|
2
18
|
import { Div, Text } from "../../../ui";
|
|
19
|
+
import { ImageLightbox } from "../../../ui/components/ImageLightbox";
|
|
20
|
+
function makePrizeItemClickHandler(it, idx, onItemClick, setLightboxIndex) {
|
|
21
|
+
return () => {
|
|
22
|
+
if (onItemClick) {
|
|
23
|
+
onItemClick(it);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
setLightboxIndex(idx);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** Build the lightbox images array from sorted prize items. */
|
|
31
|
+
function toGalleryImages(items) {
|
|
32
|
+
return items.map((it) => ({
|
|
33
|
+
src: it.images?.[0] ?? "",
|
|
34
|
+
alt: it.title || `Prize #${it.itemNumber}`,
|
|
35
|
+
badge: `#${it.itemNumber}`,
|
|
36
|
+
caption: it.title || `Prize #${it.itemNumber}`,
|
|
37
|
+
sub: it.estimatedValue != null
|
|
38
|
+
? `est. ₹${(it.estimatedValue / 100).toLocaleString("en-IN")}`
|
|
39
|
+
: undefined,
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
3
42
|
export function PrizeDrawCollage({ items, highlightItemNumber, onItemClick, wonLabel = "Won", hideWonState = false, }) {
|
|
43
|
+
const [lightboxIndex, setLightboxIndex] = useState(null);
|
|
4
44
|
if (!items.length) {
|
|
5
45
|
return (_jsx(Div, { className: "rounded border border-dashed border-[var(--appkit-color-border)] p-6 text-center", children: _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "No prizes configured yet." }) }));
|
|
6
46
|
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
47
|
+
const galleryImages = toGalleryImages(items);
|
|
48
|
+
return (_jsxs(_Fragment, { children: [_jsx(Div, { className: "grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4", children: items.map((it, idx) => {
|
|
49
|
+
const cover = it.images?.[0];
|
|
50
|
+
const isHighlight = highlightItemNumber === it.itemNumber;
|
|
51
|
+
return (_jsxs("button", { type: "button", onClick: makePrizeItemClickHandler(it, idx, onItemClick, setLightboxIndex), className: [
|
|
52
|
+
"group relative overflow-hidden rounded-lg border bg-[var(--appkit-color-surface)] text-left transition-transform",
|
|
53
|
+
"border-[var(--appkit-color-border)]",
|
|
54
|
+
isHighlight
|
|
55
|
+
? "ring-2 ring-offset-2 ring-[var(--appkit-color-primary)] scale-[1.02]"
|
|
56
|
+
: "hover:scale-[1.01]",
|
|
57
|
+
].join(" "), "aria-label": `View ${it.title || `prize #${it.itemNumber}`} in lightbox`, children: [_jsxs(Div, { className: "relative aspect-square w-full", children: [cover ? (
|
|
58
|
+
/* eslint-disable-next-line @next/next/no-img-element */
|
|
59
|
+
_jsx("img", { src: cover, alt: it.title || `Prize #${it.itemNumber}`, className: "absolute inset-0 h-full w-full object-cover", loading: "lazy" })) : (_jsx(Div, { className: "absolute inset-0 flex items-center justify-center bg-[var(--appkit-color-surface-muted)]", children: _jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: "No image" }) })), _jsxs(Div, { className: "absolute left-2 top-2 rounded bg-black/70 px-1.5 py-0.5 text-xs font-semibold text-white", children: ["#", it.itemNumber] }), it.isWon && !hideWonState ? (_jsxs(_Fragment, { children: [_jsx(Div, { "aria-hidden": true, className: "absolute inset-0 bg-gradient-to-br from-black/60 via-black/30 to-black/60 mix-blend-multiply" }), _jsx(Div, { className: "absolute inset-0 flex items-center justify-center", children: _jsx(Text, { className: "rotate-[-12deg] rounded bg-red-600 px-3 py-1 text-xs font-bold uppercase tracking-wider text-white shadow", children: wonLabel }) })] })) : null] }), _jsxs(Div, { className: "p-2", children: [_jsx(Text, { className: "line-clamp-2 text-sm font-medium", children: it.title || `Prize #${it.itemNumber}` }), it.estimatedValue != null ? (_jsxs(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: ["est. \u20B9", (it.estimatedValue / 100).toLocaleString("en-IN")] })) : null] })] }, `collage-${it.itemNumber}`));
|
|
60
|
+
}) }), _jsx(ImageLightbox, { images: galleryImages, activeIndex: lightboxIndex, onClose: () => setLightboxIndex(null), onNavigate: (i) => setLightboxIndex(i), showThumbnails: true })] }));
|
|
21
61
|
}
|
|
22
62
|
export default PrizeDrawCollage;
|
|
@@ -14,6 +14,7 @@ import { PrizeDrawCollage } from "./PrizeDrawCollage";
|
|
|
14
14
|
import { PrizeDrawEntryActions } from "./PrizeDrawEntryActions";
|
|
15
15
|
import { HistoryTracker } from "../../history/components/HistoryTracker";
|
|
16
16
|
import { formatCurrency } from "../../../utils/number.formatter";
|
|
17
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
17
18
|
function toDescriptionHtml(raw) {
|
|
18
19
|
if (!raw)
|
|
19
20
|
return "";
|
|
@@ -114,5 +115,5 @@ export async function PrizeDrawDetailPageView({ id, initialPrizeDraw, currentUse
|
|
|
114
115
|
price: pricePerEntry,
|
|
115
116
|
storeId: typeof p.storeId === "string" ? p.storeId : undefined,
|
|
116
117
|
storeName: storeName ?? undefined,
|
|
117
|
-
} }), _jsxs(Container, { size: "xl", className: "px-4 py-6", children: [_jsxs("div", { className: "mb-4 flex items-center justify-between flex-wrap gap-2", children: [_jsxs("nav", { "aria-label": "Breadcrumb", className: "flex items-center gap-1.5 text-xs text-zinc-500 dark:text-zinc-400 flex-wrap", children: [_jsx(Link, { href: String(ROUTES.HOME), className: "hover:text-primary-600 transition-colors", children: "Home" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.PRIZE_DRAWS), className: "hover:text-primary-600 transition-colors", children: "Prize Draws" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Span, { className: "text-zinc-700 dark:text-zinc-300 truncate max-w-[200px]", children: title })] }), _jsx(ShareButton, { title: title })] }), _jsx(PreOrderDetailView, { renderGallery: () => (_jsx(PrizeDrawCollage, { items: items, hideWonState: true })), renderInfo: () => (_jsxs(Stack, { gap: "md", children: [_jsxs(Div, { children: [_jsxs(Row, { gap: "xs", className: "mb-2 flex-wrap", children: [_jsx(Span, { className: "inline-block rounded-full bg-fuchsia-100 dark:bg-fuchsia-900/30 px-2.5 py-0.5 text-xs font-semibold text-fuchsia-700 dark:text-fuchsia-300", children: "Prize Draw" }), _jsx(Span, { className: `inline-block rounded-full px-2.5 py-0.5 text-xs font-semibold ${statusClass(revealStatus)}`, children: statusLabel(revealStatus) }), maxPerUser !== null && (_jsxs(Span, { className: "inline-block rounded-full bg-zinc-100 dark:bg-zinc-800 px-2.5 py-0.5 text-xs font-medium text-zinc-700 dark:text-zinc-300", children: ["Limit: ", maxPerUser, " entries per customer"] })), maxPerUser !== null && userEntriesUsed !== null && (_jsxs(Span, { className: "inline-block rounded-full bg-fuchsia-100 dark:bg-fuchsia-900/30 px-2.5 py-0.5 text-xs font-semibold text-fuchsia-700 dark:text-fuchsia-300", children: ["You have used ", userEntriesUsed, "/", maxPerUser] }))] }), _jsx(Heading, { level: 1, className: "text-xl font-bold leading-snug text-zinc-900 dark:text-zinc-50 sm:text-2xl", children: title })] }), _jsx(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-4", children: _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Entries" }), _jsxs(Text, { className: "text-sm font-semibold", children: [current, " / ", max, " (", remaining, " left)"] })] }), revealStart && (_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Reveal window opens" }), _jsx(Text, { className: "text-sm font-medium", children: revealStart.toLocaleString() })] })), revealEnd && (_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Reveal window closes" }), _jsx(Text, { className: "text-sm font-medium", children: revealEnd.toLocaleString() })] }))] }) }), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-sm leading-relaxed text-zinc-600 dark:text-zinc-400 line-clamp-4" })), safeSeller && (_jsx(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-3", children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] uppercase tracking-wide text-zinc-400 dark:text-zinc-500 mb-0.5", children: "Sold by" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-800 dark:text-zinc-200", children: safeSeller })] }), storeHref && (_jsx(Link, { href: storeHref, className: "shrink-0 rounded-lg bg-primary/10 dark:bg-primary/20 px-3 py-1.5 text-xs font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] }) }))] })), renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })) : undefined })), renderBuyBar: () => (_jsx(Div, { id: "prize-draw-buy-bar", className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-5", children: _jsx(PrizeDrawEntryActions, { productId: String(product.id), productSlug: slug, title: title, thumb: thumb, pricePerEntry: pricePerEntry, currency: currency, remainingEntries: remaining, revealStatus: revealStatus, prizeGithubFileUrl: githubUrl }) })) }), _jsxs(BuyBar, { children: [_jsx(Span, { className: "mr-auto text-sm font-bold text-zinc-900 dark:text-zinc-50", children: formatCurrency(pricePerEntry, currency) }), _jsx("a", { href: "#prize-draw-buy-bar", className: "appkit-button appkit-button--primary appkit-button--sm flex-1", children: _jsx("span", { className: "appkit-button__content", children: "
|
|
118
|
+
} }), _jsxs(Container, { size: "xl", className: "px-4 py-6", children: [_jsxs("div", { className: "mb-4 flex items-center justify-between flex-wrap gap-2", children: [_jsxs("nav", { "aria-label": "Breadcrumb", className: "flex items-center gap-1.5 text-xs text-zinc-500 dark:text-zinc-400 flex-wrap", children: [_jsx(Link, { href: String(ROUTES.HOME), className: "hover:text-primary-600 transition-colors", children: "Home" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.PRIZE_DRAWS), className: "hover:text-primary-600 transition-colors", children: "Prize Draws" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Span, { className: "text-zinc-700 dark:text-zinc-300 truncate max-w-[200px]", children: title })] }), _jsx(ShareButton, { title: title })] }), _jsx(PreOrderDetailView, { renderGallery: () => (_jsx(PrizeDrawCollage, { items: items, hideWonState: true })), renderInfo: () => (_jsxs(Stack, { gap: "md", children: [_jsxs(Div, { children: [_jsxs(Row, { gap: "xs", className: "mb-2 flex-wrap", children: [_jsx(Span, { className: "inline-block rounded-full bg-fuchsia-100 dark:bg-fuchsia-900/30 px-2.5 py-0.5 text-xs font-semibold text-fuchsia-700 dark:text-fuchsia-300", children: "Prize Draw" }), _jsx(Span, { className: `inline-block rounded-full px-2.5 py-0.5 text-xs font-semibold ${statusClass(revealStatus)}`, children: statusLabel(revealStatus) }), maxPerUser !== null && (_jsxs(Span, { className: "inline-block rounded-full bg-zinc-100 dark:bg-zinc-800 px-2.5 py-0.5 text-xs font-medium text-zinc-700 dark:text-zinc-300", children: ["Limit: ", maxPerUser, " entries per customer"] })), maxPerUser !== null && userEntriesUsed !== null && (_jsxs(Span, { className: "inline-block rounded-full bg-fuchsia-100 dark:bg-fuchsia-900/30 px-2.5 py-0.5 text-xs font-semibold text-fuchsia-700 dark:text-fuchsia-300", children: ["You have used ", userEntriesUsed, "/", maxPerUser] }))] }), _jsx(Heading, { level: 1, className: "text-xl font-bold leading-snug text-zinc-900 dark:text-zinc-50 sm:text-2xl", children: title })] }), _jsx(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-4", children: _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Entries" }), _jsxs(Text, { className: "text-sm font-semibold", children: [current, " / ", max, " (", remaining, " left)"] })] }), revealStart && (_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Reveal window opens" }), _jsx(Text, { className: "text-sm font-medium", children: revealStart.toLocaleString() })] })), revealEnd && (_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Reveal window closes" }), _jsx(Text, { className: "text-sm font-medium", children: revealEnd.toLocaleString() })] }))] }) }), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-sm leading-relaxed text-zinc-600 dark:text-zinc-400 line-clamp-4" })), safeSeller && (_jsx(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-3", children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] uppercase tracking-wide text-zinc-400 dark:text-zinc-500 mb-0.5", children: "Sold by" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-800 dark:text-zinc-200", children: safeSeller })] }), storeHref && (_jsx(Link, { href: storeHref, className: "shrink-0 rounded-lg bg-primary/10 dark:bg-primary/20 px-3 py-1.5 text-xs font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] }) }))] })), renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })) : undefined })), renderBuyBar: () => (_jsx(Div, { id: "prize-draw-buy-bar", className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-5", children: _jsx(PrizeDrawEntryActions, { productId: String(product.id), productSlug: slug, title: title, thumb: thumb, pricePerEntry: pricePerEntry, currency: currency, remainingEntries: remaining, revealStatus: revealStatus, prizeGithubFileUrl: githubUrl }) })) }), _jsxs(BuyBar, { children: [_jsx(Span, { className: "mr-auto text-sm font-bold text-zinc-900 dark:text-zinc-50", children: formatCurrency(pricePerEntry, currency) }), _jsx("a", { href: "#prize-draw-buy-bar", className: "appkit-button appkit-button--primary appkit-button--sm flex-1", children: _jsx("span", { className: "appkit-button__content", children: ACTIONS.PRIZE_DRAW["enter-draw"].label }) })] })] })] }));
|
|
118
119
|
}
|
|
@@ -10,6 +10,7 @@ import { pushCartOp } from "../../cart/utils/pending-ops";
|
|
|
10
10
|
import { NonRefundableConsentModal } from "./NonRefundableConsentModal";
|
|
11
11
|
import { useAuthGate } from "../../../react/hooks/useAuthGate";
|
|
12
12
|
import { ACTION_ID } from "../constants/action-defs";
|
|
13
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
13
14
|
/**
|
|
14
15
|
* Client buy panel for a prize-draw detail page (SB4-G).
|
|
15
16
|
*
|
|
@@ -47,5 +48,5 @@ export function PrizeDrawEntryActions({ productId, productSlug, title, thumb, pr
|
|
|
47
48
|
showToast("Entry added to cart", "success");
|
|
48
49
|
router.push(String(ROUTES.USER.CART));
|
|
49
50
|
}, [cart, productId, title, thumb, pricePerEntry, router, showToast]);
|
|
50
|
-
return (_jsxs(Stack, { gap: "md", children: [_jsxs(Text, { className: "text-2xl font-bold text-zinc-900 dark:text-zinc-50", children: [formatCurrency(pricePerEntry, currency), _jsx(Text, { as: "span", className: "ml-1 text-xs font-normal text-[var(--appkit-color-text-muted)]", children: "per entry" })] }), _jsx(Button, { variant: "primary", size: "md", className: "w-full", disabled: closed, onClick: handleEnter, children: closed ? "Draw closed" :
|
|
51
|
+
return (_jsxs(Stack, { gap: "md", children: [_jsxs(Text, { className: "text-2xl font-bold text-zinc-900 dark:text-zinc-50", children: [formatCurrency(pricePerEntry, currency), _jsx(Text, { as: "span", className: "ml-1 text-xs font-normal text-[var(--appkit-color-text-muted)]", children: "per entry" })] }), _jsx(Button, { action: closed ? undefined : ACTIONS.PRIZE_DRAW["enter-draw"], variant: "primary", size: "md", className: "w-full", disabled: closed, onClick: handleEnter, children: closed ? "Draw closed" : undefined }), prizeGithubFileUrl ? (_jsx("a", { href: prizeGithubFileUrl, target: "_blank", rel: "noopener noreferrer", className: "text-center text-xs font-medium text-primary-600 underline-offset-4 hover:underline dark:text-primary-400", children: "View RNG source code on GitHub \u2192" })) : null, _jsx(Text, { className: "text-center text-xs text-[var(--appkit-color-text-muted)]", children: "Winners chosen by Node.js crypto.randomInt \u2014 fully auditable. Entries are locked once paid; refunds only if the prize pool is exhausted." }), _jsx(NonRefundableConsentModal, { open: consentOpen, listingType: "prize-draw", itemTitle: title, priceLabel: formatCurrency(pricePerEntry, currency), onCancel: () => setConsentOpen(false), onConfirm: handleConfirm }), _jsx(LoginRequiredModal, { isOpen: modalOpen, onClose: closeModal, message: modalMessage })] }));
|
|
51
52
|
}
|