@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
|
@@ -4,11 +4,19 @@
|
|
|
4
4
|
* pages to hand `productFeatures` down as a prop and avoid per-card waterfalls.
|
|
5
5
|
*/
|
|
6
6
|
import { productFeaturesRepository } from "./product-features.repository";
|
|
7
|
+
import { safeRead } from "../../../errors/safe-read";
|
|
7
8
|
export async function loadProductFeaturesForStore(storeId) {
|
|
9
|
+
// Feature badges decorate a card; a page without them is still correct, so
|
|
10
|
+
// both reads degrade — but a failure here silently strips "Free shipping" /
|
|
11
|
+
// "Authenticity guaranteed" from every card, which nobody would notice.
|
|
8
12
|
const [platform, store] = await Promise.all([
|
|
9
|
-
|
|
13
|
+
safeRead(() => productFeaturesRepository.listPlatform(), {
|
|
14
|
+
route: "productFeatures", key: "productFeatures.platform", fallback: [],
|
|
15
|
+
}),
|
|
10
16
|
storeId
|
|
11
|
-
? productFeaturesRepository.listForStore(storeId)
|
|
17
|
+
? safeRead(() => productFeaturesRepository.listForStore(storeId), {
|
|
18
|
+
route: "productFeatures", key: "productFeatures.store", fallback: [],
|
|
19
|
+
})
|
|
12
20
|
: Promise.resolve([]),
|
|
13
21
|
]);
|
|
14
22
|
const seen = new Set();
|
|
@@ -281,7 +281,7 @@ export declare class ProductRepository extends BaseRepository<ProductDocument> {
|
|
|
281
281
|
canFilter: boolean;
|
|
282
282
|
canSort: boolean;
|
|
283
283
|
};
|
|
284
|
-
"classified.meetupArea": {
|
|
284
|
+
"classified.meetupArea.city": {
|
|
285
285
|
canFilter: boolean;
|
|
286
286
|
canSort: boolean;
|
|
287
287
|
};
|
|
@@ -317,6 +317,10 @@ export declare class ProductRepository extends BaseRepository<ProductDocument> {
|
|
|
317
317
|
canFilter: boolean;
|
|
318
318
|
canSort: boolean;
|
|
319
319
|
};
|
|
320
|
+
"liveItem.transport.method": {
|
|
321
|
+
canFilter: boolean;
|
|
322
|
+
canSort: boolean;
|
|
323
|
+
};
|
|
320
324
|
};
|
|
321
325
|
/**
|
|
322
326
|
* Virtual filter aliases — callers can pass `f=listingType==auction` for
|
|
@@ -452,10 +452,11 @@ export class ProductRepository extends BaseRepository {
|
|
|
452
452
|
.update({
|
|
453
453
|
[PRODUCT_FIELDS.VIEW_COUNT]: increment(1),
|
|
454
454
|
});
|
|
455
|
+
// Fire-and-forget analytics: a lost view increment changes no rendered
|
|
456
|
+
// content, so it must never break the product read path it rides with.
|
|
455
457
|
}
|
|
456
458
|
catch (_err) {
|
|
457
459
|
void normalizeError(_err);
|
|
458
|
-
// View analytics must not break product read path.
|
|
459
460
|
}
|
|
460
461
|
}
|
|
461
462
|
/**
|
|
@@ -593,7 +594,22 @@ ProductRepository.SIEVE_FIELDS = {
|
|
|
593
594
|
// silently skipped. The toggle did nothing at all until 2026-08-21.
|
|
594
595
|
shippingPaidBy: { canFilter: true, canSort: false },
|
|
595
596
|
searchTxt: { canFilter: true, canSort: false },
|
|
596
|
-
|
|
597
|
+
/*
|
|
598
|
+
* `classified.meetupArea.city`, NOT `classified.meetupArea`.
|
|
599
|
+
*
|
|
600
|
+
* `meetupArea` is an OBJECT (`{city, locality, pincode}`), so an equality
|
|
601
|
+
* on the parent could never match anything a user typed. The city facet
|
|
602
|
+
* emits `classified.meetupArea.city` (TYPE_FACET_FIELD), `findField` is an
|
|
603
|
+
* exact-key lookup, and `throwExceptions:false` drops what it cannot
|
|
604
|
+
* resolve — so the /classified city filter rendered, counted toward the
|
|
605
|
+
* badge, and changed nothing. Both halves of Root Cause #62 in one entry:
|
|
606
|
+
* an orphan key that matches no field, beside a real field with no entry.
|
|
607
|
+
*
|
|
608
|
+
* The schema's own docstring already named the right path ("drives the
|
|
609
|
+
* (listingType, classified.meetupArea.city, createdAt) index"), and the
|
|
610
|
+
* store-scoped index has always been on `.city`.
|
|
611
|
+
*/
|
|
612
|
+
"classified.meetupArea.city": { canFilter: true, canSort: false },
|
|
597
613
|
"classified.acceptsShipping": { canFilter: true, canSort: false },
|
|
598
614
|
"classified.negotiable": { canFilter: true, canSort: false },
|
|
599
615
|
"digitalCode.codeDeliveryMethod": { canFilter: true, canSort: false },
|
|
@@ -602,6 +618,13 @@ ProductRepository.SIEVE_FIELDS = {
|
|
|
602
618
|
"liveItem.sex": { canFilter: true, canSort: false },
|
|
603
619
|
"liveItem.jurisdictionAllowed": { canFilter: true, canSort: false },
|
|
604
620
|
"liveItem.cites": { canFilter: true, canSort: false },
|
|
621
|
+
/*
|
|
622
|
+
* The live-items transport facet. `StoreLiveItemsListing` has listed
|
|
623
|
+
* `liveTransportMethod` in its FILTER_KEYS — so ticking it inflated the
|
|
624
|
+
* active-filter badge — while the key had no TYPE_FACET_FIELD mapping and
|
|
625
|
+
* this field had no entry, so it never reached Firestore from either end.
|
|
626
|
+
*/
|
|
627
|
+
"liveItem.transport.method": { canFilter: true, canSort: false },
|
|
605
628
|
};
|
|
606
629
|
/**
|
|
607
630
|
* Virtual filter aliases — callers can pass `f=listingType==auction` for
|
|
@@ -64,11 +64,15 @@ export interface ProductClassifiedMeta {
|
|
|
64
64
|
locality?: string;
|
|
65
65
|
pincode?: string;
|
|
66
66
|
};
|
|
67
|
-
/** How the buyer reaches the seller (chat | phone | both). */
|
|
68
|
-
contactMethod?: "chat" | "phone" | "both";
|
|
69
67
|
/** Seller offers shipping in addition to meetup. */
|
|
70
68
|
acceptsShipping?: boolean;
|
|
71
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* Price is negotiable — UI hints "₹X (negotiable)".
|
|
71
|
+
*
|
|
72
|
+
* Its sibling `allowOffers` is what actually gates the offer FLOOR on this
|
|
73
|
+
* type: unset means the buyer may still request to buy, but only at the
|
|
74
|
+
* asking price.
|
|
75
|
+
*/
|
|
72
76
|
negotiable?: boolean;
|
|
73
77
|
}
|
|
74
78
|
export interface ProductDigitalCodeMeta {
|
|
@@ -110,6 +110,9 @@ export const productFeatureFormSchema = z.object({
|
|
|
110
110
|
storeId: annotate(productFeatureAdminCreateSchema.shape.storeId, {
|
|
111
111
|
section: "scope", order: 4, row: "pair",
|
|
112
112
|
help: "Only used when scope is \"store\".",
|
|
113
|
+
// Hidden for a global feature, and paired with visibleValues at the
|
|
114
|
+
// payload so a store id chosen and then abandoned is not saved.
|
|
115
|
+
when: (v) => v.scope === "store",
|
|
113
116
|
}),
|
|
114
117
|
isActive: annotate(productFeatureAdminCreateSchema.shape.isActive, {
|
|
115
118
|
section: "visibility", sectionLabel: "Visibility", order: 1, row: "quarter",
|
|
@@ -5,7 +5,6 @@ import { useState } from "react";
|
|
|
5
5
|
import { Pencil, Trash2, ToggleLeft, ToggleRight } from "lucide-react";
|
|
6
6
|
import { Badge, BaseListingCard, Button, ConfirmDeleteModal, Div, IconButton, Row, Span, Stack, Text } from "../../../ui";
|
|
7
7
|
import { useLongPress } from "../../../react/hooks/useLongPress";
|
|
8
|
-
import { useFeatureFlags } from "../../../client/api/useFeatureFlags";
|
|
9
8
|
import { ACCOUNT_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
10
9
|
const CLS_TOGGLE_ON = "h-4 w-4 text-success dark:text-success";
|
|
11
10
|
const CLS_DELETE_BTN = "p-[var(--appkit-space-1-5)] text-[var(--appkit-color-text-muted)] hover:bg-error-surface dark:hover:bg-error-surface hover:text-error dark:hover:text-error transition-colors disabled:opacity-50";
|
|
@@ -102,12 +101,14 @@ export function CouponCard({ coupon, labels: labelsProp, onCopy, className = "",
|
|
|
102
101
|
const discountLabel = formatDiscount(n, labels);
|
|
103
102
|
const hasAdminActions = Boolean(onEdit || onToggleActive || onDelete);
|
|
104
103
|
// Show Claim by default on public surfaces; hide automatically when this
|
|
105
|
-
// card is being rendered with admin/CRUD actions wired.
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
104
|
+
// card is being rendered with admin/CRUD actions wired.
|
|
105
|
+
//
|
|
106
|
+
// This also consulted the `COUPONS` env feature flag, because the claim
|
|
107
|
+
// endpoint 404'd when it was off. Both flag systems were deleted 2026-08-29 —
|
|
108
|
+
// the flag was `true` in every environment, and the endpoint now answers
|
|
109
|
+
// unconditionally under its own auth — so the fetch that backed this check
|
|
110
|
+
// is gone too, along with a network request on every coupon card render.
|
|
111
|
+
const showClaim = hideClaim === undefined ? !hasAdminActions : !hideClaim;
|
|
111
112
|
const handleCopy = () => {
|
|
112
113
|
if (!n.code)
|
|
113
114
|
return;
|
|
@@ -131,10 +132,12 @@ export function CouponCard({ coupon, labels: labelsProp, onCopy, className = "",
|
|
|
131
132
|
credentials: "include",
|
|
132
133
|
body: JSON.stringify({ couponCode: n.code, source: claimSource }),
|
|
133
134
|
});
|
|
135
|
+
// An anonymous visitor gets a 401 here by design, so a failure cannot
|
|
136
|
+
// be distinguished from the expected case. The redirect below still
|
|
137
|
+
// pre-fills the code, which is what the user actually asked for.
|
|
134
138
|
}
|
|
135
139
|
catch (_err) {
|
|
136
140
|
void normalizeError(_err);
|
|
137
|
-
/* anon/network — non-fatal */
|
|
138
141
|
}
|
|
139
142
|
if (typeof window !== "undefined") {
|
|
140
143
|
window.location.href = `/cart?coupon=${encodeURIComponent(n.code)}`;
|
|
@@ -10,6 +10,7 @@ import { serverLogger } from "../../../monitoring";
|
|
|
10
10
|
import { maskPublicReview } from "../../../security";
|
|
11
11
|
import { finalizeStagedMediaArray, finalizeStagedMediaUrl, } from "../../media/finalize";
|
|
12
12
|
import { reviewRepository } from "../repository/reviews.repository";
|
|
13
|
+
import { safeRead } from "../../../errors/safe-read";
|
|
13
14
|
import { productRepository } from "../../products/repository/products.repository";
|
|
14
15
|
import { ProductStatusValues } from "../../products/schemas";
|
|
15
16
|
import { userRepository } from "../../auth/repository/user.repository";
|
|
@@ -185,7 +186,13 @@ export async function listReviewsBySeller(sellerId) {
|
|
|
185
186
|
}
|
|
186
187
|
const reviewBatches = await Promise.all(productIds
|
|
187
188
|
.slice(0, 20)
|
|
188
|
-
|
|
189
|
+
// One product's reviews failing must not empty the whole seller feed —
|
|
190
|
+
// but it silently thins it, so each miss is recorded.
|
|
191
|
+
.map((id) => safeRead(() => reviewRepository.findApprovedByProduct(id, 50), {
|
|
192
|
+
route: "reviews.bySeller",
|
|
193
|
+
key: "reviews.findApprovedByProduct",
|
|
194
|
+
fallback: [],
|
|
195
|
+
})));
|
|
189
196
|
// Each per-product batch is newest-first, but concatenating them yields product order,
|
|
190
197
|
// not chronological order — the flattened list has to be re-sorted or callers get an
|
|
191
198
|
// arbitrarily interleaved "latest reviews" list.
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import Link from "next/link";
|
|
3
3
|
import { reviewRepository } from "../../../repositories";
|
|
4
|
+
import { safeRead } from "../../../errors/safe-read";
|
|
4
5
|
import { Container, Div, Grid, Heading, Main, Nav, Section, Span, Text } from "../../../ui";
|
|
5
6
|
import { ROUTES } from "../../../next";
|
|
6
7
|
import { ReviewDetailShell } from "./ReviewDetailShell";
|
|
7
8
|
import { ReviewCard } from "./ReviewsList";
|
|
8
9
|
export async function ReviewDetailPageView({ id }) {
|
|
9
|
-
|
|
10
|
+
// The review IS this page's subject — a read failure must surface rather than
|
|
11
|
+
// become the same `null` a removed review produces, which the "Review not
|
|
12
|
+
// found" branch below already handles.
|
|
13
|
+
const doc = await reviewRepository.findById(id);
|
|
10
14
|
const review = doc;
|
|
11
15
|
// storeId === storeSlug for stores in this project (pure slug IDs)
|
|
12
16
|
const storeSlug = doc?.storeId ?? null;
|
|
@@ -15,8 +19,14 @@ export async function ReviewDetailPageView({ id }) {
|
|
|
15
19
|
}
|
|
16
20
|
const [sameProductDocs, sameStoreDocs] = await Promise.all([
|
|
17
21
|
// 12 = the 6 rendered below, with headroom for the current review + any filtered out.
|
|
18
|
-
reviewRepository.findApprovedByProduct(review.productId, 12)
|
|
19
|
-
|
|
22
|
+
safeRead(() => reviewRepository.findApprovedByProduct(review.productId, 12), {
|
|
23
|
+
route: "/reviews/[id]", key: "review.sameProduct", fallback: [],
|
|
24
|
+
}),
|
|
25
|
+
storeSlug
|
|
26
|
+
? safeRead(() => reviewRepository.findApprovedByStore(storeSlug), {
|
|
27
|
+
route: "/reviews/[id]", key: "review.sameStore", fallback: [],
|
|
28
|
+
})
|
|
29
|
+
: Promise.resolve([]),
|
|
20
30
|
]);
|
|
21
31
|
const sameProductReviews = sameProductDocs.filter((r) => r.id !== review.id).slice(0, 6);
|
|
22
32
|
const sameStoreReviews = sameStoreDocs.filter((r) => r.id !== review.id).slice(0, 6);
|
|
@@ -80,10 +80,12 @@ export function ReviewDetailShell({ review, storeHref }) {
|
|
|
80
80
|
}
|
|
81
81
|
setVoted(true);
|
|
82
82
|
localStorage.setItem(storageKey, "1");
|
|
83
|
+
// The button stays un-voted and the count unchanged, so the user can
|
|
84
|
+
// simply press it again — this shell has no toast host of its own, and a
|
|
85
|
+
// failed helpful-vote costs nothing.
|
|
83
86
|
}
|
|
84
87
|
catch (_err) {
|
|
85
88
|
void normalizeError(_err);
|
|
86
|
-
// silently fail
|
|
87
89
|
}
|
|
88
90
|
finally {
|
|
89
91
|
setVoting(false);
|
|
@@ -30,7 +30,15 @@ export declare function getPublicScammerById(id: string): Promise<ScammerDocumen
|
|
|
30
30
|
* Returns null if not found or not verified.
|
|
31
31
|
*/
|
|
32
32
|
export declare function getScammerProfilePageData(id: string): Promise<ScammerProfilePageData | null>;
|
|
33
|
-
|
|
33
|
+
/**
|
|
34
|
+
* `unknown` exists because `clear` is a POSITIVE SAFETY CLAIM — it renders as
|
|
35
|
+
* "✓ Verified Safe" next to a seller's name. Every read in
|
|
36
|
+
* `getSellerTrustStatus` used to fail open to `clear`, so a scam-registry
|
|
37
|
+
* outage actively endorsed a seller nobody had checked. Failing open is still
|
|
38
|
+
* right (an outage must not brand a legitimate seller a scammer), but the
|
|
39
|
+
* honest failure state is "we could not check", not "we checked and it's fine".
|
|
40
|
+
*/
|
|
41
|
+
export type SellerTrustStatus = "clear" | "flagged" | "unknown";
|
|
34
42
|
export interface SellerTrustResult {
|
|
35
43
|
status: SellerTrustStatus;
|
|
36
44
|
/** seoSlug of matched verified scammer profiles — links to /scams/[slug]. Empty when clear. */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use server";
|
|
2
2
|
import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
|
|
3
3
|
import { scammerRepository } from "../repository/scammer.repository";
|
|
4
|
+
import { safeRead } from "../../../errors/safe-read";
|
|
4
5
|
import { userRepository } from "../../auth/repository/user.repository";
|
|
5
6
|
import { storeRepository } from "../../stores/repository/store.repository";
|
|
6
7
|
import { safeFireAndForget } from "../../../utils/safe-fire-forget";
|
|
@@ -39,9 +40,12 @@ export async function listVerifiedScammers(searchParams) {
|
|
|
39
40
|
*/
|
|
40
41
|
export async function getPublicScammerById(id) {
|
|
41
42
|
// Try direct id lookup first; fall back to seoSlug query.
|
|
42
|
-
|
|
43
|
+
// The profile IS the caller's subject, and both lookups already return null
|
|
44
|
+
// for "no such id/slug" — swallowing a read failure into that same null would
|
|
45
|
+
// report a real outage as a missing profile.
|
|
46
|
+
let doc = await scammerRepository.findById(id);
|
|
43
47
|
if (!doc) {
|
|
44
|
-
doc = await scammerRepository.findBySeoSlug(id)
|
|
48
|
+
doc = await scammerRepository.findBySeoSlug(id);
|
|
45
49
|
}
|
|
46
50
|
if (!doc || doc.status !== "verified")
|
|
47
51
|
return null;
|
|
@@ -66,27 +70,63 @@ export async function getScammerProfilePageData(id) {
|
|
|
66
70
|
return { scammer, incidents, comments, relatedScammers, similarScamReports };
|
|
67
71
|
}
|
|
68
72
|
const TRUST_STATUS_CLEAR = { status: "clear", matchedProfileSlugs: [] };
|
|
73
|
+
const TRUST_STATUS_UNKNOWN = { status: "unknown", matchedProfileSlugs: [] };
|
|
74
|
+
/**
|
|
75
|
+
* Wrap a read so a FAILURE is distinguishable from a legitimate empty result.
|
|
76
|
+
*
|
|
77
|
+
* `safeRead` alone cannot express this: its fallback has the same type as a
|
|
78
|
+
* successful read, so `null` from a failed store lookup and `null` from a store
|
|
79
|
+
* that does not exist are the same value. Tagging the outcome is what lets the
|
|
80
|
+
* caller answer "unknown" instead of "clear".
|
|
81
|
+
*/
|
|
82
|
+
async function readTagged(fn, key) {
|
|
83
|
+
return safeRead(async () => ({ ok: true, value: await fn() }), {
|
|
84
|
+
route: "sellerTrust",
|
|
85
|
+
key,
|
|
86
|
+
fallback: { ok: false, value: null },
|
|
87
|
+
});
|
|
88
|
+
}
|
|
69
89
|
/**
|
|
70
90
|
* P-12 — resolves a store owner's phone/email against the verified (admin-published)
|
|
71
91
|
* scammer registry only. Never surfaces "under review" reports to buyers — a report
|
|
72
92
|
* that hasn't been verified must not damage a seller's storefront reputation.
|
|
73
93
|
*/
|
|
74
94
|
export async function getSellerTrustStatus(storeId) {
|
|
75
|
-
|
|
76
|
-
|
|
95
|
+
// Every read below fails OPEN to "clear" — a deliberate choice, because a
|
|
96
|
+
// registry outage must not brand a legitimate seller a scammer. But "clear"
|
|
97
|
+
// is a positive safety claim, so a failure that produces one has to be
|
|
98
|
+
// recorded rather than inferred from a silent null.
|
|
99
|
+
const store = await readTagged(() => storeRepository.findById(storeId), "sellerTrust.store");
|
|
100
|
+
if (!store.ok)
|
|
101
|
+
return TRUST_STATUS_UNKNOWN;
|
|
102
|
+
if (!store.value?.ownerId)
|
|
77
103
|
return TRUST_STATUS_CLEAR;
|
|
78
|
-
const
|
|
79
|
-
|
|
104
|
+
const ownerId = store.value.ownerId;
|
|
105
|
+
const owner = await readTagged(() => userRepository.findById(ownerId), "sellerTrust.owner");
|
|
106
|
+
if (!owner.ok)
|
|
107
|
+
return TRUST_STATUS_UNKNOWN;
|
|
108
|
+
if (!owner.value)
|
|
80
109
|
return TRUST_STATUS_CLEAR;
|
|
110
|
+
const ownerDoc = owner.value;
|
|
81
111
|
const lookups = [];
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
112
|
+
if (ownerDoc.phoneNumber) {
|
|
113
|
+
const phone = ownerDoc.phoneNumber;
|
|
114
|
+
lookups.push(() => scammerRepository.findByContactField("phones", phone));
|
|
115
|
+
}
|
|
116
|
+
if (ownerDoc.email) {
|
|
117
|
+
const email = ownerDoc.email;
|
|
118
|
+
lookups.push(() => scammerRepository.findByContactField("emails", email));
|
|
119
|
+
}
|
|
86
120
|
if (lookups.length === 0)
|
|
87
121
|
return TRUST_STATUS_CLEAR;
|
|
88
|
-
const results = await Promise.all(lookups.map((
|
|
89
|
-
|
|
122
|
+
const results = await Promise.all(lookups.map((fn) => readTagged(fn, "sellerTrust.registryLookup")));
|
|
123
|
+
// A partial answer is not an answer: if ANY registry lookup failed we cannot
|
|
124
|
+
// say the seller is clear, only that we could not check.
|
|
125
|
+
if (results.some((r) => !r.ok))
|
|
126
|
+
return TRUST_STATUS_UNKNOWN;
|
|
127
|
+
const verified = results
|
|
128
|
+
.flatMap((r) => r.value ?? [])
|
|
129
|
+
.filter((s) => s.status === "verified");
|
|
90
130
|
if (verified.length === 0)
|
|
91
131
|
return TRUST_STATUS_CLEAR;
|
|
92
132
|
return {
|
|
@@ -13,4 +13,4 @@ export interface SellerTrustBadgeProps {
|
|
|
13
13
|
* unrelated homepage-section `TrustBadge` config type in
|
|
14
14
|
* features/homepage/index.ts (marketing trust-badge icons row).
|
|
15
15
|
*/
|
|
16
|
-
export declare function SellerTrustBadge({ trust, className }: SellerTrustBadgeProps): import("react").JSX.Element;
|
|
16
|
+
export declare function SellerTrustBadge({ trust, className }: SellerTrustBadgeProps): import("react").JSX.Element | null;
|
|
@@ -13,6 +13,19 @@ import { ROUTES } from "../../../next";
|
|
|
13
13
|
* features/homepage/index.ts (marketing trust-badge icons row).
|
|
14
14
|
*/
|
|
15
15
|
export function SellerTrustBadge({ trust, className = "" }) {
|
|
16
|
+
// 🛑 `unknown` MUST be handled before the flagged fallthrough below, and must
|
|
17
|
+
// never render as "Verified Safe".
|
|
18
|
+
//
|
|
19
|
+
// Every read in getSellerTrustStatus used to fail open to "clear", so a
|
|
20
|
+
// scam-registry outage produced an explicit safety endorsement for a seller
|
|
21
|
+
// nobody had checked. Failing open is still right — an outage must not brand
|
|
22
|
+
// a legitimate seller a scammer — but the honest failure state is "we could
|
|
23
|
+
// not check", which is neither of the two claims this badge otherwise makes.
|
|
24
|
+
// Rendering nothing is deliberate: a neutral badge would still be a statement,
|
|
25
|
+
// and the absence of a badge already means "no verified match" everywhere the
|
|
26
|
+
// registry is not consulted.
|
|
27
|
+
if (trust.status === "unknown")
|
|
28
|
+
return null;
|
|
16
29
|
if (trust.status === "clear") {
|
|
17
30
|
return (_jsx(Badge, { variant: "success", className: className, children: "\u2713 Verified Safe" }));
|
|
18
31
|
}
|
|
@@ -122,10 +122,11 @@ class ScammerRepository extends BaseRepository {
|
|
|
122
122
|
await this.getCollection()
|
|
123
123
|
.doc(id)
|
|
124
124
|
.update({ [SCAMMER_FIELDS.VIEWS]: increment(1) });
|
|
125
|
+
// Fire-and-forget analytics: a lost view increment changes no rendered
|
|
126
|
+
// content, so it must never break the profile read it rides along with.
|
|
125
127
|
}
|
|
126
128
|
catch (_err) {
|
|
127
129
|
void normalizeError(_err);
|
|
128
|
-
// Fire-and-forget by design.
|
|
129
130
|
}
|
|
130
131
|
}
|
|
131
132
|
/**
|
|
@@ -138,6 +138,20 @@ export interface ScammerDocument extends BaseDocument {
|
|
|
138
138
|
* Admin records keep the uid; public page shows "Anonymous".
|
|
139
139
|
*/
|
|
140
140
|
reportedByAnon: boolean;
|
|
141
|
+
/**
|
|
142
|
+
* The reporter ticked "I confirm this report is truthful and accurate".
|
|
143
|
+
*
|
|
144
|
+
* 🛑 The form has always REQUIRED this — a `z.literal(true)` in
|
|
145
|
+
* `scamReportFormSchema` and a hard gate on submit — and never sent it. On a
|
|
146
|
+
* surface where a false report gets someone listed publicly and has account
|
|
147
|
+
* consequences for the reporter, the attestation is precisely the record you
|
|
148
|
+
* want to keep, and it existed only as a client-side gate that any direct
|
|
149
|
+
* call to the route bypassed entirely.
|
|
150
|
+
*
|
|
151
|
+
* Optional on the document so the rows written before 2026-08-29 stay valid;
|
|
152
|
+
* absent means "not recorded", which is honest, and is NOT the same as false.
|
|
153
|
+
*/
|
|
154
|
+
reporterAttested?: boolean;
|
|
141
155
|
status: ScammerStatus;
|
|
142
156
|
/** UID of admin/employee who verified or rejected. */
|
|
143
157
|
verifiedBy?: string;
|
|
@@ -342,7 +356,7 @@ export declare const SCAMMER_INDEXED_FIELDS: readonly ["status", "scamType", "sc
|
|
|
342
356
|
export declare const DEFAULT_SCAMMER_DATA: Partial<ScammerDocument>;
|
|
343
357
|
/** Max pending submissions per user — prevents spam flooding. */
|
|
344
358
|
export declare const MAX_PENDING_SCAMMER_REPORTS_PER_USER = 5;
|
|
345
|
-
export type ScammerCreateInput = Pick<ScammerDocument, "displayNames" | "phones" | "upiIds" | "emails" | "socialMedia" | "scamType" | "scamPlatform" | "description" | "amountLost" | "itemInvolved" | "evidence" | "reportedBy" | "reportedByAnon">;
|
|
359
|
+
export type ScammerCreateInput = Pick<ScammerDocument, "displayNames" | "phones" | "upiIds" | "emails" | "socialMedia" | "scamType" | "scamPlatform" | "description" | "amountLost" | "itemInvolved" | "evidence" | "reportedBy" | "reportedByAnon" | "reporterAttested">;
|
|
346
360
|
export type ScammerAdminUpdateInput = Partial<Pick<ScammerDocument, "status" | "verifiedBy" | "verifiedAt" | "verificationNote" | "relatedScammerIds" | "mergedFromIds" | "tags" | "displayNames" | "phones" | "upiIds" | "emails" | "socialMedia" | "isContested">>;
|
|
347
361
|
export declare const SCAMMER_FIELDS: {
|
|
348
362
|
readonly ID: "id";
|
|
@@ -5,7 +5,7 @@ export declare const scamReportFormSchema: z.ZodEffects<z.ZodObject<{
|
|
|
5
5
|
upiIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
6
6
|
emails: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
7
7
|
scamType: z.ZodString;
|
|
8
|
-
scamPlatform: z.
|
|
8
|
+
scamPlatform: z.ZodString;
|
|
9
9
|
amountLost: z.ZodOptional<z.ZodNumber>;
|
|
10
10
|
itemInvolved: z.ZodOptional<z.ZodString>;
|
|
11
11
|
description: z.ZodString;
|
|
@@ -15,9 +15,9 @@ export declare const scamReportFormSchema: z.ZodEffects<z.ZodObject<{
|
|
|
15
15
|
displayName: string;
|
|
16
16
|
description: string;
|
|
17
17
|
scamType: string;
|
|
18
|
+
scamPlatform: string;
|
|
18
19
|
agreed: true;
|
|
19
20
|
reportedByAnon?: boolean | undefined;
|
|
20
|
-
scamPlatform?: string | undefined;
|
|
21
21
|
amountLost?: number | undefined;
|
|
22
22
|
itemInvolved?: string | undefined;
|
|
23
23
|
phones?: string[] | undefined;
|
|
@@ -27,9 +27,9 @@ export declare const scamReportFormSchema: z.ZodEffects<z.ZodObject<{
|
|
|
27
27
|
displayName: string;
|
|
28
28
|
description: string;
|
|
29
29
|
scamType: string;
|
|
30
|
+
scamPlatform: string;
|
|
30
31
|
agreed: true;
|
|
31
32
|
reportedByAnon?: boolean | undefined;
|
|
32
|
-
scamPlatform?: string | undefined;
|
|
33
33
|
amountLost?: number | undefined;
|
|
34
34
|
itemInvolved?: string | undefined;
|
|
35
35
|
phones?: string[] | undefined;
|
|
@@ -39,9 +39,9 @@ export declare const scamReportFormSchema: z.ZodEffects<z.ZodObject<{
|
|
|
39
39
|
displayName: string;
|
|
40
40
|
description: string;
|
|
41
41
|
scamType: string;
|
|
42
|
+
scamPlatform: string;
|
|
42
43
|
agreed: true;
|
|
43
44
|
reportedByAnon?: boolean | undefined;
|
|
44
|
-
scamPlatform?: string | undefined;
|
|
45
45
|
amountLost?: number | undefined;
|
|
46
46
|
itemInvolved?: string | undefined;
|
|
47
47
|
phones?: string[] | undefined;
|
|
@@ -51,9 +51,9 @@ export declare const scamReportFormSchema: z.ZodEffects<z.ZodObject<{
|
|
|
51
51
|
displayName: string;
|
|
52
52
|
description: string;
|
|
53
53
|
scamType: string;
|
|
54
|
+
scamPlatform: string;
|
|
54
55
|
agreed: true;
|
|
55
56
|
reportedByAnon?: boolean | undefined;
|
|
56
|
-
scamPlatform?: string | undefined;
|
|
57
57
|
amountLost?: number | undefined;
|
|
58
58
|
itemInvolved?: string | undefined;
|
|
59
59
|
phones?: string[] | undefined;
|
|
@@ -45,8 +45,17 @@ export const scamReportFormSchema = z
|
|
|
45
45
|
scamType: annotate(z.string().trim().min(1, "Choose what kind of scam this was."), {
|
|
46
46
|
section: "what", sectionLabel: "What happened", sectionRequired: true, quick: true, order: 1, row: "pair",
|
|
47
47
|
}),
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
/*
|
|
49
|
+
* Required, matching `POST /api/scams/reports` (`z.string().min(1)`).
|
|
50
|
+
*
|
|
51
|
+
* It was `.optional()` here, so a report with no platform passed every
|
|
52
|
+
* client check and came back a 400. The page papered over it with a
|
|
53
|
+
* hand-written `if (!form.scamType || !form.scamPlatform)` guard — which is
|
|
54
|
+
* the same drift as the address postal rule: two rules for one field, and
|
|
55
|
+
* the looser one is the client's.
|
|
56
|
+
*/
|
|
57
|
+
scamPlatform: annotate(z.string().trim().min(1, "Choose where this happened.").max(120), {
|
|
58
|
+
section: "what", order: 2, row: "pair", kind: "select",
|
|
50
59
|
}),
|
|
51
60
|
/*
|
|
52
61
|
* Coerced and bounded. It arrives from a text input and is rendered on the
|
|
@@ -62,10 +71,16 @@ export const scamReportFormSchema = z
|
|
|
62
71
|
itemInvolved: annotate(z.string().trim().max(200).optional(), {
|
|
63
72
|
section: "what", order: 4, row: "pair",
|
|
64
73
|
}),
|
|
74
|
+
/*
|
|
75
|
+
* 100, matching the route. It was 30 here, so a 31-character description
|
|
76
|
+
* satisfied every client check and came back a 400 — and the page's own
|
|
77
|
+
* hand-written guard used 100, which is the number that was actually
|
|
78
|
+
* enforced. Two rules, three values.
|
|
79
|
+
*/
|
|
65
80
|
description: annotate(z
|
|
66
81
|
.string()
|
|
67
82
|
.trim()
|
|
68
|
-
.min(
|
|
83
|
+
.min(100, "Describe what happened in at least 100 characters — this is the evidence.")
|
|
69
84
|
.max(5000, "Keep the description under 5000 characters."), { section: "what", order: 5, row: "full", kind: "textarea" }),
|
|
70
85
|
reportedByAnon: annotate(z.boolean().optional(), {
|
|
71
86
|
section: "declare", sectionLabel: "Declaration", order: 1, row: "quarter",
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { NavPortal, SidebarNavGroup } from "../../../_internal/shared/features/layout/types";
|
|
2
|
+
import type { ActionIndexEntry } from "./types";
|
|
3
|
+
/** A nav group set, with the portal it belongs to. */
|
|
4
|
+
export interface PortalNavGroups {
|
|
5
|
+
portal: NavPortal;
|
|
6
|
+
/** Human name for the breadcrumb — "Admin", "Seller", "Account". */
|
|
7
|
+
portalLabel: string;
|
|
8
|
+
groups: readonly SidebarNavGroup[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Every sidebar entry, as an index entry.
|
|
12
|
+
*
|
|
13
|
+
* `sectionPath` is the breadcrumb a result row shows — "Admin › System › Site
|
|
14
|
+
* Settings" — and it is the reason the group title is worth carrying: two
|
|
15
|
+
* portals both have "Orders", and without the path a result list shows the
|
|
16
|
+
* same word twice with no way to tell which one you want.
|
|
17
|
+
*/
|
|
18
|
+
export declare function deriveNavEntries(sources: readonly PortalNavGroups[]): ActionIndexEntry[];
|
|
19
|
+
/** One quick action, as the registry stores it. */
|
|
20
|
+
export interface QuickActionSource {
|
|
21
|
+
id: string;
|
|
22
|
+
label: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
keywords?: string[];
|
|
25
|
+
href?: string;
|
|
26
|
+
routeKey?: string;
|
|
27
|
+
iconKey?: string;
|
|
28
|
+
requiredPermission?: string;
|
|
29
|
+
requiredRole?: string;
|
|
30
|
+
requiresAuth?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Quick actions, as index entries.
|
|
34
|
+
*
|
|
35
|
+
* 🛑 An action with no resolvable href is DROPPED, not indexed with a blank
|
|
36
|
+
* one. `DASHBOARD_QUICK_ACTION_META`'s `routeKey` is dead — every page
|
|
37
|
+
* re-declares its own `*_QUICK_ACTION_HREFS` map instead — so a registry entry
|
|
38
|
+
* may genuinely have nowhere to go. Indexing it anyway produces a search
|
|
39
|
+
* result that does nothing when clicked, which is worse than not finding it.
|
|
40
|
+
*/
|
|
41
|
+
export declare function deriveQuickActionEntries(actions: readonly QuickActionSource[], portal: NavPortal, portalLabel: string, hrefFor: (action: QuickActionSource) => string | undefined): ActionIndexEntry[];
|
|
42
|
+
/**
|
|
43
|
+
* Assemble the static base.
|
|
44
|
+
*
|
|
45
|
+
* Deduplicated by id, first writer winning, so a quick action that shares an
|
|
46
|
+
* id with a nav entry does not produce two rows for one destination — and the
|
|
47
|
+
* nav entry, being passed first, is the one that survives.
|
|
48
|
+
*/
|
|
49
|
+
export declare function buildActionIndexBase(...groups: readonly ActionIndexEntry[][]): ActionIndexEntry[];
|