@mohasinac/appkit 4.30.18 β 4.31.0
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/digital-code/CodeRevealPanel.js +5 -2
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +3 -3
- package/dist/_internal/client/features/layout/useSidebarSearch.d.ts +21 -5
- package/dist/_internal/client/features/layout/useSidebarSearch.js +27 -6
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +23 -3
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +106 -86
- package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +16 -5
- package/dist/_internal/client/features/lottery/LotteryPullForm.js +65 -40
- package/dist/_internal/client/features/maintenance/views/AnalysisRunnerView.js +5 -2
- package/dist/_internal/client/features/maintenance/views/CloudLogsListView.js +11 -3
- package/dist/_internal/client/hand-mode/HandModeProvider.js +2 -0
- package/dist/_internal/server/features/auctions/actions.js +14 -3
- package/dist/_internal/server/features/auctions/service.js +1 -1
- package/dist/_internal/server/features/auth/permissions.d.ts +2 -0
- package/dist/_internal/server/features/auth/permissions.js +3 -2
- package/dist/_internal/server/features/blog/data.js +2 -2
- package/dist/_internal/server/features/blog/service.js +3 -3
- package/dist/_internal/server/features/brands/data.js +1 -1
- package/dist/_internal/server/features/brands/service.js +3 -3
- package/dist/_internal/server/features/bundles/actions.js +6 -1
- package/dist/_internal/server/features/bundles/data.js +21 -4
- package/dist/_internal/server/features/cart/data.js +3 -1
- package/dist/_internal/server/features/cart/service.js +13 -2
- package/dist/_internal/server/features/categories/data.js +26 -6
- package/dist/_internal/server/features/classified/index.d.ts +0 -1
- package/dist/_internal/server/features/classified/index.js +0 -1
- package/dist/_internal/server/features/digital-code/index.d.ts +0 -1
- package/dist/_internal/server/features/digital-code/index.js +0 -1
- package/dist/_internal/server/features/events/actions.js +17 -4
- package/dist/_internal/server/features/events/data.js +1 -1
- package/dist/_internal/server/features/events/service.js +1 -1
- package/dist/_internal/server/features/grouped/data.js +7 -2
- package/dist/_internal/server/features/item-requests/data.js +1 -1
- package/dist/_internal/server/features/live/index.d.ts +0 -1
- package/dist/_internal/server/features/live/index.js +0 -1
- package/dist/_internal/server/features/lottery/actions.js +2 -2
- package/dist/_internal/server/features/lottery/data.js +1 -1
- package/dist/_internal/server/features/orders/actions.js +7 -7
- package/dist/_internal/server/features/orders/data.d.ts +1 -1
- package/dist/_internal/server/features/orders/data.js +14 -2
- package/dist/_internal/server/features/orders/service.js +1 -1
- package/dist/_internal/server/features/pre-orders/service.js +1 -1
- package/dist/_internal/server/features/prize-draws/actions.js +1 -1
- package/dist/_internal/server/features/products/data.js +21 -6
- package/dist/_internal/server/features/products/list-public.d.ts +9 -0
- package/dist/_internal/server/features/products/list-public.js +95 -7
- package/dist/_internal/server/features/products/service.js +1 -1
- package/dist/_internal/server/features/promotions/actions.js +1 -1
- package/dist/_internal/server/features/promotions/data.js +1 -1
- package/dist/_internal/server/features/promotions/service.js +1 -1
- package/dist/_internal/server/features/reviews/data.d.ts +1 -1
- package/dist/_internal/server/features/reviews/data.js +6 -1
- package/dist/_internal/server/features/reviews/og-data.js +1 -1
- package/dist/_internal/server/features/shared/listing-data-factory.js +7 -2
- package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
- package/dist/_internal/server/features/site-settings/adapters.js +8 -5
- package/dist/_internal/server/features/stores/data.js +1 -1
- package/dist/_internal/server/features/sublisting-categories/data.js +1 -1
- package/dist/_internal/server/features/tester/visibility.d.ts +2 -1
- package/dist/_internal/server/features/tester/visibility.js +2 -2
- package/dist/_internal/server/functions/scheduled.d.ts +3 -1
- package/dist/_internal/server/functions/scheduled.js +27 -1
- package/dist/_internal/server/jobs/core/auctionSettlement.js +6 -1
- package/dist/_internal/server/jobs/core/hardBanCascade.js +4 -0
- package/dist/_internal/server/jobs/core/index.d.ts +2 -0
- package/dist/_internal/server/jobs/core/index.js +2 -0
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +7 -15
- package/dist/_internal/server/jobs/core/pageViewPrune.d.ts +10 -0
- package/dist/_internal/server/jobs/core/pageViewPrune.js +44 -0
- package/dist/_internal/server/jobs/core/pageViewRollup.d.ts +2 -0
- package/dist/_internal/server/jobs/core/pageViewRollup.js +87 -0
- package/dist/_internal/server/jobs/core/revenueRollup.js +7 -1
- package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/index.js +2 -0
- package/dist/_internal/server/jobs/handlers/pageViewPrune.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/pageViewPrune.js +2 -0
- package/dist/_internal/server/jobs/handlers/pageViewRollup.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/pageViewRollup.js +2 -0
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +69 -22
- package/dist/_internal/shared/checkout/rules/classified.rule.d.ts +9 -4
- package/dist/_internal/shared/checkout/rules/classified.rule.js +7 -2
- package/dist/_internal/shared/features/layout/matchesNavQuery.d.ts +14 -0
- package/dist/_internal/shared/features/layout/matchesNavQuery.js +72 -0
- package/dist/_internal/shared/features/layout/types.d.ts +37 -1
- package/dist/_internal/shared/features/layout/types.js +19 -1
- package/dist/_internal/shared/features/notifications/action-url.d.ts +9 -1
- package/dist/_internal/shared/features/notifications/action-url.js +47 -0
- package/dist/_internal/shared/features/offers/config.d.ts +65 -0
- package/dist/_internal/shared/features/offers/config.js +73 -2
- package/dist/_internal/shared/features/orders/schema.d.ts +19 -1
- package/dist/_internal/shared/features/orders/schema.js +22 -2
- package/dist/_internal/shared/features/site-settings/types.d.ts +12 -3
- package/dist/_internal/shared/listing-types/capabilities.d.ts +8 -2
- package/dist/_internal/shared/listing-types/capabilities.js +6 -1
- package/dist/_internal/shared/listing-types/classified/ctas.js +6 -1
- package/dist/_internal/shared/listing-types/feature-flags.d.ts +10 -5
- package/dist/_internal/shared/listing-types/feature-flags.js +11 -6
- package/dist/client/api/useApiQuery.js +17 -6
- package/dist/client.d.ts +38 -20
- package/dist/client.js +39 -14
- package/dist/configs/next.js +10 -2
- package/dist/constants/api-endpoints.d.ts +18 -54
- package/dist/constants/api-endpoints.js +6 -26
- package/dist/constants/field-names.d.ts +6 -24
- package/dist/constants/field-names.js +10 -27
- package/dist/constants/geo/countries.d.ts +50 -0
- package/dist/constants/geo/countries.js +129 -0
- package/dist/constants/geo/subdivisions.d.ts +13 -0
- package/dist/constants/geo/subdivisions.js +104 -0
- package/dist/constants/index.d.ts +2 -2
- package/dist/constants/index.js +2 -2
- package/dist/constants/table-keys.d.ts +24 -0
- package/dist/constants/table-keys.js +28 -0
- package/dist/contracts/client-realtime.d.ts +6 -0
- package/dist/contracts/extend.d.ts +0 -9
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/realtime-session.d.ts +12 -12
- package/dist/contracts/realtime-session.js +79 -77
- package/dist/core/browser.d.ts +1 -1
- package/dist/core/browser.js +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/site-config.d.ts +0 -3
- package/dist/core/site-config.js +0 -3
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/errors/messages.d.ts +0 -8
- package/dist/errors/messages.js +0 -9
- package/dist/features/about/components/DeveloperView.js +7 -2
- package/dist/features/about/components/PolicyPageView.js +9 -1
- package/dist/features/about/components/PublicProfileView.js +23 -5
- package/dist/features/about/schemas/index.d.ts +8 -8
- package/dist/features/account/components/AddressFilters.js +32 -11
- package/dist/features/account/components/AddressForm.d.ts +26 -25
- package/dist/features/account/components/AddressForm.js +81 -103
- package/dist/features/account/components/AddressesIndexListing.js +8 -4
- package/dist/features/account/components/NotificationBell.js +4 -3
- package/dist/features/account/components/NotificationPreferencesPanel.js +1 -1
- package/dist/features/account/components/UserOffersPanel.js +1 -1
- package/dist/features/account/components/UserSidebar.d.ts +3 -4
- package/dist/features/account/components/UserSupportView.js +89 -58
- package/dist/features/account/components/index.d.ts +1 -7
- package/dist/features/account/components/index.js +0 -3
- package/dist/features/account/hooks/useAddresses.d.ts +4 -3
- package/dist/features/account/hooks/useAddresses.js +4 -6
- package/dist/features/account/hooks/useCollapsedSections.d.ts +51 -10
- package/dist/features/account/hooks/useCollapsedSections.js +211 -38
- package/dist/features/account/hooks/useProfile.d.ts +8 -0
- package/dist/features/account/index.d.ts +0 -3
- package/dist/features/account/index.js +0 -3
- package/dist/features/account/schemas/index.d.ts +0 -92
- package/dist/features/account/schemas/index.js +42 -20
- package/dist/features/addresses/components/AddressLocationFields.d.ts +13 -0
- package/dist/features/addresses/components/AddressLocationFields.js +41 -0
- package/dist/features/addresses/hooks/usePostalLookup.d.ts +17 -0
- package/dist/features/addresses/hooks/usePostalLookup.js +133 -0
- package/dist/features/addresses/schemas/address-form.d.ts +423 -0
- package/dist/features/addresses/schemas/address-form.js +212 -0
- package/dist/features/addresses/schemas/index.d.ts +1 -0
- package/dist/features/addresses/schemas/index.js +8 -0
- package/dist/features/admin/actions/admin-read-actions.d.ts +1 -1
- package/dist/features/admin/actions/index.d.ts +0 -1
- package/dist/features/admin/actions/index.js +0 -1
- package/dist/features/admin/actions/notification-actions.js +1 -41
- package/dist/features/admin/components/AdminActionIndexView.d.ts +32 -0
- package/dist/features/admin/components/AdminActionIndexView.js +128 -0
- package/dist/features/admin/components/AdminAdEditorView.js +159 -163
- package/dist/features/admin/components/AdminAddressEditorView.js +97 -55
- package/dist/features/admin/components/AdminBrandEditorView.d.ts +15 -0
- package/dist/features/admin/components/AdminBrandEditorView.js +113 -77
- package/dist/features/admin/components/AdminBundleEditorView.d.ts +19 -9
- package/dist/features/admin/components/AdminBundleEditorView.js +136 -168
- package/dist/features/admin/components/AdminCategoryEditorView.js +120 -43
- package/dist/features/admin/components/AdminCouponEditorView.js +145 -109
- package/dist/features/admin/components/AdminEmployeeEditorView.js +125 -56
- package/dist/features/admin/components/AdminFaqEditorView.js +112 -58
- package/dist/features/admin/components/AdminFeatureEditorView.js +108 -68
- package/dist/features/admin/components/AdminFulfillmentView.js +5 -2
- package/dist/features/admin/components/AdminMediaView.js +3 -3
- package/dist/features/admin/components/AdminNavEditorView.js +69 -44
- package/dist/features/admin/components/AdminOrderEditorView.js +47 -10
- package/dist/features/admin/components/AdminPrizeDrawsView.js +16 -2
- package/dist/features/admin/components/AdminSidebar.d.ts +11 -7
- package/dist/features/admin/components/AdminSiteSettingsView.js +37 -37
- package/dist/features/admin/components/AdminStoreEditorView.js +75 -52
- package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +71 -30
- package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +95 -65
- package/dist/features/admin/components/BrandQuickCreateForm.d.ts +10 -0
- package/dist/features/admin/components/BrandQuickCreateForm.js +49 -26
- package/dist/features/admin/components/CategoryQuickCreateForm.d.ts +11 -0
- package/dist/features/admin/components/CategoryQuickCreateForm.js +48 -26
- package/dist/features/admin/components/index.d.ts +2 -2
- package/dist/features/admin/components/index.js +1 -1
- package/dist/features/admin/constants/site-settings-tabs.d.ts +120 -0
- package/dist/features/admin/constants/site-settings-tabs.js +152 -0
- package/dist/features/admin/index.d.ts +0 -3
- package/dist/features/admin/index.js +0 -2
- package/dist/features/admin/repository/analytics-rollup.repository.d.ts +35 -0
- package/dist/features/admin/repository/analytics-rollup.repository.js +30 -0
- package/dist/features/admin/schemas/admin-editor-forms.d.ts +56 -57
- package/dist/features/admin/schemas/admin-editor-forms.js +97 -54
- package/dist/features/admin/schemas/admin-ops-forms.d.ts +57 -5
- package/dist/features/admin/schemas/admin-ops-forms.js +104 -20
- package/dist/features/admin/schemas/admin-user-form.js +7 -0
- package/dist/features/admin/schemas/firestore.d.ts +48 -95
- package/dist/features/admin/schemas/firestore.js +15 -151
- package/dist/features/admin/schemas/nav-item-form.js +9 -2
- package/dist/features/admin/server.d.ts +0 -4
- package/dist/features/admin/server.js +0 -2
- package/dist/features/admin/types/index.d.ts +0 -7
- package/dist/features/analytics/repository/page-views.repository.d.ts +14 -0
- package/dist/features/analytics/repository/page-views.repository.js +24 -0
- package/dist/features/analytics/types.d.ts +1 -1
- package/dist/features/analytics/types.js +13 -0
- package/dist/features/auctions/components/AuctionDetailPageView.js +6 -2
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +3 -1
- package/dist/features/auth/actions/index.d.ts +0 -1
- package/dist/features/auth/actions/index.js +0 -1
- package/dist/features/auth/actions/profile-actions.js +4 -3
- package/dist/features/auth/actions/realtime-token-actions.js +1 -12
- package/dist/features/auth/auth-helpers.js +5 -7
- package/dist/features/auth/components/ForgotPasswordView.js +1 -1
- package/dist/features/auth/components/Guards.js +2 -1
- package/dist/features/auth/components/LoginForm.d.ts +0 -2
- package/dist/features/auth/components/LoginForm.js +2 -4
- package/dist/features/auth/components/RegisterForm.js +62 -19
- package/dist/features/auth/components/ResetPasswordView.js +1 -1
- package/dist/features/auth/hooks/useAuth.js +3 -0
- package/dist/features/auth/permissions/constants.d.ts +27 -1
- package/dist/features/auth/role-predicates.d.ts +75 -7
- package/dist/features/auth/role-predicates.js +28 -2
- package/dist/features/auth/schemas/firestore.d.ts +22 -0
- package/dist/features/auth/schemas/index.d.ts +1 -1
- package/dist/features/auth/schemas/index.js +44 -8
- package/dist/features/auth/types/index.d.ts +14 -1
- package/dist/features/blog/api/route.js +10 -2
- package/dist/features/blog/components/BlogIndexListing.js +1 -1
- package/dist/features/blog/hooks/useBlog.js +2 -2
- package/dist/features/blog/repository/blog.repository.js +3 -1
- package/dist/features/blog/schemas/index.d.ts +4 -0
- package/dist/features/blog/schemas/index.js +2 -0
- package/dist/features/blog/types/index.d.ts +1 -1
- package/dist/features/cart/actions/cart-actions.js +13 -4
- package/dist/features/cart/utils/pending-ops.js +1 -1
- package/dist/features/catalogue/components/CatalogueItemEditorView.d.ts +22 -0
- package/dist/features/catalogue/components/CatalogueItemEditorView.js +112 -52
- package/dist/features/catalogue/schemas/validation.d.ts +4 -4
- package/dist/features/catalogue/schemas/validation.js +47 -10
- package/dist/features/categories/components/BrandDetailPageView.js +28 -12
- package/dist/features/categories/components/CategoryDetailPageView.js +37 -20
- package/dist/features/categories/repository/categories.repository.js +3 -1
- package/dist/features/categories/schemas/bundle-form.d.ts +142 -0
- package/dist/features/categories/schemas/bundle-form.js +149 -0
- package/dist/features/checkout/actions/checkout-value-otp-actions.js +10 -1
- package/dist/features/classified/components/ClassifiedContactSellerPanel.js +1 -1
- package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +5 -4
- package/dist/features/classified/components/ClassifiedDetailPageView.js +47 -18
- package/dist/features/consultation/components/ConsultationForm.js +1 -1
- package/dist/features/consultation/schemas/index.js +34 -10
- package/dist/features/corporate/schemas/index.js +36 -15
- package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +4 -1
- package/dist/features/events/components/EventBanner.js +5 -2
- package/dist/features/events/components/EventOfferCard.js +3 -1
- package/dist/features/events/components/EventPollWidget.js +1 -1
- package/dist/features/events/components/SpinWheelView.js +3 -2
- package/dist/features/filters/FilterPanel.js +3 -3
- package/dist/features/filters/RangeFilter.d.ts +10 -0
- package/dist/features/filters/RangeFilter.js +41 -4
- package/dist/features/grouped/components/GroupedListingEditorView.js +2 -1
- package/dist/features/history/hooks/useHistory.js +29 -27
- package/dist/features/homepage/components/AdSlot.js +3 -1
- package/dist/features/homepage/components/GoogleReviewsSection.js +8 -2
- package/dist/features/homepage/components/MarketplaceHomepageView.js +58 -15
- package/dist/features/homepage/components/SocialFeedSection.js +4 -1
- package/dist/features/homepage/hooks/useBlogArticles.js +1 -1
- package/dist/features/homepage/lib/live-stats.js +8 -1
- package/dist/features/homepage/repository/carousel.repository.js +2 -1
- package/dist/features/layout/BottomActions.js +84 -11
- package/dist/features/layout/BottomActionsContext.d.ts +1 -6
- package/dist/features/layout/BottomActionsContext.js +1 -1
- package/dist/features/layout/hooks/useBottomActions.js +2 -2
- package/dist/features/layout/hooks/useFormBottomActions.d.ts +12 -1
- package/dist/features/layout/hooks/useFormBottomActions.js +12 -6
- package/dist/features/live/components/LiveItemDetailPageView.js +4 -1
- package/dist/features/lottery/schemas/config-write.d.ts +9 -5
- package/dist/features/lottery/schemas/config-write.js +69 -9
- package/dist/features/media/finalize.js +3 -1
- package/dist/features/media/modals/ImageEditor.js +1 -1
- package/dist/features/media/modals/VideoThumbnailSelector.js +5 -2
- package/dist/features/media/modals/VideoTrimModal.js +5 -2
- package/dist/features/media/upload/MediaUploadField.js +2 -2
- package/dist/features/messages/hooks/useConversation.js +18 -4
- package/dist/features/messages/hooks/useConversations.js +25 -8
- package/dist/features/orders/components/RefundRequestView.js +5 -2
- package/dist/features/orders/schemas/buyer-forms.d.ts +6 -3
- package/dist/features/orders/schemas/buyer-forms.js +31 -3
- package/dist/features/orders/schemas/index.d.ts +2 -2
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -1
- package/dist/features/pre-orders/components/PreOrderActionsClient.js +1 -1
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +4 -1
- package/dist/features/products/components/GroupSettingsPanel.js +3 -1
- package/dist/features/products/components/MakeOfferButton.d.ts +13 -2
- package/dist/features/products/components/MakeOfferButton.js +33 -11
- package/dist/features/products/components/PrizeDrawDetailPageView.js +4 -1
- package/dist/features/products/components/ProductDetailActions.js +0 -1
- package/dist/features/products/components/ProductDetailPageView.d.ts +7 -3
- package/dist/features/products/components/ProductDetailPageView.js +16 -7
- package/dist/features/products/components/ShareButton.js +3 -1
- package/dist/features/products/constants/action-defs.d.ts +1 -2
- package/dist/features/products/constants/action-defs.js +40 -43
- package/dist/features/products/repository/loadProductFeatures.js +10 -2
- package/dist/features/products/repository/products.repository.d.ts +5 -1
- package/dist/features/products/repository/products.repository.js +25 -2
- package/dist/features/products/schemas/firestore.d.ts +7 -3
- package/dist/features/products/schemas/product-features.validators.js +3 -0
- package/dist/features/promotions/components/CouponCard.js +11 -8
- package/dist/features/reviews/actions/review-actions.js +8 -1
- package/dist/features/reviews/components/ReviewDetailPageView.js +13 -3
- package/dist/features/reviews/components/ReviewDetailShell.js +3 -1
- package/dist/features/scams/actions/scam-actions.d.ts +9 -1
- package/dist/features/scams/actions/scam-actions.js +52 -12
- package/dist/features/scams/components/SellerTrustBadge.d.ts +1 -1
- package/dist/features/scams/components/SellerTrustBadge.js +13 -0
- package/dist/features/scams/repository/scammer.repository.js +2 -1
- package/dist/features/scams/schemas/firestore.d.ts +15 -1
- package/dist/features/scams/schemas/report-form.d.ts +5 -5
- package/dist/features/scams/schemas/report-form.js +18 -3
- package/dist/features/search/action-index/derive.d.ts +49 -0
- package/dist/features/search/action-index/derive.js +121 -0
- package/dist/features/search/action-index/repository.d.ts +42 -0
- package/dist/features/search/action-index/repository.js +100 -0
- package/dist/features/search/action-index/settings-entries.d.ts +41 -0
- package/dist/features/search/action-index/settings-entries.js +268 -0
- package/dist/features/search/action-index/types.d.ts +81 -0
- package/dist/features/search/action-index/types.js +102 -0
- package/dist/features/search/action-index/validate-entry.d.ts +34 -0
- package/dist/features/search/action-index/validate-entry.js +114 -0
- package/dist/features/search/hooks/useNavSuggestions.d.ts +5 -1
- package/dist/features/search/hooks/useNavSuggestions.js +23 -3
- package/dist/features/search/repository/search.repository.js +3 -1
- package/dist/features/seller/actions/offer-actions.js +43 -19
- package/dist/features/seller/actions/seller-actions.js +29 -5
- package/dist/features/seller/components/CategoryChipPicker.d.ts +9 -0
- package/dist/features/seller/components/CategoryChipPicker.js +12 -0
- package/dist/features/seller/components/FulfillmentView.js +5 -2
- package/dist/features/seller/components/PhysicalLocationModal.js +1 -1
- package/dist/features/seller/components/PrintCenterView.js +3 -1
- package/dist/features/seller/components/SellerAddressesView.js +5 -1
- package/dist/features/seller/components/SellerAnalyticsAlertsView.js +83 -43
- package/dist/features/seller/components/SellerArtView.d.ts +14 -7
- package/dist/features/seller/components/SellerArtView.js +4 -119
- package/dist/features/seller/components/SellerBidsView.js +1 -1
- package/dist/features/seller/components/SellerClassifiedView.d.ts +14 -7
- package/dist/features/seller/components/SellerClassifiedView.js +4 -124
- package/dist/features/seller/components/SellerCouponEditorView.d.ts +22 -1
- package/dist/features/seller/components/SellerCouponEditorView.js +91 -45
- package/dist/features/seller/components/SellerCouponsView.js +1 -1
- package/dist/features/seller/components/SellerDigitalCodesView.d.ts +14 -7
- package/dist/features/seller/components/SellerDigitalCodesView.js +4 -126
- package/dist/features/seller/components/SellerGoogleReviewsView.js +2 -2
- package/dist/features/seller/components/SellerListingTypeView.d.ts +66 -0
- package/dist/features/seller/components/SellerListingTypeView.js +277 -0
- package/dist/features/seller/components/SellerLiveView.d.ts +14 -7
- package/dist/features/seller/components/SellerLiveView.js +4 -126
- package/dist/features/seller/components/SellerOrdersView.js +3 -3
- package/dist/features/seller/components/SellerPayoutMethodsView.js +2 -2
- package/dist/features/seller/components/SellerProductShell.d.ts +5 -0
- package/dist/features/seller/components/SellerProductShell.js +15 -5
- package/dist/features/seller/components/SellerProductsView.js +24 -10
- package/dist/features/seller/components/SellerReviewsView.js +47 -16
- package/dist/features/seller/components/SellerShippingConfigsView.js +5 -4
- package/dist/features/seller/components/SellerSidebar.d.ts +3 -6
- package/dist/features/seller/components/SellerStickersView.d.ts +14 -7
- package/dist/features/seller/components/SellerStickersView.js +4 -119
- package/dist/features/seller/components/SellerStoreCategoriesView.js +3 -2
- package/dist/features/seller/components/SellerSupportView.d.ts +31 -0
- package/dist/features/seller/components/SellerSupportView.js +100 -0
- package/dist/features/seller/components/index.d.ts +4 -8
- package/dist/features/seller/components/index.js +2 -4
- package/dist/features/seller/index.d.ts +0 -1
- package/dist/features/seller/index.js +0 -1
- package/dist/features/seller/schemas/coupon-form.d.ts +214 -0
- package/dist/features/seller/schemas/coupon-form.js +155 -23
- package/dist/features/seller/schemas/offer-forms.d.ts +16 -7
- package/dist/features/seller/schemas/offer-forms.js +28 -12
- package/dist/features/shell/FormShell.js +2 -2
- package/dist/features/shell/QuickFormDrawer.js +2 -2
- package/dist/features/shell/SectionForm.d.ts +19 -1
- package/dist/features/shell/SectionForm.js +104 -17
- package/dist/features/shell/build-sections.d.ts +23 -0
- package/dist/features/shell/build-sections.js +106 -8
- package/dist/features/shell/field-ui-meta.d.ts +44 -0
- package/dist/features/shell/field-ui-meta.js +14 -7
- package/dist/features/shell/form-sections.d.ts +46 -0
- package/dist/features/shell/form-sections.js +114 -0
- package/dist/features/shipments/components/AdminShipmentEditorView.js +87 -64
- package/dist/features/shipments/schemas/validation.d.ts +2 -2
- package/dist/features/shipments/schemas/validation.js +44 -13
- package/dist/features/store-extensions/schemas/custom-role-form.js +6 -2
- package/dist/features/store-extensions/schemas/listing-template-form.d.ts +7 -7
- package/dist/features/store-extensions/schemas/payout-method-form.js +14 -0
- package/dist/features/stores/actions/store-query-actions.js +3 -2
- package/dist/features/stores/api/[storeSlug]/auctions/route.js +3 -1
- package/dist/features/stores/api/[storeSlug]/products/route.js +3 -1
- package/dist/features/stores/components/StoreDetailLayoutView.d.ts +1 -1
- package/dist/features/stores/components/StoreDetailLayoutView.js +12 -3
- package/dist/features/support/repository/support.repository.d.ts +21 -0
- package/dist/features/support/repository/support.repository.js +63 -0
- package/dist/features/support/schemas/firestore.d.ts +27 -2
- package/dist/features/support/schemas/firestore.js +2 -0
- package/dist/features/support/schemas/ticket-create-form.js +7 -0
- package/dist/features/tester/schemas/checklist-item-form.d.ts +43 -0
- package/dist/features/tester/schemas/checklist-item-form.js +109 -0
- package/dist/features/tester/seed-data/blog-tester-seed-data.js +2 -2
- package/dist/features/tester/seed-data/categories-tester-seed-data.js +2 -2
- package/dist/features/tester/seed-data/events-tester-seed-data.js +5 -5
- package/dist/features/tester/seed-data/orders-tester-seed-data.js +2 -2
- package/dist/features/tester/seed-data/products-tester-seed-data.js +48 -49
- package/dist/features/tester/seed-data/stores-tester-seed-data.js +3 -3
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +291 -30
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +51 -14
- package/dist/features/wishlist/hooks/useWishlistToggle.js +8 -1
- package/dist/http/api-handler.js +2 -1
- package/dist/index.d.ts +25 -104
- package/dist/index.js +38 -143
- package/dist/jobs.d.ts +1 -1
- package/dist/jobs.js +1 -1
- package/dist/monitoring/browser.d.ts +0 -2
- package/dist/monitoring/browser.js +12 -1
- package/dist/monitoring/index.d.ts +0 -2
- package/dist/monitoring/index.js +0 -1
- package/dist/next/api/routeHandler.js +9 -4
- package/dist/next/index.d.ts +1 -2
- package/dist/next/index.js +0 -1
- package/dist/next/middleware/index.d.ts +0 -2
- package/dist/next/middleware/index.js +0 -1
- package/dist/next/routing/route-map.d.ts +8 -7
- package/dist/next/routing/route-map.js +10 -3
- package/dist/providers/auth-firebase/session.js +3 -1
- package/dist/providers/db-firebase/admin-app-lite.js +8 -8
- package/dist/providers/db-firebase/admin.js +27 -13
- package/dist/providers/db-firebase/browser-stub.d.ts +1 -11
- package/dist/providers/db-firebase/browser-stub.js +6 -11
- package/dist/providers/db-firebase/index.d.ts +0 -1
- package/dist/providers/db-firebase/index.js +0 -1
- package/dist/providers/db-firebase/rtdb-paths.d.ts +15 -6
- package/dist/providers/db-firebase/rtdb-paths.js +15 -6
- package/dist/providers/db-firebase/rtdb-url.d.ts +27 -0
- package/dist/providers/db-firebase/rtdb-url.js +50 -0
- package/dist/providers/db-firebase/sieve.d.ts +22 -0
- package/dist/providers/firebase-client/realtime.d.ts +20 -0
- package/dist/providers/firebase-client/realtime.js +34 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +1 -1
- package/dist/react/hooks/use-action-dispatch.js +8 -2
- package/dist/react/hooks/useFormStatePreservation.js +3 -1
- package/dist/react/hooks/useListingTypeFlags.d.ts +1 -1
- package/dist/react/hooks/useListingTypeFlags.js +1 -1
- package/dist/react/hooks/usePendingFilters.js +5 -3
- package/dist/react/hooks/usePendingTable.js +15 -3
- package/dist/react/hooks/useRealtimeEvent.js +20 -9
- package/dist/repositories/index.d.ts +0 -1
- package/dist/repositories/index.js +0 -1
- package/dist/schemas/registry.d.ts +197 -232
- package/dist/schemas/registry.js +5 -6
- package/dist/schemas/webhooks/razorpay.d.ts +50 -50
- package/dist/security/authorization.d.ts +9 -0
- package/dist/security/authorization.js +16 -2
- package/dist/security/browser.d.ts +1 -3
- package/dist/security/browser.js +5 -2
- package/dist/security/index.d.ts +1 -3
- package/dist/security/index.js +19 -2
- package/dist/security/pii-encrypt.js +16 -0
- package/dist/security/pii-schemas.d.ts +0 -14
- package/dist/security/pii-schemas.js +7 -15
- package/dist/seed/_helpers/category-forest.js +2 -2
- package/dist/seed/_helpers/media.d.ts +19 -0
- package/dist/seed/_helpers/media.js +75 -0
- package/dist/seed/blog-posts-seed-data.js +17 -17
- package/dist/seed/carousel-slides-seed-data.js +7 -7
- package/dist/seed/cart-seed-data.js +13 -13
- package/dist/seed/categories-seed-data.js +10 -10
- package/dist/seed/events-seed-data.js +24 -24
- package/dist/seed/factories/product.factory.js +4 -4
- package/dist/seed/factories/store.factory.js +3 -3
- package/dist/seed/factories/user.factory.js +2 -2
- package/dist/seed/grouped-listings-seed-data.js +11 -11
- package/dist/seed/homepage-sections-seed-data.js +2 -2
- package/dist/seed/index.d.ts +0 -1
- package/dist/seed/index.js +0 -1
- package/dist/seed/manifest.d.ts +1 -1
- package/dist/seed/manifest.js +0 -5
- package/dist/seed/notifications-seed-data.js +20 -1
- package/dist/seed/orders-seed-data.js +2 -2
- package/dist/seed/products-art-seed-data.js +16 -16
- package/dist/seed/products-auctions-seed-data.js +34 -34
- package/dist/seed/products-classifieds-seed-data.js +35 -37
- package/dist/seed/products-digital-codes-seed-data.js +20 -20
- package/dist/seed/products-live-items-seed-data.js +11 -11
- package/dist/seed/products-preorders-seed-data.js +13 -13
- package/dist/seed/products-prize-draws-seed-data.js +43 -43
- package/dist/seed/products-standard-seed-data.js +54 -54
- package/dist/seed/products-stickers-seed-data.js +15 -15
- package/dist/seed/reviews-seed-data.js +4 -4
- package/dist/seed/scammers-seed-data.js +3 -3
- package/dist/seed/site-settings-seed-data.js +11 -24
- package/dist/seed/store-extensions-seed-data.js +10 -10
- package/dist/seed/stores-seed-data.js +11 -11
- package/dist/seed/support-tickets-seed-data.d.ts +14 -0
- package/dist/seed/support-tickets-seed-data.js +20 -1
- package/dist/seed/users-seed-data.js +20 -20
- package/dist/server-entry.d.ts +0 -1
- package/dist/server-entry.js +0 -1
- package/dist/server.d.ts +9 -6
- package/dist/server.js +7 -13
- package/dist/styles.css +248 -68
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +2 -2
- package/dist/tokens/themes/default-light.js +2 -2
- package/dist/tokens/tokens.css +24 -4
- package/dist/ui/components/ActionRow.d.ts +50 -0
- package/dist/ui/components/ActionRow.js +53 -0
- package/dist/ui/components/ActionRow.style.css +145 -0
- package/dist/ui/components/Drawer.d.ts +10 -0
- package/dist/ui/components/Drawer.js +2 -1
- package/dist/ui/components/FilterDrawer.js +4 -1
- package/dist/ui/components/FilterDrawer.style.css +6 -12
- package/dist/ui/components/FormActionBar.js +14 -1
- package/dist/ui/components/FormActionBar.style.css +12 -11
- package/dist/ui/components/ListingLayout.js +8 -1
- package/dist/ui/components/ListingLayout.style.css +6 -13
- package/dist/ui/components/Modal.d.ts +15 -1
- package/dist/ui/components/Modal.js +17 -3
- package/dist/ui/components/QuickCreateModal.js +2 -2
- package/dist/ui/components/QuickCreateModal.style.css +78 -84
- package/dist/ui/components/RecordDetailModal.js +2 -2
- package/dist/ui/components/SideDrawer.d.ts +8 -0
- package/dist/ui/components/SideDrawer.js +2 -1
- package/dist/ui/components/SideDrawer.style.css +6 -3
- package/dist/ui/components/SideModal.d.ts +11 -1
- package/dist/ui/components/SideModal.js +3 -2
- package/dist/ui/components/SideModal.style.css +14 -0
- package/dist/ui/components/Typography.style.css +33 -24
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/components/toolbar-collapse.js +1 -2
- package/dist/ui/forms/FormShell.style.css +260 -311
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1 -0
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +1 -1
- package/dist/validation/schemas.d.ts +0 -19
- package/dist/validation/schemas.js +8 -19
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +3 -6
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { annotate } from "../../shell/field-ui-meta";
|
|
2
3
|
export const corporateInquiryStatusSchema = z.enum([
|
|
3
4
|
"pending",
|
|
4
5
|
"contacted",
|
|
@@ -37,23 +38,30 @@ export const corporateInquirySchema = z.object({
|
|
|
37
38
|
* Form schema for submitting a corporate inquiry.
|
|
38
39
|
*/
|
|
39
40
|
export const submitCorporateInquirySchema = z.object({
|
|
40
|
-
companyName: z.string().trim().min(2, "A company name is required.").max(160),
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
companyName: annotate(z.string().trim().min(2, "A company name is required.").max(160), {
|
|
42
|
+
section: "who", sectionLabel: "Your company", sectionRequired: true,
|
|
43
|
+
order: 1, row: "pair", label: "Company name",
|
|
44
|
+
}),
|
|
45
|
+
contactPerson: annotate(z.string().trim().min(2, "Who should we reply to?").max(120), {
|
|
46
|
+
section: "who", order: 2, row: "pair", label: "Contact person",
|
|
47
|
+
}),
|
|
48
|
+
designation: annotate(z.string().trim().max(120).optional(), {
|
|
49
|
+
section: "who", order: 3, row: "pair", label: "Designation",
|
|
50
|
+
}),
|
|
51
|
+
email: annotate(z
|
|
44
52
|
.string()
|
|
45
53
|
.trim()
|
|
46
54
|
.toLowerCase()
|
|
47
55
|
.min(1, "An email address is required.")
|
|
48
|
-
.email("That doesn't look like an email address."),
|
|
56
|
+
.email("That doesn't look like an email address."), { section: "who", order: 4, row: "pair", inputType: "email", label: "Email" }),
|
|
49
57
|
// Indian mobile, tolerant of spacing and a country code. Optional β a
|
|
50
58
|
// reachable email is enough, and demanding a phone number loses enquiries.
|
|
51
|
-
phone: z
|
|
59
|
+
phone: annotate(z
|
|
52
60
|
.string()
|
|
53
61
|
.trim()
|
|
54
62
|
.regex(/^(\+?91[-\s]?)?[6-9]\d{9}$/, "Enter a 10-digit Indian mobile number.")
|
|
55
63
|
.optional()
|
|
56
|
-
.or(z.literal("")),
|
|
64
|
+
.or(z.literal("")), { section: "who", order: 5, row: "pair", inputType: "tel", label: "Phone" }),
|
|
57
65
|
/*
|
|
58
66
|
* π COERCED. These were `z.number()`, and this schema's own form sends
|
|
59
67
|
* strings β so every submission carrying a unit count failed to parse the
|
|
@@ -62,19 +70,32 @@ export const submitCorporateInquirySchema = z.object({
|
|
|
62
70
|
*
|
|
63
71
|
* A sales reply is priced from these two, and until now both were free text.
|
|
64
72
|
*/
|
|
65
|
-
units: z.coerce
|
|
73
|
+
units: annotate(z.coerce
|
|
66
74
|
.number({ invalid_type_error: "Enter the number of units as a number." })
|
|
67
75
|
.int("Units must be a whole number.")
|
|
68
76
|
.positive("At least one unit.")
|
|
69
77
|
.max(1000000, "That looks like a typo β contact us directly for orders this large.")
|
|
70
|
-
.optional(),
|
|
71
|
-
budgetPerUnit: z.coerce
|
|
78
|
+
.optional(), { section: "pricing", sectionLabel: "What you need", order: 1, row: "pair", kind: "number", label: "Units" }),
|
|
79
|
+
budgetPerUnit: annotate(z.coerce
|
|
72
80
|
.number({ invalid_type_error: "Enter a per-unit budget as a number." })
|
|
73
81
|
.min(0, "A budget cannot be negative.")
|
|
74
82
|
.max(10000000, "That looks like a typo.")
|
|
75
|
-
.optional(),
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
83
|
+
.optional(), { section: "pricing", order: 2, row: "pair", kind: "number", label: "Budget per unit (βΉ)" }),
|
|
84
|
+
// Computed from units Γ budgetPerUnit on the client, so it is shown as a
|
|
85
|
+
// live read-only preview rather than asked for twice.
|
|
86
|
+
totalBudget: annotate(z.coerce.number().min(0).optional(), {
|
|
87
|
+
section: "pricing", order: 3, row: "pair", kind: "number", label: "Total budget (βΉ)",
|
|
88
|
+
derived: true, tier: "t1-derive",
|
|
89
|
+
}),
|
|
90
|
+
deliveryDateRequired: annotate(z.string().optional(), {
|
|
91
|
+
section: "schedule", sectionLabel: "Timeline", order: 1, row: "pair", kind: "date",
|
|
92
|
+
label: "Delivery date required by",
|
|
93
|
+
}),
|
|
94
|
+
customBranding: annotate(z.boolean().default(false), {
|
|
95
|
+
section: "schedule", order: 2, row: "full", kind: "toggle", label: "We need custom branding",
|
|
96
|
+
}),
|
|
97
|
+
message: annotate(z.string().trim().max(4000).optional(), {
|
|
98
|
+
section: "detail", sectionLabel: "Anything else", order: 1, row: "full", kind: "textarea",
|
|
99
|
+
label: "Message",
|
|
100
|
+
}),
|
|
80
101
|
});
|
|
@@ -30,7 +30,10 @@ function toDescriptionHtml(raw) {
|
|
|
30
30
|
export async function DigitalCodeDetailPageView({ slug, initialProduct, renderPrimaryActions }) {
|
|
31
31
|
const product = initialProduct !== undefined
|
|
32
32
|
? (initialProduct ?? undefined)
|
|
33
|
-
|
|
33
|
+
// The listing IS this page's subject β a read failure must surface rather
|
|
34
|
+
// than become the same `undefined` a removed listing produces, which the
|
|
35
|
+
// "Not Found" branch below already handles.
|
|
36
|
+
: await getDigitalCodeForDetail(slug);
|
|
34
37
|
if (!product) {
|
|
35
38
|
return (_jsx(Main, { children: _jsx(Section, { padding: "y-5xl", children: _jsx(Container, { size: "md", children: _jsxs(Stack, { align: "start", gap: "md", className: "text-left", children: [_jsx(Heading, { level: 1, size: "2xl", weight: "semibold", color: "primary", children: "Digital Code Listing Not Found" }), _jsx(Text, { color: "muted", children: "The digital code listing you are looking for may have been removed." }), _jsx(Link, { href: String(ROUTES.PUBLIC.DIGITAL_CODES), className: "text-[length:var(--appkit-text-sm)] font-medium text-primary-600 hover:underline", children: "Browse Digital Codes" })] }) }) }) }));
|
|
36
39
|
}
|
|
@@ -13,10 +13,12 @@ export function EventBanner({ storageKey = "dismissed_event_banners", className
|
|
|
13
13
|
const stored = sessionStorage.getItem(storageKey);
|
|
14
14
|
if (stored)
|
|
15
15
|
setDismissedIds(JSON.parse(stored));
|
|
16
|
+
// sessionStorage is unavailable in private mode and over quota in some
|
|
17
|
+
// embedded browsers. Losing the dismissal list only means the banner
|
|
18
|
+
// reappears β nothing an operator can act on, and nothing the user loses.
|
|
16
19
|
}
|
|
17
20
|
catch (_err) {
|
|
18
21
|
void normalizeError(_err);
|
|
19
|
-
// ignore session storage failures
|
|
20
22
|
}
|
|
21
23
|
setMounted(true);
|
|
22
24
|
}, [storageKey]);
|
|
@@ -38,10 +40,11 @@ export function EventBanner({ storageKey = "dismissed_event_banners", className
|
|
|
38
40
|
setDismissedIds(next);
|
|
39
41
|
try {
|
|
40
42
|
sessionStorage.setItem(storageKey, JSON.stringify(next));
|
|
43
|
+
// Same as the read above: the banner is already hidden in local state, so
|
|
44
|
+
// a failed persist only means it returns on the next page load.
|
|
41
45
|
}
|
|
42
46
|
catch (_err) {
|
|
43
47
|
void normalizeError(_err);
|
|
44
|
-
// ignore
|
|
45
48
|
}
|
|
46
49
|
};
|
|
47
50
|
return (_jsxs(Section, { tone: "accent-banner", className: [
|
|
@@ -24,10 +24,12 @@ export function EventOfferCard({ couponCode, offerDescription, title = "Exclusiv
|
|
|
24
24
|
await navigator.clipboard.writeText(couponCode);
|
|
25
25
|
setCopied(true);
|
|
26
26
|
setTimeout(() => setCopied(false), 2000);
|
|
27
|
+
// Clipboard access is denied outright on insecure origins and by user
|
|
28
|
+
// permission. The button simply never flips to "Copied", and the code is
|
|
29
|
+
// still visible on screen to select by hand.
|
|
27
30
|
}
|
|
28
31
|
catch (_err) {
|
|
29
32
|
void normalizeError(_err);
|
|
30
|
-
/* clipboard unavailable β leave button as-is */
|
|
31
33
|
}
|
|
32
34
|
};
|
|
33
35
|
return (_jsx(Div, { className: `${__P.p6}`, rounded: "2xl", border: "default", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Heading, { level: 2, weight: "semibold", size: "2xl", children: title }), offerDescription ? (_jsx(Text, { size: "sm", color: "muted", children: offerDescription })) : null] }), _jsxs(Row, { surface: "muted", padding: "inline", align: "center", gap: "3", rounded: "lg", children: [_jsx(Code, { className: "flex-1", weight: "bold", size: "base", color: "primary", children: couponCode }), _jsx(Button, { type: "button", variant: "outline", onClick: copyCode, children: copied ? "Copied!" : "Copy code" })] }), _jsx(Div, { children: _jsx(Link, { href: href, children: _jsx(Button, { variant: "primary", children: "Apply at checkout" }) }) })] }) }));
|
|
@@ -53,7 +53,7 @@ export function EventPollWidget({ eventId, pollConfig, eventStatus, totalEntries
|
|
|
53
53
|
}
|
|
54
54
|
catch (err) {
|
|
55
55
|
void normalizeError(err);
|
|
56
|
-
setError(
|
|
56
|
+
setError("Something went wrong");
|
|
57
57
|
}
|
|
58
58
|
finally {
|
|
59
59
|
setIsLoading(false);
|
|
@@ -4,6 +4,7 @@ import { useCallback, useMemo, useState } from "react";
|
|
|
4
4
|
import { Button, ClaimCouponButton, Div, Heading, LoginRequiredModal, Row, Span, Stack, Text, useToast } from "../../../ui";
|
|
5
5
|
import { isAuthError } from "../../../utils/auth-error";
|
|
6
6
|
import { normalizeError } from "../../../errors/normalize";
|
|
7
|
+
import { toUserMessage } from "../../../errors/error-display-map";
|
|
7
8
|
const CLS_WHEEL = "relative mx-auto aspect-square w-64 overflow-hidden rounded-full border-4 border-warning bg-[image:var(--appkit-gradient-promotion)]";
|
|
8
9
|
// audit-content-alignment-ok: self-contained circular spin-wheel game widget, all text centered under the wheel by design
|
|
9
10
|
const CLS_PRIZE_BOX = "rounded-xl border border-success bg-success-surface dark:border-success p-[var(--appkit-space-4)] text-center";
|
|
@@ -55,14 +56,14 @@ export function SpinWheelView({ eventId, prizes, alreadyUsed, initialPrizeId, in
|
|
|
55
56
|
}, ANIMATION_MS);
|
|
56
57
|
}
|
|
57
58
|
catch (err) {
|
|
58
|
-
|
|
59
|
+
const e = normalizeError(err);
|
|
59
60
|
setSpinning(false);
|
|
60
61
|
if (isAuthError(err)) {
|
|
61
62
|
setShowLoginModal(true);
|
|
62
63
|
}
|
|
63
64
|
else {
|
|
64
65
|
setError(l.errorFallback);
|
|
65
|
-
showToast(
|
|
66
|
+
showToast(toUserMessage(e.code, undefined, { fallback: l.errorFallback }), "error");
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
}, [disabled, eventId, l.errorFallback, onSpin, showToast]);
|
|
@@ -5,6 +5,7 @@ import { Div } from "../../ui";
|
|
|
5
5
|
import { FilterFacetSection } from "./FilterFacetSection";
|
|
6
6
|
import { RangeFilter } from "./RangeFilter";
|
|
7
7
|
import { SwitchFilter } from "./SwitchFilter";
|
|
8
|
+
import { joinFilterValues, splitFilterValues } from "../../constants/table-keys";
|
|
8
9
|
export function FilterPanel({ config, table, className = "", }) {
|
|
9
10
|
const [expandedIndex, setExpandedIndex] = useState(() => config.findIndex((c) => !c.defaultCollapsed));
|
|
10
11
|
const handleToggle = (idx) => setExpandedIndex((prev) => (prev === idx ? null : idx));
|
|
@@ -17,9 +18,8 @@ export function FilterPanel({ config, table, className = "", }) {
|
|
|
17
18
|
return (_jsx(FilterFacetSection, { title: item.title, options: item.options, selectionMode: "single", selected: selected, defaultCollapsed: item.defaultCollapsed, searchable: item.searchable, isOpen: isOpen, onToggle: () => handleToggle(idx), onClear: () => table.set(item.key, ""), onChange: (vals) => table.set(item.key, vals[0] ?? "") }, `${item.type}-${item.key}`));
|
|
18
19
|
}
|
|
19
20
|
case "facet-multi": {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
return (_jsx(FilterFacetSection, { title: item.title, options: item.options, selectionMode: "multi", selected: selected, defaultCollapsed: item.defaultCollapsed, searchable: item.searchable, isOpen: isOpen, onToggle: () => handleToggle(idx), onClear: () => table.set(item.key, ""), onChange: (vals) => table.set(item.key, vals.join(",")) }, `${item.type}-${item.key}`));
|
|
21
|
+
const selected = splitFilterValues(table.get(item.key));
|
|
22
|
+
return (_jsx(FilterFacetSection, { title: item.title, options: item.options, selectionMode: "multi", selected: selected, defaultCollapsed: item.defaultCollapsed, searchable: item.searchable, isOpen: isOpen, onToggle: () => handleToggle(idx), onClear: () => table.set(item.key, ""), onChange: (vals) => table.set(item.key, joinFilterValues(vals)) }, `${item.type}-${item.key}`));
|
|
23
23
|
}
|
|
24
24
|
case "switch": {
|
|
25
25
|
const checked = table.get(item.key) === "true";
|
|
@@ -18,6 +18,16 @@ export interface RangeFilterProps {
|
|
|
18
18
|
className?: string;
|
|
19
19
|
isOpen?: boolean;
|
|
20
20
|
onToggle?: () => void;
|
|
21
|
+
/**
|
|
22
|
+
* Override the clear behaviour. **Rarely needed** β clearing a range is
|
|
23
|
+
* `onMinChange("") + onMaxChange("")`, which is now the default, so the X
|
|
24
|
+
* appears on every range filter without a call site opting in.
|
|
25
|
+
*
|
|
26
|
+
* It used to be required-in-practice: 18 of the 19 call sites passed nothing
|
|
27
|
+
* and therefore rendered no clear button at all, leaving a range you could
|
|
28
|
+
* set and not unset. Pass this only when clearing must ALSO reset something
|
|
29
|
+
* outside the two values (`FilterPanel` clears its own pending map).
|
|
30
|
+
*/
|
|
21
31
|
onClear?: () => void;
|
|
22
32
|
}
|
|
23
33
|
export declare function RangeFilter({ title, minLabel, maxLabel, minValue, maxValue, onMinChange, onMaxChange, type, prefix, minPlaceholder, maxPlaceholder, defaultCollapsed, showSlider, minBound, maxBound, step, className, isOpen: controlledOpen, onToggle, onClear, }: RangeFilterProps): import("react").JSX.Element;
|
|
@@ -5,10 +5,41 @@ import { Button, Div, Input, Row, Slider, Span, Stack, Text } from "../../ui";
|
|
|
5
5
|
import { cn } from "./filterUtils";
|
|
6
6
|
const CLS_BADGE_COUNT = "inline-flex items-center justify-center w-5 h-5 rounded-full bg-success-surface dark:bg-success-surface text-success dark:text-success ring-1 ring-success/20";
|
|
7
7
|
const CLS_CLEAR_BTN = "inline-flex items-center justify-center w-5 h-5 text-[var(--appkit-color-text-muted)] hover:text-error dark:hover:text-error rounded-full transition-colors";
|
|
8
|
+
/**
|
|
9
|
+
* Parse a filter value, distinguishing "not set" from a legitimate zero.
|
|
10
|
+
*
|
|
11
|
+
* π NOT `parseFloat(v) || bound`. `parseFloat("")` is NaN and falsy, which is
|
|
12
|
+
* the intended case β but so is `parseFloat("0")`, so a user asking for a max
|
|
13
|
+
* of 0 got the 500000 bound instead, and the filter they could see in the
|
|
14
|
+
* inputs was not the one being applied.
|
|
15
|
+
*/
|
|
16
|
+
function rawNum(value) {
|
|
17
|
+
const n = Number.parseFloat(value);
|
|
18
|
+
return Number.isFinite(n) ? n : null;
|
|
19
|
+
}
|
|
8
20
|
function DualSlider({ minValue, maxValue, onMinChange, onMaxChange, minBound, maxBound, step = 1, prefix = "", }) {
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
21
|
+
const minRaw = rawNum(minValue);
|
|
22
|
+
const maxRaw = rawNum(maxValue);
|
|
23
|
+
/*
|
|
24
|
+
* Display only. An unset side shows its bound so the track reads sensibly β
|
|
25
|
+
* but the bound is never what gets WRITTEN, which is the distinction the old
|
|
26
|
+
* `|| bound` collapsed.
|
|
27
|
+
*/
|
|
28
|
+
const minNum = Math.min(Math.max(minRaw ?? minBound, minBound), maxBound);
|
|
29
|
+
const maxNum = Math.max(Math.min(maxRaw ?? maxBound, maxBound), minBound);
|
|
30
|
+
/*
|
|
31
|
+
* Each slider spans the FULL range and clamps itself on write.
|
|
32
|
+
*
|
|
33
|
+
* It used to derive its opposite end from the other thumb β the min slider's
|
|
34
|
+
* `max` was `maxNum - step` β so with max unset, `maxNum` collapsed to the
|
|
35
|
+
* bound, and any later change to one side silently re-scaled and appeared to
|
|
36
|
+
* reset the other. Clamping on write instead of on range means dragging one
|
|
37
|
+
* thumb can never move or clear the other, and a value that would cross is
|
|
38
|
+
* pinned rather than the whole control rescaling underneath the user.
|
|
39
|
+
*/
|
|
40
|
+
const writeMin = (v) => onMinChange(String(Math.min(v, maxRaw ?? maxBound)));
|
|
41
|
+
const writeMax = (v) => onMaxChange(String(Math.max(v, minRaw ?? minBound)));
|
|
42
|
+
return (_jsxs(Stack, { gap: "sm", className: "w-full", children: [_jsxs(Row, { align: "center", justify: "between", children: [_jsxs(Span, { size: "sm", weight: "semibold", className: "tabular-nums text-primary-600 dark:text-secondary-400", children: [prefix, minNum] }), _jsx(Span, { size: "xs", color: "muted", children: "-" }), _jsxs(Span, { size: "sm", weight: "semibold", className: "tabular-nums text-primary-600 dark:text-secondary-400", children: [prefix, maxNum] })] }), _jsxs(Stack, { gap: "xs", "aria-hidden": "true", children: [_jsx(Slider, { value: minNum, min: minBound, max: maxBound, step: step, onChange: writeMin }), _jsx(Slider, { value: maxNum, min: minBound, max: maxBound, step: step, onChange: writeMax })] }), _jsxs(Row, { align: "center", justify: "between", children: [_jsxs(Span, { size: "xs", color: "muted", children: [prefix, minBound] }), _jsxs(Span, { size: "xs", color: "muted", children: [prefix, maxBound] })] })] }));
|
|
12
43
|
}
|
|
13
44
|
export function RangeFilter({ title, minLabel, maxLabel, minValue, maxValue, onMinChange, onMaxChange, type = "number", prefix, minPlaceholder, maxPlaceholder, defaultCollapsed = true, showSlider = false, minBound, maxBound, step = 1, className = "", isOpen: controlledOpen, onToggle, onClear, }) {
|
|
14
45
|
const isControlled = controlledOpen !== undefined;
|
|
@@ -25,6 +56,12 @@ export function RangeFilter({ title, minLabel, maxLabel, minValue, maxValue, onM
|
|
|
25
56
|
minBound !== undefined &&
|
|
26
57
|
maxBound !== undefined;
|
|
27
58
|
const hasValue = !!(minValue || maxValue);
|
|
59
|
+
// Clearing a range needs nothing a caller has to supply. See `onClear` above.
|
|
60
|
+
const handleClear = onClear ??
|
|
61
|
+
(() => {
|
|
62
|
+
onMinChange("");
|
|
63
|
+
onMaxChange("");
|
|
64
|
+
});
|
|
28
65
|
const inputClass = "w-full rounded-md border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-input)] px-[var(--appkit-space-2-5)] py-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-xs)] text-[var(--appkit-color-text)] focus:outline-none focus:ring-2 focus:ring-primary-500/20 ";
|
|
29
|
-
return (_jsxs(Div, { role: "group", "aria-labelledby": `rf-${title}`, className: cn("p-[var(--appkit-space-4)] border-b border-[var(--appkit-color-border)] last:border-b-0", className), children: [_jsxs(Row, { align: "center", gap: "sm", children: [_jsxs(Button, { type: "button", id: `rf-${title}`, onClick: handleToggle, variant: "ghost", size: "sm", className: "flex-1 justify-[space-between] text-[0.875rem] font-[600] text-[var(--appkit-color-text)] py-[0.25rem] hover:opacity-80 transition-opacity", "aria-expanded": !isCollapsed, children: [_jsxs(Span, { layout: "flex", gap: "md", children: [title, hasValue && (_jsx(Span, { size: "xs", className: CLS_BADGE_COUNT, children: "1" }))] }), _jsx("svg", { className: cn("w-4 h-4 shrink-0 text-[var(--appkit-color-text-muted)] transition-transform duration-200", isCollapsed ? "" : "rotate-180"), fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) })] }),
|
|
66
|
+
return (_jsxs(Div, { role: "group", "aria-labelledby": `rf-${title}`, className: cn("p-[var(--appkit-space-4)] border-b border-[var(--appkit-color-border)] last:border-b-0", className), children: [_jsxs(Row, { align: "center", gap: "sm", children: [_jsxs(Button, { type: "button", id: `rf-${title}`, onClick: handleToggle, variant: "ghost", size: "sm", className: "flex-1 justify-[space-between] text-[0.875rem] font-[600] text-[var(--appkit-color-text)] py-[0.25rem] hover:opacity-80 transition-opacity", "aria-expanded": !isCollapsed, children: [_jsxs(Span, { layout: "flex", gap: "md", children: [title, hasValue && (_jsx(Span, { size: "xs", className: CLS_BADGE_COUNT, children: "1" }))] }), _jsx("svg", { className: cn("w-4 h-4 shrink-0 text-[var(--appkit-color-text-muted)] transition-transform duration-200", isCollapsed ? "" : "rotate-180"), fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) })] }), hasValue && (_jsx(Button, { type: "button", onClick: handleClear, variant: "ghost", size: "sm", className: CLS_CLEAR_BTN, "aria-label": "Clear", children: _jsx("svg", { className: "w-3 h-3 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }) }))] }), !isCollapsed && (_jsxs(Stack, { gap: "3", className: "mt-3", children: [canShowSlider && (_jsx(DualSlider, { minValue: minValue, maxValue: maxValue, onMinChange: onMinChange, onMaxChange: onMaxChange, minBound: minBound, maxBound: maxBound, step: step, prefix: prefix })), _jsxs(Row, { align: "end", gap: "sm", children: [_jsxs(Div, { className: "flex-1 min-w-0", children: [minLabel && (_jsx(Text, { className: "mb-1", color: "muted", size: "xs", children: minLabel })), _jsxs(Div, { className: "relative", children: [prefix && (_jsx(Span, { size: "xs", className: "absolute left-2 top-1/2 -translate-y-1/2 pointer-events-none", color: "faint", children: prefix })), _jsx(Input, { type: type, value: minValue, onChange: (e) => onMinChange(e.target.value), placeholder: minPlaceholder ?? (type === "date" ? "From" : "Min"), className: cn(inputClass, prefix ? "pl-5" : "") })] })] }), _jsx(Span, { size: "xs", className: "flex-shrink-0 pb-[0.375rem]", color: "faint", children: "-" }), _jsxs(Div, { className: "flex-1 min-w-0", children: [maxLabel && (_jsx(Text, { className: "mb-1", color: "muted", size: "xs", children: maxLabel })), _jsxs(Div, { className: "relative", children: [prefix && (_jsx(Span, { size: "xs", className: "absolute left-2 top-1/2 -translate-y-1/2 pointer-events-none", color: "faint", children: prefix })), _jsx(Input, { type: type, value: maxValue, onChange: (e) => onMaxChange(e.target.value), placeholder: maxPlaceholder ?? (type === "date" ? "To" : "Max"), className: cn(inputClass, prefix ? "pl-5" : "") })] })] })] })] }))] }));
|
|
30
67
|
}
|
|
@@ -46,6 +46,7 @@ import { apiClient } from "../../../http";
|
|
|
46
46
|
import { ADMIN_ENDPOINTS, SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
47
47
|
import { ROUTES } from "../../../next/routing/route-map";
|
|
48
48
|
import { normalizeError } from "../../../errors/normalize";
|
|
49
|
+
import { toUserMessage } from "../../../errors/error-display-map";
|
|
49
50
|
import { ProductInlineSelect } from "../../seller/components/ProductInlineSelect";
|
|
50
51
|
import { groupedListingFormSchema, } from "../schemas/grouped-listing-form";
|
|
51
52
|
const EMPTY = {
|
|
@@ -173,7 +174,7 @@ export function GroupedListingEditorView({ scope, groupId, fixedStoreId, onSaved
|
|
|
173
174
|
}
|
|
174
175
|
catch (err) {
|
|
175
176
|
const e = normalizeError(err);
|
|
176
|
-
showToast(e.
|
|
177
|
+
showToast(toUserMessage(e.code, undefined, { fallback: "Failed to save the group." }), "error");
|
|
177
178
|
}
|
|
178
179
|
finally {
|
|
179
180
|
setSaving(false);
|
|
@@ -38,35 +38,28 @@ async function postAuthTrack(args) {
|
|
|
38
38
|
headers: { "Content-Type": "application/json" },
|
|
39
39
|
body: JSON.stringify(args),
|
|
40
40
|
});
|
|
41
|
+
// Recently-viewed tracking is a side effect of browsing, fired from a
|
|
42
|
+
// debounced timer with no UI attached. A lost entry costs the user nothing
|
|
43
|
+
// and there is no caller in a position to retry or report it.
|
|
41
44
|
}
|
|
42
45
|
catch (_err) {
|
|
43
46
|
void normalizeError(_err);
|
|
44
|
-
// best-effort tracking
|
|
45
47
|
}
|
|
46
48
|
}
|
|
49
|
+
// Both deletes below are user-initiated and deliberately let failures throw:
|
|
50
|
+
// swallowing them made `remove`/`clear` report success for a DELETE that never
|
|
51
|
+
// landed, and the row would silently return on the next load.
|
|
47
52
|
async function deleteAuthItem(productId) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
catch (_err) {
|
|
55
|
-
void normalizeError(_err);
|
|
56
|
-
// ignore
|
|
57
|
-
}
|
|
53
|
+
await fetch(ACCOUNT_ENDPOINTS.HISTORY_ITEM(productId), {
|
|
54
|
+
method: "DELETE",
|
|
55
|
+
credentials: "include",
|
|
56
|
+
});
|
|
58
57
|
}
|
|
59
58
|
async function deleteAuthAll() {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
catch (_err) {
|
|
67
|
-
void normalizeError(_err);
|
|
68
|
-
// ignore
|
|
69
|
-
}
|
|
59
|
+
await fetch(ACCOUNT_ENDPOINTS.HISTORY, {
|
|
60
|
+
method: "DELETE",
|
|
61
|
+
credentials: "include",
|
|
62
|
+
});
|
|
70
63
|
}
|
|
71
64
|
export function useHistory(userId) {
|
|
72
65
|
const isAuth = !!userId;
|
|
@@ -81,6 +74,9 @@ export function useHistory(userId) {
|
|
|
81
74
|
else {
|
|
82
75
|
setItems(getGuestHistory());
|
|
83
76
|
}
|
|
77
|
+
// fetchAuthHistory already degrades to [] on its own, and getGuestHistory
|
|
78
|
+
// is a localStorage read that fails only in private mode β either way the
|
|
79
|
+
// list stays as it was, which is the correct visible outcome here.
|
|
84
80
|
}
|
|
85
81
|
catch (err) {
|
|
86
82
|
void normalizeError(err);
|
|
@@ -131,14 +127,20 @@ export function useHistory(userId) {
|
|
|
131
127
|
trackTimers.current.set(key, timer);
|
|
132
128
|
}, [isAuth]);
|
|
133
129
|
const remove = useCallback(async (productId) => {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
130
|
+
try {
|
|
131
|
+
if (isAuth) {
|
|
132
|
+
await deleteAuthItem(productId);
|
|
133
|
+
await loadItems();
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
setItems(removeGuestHistoryItem(productId));
|
|
137
|
+
}
|
|
137
138
|
}
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
catch (_err) {
|
|
140
|
+
void normalizeError(_err);
|
|
141
|
+
showToast("Failed to remove this item from history.", "error");
|
|
140
142
|
}
|
|
141
|
-
}, [isAuth, loadItems]);
|
|
143
|
+
}, [isAuth, loadItems, showToast]);
|
|
142
144
|
const clear = useCallback(async () => {
|
|
143
145
|
try {
|
|
144
146
|
if (isAuth) {
|
|
@@ -16,10 +16,12 @@ function AdsenseAd({ config }) {
|
|
|
16
16
|
return;
|
|
17
17
|
try {
|
|
18
18
|
(window.adsbygoogle = window.adsbygoogle || []).push({});
|
|
19
|
+
// adsbygoogle is injected by a third-party script that ad blockers and
|
|
20
|
+
// consent walls routinely prevent from loading. The <ins> below simply
|
|
21
|
+
// stays unfilled β there is no failure the site can act on.
|
|
19
22
|
}
|
|
20
23
|
catch (_err) {
|
|
21
24
|
void normalizeError(_err);
|
|
22
|
-
// AdSense not loaded yet β no-op
|
|
23
25
|
}
|
|
24
26
|
}, []);
|
|
25
27
|
return (_jsx(Div, { ref: ref, children: _jsx("ins", { className: "adsbygoogle block", "data-ad-client": config.adsenseClient ?? "", "data-ad-slot": config.adsenseSlot ?? "", "data-ad-format": config.adsenseFormat ?? "auto", "data-full-width-responsive": "true" }) }));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { normalizeError } from "../../../errors/normalize";
|
|
3
|
+
import { serverLogger } from "../../../monitoring/server-logger";
|
|
3
4
|
import { Anchor, Div, GRID_MAP, Heading, HandModeRow, Row, Section, Span, Stack, Text } from "../../../ui";
|
|
4
5
|
import { MediaImage } from "../../media/MediaImage";
|
|
5
6
|
import { siteSettingsRepository } from "../../admin/repository/site-settings.repository";
|
|
@@ -60,8 +61,13 @@ export async function GoogleReviewsSection(config) {
|
|
|
60
61
|
totalRatings = result.totalRatings;
|
|
61
62
|
}
|
|
62
63
|
catch (_err) {
|
|
63
|
-
|
|
64
|
-
//
|
|
64
|
+
// The section renders its empty state below, which is indistinguishable
|
|
65
|
+
// from a place that genuinely has no reviews β and Google Places calls are
|
|
66
|
+
// billed, so a persistent failure is worth an operator seeing.
|
|
67
|
+
serverLogger.warn("homepage.googleReviews: Places fetch failed", {
|
|
68
|
+
placeId,
|
|
69
|
+
error: normalizeError(_err).message,
|
|
70
|
+
});
|
|
65
71
|
}
|
|
66
72
|
const gridClass = layout === "carousel"
|
|
67
73
|
? "flex gap-[var(--appkit-space-4)] overflow-x-auto pb-[var(--appkit-space-2)] snap-x snap-mandatory"
|
|
@@ -3,10 +3,21 @@ import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
|
|
|
3
3
|
import { sortBy } from "@mohasinac/appkit";
|
|
4
4
|
import { Div, Main } from "../../../ui";
|
|
5
5
|
import { carouselRepository, faqsRepository, siteSettingsRepository } from "../../../repositories";
|
|
6
|
+
import { safeRead } from "../../../errors/safe-read";
|
|
6
7
|
import { fetchLiveStats } from "../lib/live-stats";
|
|
7
8
|
import { renderSection, AnnouncementBar } from "../lib/section-renderer";
|
|
8
9
|
import { homepageSectionsRepository } from "../repository/homepage-sections.repository";
|
|
9
|
-
import {
|
|
10
|
+
import { isListingTypeEnabled } from "../../../_internal/shared/listing-types/feature-flags";
|
|
11
|
+
/**
|
|
12
|
+
* Homepage sections that advertise a specific listing type, and must therefore
|
|
13
|
+
* disappear when the site stops offering it. A section type absent from this
|
|
14
|
+
* map always renders.
|
|
15
|
+
*/
|
|
16
|
+
const HOMEPAGE_SECTION_LISTING_TYPE = {
|
|
17
|
+
auctions: "auction",
|
|
18
|
+
"pre-orders": "pre-order",
|
|
19
|
+
"prize-draws": "prize-draw",
|
|
20
|
+
};
|
|
10
21
|
import { getFeaturedProducts, getFeaturedAuctions, getFeaturedPreOrders } from "../../products/actions/product-actions";
|
|
11
22
|
import { listTopLevelCategories, listBrandCategories } from "../../categories/actions/category-actions";
|
|
12
23
|
import { listFeaturedBundles } from "../../../_internal/server/features/bundles/data";
|
|
@@ -28,19 +39,39 @@ function toCarouselSlides(docs) {
|
|
|
28
39
|
}));
|
|
29
40
|
}
|
|
30
41
|
export async function MarketplaceHomepageView({ adSlots, newsletterFormSlot, onBannerDismiss, } = {}) {
|
|
31
|
-
|
|
32
|
-
|
|
42
|
+
// Every read on this page is a RAIL: the homepage must still render when one
|
|
43
|
+
// fails, but a failure has to be distinguishable from an empty catalogue β
|
|
44
|
+
// that is exactly Root Cause #59, and safeRead is what records it.
|
|
45
|
+
const slides = await safeRead(() => carouselRepository.getActiveSlides(), {
|
|
46
|
+
route: "/", key: "homepage.carouselSlides", fallback: [],
|
|
47
|
+
});
|
|
48
|
+
const siteSettings = await safeRead(() => siteSettingsRepository.getSingleton(), {
|
|
49
|
+
route: "/", key: "homepage.siteSettings", fallback: null,
|
|
50
|
+
});
|
|
33
51
|
const announcementMessage = siteSettings?.announcementBar?.message?.trim() ||
|
|
34
52
|
"π Up to 15% Off on PokΓ©mon TCG this week β Use code SAVE15";
|
|
35
53
|
const showAnnouncement = siteSettings?.announcementBar?.enabled ?? true;
|
|
36
54
|
const [allSections, rawFaqItems] = await Promise.all([
|
|
37
|
-
|
|
38
|
-
|
|
55
|
+
safeRead(() => homepageSectionsRepository.getEnabledSections(), {
|
|
56
|
+
route: "/", key: "homepage.enabledSections", fallback: [],
|
|
57
|
+
}),
|
|
58
|
+
safeRead(() => faqsRepository.getHomepageFAQs(), {
|
|
59
|
+
route: "/", key: "homepage.faqs", fallback: [],
|
|
60
|
+
}),
|
|
39
61
|
]);
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
|
|
62
|
+
// A homepage section must not advertise a listing type the site does not
|
|
63
|
+
// offer. This gate previously read `featureFlags.{auctions,preOrders,events,
|
|
64
|
+
// blog}`; that group was deleted on 2026-08-29, and only the listing-type
|
|
65
|
+
// half of it had a real successor (`settings.listings.listingTypes`).
|
|
66
|
+
//
|
|
67
|
+
// So auctions / pre-orders / prize-draws are gated by the same control that
|
|
68
|
+
// hides them on every other surface, and the `events` / `blog` sections are
|
|
69
|
+
// now unconditional β there is no product control for "we don't run events",
|
|
70
|
+
// and there never was one that anything but this line read.
|
|
71
|
+
const enabledSections = allSections.filter((section) => {
|
|
72
|
+
const gated = HOMEPAGE_SECTION_LISTING_TYPE[section.type];
|
|
73
|
+
return !gated || isListingTypeEnabled(gated, siteSettings);
|
|
74
|
+
});
|
|
44
75
|
// Collect live metric requests from all enabled stats sections
|
|
45
76
|
const liveStatRequests = [];
|
|
46
77
|
for (const section of enabledSections) {
|
|
@@ -87,12 +118,24 @@ export async function MarketplaceHomepageView({ adSlots, newsletterFormSlot, onB
|
|
|
87
118
|
activeTypes.has("products") ? getFeaturedProducts(12) : null,
|
|
88
119
|
activeTypes.has("auctions") ? getFeaturedAuctions(12) : null,
|
|
89
120
|
activeTypes.has("pre-orders") ? getFeaturedPreOrders(12) : null,
|
|
90
|
-
activeTypes.has("categories")
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
activeTypes.has("
|
|
94
|
-
|
|
95
|
-
|
|
121
|
+
activeTypes.has("categories")
|
|
122
|
+
? safeRead(() => listTopLevelCategories(12), { route: "/", key: "homepage.categories", fallback: null })
|
|
123
|
+
: null,
|
|
124
|
+
activeTypes.has("brands")
|
|
125
|
+
? safeRead(() => listBrandCategories(12), { route: "/", key: "homepage.brands", fallback: null })
|
|
126
|
+
: null,
|
|
127
|
+
activeTypes.has("featured-bundles")
|
|
128
|
+
? safeRead(() => listFeaturedBundles(8), { route: "/", key: "homepage.featuredBundles", fallback: null })
|
|
129
|
+
: null,
|
|
130
|
+
activeTypes.has("stores")
|
|
131
|
+
? safeRead(() => listStores({ pageSize: 8, sorts: sortBy("averageRating", "DESC") }), { route: "/", key: "homepage.stores", fallback: null })
|
|
132
|
+
: null,
|
|
133
|
+
activeTypes.has("blog-articles")
|
|
134
|
+
? safeRead(() => getFeaturedBlogPosts(6), { route: "/", key: "homepage.blogPosts", fallback: null })
|
|
135
|
+
: null,
|
|
136
|
+
activeTypes.has("events")
|
|
137
|
+
? safeRead(() => listPublicEvents({ filters: sieveFilter("status", SIEVE_OP.EQ, "active"), pageSize: 6 }), { route: "/", key: "homepage.events", fallback: null })
|
|
138
|
+
: null,
|
|
96
139
|
]);
|
|
97
140
|
// ProductDocument / BlogDocument / EventDocument have Date fields and extra Firestore-only
|
|
98
141
|
// fields absent from the corresponding *Item types. The casts below are safe: section
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { normalizeError } from "../../../errors/normalize";
|
|
3
|
+
import { safeRead } from "../../../errors/safe-read";
|
|
3
4
|
import { Anchor, Div, GRID_MAP, Heading, HandModeRow, Section, Stack, Text } from "../../../ui";
|
|
4
5
|
import { SocialPostCard } from "./SocialPostCard";
|
|
5
6
|
import { fetchInstagramPosts, fetchFacebookPosts, fetchTikTokPosts, fetchDeviantArtPosts, } from "../lib/social-feed-fetcher";
|
|
@@ -47,7 +48,9 @@ async function loadPosts(config) {
|
|
|
47
48
|
if (!handle)
|
|
48
49
|
return { posts: [], error: `A handle is required for ${PLATFORM_LABELS[platform]}.` };
|
|
49
50
|
try {
|
|
50
|
-
|
|
51
|
+
// A failed credentials read is reported below as "token not configured in
|
|
52
|
+
// Site Settings", which is actionable but wrong β record the real cause.
|
|
53
|
+
const credentials = await safeRead(() => siteSettingsRepository.getDecryptedCredentials(), { route: "/", key: "homepage.socialFeed.credentials", fallback: null });
|
|
51
54
|
switch (platform) {
|
|
52
55
|
case "instagram": {
|
|
53
56
|
const token = credentials?.metaPageAccessToken;
|
|
@@ -23,7 +23,7 @@ export function useBlogArticles(options) {
|
|
|
23
23
|
return featuredResult;
|
|
24
24
|
}
|
|
25
25
|
const remaining = MIN_BLOG_COUNT - featured.length;
|
|
26
|
-
const latestResult = await apiClient.get(`${BLOG_ENDPOINTS.SORTED("-publishedAt")}&
|
|
26
|
+
const latestResult = await apiClient.get(`${BLOG_ENDPOINTS.SORTED("-publishedAt")}&pageSize=${MIN_BLOG_COUNT + remaining}`);
|
|
27
27
|
const existingIds = new Set(featured.map((p) => p.id));
|
|
28
28
|
const filler = latestResult.posts
|
|
29
29
|
.filter((p) => !existingIds.has(p.id))
|
|
@@ -81,7 +81,14 @@ export async function fetchLiveStats(requests) {
|
|
|
81
81
|
}
|
|
82
82
|
catch (_err) {
|
|
83
83
|
void normalizeError(_err);
|
|
84
|
-
//
|
|
84
|
+
// Falling back to the admin-authored static value is correct β but a
|
|
85
|
+
// stale number that looks live is exactly the failure this must not
|
|
86
|
+
// hide, so name the collection that could not be counted.
|
|
87
|
+
serverLogger.warn("homepage.liveStats: collection count failed", {
|
|
88
|
+
statKey: key,
|
|
89
|
+
collection,
|
|
90
|
+
error: normalizeError(_err).message,
|
|
91
|
+
});
|
|
85
92
|
}
|
|
86
93
|
})());
|
|
87
94
|
}
|
|
@@ -234,10 +234,11 @@ export class CarouselRepository extends BaseRepository {
|
|
|
234
234
|
"stats.views": increment(1),
|
|
235
235
|
"stats.lastViewed": new Date(),
|
|
236
236
|
});
|
|
237
|
+
// Fire-and-forget analytics: a lost view increment changes nothing that
|
|
238
|
+
// renders, and it must never break the carousel read it rides along with.
|
|
237
239
|
}
|
|
238
240
|
catch (_e) {
|
|
239
241
|
void normalizeError(_e);
|
|
240
|
-
// Swallow errors β analytics failures must not break the carousel response
|
|
241
242
|
}
|
|
242
243
|
}
|
|
243
244
|
}
|