@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
|
@@ -153,50 +153,6 @@ export const notificationQueryHelpers = {
|
|
|
153
153
|
],
|
|
154
154
|
byType: (type) => ["type", "==", type],
|
|
155
155
|
};
|
|
156
|
-
export const CHAT_ROOM_COLLECTION = "chatRooms";
|
|
157
|
-
export const CHAT_ROOM_INDEXED_FIELDS = [
|
|
158
|
-
"buyerId",
|
|
159
|
-
"ownerId",
|
|
160
|
-
"orderId",
|
|
161
|
-
"participantIds",
|
|
162
|
-
"adminDeleted",
|
|
163
|
-
"updatedAt",
|
|
164
|
-
];
|
|
165
|
-
export const CHAT_ROOM_FIELDS = {
|
|
166
|
-
ID: "id",
|
|
167
|
-
BUYER_ID: "buyerId",
|
|
168
|
-
OWNER_ID: "ownerId",
|
|
169
|
-
ORDER_ID: "orderId",
|
|
170
|
-
PRODUCT_ID: "productId",
|
|
171
|
-
PRODUCT_TITLE: "productTitle",
|
|
172
|
-
BUYER_NAME: "buyerName",
|
|
173
|
-
OWNER_NAME: "ownerName",
|
|
174
|
-
LAST_MESSAGE: "lastMessage",
|
|
175
|
-
LAST_MESSAGE_AT: "lastMessageAt",
|
|
176
|
-
CREATED_AT: "createdAt",
|
|
177
|
-
UPDATED_AT: "updatedAt",
|
|
178
|
-
DELETED_BY: "deletedBy",
|
|
179
|
-
IS_GROUP: "isGroup",
|
|
180
|
-
PARTICIPANT_IDS: "participantIds",
|
|
181
|
-
ADMIN_DELETED: "adminDeleted",
|
|
182
|
-
};
|
|
183
|
-
export const DEFAULT_CHAT_ROOM_DATA = {
|
|
184
|
-
buyerId: "",
|
|
185
|
-
ownerId: "",
|
|
186
|
-
orderId: "",
|
|
187
|
-
buyerName: "",
|
|
188
|
-
ownerName: "",
|
|
189
|
-
deletedBy: [],
|
|
190
|
-
isGroup: false,
|
|
191
|
-
participantIds: [],
|
|
192
|
-
adminDeleted: false,
|
|
193
|
-
};
|
|
194
|
-
export const chatRoomQueryHelpers = {
|
|
195
|
-
byBuyer: (buyerId) => ["buyerId", "==", buyerId],
|
|
196
|
-
byOwner: (ownerId) => ["ownerId", "==", ownerId],
|
|
197
|
-
byOrder: (orderId) => ["orderId", "==", orderId],
|
|
198
|
-
active: () => ["adminDeleted", "==", false],
|
|
199
|
-
};
|
|
200
156
|
export const DEFAULT_NOTIFICATION_CHANNELS = {
|
|
201
157
|
inApp: { enabled: true, readOnly: true },
|
|
202
158
|
email: { enabled: false, minPriority: "normal" },
|
|
@@ -212,6 +168,11 @@ const PRIORITY_ORDER = {
|
|
|
212
168
|
export function meetsMinPriority(priority, minPriority = "normal") {
|
|
213
169
|
return PRIORITY_ORDER[priority] >= PRIORITY_ORDER[minPriority];
|
|
214
170
|
}
|
|
171
|
+
// `FeatureFlagKey` / `FeatureFlagMeta` / `FEATURE_FLAG_META` were deleted with
|
|
172
|
+
// the `featureFlags` group on 2026-08-29. They described 14 toggles of which 11
|
|
173
|
+
// had no reader anywhere — an admin could switch "Wishlists" or "Reviews" off
|
|
174
|
+
// and watch nothing happen, which is worse than the feature not being
|
|
175
|
+
// configurable at all.
|
|
215
176
|
export const SITE_SETTINGS_COLLECTION = "siteSettings";
|
|
216
177
|
export const SITE_SETTINGS_INDEXED_FIELDS = [];
|
|
217
178
|
/**
|
|
@@ -235,6 +196,8 @@ export const DEFAULT_SITE_SETTINGS_DATA = {
|
|
|
235
196
|
upiManualEnabled: true,
|
|
236
197
|
codEnabled: true,
|
|
237
198
|
otpCheckoutThreshold: 5000,
|
|
199
|
+
smsVerification: false,
|
|
200
|
+
adminCheckoutBypass: false,
|
|
238
201
|
},
|
|
239
202
|
emi: {
|
|
240
203
|
enabled: false,
|
|
@@ -293,35 +256,22 @@ export const DEFAULT_SITE_SETTINGS_DATA = {
|
|
|
293
256
|
autoExtendWindowMinutes: 5,
|
|
294
257
|
settlementGracePeriodHours: 24,
|
|
295
258
|
},
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
smsVerification: false,
|
|
303
|
-
translations: true,
|
|
304
|
-
wishlists: true,
|
|
305
|
-
auctions: true,
|
|
306
|
-
reviews: true,
|
|
307
|
-
events: true,
|
|
308
|
-
blog: true,
|
|
309
|
-
coupons: true,
|
|
310
|
-
notifications: true,
|
|
311
|
-
sellerRegistration: true,
|
|
312
|
-
preOrders: true,
|
|
313
|
-
offers: true,
|
|
314
|
-
// W1-37 2026-05-23 — Phase 2 listing types enabled by default; all per-type
|
|
315
|
-
// surfaces (seller + admin via W1-29 + public) are now shipped.
|
|
259
|
+
// Every type on by default. `isListingTypeEnabled` treats a MISSING key as
|
|
260
|
+
// enabled, so this block is documentation of the full set rather than the
|
|
261
|
+
// mechanism — a type absent here still renders. `art` and `stickers` were
|
|
262
|
+
// missing from the old `featureFlags.listingTypes` literal for exactly that
|
|
263
|
+
// reason: nothing broke, so nobody noticed (Root Cause #58).
|
|
264
|
+
listings: {
|
|
316
265
|
listingTypes: {
|
|
317
266
|
standard: true,
|
|
318
267
|
auction: true,
|
|
319
268
|
"pre-order": true,
|
|
320
269
|
"prize-draw": true,
|
|
321
|
-
bundle: true,
|
|
322
270
|
classified: true,
|
|
323
271
|
"digital-code": true,
|
|
324
272
|
live: true,
|
|
273
|
+
art: true,
|
|
274
|
+
stickers: true,
|
|
325
275
|
},
|
|
326
276
|
categoryTypes: {
|
|
327
277
|
category: true,
|
|
@@ -371,89 +321,3 @@ export const DEFAULT_TRUST_BAR_ITEMS = [
|
|
|
371
321
|
// NOTE: labelKey/descKey hold plain display text (not i18n message keys) —
|
|
372
322
|
// this feature-flag list has no matching next-intl namespace, so the admin
|
|
373
323
|
// UI reads these two fields directly rather than through getTranslations().
|
|
374
|
-
export const FEATURE_FLAG_META = [
|
|
375
|
-
{
|
|
376
|
-
key: "chats",
|
|
377
|
-
labelKey: "In-app chats",
|
|
378
|
-
descKey: "Buyer/seller direct messaging.",
|
|
379
|
-
icon: "\u{1F4AC}",
|
|
380
|
-
category: "platform",
|
|
381
|
-
},
|
|
382
|
-
{
|
|
383
|
-
key: "smsVerification",
|
|
384
|
-
labelKey: "SMS verification",
|
|
385
|
-
descKey: "Phone-number OTP verification during signup/checkout.",
|
|
386
|
-
icon: "\u{1F4F1}",
|
|
387
|
-
category: "platform",
|
|
388
|
-
},
|
|
389
|
-
{
|
|
390
|
-
key: "translations",
|
|
391
|
-
labelKey: "Translations",
|
|
392
|
-
descKey: "Locale switcher and translated UI strings.",
|
|
393
|
-
icon: "\u{1F310}",
|
|
394
|
-
category: "platform",
|
|
395
|
-
},
|
|
396
|
-
{
|
|
397
|
-
key: "auctions",
|
|
398
|
-
labelKey: "Auctions",
|
|
399
|
-
descKey: "Auction listings and bidding.",
|
|
400
|
-
icon: "\u{1F528}",
|
|
401
|
-
category: "platform",
|
|
402
|
-
},
|
|
403
|
-
{
|
|
404
|
-
key: "reviews",
|
|
405
|
-
labelKey: "Reviews",
|
|
406
|
-
descKey: "Product and store reviews.",
|
|
407
|
-
icon: "⭐",
|
|
408
|
-
category: "platform",
|
|
409
|
-
},
|
|
410
|
-
{
|
|
411
|
-
key: "notifications",
|
|
412
|
-
labelKey: "Notifications",
|
|
413
|
-
descKey: "In-app notification bell and inbox.",
|
|
414
|
-
icon: "\u{1F514}",
|
|
415
|
-
category: "platform",
|
|
416
|
-
},
|
|
417
|
-
{
|
|
418
|
-
key: "sellerRegistration",
|
|
419
|
-
labelKey: "Seller registration",
|
|
420
|
-
descKey: "\"Become a seller\" signup flow.",
|
|
421
|
-
icon: "\u{1F3EA}",
|
|
422
|
-
category: "platform",
|
|
423
|
-
},
|
|
424
|
-
{
|
|
425
|
-
key: "preOrders",
|
|
426
|
-
labelKey: "Pre-orders",
|
|
427
|
-
descKey: "Pre-order listings and deposit checkout.",
|
|
428
|
-
icon: "\u{1F4E6}",
|
|
429
|
-
category: "platform",
|
|
430
|
-
},
|
|
431
|
-
{
|
|
432
|
-
key: "wishlists",
|
|
433
|
-
labelKey: "Wishlists",
|
|
434
|
-
descKey: "Save-for-later wishlist feature.",
|
|
435
|
-
icon: "❤️",
|
|
436
|
-
category: "platform",
|
|
437
|
-
},
|
|
438
|
-
{
|
|
439
|
-
key: "events",
|
|
440
|
-
labelKey: "Events",
|
|
441
|
-
descKey: "Sales, raffles, spin-wheel, and lottery events.",
|
|
442
|
-
icon: "\u{1F389}",
|
|
443
|
-
category: "platform",
|
|
444
|
-
},
|
|
445
|
-
{
|
|
446
|
-
key: "blog",
|
|
447
|
-
labelKey: "Blog",
|
|
448
|
-
descKey: "Blog posts section.",
|
|
449
|
-
icon: "\u{1F4DD}",
|
|
450
|
-
category: "platform",
|
|
451
|
-
},
|
|
452
|
-
{
|
|
453
|
-
key: "coupons",
|
|
454
|
-
labelKey: "Coupons",
|
|
455
|
-
descKey: "Coupon codes and discounts.",
|
|
456
|
-
icon: "\u{1F3AB}",
|
|
457
|
-
category: "platform",
|
|
458
|
-
},
|
|
459
|
-
];
|
|
@@ -53,9 +53,16 @@ export const navItemFormSchema = z.object({
|
|
|
53
53
|
section: "basics", sectionLabel: "Nav item", sectionRequired: true,
|
|
54
54
|
quick: true, order: 1, row: "pair",
|
|
55
55
|
}),
|
|
56
|
-
href: annotate(hrefSchema, {
|
|
56
|
+
href: annotate(hrefSchema, {
|
|
57
|
+
section: "basics", quick: true, order: 2, row: "pair",
|
|
58
|
+
label: "URL / href",
|
|
59
|
+
// On the schema rather than the control, so every surface that renders this
|
|
60
|
+
// field gets it — the editor used to carry it as a local `helperText`.
|
|
61
|
+
help: "Use relative paths (e.g. /products) or full URLs.",
|
|
62
|
+
}),
|
|
57
63
|
icon: annotate(z.string().max(60).optional(), {
|
|
58
|
-
section: "basics", order: 3, row: "pair",
|
|
64
|
+
section: "basics", order: 3, row: "pair", kind: "select",
|
|
65
|
+
label: "Icon (optional)",
|
|
59
66
|
}),
|
|
60
67
|
order: annotate(z.coerce.number().int("Order must be a whole number.").min(0, "Order cannot be negative.").optional(), { section: "placement", sectionLabel: "Placement", order: 1, row: "pair" }),
|
|
61
68
|
parentId: annotate(z.string().max(80).optional(), {
|
|
@@ -5,11 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export * from "./actions";
|
|
7
7
|
export { notificationRepository } from "./repository/notification.repository";
|
|
8
|
-
export { chatRepository } from "./repository/chat.repository";
|
|
9
8
|
export { contactSubmissionsRepository } from "../../core/contact-submissions.repository";
|
|
10
|
-
export type { ContactSubmissionDocument, ContactSubmissionCreateInput } from "../../core/contact-submissions.repository";
|
|
11
|
-
export { newsletterRepository } from "../../core/newsletter.repository";
|
|
12
|
-
export type { ChatRoomDocument, ChatRoomCreateInput, } from "./repository/chat.repository";
|
|
13
9
|
export { siteSettingsRepository } from "./repository/site-settings.repository";
|
|
14
10
|
export { GET as adminProductsGET } from "./api/products/route";
|
|
15
11
|
export { GET as adminCouponsGET } from "./api/coupons/route";
|
|
@@ -5,9 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export * from "./actions";
|
|
7
7
|
export { notificationRepository } from "./repository/notification.repository";
|
|
8
|
-
export { chatRepository } from "./repository/chat.repository";
|
|
9
8
|
export { contactSubmissionsRepository } from "../../core/contact-submissions.repository";
|
|
10
|
-
export { newsletterRepository } from "../../core/newsletter.repository";
|
|
11
9
|
export { siteSettingsRepository } from "./repository/site-settings.repository";
|
|
12
10
|
export { GET as adminProductsGET } from "./api/products/route";
|
|
13
11
|
export { GET as adminCouponsGET } from "./api/coupons/route";
|
|
@@ -27,13 +27,6 @@ export interface AdminListParams {
|
|
|
27
27
|
sort?: string;
|
|
28
28
|
filters?: string;
|
|
29
29
|
}
|
|
30
|
-
export interface AdminListResponse<T> {
|
|
31
|
-
items: T[];
|
|
32
|
-
total: number;
|
|
33
|
-
page: number;
|
|
34
|
-
perPage: number;
|
|
35
|
-
totalPages: number;
|
|
36
|
-
}
|
|
37
30
|
export interface AnalyticsMonthEntry {
|
|
38
31
|
month: string;
|
|
39
32
|
orders: number;
|
|
@@ -28,5 +28,19 @@ export declare class PageViewsRepository extends BaseRepository<PageViewDocument
|
|
|
28
28
|
/** All day-buckets in [startDate, endDate] (inclusive, YYYY-MM-DD), optionally
|
|
29
29
|
* scoped to one entityType. Used by the admin page-views report tab. */
|
|
30
30
|
listInRange(startDate: string, endDate: string, entityType?: PageViewEntityType): Promise<PageViewDocument[]>;
|
|
31
|
+
/**
|
|
32
|
+
* Day-buckets older than `days`, as refs for `batchDelete`.
|
|
33
|
+
*
|
|
34
|
+
* 🛑 This collection had NO prune and NO rollup until 2026-08-31. It writes
|
|
35
|
+
* one document per entity per day, forever, and 27 scheduled functions
|
|
36
|
+
* existed without one of them touching it — so its growth was bounded only by
|
|
37
|
+
* how many distinct pages the catalogue had times how long the site had been
|
|
38
|
+
* up. See `pageViewPrune`.
|
|
39
|
+
*
|
|
40
|
+
* Returns refs rather than documents, matching `getOldReadRefs` on
|
|
41
|
+
* notifications: a prune needs the id, and hydrating the body of every doc it
|
|
42
|
+
* is about to delete is read budget spent on nothing (Rule #6).
|
|
43
|
+
*/
|
|
44
|
+
getOlderThanRefs(days: number): Promise<FirebaseFirestore.DocumentReference[]>;
|
|
31
45
|
}
|
|
32
46
|
export declare const pageViewsRepository: PageViewsRepository;
|
|
@@ -39,5 +39,29 @@ export class PageViewsRepository extends BaseRepository {
|
|
|
39
39
|
const snap = await query.get();
|
|
40
40
|
return snap.docs.map((d) => this.mapDoc(d));
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Day-buckets older than `days`, as refs for `batchDelete`.
|
|
44
|
+
*
|
|
45
|
+
* 🛑 This collection had NO prune and NO rollup until 2026-08-31. It writes
|
|
46
|
+
* one document per entity per day, forever, and 27 scheduled functions
|
|
47
|
+
* existed without one of them touching it — so its growth was bounded only by
|
|
48
|
+
* how many distinct pages the catalogue had times how long the site had been
|
|
49
|
+
* up. See `pageViewPrune`.
|
|
50
|
+
*
|
|
51
|
+
* Returns refs rather than documents, matching `getOldReadRefs` on
|
|
52
|
+
* notifications: a prune needs the id, and hydrating the body of every doc it
|
|
53
|
+
* is about to delete is read budget spent on nothing (Rule #6).
|
|
54
|
+
*/
|
|
55
|
+
async getOlderThanRefs(days) {
|
|
56
|
+
const cutoff = new Date();
|
|
57
|
+
cutoff.setUTCDate(cutoff.getUTCDate() - days);
|
|
58
|
+
const cutoffKey = cutoff.toISOString().slice(0, 10);
|
|
59
|
+
// `<` and not `<=`: the cutoff day itself is still inside the window.
|
|
60
|
+
const snap = await this.getCollection()
|
|
61
|
+
.where(PAGE_VIEW_FIELDS.DATE, "<", cutoffKey)
|
|
62
|
+
.select()
|
|
63
|
+
.get();
|
|
64
|
+
return snap.docs.map((d) => d.ref);
|
|
65
|
+
}
|
|
42
66
|
}
|
|
43
67
|
export const pageViewsRepository = new PageViewsRepository();
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* page-views.repository.ts (server-only, imports firebase-admin) so the
|
|
3
3
|
* client-side tracker component can import just this without pulling
|
|
4
4
|
* firebase-admin into the client bundle. */
|
|
5
|
-
export declare const PAGE_VIEW_ENTITY_TYPES: readonly ["product", "store", "category", "homepage", "auction", "review", "user-profile", "blog", "event", "pre-order", "prize-draw", "classified", "digital-code", "live", "bundle", "grouped-listing"];
|
|
5
|
+
export declare const PAGE_VIEW_ENTITY_TYPES: readonly ["product", "store", "category", "homepage", "auction", "review", "user-profile", "blog", "event", "pre-order", "prize-draw", "classified", "digital-code", "live", "bundle", "grouped-listing", "listing"];
|
|
6
6
|
export type PageViewEntityType = (typeof PAGE_VIEW_ENTITY_TYPES)[number];
|
|
@@ -21,4 +21,17 @@ export const PAGE_VIEW_ENTITY_TYPES = [
|
|
|
21
21
|
/** A `groupedListings` document's own page. Distinct from "bundle" — a
|
|
22
22
|
* bundle is a priced, all-or-nothing set; a group is pick-as-you-wish. */
|
|
23
23
|
"grouped-listing",
|
|
24
|
+
/**
|
|
25
|
+
* A public BROWSE page — `/products`, `/auctions`, `/stores`, … — as opposed
|
|
26
|
+
* to one entity's detail page.
|
|
27
|
+
*
|
|
28
|
+
* 🛑 `entityId` must be the bare route name ("products"), NEVER the filtered
|
|
29
|
+
* URL. `pageViews` doc ids are `${date}_${entityType}_${entityId}` with a
|
|
30
|
+
* `FieldValue.increment`, so a bounded id costs ONE write per day per page,
|
|
31
|
+
* while keying on a query string would create a new document per filter
|
|
32
|
+
* combination — unbounded doc creation on the highest-traffic pages, against
|
|
33
|
+
* the Firestore write budget in Rule #6. The full URL still travels in the
|
|
34
|
+
* `url` field, which is recorded but not part of the key.
|
|
35
|
+
*/
|
|
36
|
+
"listing",
|
|
24
37
|
];
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import Link from "next/link";
|
|
3
3
|
import { productRepository } from "../../../repositories";
|
|
4
4
|
import { listBidsByProduct } from "../../auctions/actions/bid-actions";
|
|
5
|
+
import { safeRead } from "../../../errors/safe-read";
|
|
5
6
|
const __P = {
|
|
6
7
|
p3: "p-[var(--appkit-space-3)]",
|
|
7
8
|
p4: "p-[var(--appkit-space-4)]",
|
|
@@ -62,11 +63,14 @@ function renderAuctionStoreReviews(storeSlug) {
|
|
|
62
63
|
return (_jsxs(Section, { className: "mt-10", children: [_jsx(Heading, { level: 2, className: "mb-2", color: "primary", size: "xl", weight: "semibold", children: "Store Reviews" }), _jsx(ReviewsListingPanel, { source: { kind: "store", storeSlug }, stateMode: "local", context: "store", emptyLabel: "This store has no reviews yet." })] }));
|
|
63
64
|
}
|
|
64
65
|
export async function AuctionDetailPageView({ id, initialAuction, onPlaceBid, onBuyNow, productFeatures }) {
|
|
66
|
+
// The auction IS this page's subject. A read failure must surface rather than
|
|
67
|
+
// become the same `undefined` a genuinely missing slug produces — the
|
|
68
|
+
// "Auction Not Found" branch below still handles that real case.
|
|
65
69
|
const product = initialAuction !== undefined
|
|
66
70
|
? (initialAuction ?? undefined)
|
|
67
|
-
: await productRepository.findByIdOrSlug(id)
|
|
71
|
+
: await productRepository.findByIdOrSlug(id);
|
|
68
72
|
const bidsResult = product
|
|
69
|
-
? await listBidsByProduct(String(product.id), { pageSize: 5 }).
|
|
73
|
+
? await safeRead(() => listBidsByProduct(String(product.id), { pageSize: 5 }), { route: "/auctions/[slug]", key: "auction.bidHistory", fallback: null })
|
|
70
74
|
: null;
|
|
71
75
|
const storeId = product?.storeId;
|
|
72
76
|
if (!product) {
|
|
@@ -163,8 +163,10 @@ export function MarketplaceAuctionCard({ product, buyoutPrice, className = "", v
|
|
|
163
163
|
await toggle();
|
|
164
164
|
}
|
|
165
165
|
catch (_err) {
|
|
166
|
+
// useWishlistToggle rolls back its optimistic state and raises its own
|
|
167
|
+
// toast on failure, so the heart returns to its true value on screen.
|
|
168
|
+
// Reporting again here would double-notify for one user action.
|
|
166
169
|
void normalizeError(_err);
|
|
167
|
-
// The hook rolls back optimistic state when the mutation fails.
|
|
168
170
|
}
|
|
169
171
|
}, [toggle]);
|
|
170
172
|
const countdownClass = isEnded
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Auth, rate-limiting, and Next.js specifics are handled by the consumer.
|
|
6
6
|
*/
|
|
7
7
|
import { maskPublicReview } from "../../../security";
|
|
8
|
+
import { safeRead } from "../../../errors/safe-read";
|
|
8
9
|
import { finalizeStagedMediaField } from "../../media/finalize";
|
|
9
10
|
import { userRepository } from "../repository/user.repository";
|
|
10
11
|
import { sessionRepository } from "../repository/session.repository";
|
|
@@ -65,7 +66,7 @@ export async function getPublicUserProfile(userId) {
|
|
|
65
66
|
}
|
|
66
67
|
/** Fetch approved reviews for a store. storeId === storeSlug in this project. */
|
|
67
68
|
export async function getSellerReviews(storeId) {
|
|
68
|
-
const snapshot = await reviewRepository.findApprovedByStore(storeId).
|
|
69
|
+
const snapshot = await safeRead(() => reviewRepository.findApprovedByStore(storeId), { route: "/profile/[userId]", key: "reviews.findApprovedByStore", fallback: [] });
|
|
69
70
|
return snapshot.map((r) => ({
|
|
70
71
|
id: r.id,
|
|
71
72
|
productId: r.productId,
|
|
@@ -94,7 +95,7 @@ export async function getProfileStoreProducts(storeId) {
|
|
|
94
95
|
}
|
|
95
96
|
/** Approved product reviews written by this user as a buyer. Excludes seller→buyer ratings. */
|
|
96
97
|
export async function getReviewsAuthoredBy(userId) {
|
|
97
|
-
const all = await reviewRepository.findApprovedByUser(userId).
|
|
98
|
+
const all = await safeRead(() => reviewRepository.findApprovedByUser(userId), { route: "/profile/[userId]", key: "reviews.findApprovedByUser", fallback: [] });
|
|
98
99
|
// reviewerRole:"seller" means this user rated a buyer — not a product review
|
|
99
100
|
const snapshot = all.filter((r) => r.reviewerRole !== "seller");
|
|
100
101
|
return snapshot.map((r) => ({
|
|
@@ -121,7 +122,7 @@ export async function getReviewsAuthoredBy(userId) {
|
|
|
121
122
|
}
|
|
122
123
|
/** Approved seller→buyer reviews received by this buyer. */
|
|
123
124
|
export async function getReviewsReceivedBy(userId) {
|
|
124
|
-
const snapshot = await reviewRepository.findByReviewee(userId).
|
|
125
|
+
const snapshot = await safeRead(() => reviewRepository.findByReviewee(userId), { route: "/profile/[userId]", key: "reviews.findByReviewee", fallback: [] });
|
|
125
126
|
return snapshot.map((r) => ({
|
|
126
127
|
id: r.id,
|
|
127
128
|
productId: r.productId,
|
|
@@ -5,21 +5,11 @@
|
|
|
5
5
|
* Called by letitrip thin wrapper which handles auth + rate limiting.
|
|
6
6
|
*/
|
|
7
7
|
import { getAdminAuth } from "../../../providers/db-firebase/index";
|
|
8
|
-
import { chatRepository } from "../../admin/repository/chat.repository";
|
|
9
8
|
import { conversationsRepository } from "../../messages/repository/conversations.repository";
|
|
10
9
|
import { storeRepository } from "../../stores/repository/store.repository";
|
|
11
10
|
import { serverLogger } from "../../../monitoring/index";
|
|
12
11
|
import { normalizeError } from "../../../errors/normalize";
|
|
13
12
|
export async function issueRealtimeToken(userId, userRole) {
|
|
14
|
-
let chatIds = {};
|
|
15
|
-
try {
|
|
16
|
-
const userChatIds = await chatRepository.getChatIdsForUser(userId);
|
|
17
|
-
chatIds = Object.fromEntries(userChatIds.map((id) => [id, true]));
|
|
18
|
-
}
|
|
19
|
-
catch (err) {
|
|
20
|
-
void normalizeError(err);
|
|
21
|
-
serverLogger.warn("Could not resolve chatIds for realtime token", { userId, err });
|
|
22
|
-
}
|
|
23
13
|
const conversationIds = {};
|
|
24
14
|
try {
|
|
25
15
|
const buyerConvs = await conversationsRepository.listByBuyer(userId);
|
|
@@ -38,12 +28,11 @@ export async function issueRealtimeToken(userId, userRole) {
|
|
|
38
28
|
}
|
|
39
29
|
const customToken = await getAdminAuth().createCustomToken(userId, {
|
|
40
30
|
role: userRole,
|
|
41
|
-
chatIds,
|
|
42
31
|
conversationIds,
|
|
43
32
|
});
|
|
44
33
|
serverLogger.info("issueRealtimeToken: token issued", {
|
|
45
34
|
userId,
|
|
46
|
-
|
|
35
|
+
conversationCount: Object.keys(conversationIds).length,
|
|
47
36
|
});
|
|
48
37
|
return { customToken, expiresAt: Date.now() + 3600000 };
|
|
49
38
|
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { getTokenTimeRemaining, isTokenExpired } from "./token-helpers";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
admin: 3,
|
|
8
|
-
};
|
|
2
|
+
// Was a SECOND, disagreeing copy of the hierarchy (employee and moderator both
|
|
3
|
+
// ranked 2, where the canonical one puts moderator above employee), so
|
|
4
|
+
// `hasRole` gave a different answer depending on which module you imported.
|
|
5
|
+
// Deleted 2026-08-29 in favour of the one in security/authorization.
|
|
6
|
+
import { ROLE_HIERARCHY } from "../../security/authorization";
|
|
9
7
|
export function hasRole(userRole, requiredRole) {
|
|
10
8
|
return ROLE_HIERARCHY[userRole] >= ROLE_HIERARCHY[requiredRole];
|
|
11
9
|
}
|
|
@@ -22,7 +22,7 @@ export function ForgotPasswordView({ onSubmit, isLoading = false, error, success
|
|
|
22
22
|
}
|
|
23
23
|
catch (err) {
|
|
24
24
|
void normalizeError(err);
|
|
25
|
-
showToast(
|
|
25
|
+
showToast("Failed to send reset link", "error");
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
28
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useMemo } from "react";
|
|
4
|
+
import { isAccountDisabled } from "../role-predicates";
|
|
4
5
|
import { Button, Div, Heading, Row, Text } from "../../../ui";
|
|
5
6
|
export function RoleGate({ children, user, allowedRoles, fallback = null, }) {
|
|
6
7
|
if (!user?.role) {
|
|
@@ -31,7 +32,7 @@ export function ProtectedRoute({ children, user, loading = false, requireAuth =
|
|
|
31
32
|
}
|
|
32
33
|
if (user) {
|
|
33
34
|
// Check account status
|
|
34
|
-
if (requireActiveAccount && user
|
|
35
|
+
if (requireActiveAccount && isAccountDisabled(user)) {
|
|
35
36
|
return { isAuthorized: false, redirectPath: unauthorizedPath };
|
|
36
37
|
}
|
|
37
38
|
// Check email verification
|
|
@@ -2,7 +2,6 @@ import React from "react";
|
|
|
2
2
|
export interface LoginFormValues {
|
|
3
3
|
email: string;
|
|
4
4
|
password: string;
|
|
5
|
-
rememberMe?: boolean;
|
|
6
5
|
}
|
|
7
6
|
export interface LoginFormProps {
|
|
8
7
|
onSubmit: (values: LoginFormValues) => Promise<void>;
|
|
@@ -17,7 +16,6 @@ export interface LoginFormProps {
|
|
|
17
16
|
emailPlaceholder?: string;
|
|
18
17
|
passwordLabel?: string;
|
|
19
18
|
passwordPlaceholder?: string;
|
|
20
|
-
rememberMe?: string;
|
|
21
19
|
forgotPasswordLabel?: string;
|
|
22
20
|
submitLabel?: string;
|
|
23
21
|
submittingLabel?: string;
|
|
@@ -5,7 +5,6 @@ import { useState } from "react";
|
|
|
5
5
|
import { Alert, Button, Div, Heading, Row, SiteMark, Stack, Text, useToast } from "../../../ui";
|
|
6
6
|
import { Form } from "../../../ui/components/Form";
|
|
7
7
|
import { FieldInput } from "../../../ui/forms/FieldInput";
|
|
8
|
-
import { FieldCheckbox } from "../../../ui/forms/FieldCheckbox";
|
|
9
8
|
import { applyZodIssues } from "../../../ui/forms/apply-zod-issues";
|
|
10
9
|
import { loginSchema } from "../schemas";
|
|
11
10
|
import { SocialAuthButtons } from "./SocialAuthButtons";
|
|
@@ -15,9 +14,8 @@ export function LoginForm({ onSubmit, onGoogleLogin, isLoading = false, error, l
|
|
|
15
14
|
const [values, setValues] = useState({
|
|
16
15
|
email: "",
|
|
17
16
|
password: "",
|
|
18
|
-
rememberMe: false,
|
|
19
17
|
});
|
|
20
|
-
return (_jsx(Row, { className: `min-h-[60vh] ${className}`, align: "center", justify: "center", padding: "x-md", children: _jsxs(Stack, { className: "max-w-md w-full", gap: "lg", children: [_jsxs(Div, { className: "text-center", children: [_jsx(Row, { justify: "center", className: "mb-3", children: _jsx(SiteMark, { size: "lg" }) }), _jsx(Heading, { level: 1, className: "font-extrabold", size: "3xl", children: labels.title ?? "Sign In" }), (labels.subtitle || renderCreateAccountLink) && (_jsxs(Text, { className: "mt-2", color: "muted", size: "sm", children: [labels.subtitle ?? "Or", " ", renderCreateAccountLink?.()] }))] }), error && (_jsx(Alert, { variant: "error", compact: true, children: error })), _jsx(Form, { schema: loginSchema, noValidate: true, onSubmit: (e) => e.preventDefault(), spacing: "md", children: ({ setFieldError, clearErrors }) => (_jsxs(_Fragment, { children: [_jsx(FormErrorSummary, {}), _jsx(FieldInput, { name: "email", label: labels.emailLabel ?? "Email address", type: "email", autoComplete: "username", required: true, placeholder: labels.emailPlaceholder ?? "you@example.com", value: values.email, onChange: (v) => setValues({ ...values, email: v }) }), _jsx(FieldInput, { name: "password", label: labels.passwordLabel ?? "Password", type: "password", autoComplete: "current-password", required: true, placeholder: labels.passwordPlaceholder ?? "••••••••", value: values.password, onChange: (v) => setValues({ ...values, password: v }) }),
|
|
18
|
+
return (_jsx(Row, { className: `min-h-[60vh] ${className}`, align: "center", justify: "center", padding: "x-md", children: _jsxs(Stack, { className: "max-w-md w-full", gap: "lg", children: [_jsxs(Div, { className: "text-center", children: [_jsx(Row, { justify: "center", className: "mb-3", children: _jsx(SiteMark, { size: "lg" }) }), _jsx(Heading, { level: 1, className: "font-extrabold", size: "3xl", children: labels.title ?? "Sign In" }), (labels.subtitle || renderCreateAccountLink) && (_jsxs(Text, { className: "mt-2", color: "muted", size: "sm", children: [labels.subtitle ?? "Or", " ", renderCreateAccountLink?.()] }))] }), error && (_jsx(Alert, { variant: "error", compact: true, children: error })), _jsx(Form, { schema: loginSchema, noValidate: true, onSubmit: (e) => e.preventDefault(), spacing: "md", children: ({ setFieldError, clearErrors }) => (_jsxs(_Fragment, { children: [_jsx(FormErrorSummary, {}), _jsx(FieldInput, { name: "email", label: labels.emailLabel ?? "Email address", type: "email", autoComplete: "username", required: true, placeholder: labels.emailPlaceholder ?? "you@example.com", value: values.email, onChange: (v) => setValues({ ...values, email: v }) }), _jsx(FieldInput, { name: "password", label: labels.passwordLabel ?? "Password", type: "password", autoComplete: "current-password", required: true, placeholder: labels.passwordPlaceholder ?? "••••••••", value: values.password, onChange: (v) => setValues({ ...values, password: v }) }), _jsx(Row, { justify: "end", children: renderForgotPasswordLink?.() }), _jsx(Button, { type: "submit", isLoading: isLoading, disabled: isLoading, className: "w-full", onClick: async () => {
|
|
21
19
|
clearErrors();
|
|
22
20
|
const parsed = loginSchema.safeParse(values);
|
|
23
21
|
if (!parsed.success)
|
|
@@ -27,7 +25,7 @@ export function LoginForm({ onSubmit, onGoogleLogin, isLoading = false, error, l
|
|
|
27
25
|
}
|
|
28
26
|
catch (err) {
|
|
29
27
|
void normalizeError(err);
|
|
30
|
-
showToast(
|
|
28
|
+
showToast("Sign in failed", "error");
|
|
31
29
|
}
|
|
32
30
|
}, children: isLoading
|
|
33
31
|
? (labels.submittingLabel ?? "Signing in…")
|