@mohasinac/appkit 4.26.0 → 4.28.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/lottery/LotteryAdminEditView.d.ts +16 -16
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +29 -6
- package/dist/_internal/client/features/lottery/LotteryListView.js +13 -1
- package/dist/_internal/server/features/bundles/data.d.ts +19 -0
- package/dist/_internal/server/features/bundles/data.js +32 -0
- package/dist/_internal/server/features/bundles/index.d.ts +1 -1
- package/dist/_internal/server/features/bundles/index.js +1 -1
- package/dist/_internal/server/features/checkout/actions.js +6 -4
- package/dist/_internal/server/features/classified/metadata.js +3 -1
- package/dist/_internal/server/features/digital-code/metadata.js +3 -1
- package/dist/_internal/server/features/live/metadata.js +3 -1
- package/dist/_internal/server/features/refunds/actions.js +3 -2
- package/dist/_internal/server/features/reviews/actions.js +3 -2
- package/dist/_internal/server/features/seo/sitemap.js +189 -40
- package/dist/_internal/server/jobs/core/listingProcessor.d.ts +0 -1
- package/dist/_internal/server/jobs/core/listingProcessor.js +19 -1
- package/dist/_internal/shared/actions/action-registry.js +14 -0
- package/dist/_internal/shared/checkout/order-math.d.ts +25 -3
- package/dist/_internal/shared/features/checkout/config.d.ts +3 -3
- package/dist/_internal/shared/features/checkout/config.js +6 -3
- package/dist/client.d.ts +32 -2
- package/dist/client.js +37 -2
- package/dist/constants/api-endpoints.d.ts +21 -3
- package/dist/constants/api-endpoints.js +14 -1
- package/dist/constants/field-names.d.ts +2 -2
- package/dist/constants/field-names.js +2 -2
- package/dist/core/newsletter.repository.js +14 -1
- package/dist/features/about/components/FAQPageView.js +1 -1
- package/dist/features/about/components/FeesView.js +1 -1
- package/dist/features/account/components/AddressForm.d.ts +2 -0
- package/dist/features/account/components/AddressForm.js +5 -1
- package/dist/features/account/components/UserBidsView.js +1 -1
- package/dist/features/account/components/UserSidebar.js +1 -1
- package/dist/features/account/components/UserSupportView.js +24 -2
- package/dist/features/account/hooks/useAddresses.d.ts +29 -1
- package/dist/features/account/hooks/useAddresses.js +4 -1
- package/dist/features/account/hooks/useProfile.d.ts +1 -1
- package/dist/features/account/hooks/useProfile.js +1 -1
- package/dist/features/addresses/repository/addresses.repository.d.ts +13 -0
- package/dist/features/addresses/repository/addresses.repository.js +19 -0
- package/dist/features/admin/actions/chat-actions.js +5 -1
- package/dist/features/admin/components/AdminAdsView.js +1 -1
- package/dist/features/admin/components/AdminBidsView.js +6 -1
- package/dist/features/admin/components/AdminCarouselGroupEditorView.d.ts +9 -1
- package/dist/features/admin/components/AdminCarouselGroupEditorView.js +42 -10
- package/dist/features/admin/components/AdminCarouselView.js +1 -1
- package/dist/features/admin/components/AdminFeatureEditorView.js +1 -1
- package/dist/features/admin/components/AdminGroupedListingsView.js +14 -2
- package/dist/features/admin/components/AdminSidebar.js +1 -1
- package/dist/features/admin/components/AdminViewCards.js +2 -2
- package/dist/features/admin/components/DataTable.js +2 -2
- package/dist/features/admin/schemas/firestore.js +9 -3
- package/dist/features/auctions/actions/bid-actions.js +45 -4
- package/dist/features/auctions/components/AuctionBottomActions.d.ts +21 -6
- package/dist/features/auctions/components/AuctionBottomActions.js +42 -11
- package/dist/features/auctions/components/AuctionDetailPageView.d.ts +8 -3
- package/dist/features/auctions/components/AuctionDetailPageView.js +2 -2
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +4 -5
- package/dist/features/auctions/components/PlaceBidFormClient.d.ts +27 -2
- package/dist/features/auctions/components/PlaceBidFormClient.js +42 -20
- package/dist/features/auth/components/SocialAuthButtons.js +1 -1
- package/dist/features/auth/hooks/useAuth.d.ts +23 -1
- package/dist/features/auth/hooks/useAuth.js +27 -1
- package/dist/features/auth/permissions/constants.d.ts +1 -1
- package/dist/features/auth/permissions/constants.js +3 -0
- package/dist/features/auth/repository/session.repository.d.ts +16 -1
- package/dist/features/auth/repository/session.repository.js +23 -0
- package/dist/features/auth/repository/user.repository.js +13 -2
- package/dist/features/blog/components/BlogListView.js +2 -2
- package/dist/features/cart/components/CartPriceBreakdown.d.ts +11 -1
- package/dist/features/cart/components/CartPriceBreakdown.js +3 -3
- package/dist/features/cart/components/StoreAddonsPicker.d.ts +9 -0
- package/dist/features/cart/components/StoreAddonsPicker.js +15 -5
- package/dist/features/cart/components/index.d.ts +1 -1
- package/dist/features/cart/components/index.js +1 -1
- package/dist/features/cart/hooks/useGuestCartMerge.d.ts +8 -1
- package/dist/features/cart/hooks/useGuestCartMerge.js +2 -1
- package/dist/features/cart/utils/line-total.d.ts +25 -0
- package/dist/features/cart/utils/line-total.js +26 -0
- package/dist/features/catalogue/repository/catalogue.repository.d.ts +12 -0
- package/dist/features/catalogue/repository/catalogue.repository.js +15 -0
- package/dist/features/categories/components/CategoryTree.js +2 -2
- package/dist/features/contact/components/ContactForm.js +1 -1
- package/dist/features/copilot/hooks/useCopilotFeedback.d.ts +1 -1
- package/dist/features/copilot/hooks/useCopilotFeedback.js +1 -1
- package/dist/features/events/components/AdminEventEditorView.js +16 -9
- package/dist/features/events/components/AdminEventEntriesView.js +7 -13
- package/dist/features/events/components/EventRafflesSection.js +14 -2
- package/dist/features/events/components/EventStatusBadge.js +1 -1
- package/dist/features/events/components/event-entry-detail-fields.d.ts +24 -0
- package/dist/features/events/components/event-entry-detail-fields.js +13 -0
- package/dist/features/faq/components/ContactCTA.js +1 -1
- package/dist/features/faq/components/FAQHelpfulButtons.js +2 -2
- package/dist/features/faq/repository/faqs.repository.d.ts +16 -1
- package/dist/features/faq/repository/faqs.repository.js +64 -54
- package/dist/features/faq/schemas/firestore.d.ts +3 -2
- package/dist/features/faq/schemas/firestore.js +2 -2
- package/dist/features/faq/schemas/index.d.ts +3 -3
- package/dist/features/faq/schemas/index.js +1 -1
- package/dist/features/filters/FilterFacetSection.js +2 -2
- package/dist/features/forms/Toggle.js +1 -1
- package/dist/features/grouped/components/GroupedListingEditorView.d.ts +18 -0
- package/dist/features/grouped/components/GroupedListingEditorView.js +192 -0
- package/dist/features/homepage/components/AdvertisementBanner.js +2 -2
- package/dist/features/homepage/components/BrandsSection.js +1 -1
- package/dist/features/homepage/components/CTABannerSection.js +1 -1
- package/dist/features/homepage/components/HomepageCustomerReviewsSection.js +1 -1
- package/dist/features/homepage/components/HomepageSectionBoundary.d.ts +39 -0
- package/dist/features/homepage/components/HomepageSectionBoundary.js +49 -0
- package/dist/features/homepage/components/ShopByCategorySection.js +1 -1
- package/dist/features/homepage/components/WelcomeSection.js +1 -1
- package/dist/features/homepage/lib/section-renderer.js +2 -1
- package/dist/features/layout/AppLayoutShell.js +5 -5
- package/dist/features/layout/BottomActions.js +5 -5
- package/dist/features/layout/BottomSheet.js +1 -1
- package/dist/features/layout/MainNavbar.js +1 -1
- package/dist/features/layout/NavbarLayout.js +1 -1
- package/dist/features/layout/TitleBarLayout.js +3 -3
- package/dist/features/layout/hooks/useFormBottomActions.d.ts +11 -1
- package/dist/features/layout/hooks/useFormBottomActions.js +16 -2
- package/dist/features/lottery/schemas/config-write.d.ts +141 -0
- package/dist/features/lottery/schemas/config-write.js +139 -0
- package/dist/features/media/MediaPickerModal.js +3 -1
- package/dist/features/media/MediaVideo.js +4 -2
- package/dist/features/media/components/MediaSlider.js +1 -1
- package/dist/features/orders/components/OrdersList.js +2 -2
- package/dist/features/payments/repository/payout.repository.d.ts +11 -1
- package/dist/features/payments/repository/payout.repository.js +14 -6
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -2
- package/dist/features/pre-orders/components/PreOrderBadge.js +1 -1
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -1
- package/dist/features/products/columns/productTableColumns.js +3 -3
- package/dist/features/products/components/CompareOverlay.js +1 -1
- package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
- package/dist/features/products/components/PrizeDrawEntryActions.js +2 -2
- package/dist/features/products/components/PrizeDrawsSection.js +5 -1
- package/dist/features/products/components/ProductDetailActions.js +11 -7
- package/dist/features/products/components/ProductDetailPageView.js +3 -3
- package/dist/features/products/components/ProductFeatureBadges.js +2 -2
- package/dist/features/products/components/ProductFeaturesSelector.js +1 -1
- package/dist/features/products/components/ProductFilters.js +15 -8
- package/dist/features/products/components/ProductGrid.js +8 -17
- package/dist/features/products/components/ProductTabs.js +7 -4
- package/dist/features/products/components/ProductTabsShell.js +2 -7
- package/dist/features/products/constants/action-defs.d.ts +21 -4
- package/dist/features/products/constants/action-defs.js +7 -3
- package/dist/features/products/hooks/useRelatedProducts.js +2 -1
- package/dist/features/products/repository/products.repository.d.ts +1 -1
- package/dist/features/products/repository/products.repository.js +27 -13
- package/dist/features/products/schemas/firestore.d.ts +3 -2
- package/dist/features/products/schemas/firestore.js +1 -1
- package/dist/features/reviews/actions/review-actions.d.ts +8 -1
- package/dist/features/reviews/actions/review-actions.js +14 -3
- package/dist/features/reviews/components/ReviewDetailShell.js +10 -4
- package/dist/features/reviews/components/ReviewModal.js +1 -1
- package/dist/features/reviews/repository/reviews.repository.d.ts +25 -1
- package/dist/features/reviews/repository/reviews.repository.js +53 -13
- package/dist/features/reviews/schemas/firestore.d.ts +6 -0
- package/dist/features/scams/components/ScamRegistryView.js +2 -2
- package/dist/features/search/components/Search.js +3 -3
- package/dist/features/search/components/SearchResultsSection.js +1 -1
- package/dist/features/seller/components/SellerAddressesView.js +3 -1
- package/dist/features/seller/components/SellerBidsView.js +6 -1
- package/dist/features/seller/components/SellerSidebar.js +1 -1
- package/dist/features/shell/SectionForm.d.ts +21 -1
- package/dist/features/shell/SectionForm.js +15 -3
- package/dist/features/shell/build-sections.js +10 -1
- package/dist/features/shell/field-ui-meta.d.ts +21 -0
- package/dist/features/shipments/components/AdminShipmentLotItemsView.js +23 -6
- package/dist/features/site-settings/components/ActionPermissionsManager.js +1 -1
- package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +21 -4
- package/dist/features/store-extensions/repository/store-extensions.repositories.js +24 -4
- package/dist/features/store-extensions/schemas/shipping-config-form.js +13 -0
- package/dist/features/store-extensions/schemas/store-category-form.js +1 -1
- package/dist/features/stores/actions/store-query-actions.js +25 -1
- package/dist/features/stores/components/InteractiveStoreCard.js +1 -1
- package/dist/features/stores/components/StoreHeader.js +1 -1
- package/dist/features/stores/components/StoreNavTabs.js +20 -8
- package/dist/features/support/repository/support.repository.d.ts +12 -0
- package/dist/features/support/repository/support.repository.js +15 -0
- package/dist/features/support/schemas/ticket-create-form.d.ts +33 -0
- package/dist/features/support/schemas/ticket-create-form.js +82 -0
- package/dist/features/tester/seed-data/products-tester-seed-data.js +108 -2
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +235 -13
- package/dist/features/wishlist/components/WishlistHeartButton.d.ts +55 -0
- package/dist/features/wishlist/components/WishlistHeartButton.js +52 -0
- package/dist/features/wishlist/components/index.d.ts +2 -1
- package/dist/features/wishlist/components/index.js +1 -1
- package/dist/index.d.ts +10 -3
- package/dist/index.js +19 -4
- package/dist/monitoring/error-tracking.js +39 -5
- package/dist/monitoring/server-logger.js +70 -32
- package/dist/next/components/ErrorView.js +1 -1
- package/dist/next/routing/route-map.d.ts +39 -7
- package/dist/next/routing/route-map.js +34 -4
- package/dist/providers/db-firebase/base.repository.d.ts +30 -0
- package/dist/providers/db-firebase/base.repository.js +56 -9
- package/dist/react/ErrorBoundary.js +9 -1
- package/dist/react/contexts/SessionContext.js +6 -2
- package/dist/react/hooks/useAuthGate.d.ts +22 -0
- package/dist/react/hooks/useAuthGate.js +86 -7
- package/dist/schemas/registry.d.ts +3 -3
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/pii-encrypt.d.ts +13 -5
- package/dist/security/pii-encrypt.js +132 -6
- package/dist/security/pii-schemas.d.ts +20 -4
- package/dist/security/pii-schemas.js +23 -5
- package/dist/seed/_helpers/product-search-txt.d.ts +18 -0
- package/dist/seed/_helpers/product-search-txt.js +33 -0
- package/dist/seed/faq-seed-data.d.ts +16 -0
- package/dist/seed/faq-seed-data.js +22 -1
- package/dist/seed/products-art-seed-data.js +49 -7
- package/dist/seed/products-auctions-seed-data.js +12 -4
- package/dist/seed/products-classifieds-seed-data.d.ts +5 -0
- package/dist/seed/products-classifieds-seed-data.js +65 -9
- package/dist/seed/products-digital-codes-seed-data.d.ts +5 -0
- package/dist/seed/products-digital-codes-seed-data.js +65 -9
- package/dist/seed/products-live-items-seed-data.d.ts +5 -0
- package/dist/seed/products-live-items-seed-data.js +33 -5
- package/dist/seed/products-preorders-seed-data.d.ts +1 -1
- package/dist/seed/products-preorders-seed-data.js +6 -2
- package/dist/seed/products-prize-draws-seed-data.d.ts +5 -0
- package/dist/seed/products-prize-draws-seed-data.js +57 -8
- package/dist/seed/products-standard-seed-data.js +6 -2
- package/dist/seed/products-stickers-seed-data.js +49 -7
- package/dist/seed/site-settings-seed-data.js +5 -3
- package/dist/seo/json-ld.d.ts +44 -2
- package/dist/seo/json-ld.js +57 -11
- package/dist/server.d.ts +1 -1
- package/dist/server.js +1 -1
- package/dist/styles.css +368 -90
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/index.d.ts +1 -1
- package/dist/tokens/index.js +1 -1
- package/dist/tokens/themes/default-dark.js +6 -0
- package/dist/tokens/themes/default-light.js +5 -0
- package/dist/tokens/tokens.css +84 -0
- package/dist/ui/DataTable.js +1 -1
- package/dist/ui/DataTable.style.css +3 -3
- package/dist/ui/components/BulkActionBar.style.css +1 -3
- package/dist/ui/components/Button.js +15 -6
- package/dist/ui/components/Dropdown.style.css +1 -4
- package/dist/ui/components/FilterChipGroup.js +1 -1
- package/dist/ui/components/FilterDrawer.style.css +1 -1
- package/dist/ui/components/Icon.d.ts +53 -0
- package/dist/ui/components/Icon.js +41 -0
- package/dist/ui/components/IconButton.d.ts +13 -0
- package/dist/ui/components/IconButton.js +13 -0
- package/dist/ui/components/IconButton.style.css +18 -10
- package/dist/ui/components/ListingLayout.style.css +2 -10
- package/dist/ui/components/ListingToolbar.js +6 -6
- package/dist/ui/components/Modal.js +1 -1
- package/dist/ui/components/PaginatedSelect.style.css +3 -3
- package/dist/ui/components/Pagination.style.css +1 -6
- package/dist/ui/components/RichTextEditor.js +1 -1
- package/dist/ui/components/RowActionMenu.style.css +1 -1
- package/dist/ui/components/SideDrawer.style.css +1 -1
- package/dist/ui/components/Slider.js +1 -1
- package/dist/ui/components/TabBarShell.d.ts +78 -0
- package/dist/ui/components/TabBarShell.js +95 -0
- package/dist/ui/components/Tabs.js +12 -8
- package/dist/ui/components/Tabs.style.css +249 -41
- package/dist/ui/components/ViewToggle.style.css +1 -5
- package/dist/ui/components/tabs-overflow.d.ts +17 -0
- package/dist/ui/components/tabs-overflow.js +142 -0
- package/dist/ui/icons/icon-registry.d.ts +38 -0
- package/dist/ui/icons/icon-registry.js +37 -0
- package/dist/ui/index.d.ts +6 -0
- package/dist/ui/index.js +3 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/media-url.d.ts +27 -4
- package/dist/utils/media-url.js +37 -6
- package/dist/utils/search-txt.d.ts +71 -0
- package/dist/utils/search-txt.js +118 -0
- package/package.json +1 -1
|
@@ -14,6 +14,50 @@ const PRODUCT_STATUS = "status";
|
|
|
14
14
|
const PRODUCT_STATUS_PUBLISHED = "published";
|
|
15
15
|
const PRODUCT_SLUG = "slug";
|
|
16
16
|
const PRODUCT_UPDATED_AT = "updatedAt";
|
|
17
|
+
/**
|
|
18
|
+
* Tester-sandbox fixtures must never reach the public sitemap. They are created
|
|
19
|
+
* and destroyed on a cycle by `testerSandboxCleanup` / `testerSandboxRefresh`,
|
|
20
|
+
* so anything Google indexes from them 404s shortly after. 34 of 182 sitemap
|
|
21
|
+
* URLs were disposable test fixtures before this filter existed.
|
|
22
|
+
*
|
|
23
|
+
* 🛑 This MUST be an in-memory filter, never a Firestore inequality on the
|
|
24
|
+
* field. An inequality silently excludes every document that does not have the
|
|
25
|
+
* field at all — which is every real product, store, category and post, since
|
|
26
|
+
* the flag is optional and was added later. Such a query returns ONLY test
|
|
27
|
+
* data. Same trap documented in CLAUDE.md § Tester QA Program.
|
|
28
|
+
*
|
|
29
|
+
* The field must therefore appear in each fetcher's `.select(...)` list, or it
|
|
30
|
+
* comes back undefined and nothing is filtered.
|
|
31
|
+
*
|
|
32
|
+
* The flag is not product-specific — it is set on categories, stores, blog
|
|
33
|
+
* posts and events too — but `PRODUCT_FIELDS` is where the canonical constant
|
|
34
|
+
* lives, so alias it rather than reintroducing a raw string.
|
|
35
|
+
*/
|
|
36
|
+
const TEST_DATA_FIELD = PRODUCT_FIELDS.IS_TEST_DATA;
|
|
37
|
+
const isTestDoc = (data) => data.isTestData === true;
|
|
38
|
+
/**
|
|
39
|
+
* A sitemap section that throws returns `[]` so a single broken query degrades
|
|
40
|
+
* the sitemap instead of 500-ing the whole route. That trade-off is right, but
|
|
41
|
+
* it is also why `fetchCategoryUrls` could return zero URLs for months without
|
|
42
|
+
* anyone noticing — it was logged at `warn` and looked identical to "this site
|
|
43
|
+
* genuinely has no categories".
|
|
44
|
+
*
|
|
45
|
+
* Log at `error`, and always name the section, so a section dropping to zero is
|
|
46
|
+
* greppable in production logs. `buildSitemap` additionally logs a per-section
|
|
47
|
+
* count digest on every build (see below), and `scripts/deploy.mjs` fails the
|
|
48
|
+
* deploy when any section is empty.
|
|
49
|
+
*
|
|
50
|
+
* NOTE: callers must still call `normalizeError(err)` themselves, in the catch
|
|
51
|
+
* block, BEFORE delegating here. `audit-catch-normalize` requires that call to
|
|
52
|
+
* be lexically inside the `catch` — a helper that normalises on the caller's
|
|
53
|
+
* behalf reads as an unnormalised catch and fails the audit. Keeping the call at
|
|
54
|
+
* the catch site is also what guarantees `unknown` never escapes into downstream
|
|
55
|
+
* logic, which is the rule's actual point.
|
|
56
|
+
*/
|
|
57
|
+
function sitemapSectionFailed(label, err) {
|
|
58
|
+
serverLogger.error(`sitemap: section "${label}" failed and returned 0 URLs`, { section: label, error: err });
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
17
61
|
function staticPages(baseUrl) {
|
|
18
62
|
const page = (path, changeFreq, priority) => ({ url: `${baseUrl}${path}`, lastModified: new Date(), changeFrequency: changeFreq, priority });
|
|
19
63
|
return [
|
|
@@ -70,10 +114,12 @@ async function fetchProductUrls(baseUrl) {
|
|
|
70
114
|
.collection(PRODUCT_COLLECTION)
|
|
71
115
|
.where(PRODUCT_STATUS, "==", PRODUCT_STATUS_PUBLISHED)
|
|
72
116
|
.where("listingType", "in", PRODUCT_DETAIL_LISTING_TYPES)
|
|
73
|
-
.select(PRODUCT_SLUG, PRODUCT_UPDATED_AT)
|
|
117
|
+
.select(PRODUCT_SLUG, PRODUCT_UPDATED_AT, TEST_DATA_FIELD)
|
|
74
118
|
.limit(5000)
|
|
75
119
|
.get();
|
|
76
|
-
return snap.docs
|
|
120
|
+
return snap.docs
|
|
121
|
+
.filter((doc) => !isTestDoc(doc.data()))
|
|
122
|
+
.map((doc) => {
|
|
77
123
|
const data = doc.data();
|
|
78
124
|
const slug = data[PRODUCT_SLUG] ?? doc.id;
|
|
79
125
|
return {
|
|
@@ -86,8 +132,7 @@ async function fetchProductUrls(baseUrl) {
|
|
|
86
132
|
}
|
|
87
133
|
catch (err) {
|
|
88
134
|
void normalizeError(err);
|
|
89
|
-
|
|
90
|
-
return [];
|
|
135
|
+
return sitemapSectionFailed("product", err);
|
|
91
136
|
}
|
|
92
137
|
}
|
|
93
138
|
async function fetchListingTypeUrls(baseUrl, listingType, buildUrl, label) {
|
|
@@ -97,10 +142,12 @@ async function fetchListingTypeUrls(baseUrl, listingType, buildUrl, label) {
|
|
|
97
142
|
.collection(PRODUCT_COLLECTION)
|
|
98
143
|
.where(PRODUCT_STATUS, "==", PRODUCT_STATUS_PUBLISHED)
|
|
99
144
|
.where("listingType", "==", listingType)
|
|
100
|
-
.select(PRODUCT_SLUG, PRODUCT_UPDATED_AT)
|
|
145
|
+
.select(PRODUCT_SLUG, PRODUCT_UPDATED_AT, TEST_DATA_FIELD)
|
|
101
146
|
.limit(2000)
|
|
102
147
|
.get();
|
|
103
|
-
return snap.docs
|
|
148
|
+
return snap.docs
|
|
149
|
+
.filter((doc) => !isTestDoc(doc.data()))
|
|
150
|
+
.map((doc) => {
|
|
104
151
|
const data = doc.data();
|
|
105
152
|
const slug = data[PRODUCT_SLUG] ?? doc.id;
|
|
106
153
|
return {
|
|
@@ -113,8 +160,7 @@ async function fetchListingTypeUrls(baseUrl, listingType, buildUrl, label) {
|
|
|
113
160
|
}
|
|
114
161
|
catch (err) {
|
|
115
162
|
void normalizeError(err);
|
|
116
|
-
|
|
117
|
-
return [];
|
|
163
|
+
return sitemapSectionFailed(label, err);
|
|
118
164
|
}
|
|
119
165
|
}
|
|
120
166
|
const fetchPreOrderUrls = (baseUrl) => fetchListingTypeUrls(baseUrl, "pre-order", (slug) => ROUTES.PUBLIC.PRE_ORDER_DETAIL(slug), "pre-order");
|
|
@@ -129,10 +175,12 @@ async function fetchAuctionUrls(baseUrl) {
|
|
|
129
175
|
.collection(PRODUCT_COLLECTION)
|
|
130
176
|
.where(PRODUCT_STATUS, "==", PRODUCT_STATUS_PUBLISHED)
|
|
131
177
|
.where("listingType", "==", "auction")
|
|
132
|
-
.select(PRODUCT_SLUG, PRODUCT_UPDATED_AT)
|
|
178
|
+
.select(PRODUCT_SLUG, PRODUCT_UPDATED_AT, TEST_DATA_FIELD)
|
|
133
179
|
.limit(2000)
|
|
134
180
|
.get();
|
|
135
|
-
return snap.docs
|
|
181
|
+
return snap.docs
|
|
182
|
+
.filter((doc) => !isTestDoc(doc.data()))
|
|
183
|
+
.map((doc) => {
|
|
136
184
|
const data = doc.data();
|
|
137
185
|
const slug = data[PRODUCT_SLUG] ?? doc.id;
|
|
138
186
|
return {
|
|
@@ -145,8 +193,7 @@ async function fetchAuctionUrls(baseUrl) {
|
|
|
145
193
|
}
|
|
146
194
|
catch (err) {
|
|
147
195
|
void normalizeError(err);
|
|
148
|
-
|
|
149
|
-
return [];
|
|
196
|
+
return sitemapSectionFailed("auction", err);
|
|
150
197
|
}
|
|
151
198
|
}
|
|
152
199
|
async function fetchEventUrls(baseUrl) {
|
|
@@ -155,10 +202,12 @@ async function fetchEventUrls(baseUrl) {
|
|
|
155
202
|
const snap = await db
|
|
156
203
|
.collection(EVENTS_COLLECTION)
|
|
157
204
|
.where(EVENT_FIELDS.STATUS, "==", EVENT_FIELDS.STATUS_VALUES.ACTIVE)
|
|
158
|
-
.select(EVENT_FIELDS.UPDATED_AT, EVENT_FIELDS.SLUG)
|
|
205
|
+
.select(EVENT_FIELDS.UPDATED_AT, EVENT_FIELDS.SLUG, TEST_DATA_FIELD)
|
|
159
206
|
.limit(500)
|
|
160
207
|
.get();
|
|
161
|
-
return snap.docs
|
|
208
|
+
return snap.docs
|
|
209
|
+
.filter((doc) => !isTestDoc(doc.data()))
|
|
210
|
+
.map((doc) => {
|
|
162
211
|
const data = doc.data();
|
|
163
212
|
const slug = typeof data[EVENT_FIELDS.SLUG] === "string" ? data[EVENT_FIELDS.SLUG] : undefined;
|
|
164
213
|
return {
|
|
@@ -171,15 +220,25 @@ async function fetchEventUrls(baseUrl) {
|
|
|
171
220
|
}
|
|
172
221
|
catch (err) {
|
|
173
222
|
void normalizeError(err);
|
|
174
|
-
|
|
175
|
-
return [];
|
|
223
|
+
return sitemapSectionFailed("event", err);
|
|
176
224
|
}
|
|
177
225
|
}
|
|
178
|
-
// categories is a discriminated-union collection
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
//
|
|
226
|
+
// `categories` is a discriminated-union collection. Each discriminator renders
|
|
227
|
+
// at a different public route, so each needs its own filtered query; querying
|
|
228
|
+
// the collection without a categoryType filter (an older bug here) mapped
|
|
229
|
+
// brand/bundle rows onto the wrong /categories/{slug} URL.
|
|
230
|
+
//
|
|
231
|
+
// 🛑 The union is `"category" | "sublisting" | "brand" | "bundle"` — see
|
|
232
|
+
// CategoryType in features/categories/types/index.ts. There is NO "listing"
|
|
233
|
+
// value and there never was. This function used to be called with "listing"
|
|
234
|
+
// for the plain-category case, which matched zero documents, so ~47 category
|
|
235
|
+
// pages were missing from the sitemap for as long as that call existed — with
|
|
236
|
+
// no error, because a zero-row query is indistinguishable from "no categories".
|
|
237
|
+
//
|
|
238
|
+
// It is still only safe to use this helper for discriminators that are actually
|
|
239
|
+
// STORED. A plain listing category OMITS `categoryType` entirely (that is the
|
|
240
|
+
// convention every seeded listing category follows), so no equality can select
|
|
241
|
+
// it — see fetchCategoryUrls below, which inverts the test instead.
|
|
183
242
|
async function fetchCategoryTypeUrls(baseUrl, categoryType, buildUrl, label) {
|
|
184
243
|
try {
|
|
185
244
|
const db = getAdminDb();
|
|
@@ -187,10 +246,12 @@ async function fetchCategoryTypeUrls(baseUrl, categoryType, buildUrl, label) {
|
|
|
187
246
|
.collection(CATEGORIES_COLLECTION)
|
|
188
247
|
.where(CATEGORY_FIELDS.CATEGORY_TYPE, "==", categoryType)
|
|
189
248
|
.where(CATEGORY_FIELDS.IS_ACTIVE, "==", true)
|
|
190
|
-
.select(CATEGORY_FIELDS.SLUG, CATEGORY_FIELDS.UPDATED_AT)
|
|
249
|
+
.select(CATEGORY_FIELDS.SLUG, CATEGORY_FIELDS.UPDATED_AT, TEST_DATA_FIELD)
|
|
191
250
|
.limit(500)
|
|
192
251
|
.get();
|
|
193
|
-
return snap.docs
|
|
252
|
+
return snap.docs
|
|
253
|
+
.filter((doc) => !isTestDoc(doc.data()))
|
|
254
|
+
.map((doc) => {
|
|
194
255
|
const data = doc.data();
|
|
195
256
|
const slug = data[CATEGORY_FIELDS.SLUG] ?? doc.id;
|
|
196
257
|
return {
|
|
@@ -203,11 +264,57 @@ async function fetchCategoryTypeUrls(baseUrl, categoryType, buildUrl, label) {
|
|
|
203
264
|
}
|
|
204
265
|
catch (err) {
|
|
205
266
|
void normalizeError(err);
|
|
206
|
-
|
|
207
|
-
|
|
267
|
+
return sitemapSectionFailed(label, err);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Plain listing categories — the /categories/{slug} pages.
|
|
272
|
+
*
|
|
273
|
+
* These CANNOT be selected by an equality on `categoryType`, because a plain
|
|
274
|
+
* listing category omits the field entirely rather than storing "category".
|
|
275
|
+
* `.where(CATEGORY_TYPE, "==", <anything>)` therefore excludes every one of
|
|
276
|
+
* them, and a Firestore `!=` would be worse still — it silently drops documents
|
|
277
|
+
* that lack the field, which is exactly the set we want.
|
|
278
|
+
*
|
|
279
|
+
* So: select on `isActive` alone (the one predicate that IS stored on every
|
|
280
|
+
* row) and reject the three discriminated kinds in memory. `categoryType` must
|
|
281
|
+
* stay in the `.select()` list or it comes back undefined and nothing is
|
|
282
|
+
* rejected.
|
|
283
|
+
*/
|
|
284
|
+
const NON_LISTING_CATEGORY_TYPES = new Set(["brand", "bundle", "sublisting"]);
|
|
285
|
+
async function fetchCategoryUrls(baseUrl) {
|
|
286
|
+
try {
|
|
287
|
+
const db = getAdminDb();
|
|
288
|
+
const snap = await db
|
|
289
|
+
.collection(CATEGORIES_COLLECTION)
|
|
290
|
+
.where(CATEGORY_FIELDS.IS_ACTIVE, "==", true)
|
|
291
|
+
.select(CATEGORY_FIELDS.SLUG, CATEGORY_FIELDS.UPDATED_AT, CATEGORY_FIELDS.CATEGORY_TYPE, TEST_DATA_FIELD)
|
|
292
|
+
.limit(500)
|
|
293
|
+
.get();
|
|
294
|
+
return snap.docs
|
|
295
|
+
.filter((doc) => {
|
|
296
|
+
const data = doc.data();
|
|
297
|
+
if (isTestDoc(data))
|
|
298
|
+
return false;
|
|
299
|
+
const kind = data[CATEGORY_FIELDS.CATEGORY_TYPE];
|
|
300
|
+
return typeof kind !== "string" || !NON_LISTING_CATEGORY_TYPES.has(kind);
|
|
301
|
+
})
|
|
302
|
+
.map((doc) => {
|
|
303
|
+
const data = doc.data();
|
|
304
|
+
const slug = data[CATEGORY_FIELDS.SLUG] ?? doc.id;
|
|
305
|
+
return {
|
|
306
|
+
url: `${baseUrl}${ROUTES.PUBLIC.CATEGORY_DETAIL(slug)}`,
|
|
307
|
+
lastModified: data[CATEGORY_FIELDS.UPDATED_AT]?.toDate?.() ?? new Date(),
|
|
308
|
+
changeFrequency: "weekly",
|
|
309
|
+
priority: 0.7,
|
|
310
|
+
};
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
catch (err) {
|
|
314
|
+
void normalizeError(err);
|
|
315
|
+
return sitemapSectionFailed("category", err);
|
|
208
316
|
}
|
|
209
317
|
}
|
|
210
|
-
const fetchCategoryUrls = (baseUrl) => fetchCategoryTypeUrls(baseUrl, "listing", (slug) => ROUTES.PUBLIC.CATEGORY_DETAIL(slug), "category");
|
|
211
318
|
const fetchBrandUrls = (baseUrl) => fetchCategoryTypeUrls(baseUrl, "brand", (slug) => ROUTES.PUBLIC.BRAND_DETAIL(slug), "brand");
|
|
212
319
|
const fetchBundleUrls = (baseUrl) => fetchCategoryTypeUrls(baseUrl, "bundle", (slug) => ROUTES.PUBLIC.BUNDLE_DETAIL(slug), "bundle");
|
|
213
320
|
/**
|
|
@@ -228,7 +335,9 @@ async function fetchGroupedListingUrls(baseUrl) {
|
|
|
228
335
|
}
|
|
229
336
|
catch (err) {
|
|
230
337
|
void normalizeError(err);
|
|
231
|
-
|
|
338
|
+
// This catch used to swallow silently — no log at all, so a failure here was
|
|
339
|
+
// indistinguishable from "this site has no grouped listings".
|
|
340
|
+
return sitemapSectionFailed("grouped-listing", err);
|
|
232
341
|
}
|
|
233
342
|
}
|
|
234
343
|
async function fetchBlogPostUrls(baseUrl) {
|
|
@@ -237,10 +346,12 @@ async function fetchBlogPostUrls(baseUrl) {
|
|
|
237
346
|
const snap = await db
|
|
238
347
|
.collection(BLOG_POSTS_COLLECTION)
|
|
239
348
|
.where(BLOG_POST_FIELDS.STATUS, "==", BLOG_POST_FIELDS.STATUS_VALUES.PUBLISHED)
|
|
240
|
-
.select(BLOG_POST_FIELDS.SLUG, BLOG_POST_FIELDS.PUBLISHED_AT, BLOG_POST_FIELDS.UPDATED_AT)
|
|
349
|
+
.select(BLOG_POST_FIELDS.SLUG, BLOG_POST_FIELDS.PUBLISHED_AT, BLOG_POST_FIELDS.UPDATED_AT, TEST_DATA_FIELD)
|
|
241
350
|
.limit(1000)
|
|
242
351
|
.get();
|
|
243
|
-
return snap.docs
|
|
352
|
+
return snap.docs
|
|
353
|
+
.filter((doc) => !isTestDoc(doc.data()))
|
|
354
|
+
.map((doc) => {
|
|
244
355
|
const data = doc.data();
|
|
245
356
|
const slug = data[BLOG_POST_FIELDS.SLUG] ?? doc.id;
|
|
246
357
|
const lastModified = data[BLOG_POST_FIELDS.UPDATED_AT]?.toDate?.() ??
|
|
@@ -256,8 +367,7 @@ async function fetchBlogPostUrls(baseUrl) {
|
|
|
256
367
|
}
|
|
257
368
|
catch (err) {
|
|
258
369
|
void normalizeError(err);
|
|
259
|
-
|
|
260
|
-
return [];
|
|
370
|
+
return sitemapSectionFailed("blog-post", err);
|
|
261
371
|
}
|
|
262
372
|
}
|
|
263
373
|
async function fetchStoreUrls(baseUrl) {
|
|
@@ -267,10 +377,12 @@ async function fetchStoreUrls(baseUrl) {
|
|
|
267
377
|
.collection(STORE_COLLECTION)
|
|
268
378
|
.where(STORE_FIELDS.STATUS, "==", STORE_FIELDS.STATUS_VALUES.ACTIVE)
|
|
269
379
|
.where(STORE_FIELDS.IS_PUBLIC, "==", true)
|
|
270
|
-
.select(STORE_FIELDS.STORE_SLUG, STORE_FIELDS.UPDATED_AT)
|
|
380
|
+
.select(STORE_FIELDS.STORE_SLUG, STORE_FIELDS.UPDATED_AT, TEST_DATA_FIELD)
|
|
271
381
|
.limit(1000)
|
|
272
382
|
.get();
|
|
273
|
-
return snap.docs
|
|
383
|
+
return snap.docs
|
|
384
|
+
.filter((doc) => !isTestDoc(doc.data()))
|
|
385
|
+
.map((doc) => {
|
|
274
386
|
const data = doc.data();
|
|
275
387
|
const slug = data[STORE_FIELDS.STORE_SLUG] ?? doc.id;
|
|
276
388
|
return {
|
|
@@ -283,8 +395,7 @@ async function fetchStoreUrls(baseUrl) {
|
|
|
283
395
|
}
|
|
284
396
|
catch (err) {
|
|
285
397
|
void normalizeError(err);
|
|
286
|
-
|
|
287
|
-
return [];
|
|
398
|
+
return sitemapSectionFailed("store", err);
|
|
288
399
|
}
|
|
289
400
|
}
|
|
290
401
|
async function fetchScammerUrls(baseUrl) {
|
|
@@ -293,10 +404,12 @@ async function fetchScammerUrls(baseUrl) {
|
|
|
293
404
|
const snap = await db
|
|
294
405
|
.collection(SCAMMER_COLLECTION)
|
|
295
406
|
.where(PRODUCT_FIELDS.STATUS, "==", "verified")
|
|
296
|
-
.select("seo", "updatedAt")
|
|
407
|
+
.select("seo", "updatedAt", TEST_DATA_FIELD)
|
|
297
408
|
.limit(2000)
|
|
298
409
|
.get();
|
|
299
|
-
return snap.docs
|
|
410
|
+
return snap.docs
|
|
411
|
+
.filter((doc) => !isTestDoc(doc.data()))
|
|
412
|
+
.map((doc) => {
|
|
300
413
|
const data = doc.data();
|
|
301
414
|
const slug = data.seo?.slug ?? doc.id;
|
|
302
415
|
return {
|
|
@@ -309,8 +422,7 @@ async function fetchScammerUrls(baseUrl) {
|
|
|
309
422
|
}
|
|
310
423
|
catch (err) {
|
|
311
424
|
void normalizeError(err);
|
|
312
|
-
|
|
313
|
-
return [];
|
|
425
|
+
return sitemapSectionFailed("scammer", err);
|
|
314
426
|
}
|
|
315
427
|
}
|
|
316
428
|
export async function buildSitemap({ baseUrl }) {
|
|
@@ -331,8 +443,45 @@ export async function buildSitemap({ baseUrl }) {
|
|
|
331
443
|
fetchStoreUrls(baseUrl),
|
|
332
444
|
fetchScammerUrls(baseUrl),
|
|
333
445
|
]);
|
|
446
|
+
const staticUrls = staticPages(baseUrl);
|
|
447
|
+
// Per-section count digest. A section that drops to zero is otherwise
|
|
448
|
+
// indistinguishable from a site that genuinely has none of that thing — which
|
|
449
|
+
// is exactly how `category: 0` survived unnoticed while every other section
|
|
450
|
+
// worked (the query filtered on a `categoryType` value that does not exist).
|
|
451
|
+
//
|
|
452
|
+
// `scripts/deploy.mjs` asserts the same counts against the deployed sitemap
|
|
453
|
+
// and fails the deploy on an empty section; this log is the production-side
|
|
454
|
+
// record for when a section empties out later, between deploys.
|
|
455
|
+
const sections = {
|
|
456
|
+
static: staticUrls.length,
|
|
457
|
+
category: categoryUrls.length,
|
|
458
|
+
brand: brandUrls.length,
|
|
459
|
+
bundle: bundleUrls.length,
|
|
460
|
+
group: groupedListingUrls.length,
|
|
461
|
+
blog: blogUrls.length,
|
|
462
|
+
product: productUrls.length,
|
|
463
|
+
auction: auctionUrls.length,
|
|
464
|
+
preOrder: preOrderUrls.length,
|
|
465
|
+
prizeDraw: prizeDrawUrls.length,
|
|
466
|
+
classified: classifiedUrls.length,
|
|
467
|
+
digitalCode: digitalCodeUrls.length,
|
|
468
|
+
live: liveUrls.length,
|
|
469
|
+
event: eventUrls.length,
|
|
470
|
+
store: storeUrls.length,
|
|
471
|
+
scammer: scammerUrls.length,
|
|
472
|
+
};
|
|
473
|
+
const empty = Object.entries(sections)
|
|
474
|
+
.filter(([, n]) => n === 0)
|
|
475
|
+
.map(([name]) => name);
|
|
476
|
+
const total = Object.values(sections).reduce((a, b) => a + b, 0);
|
|
477
|
+
if (empty.length > 0) {
|
|
478
|
+
serverLogger.warn(`sitemap: ${empty.length} section(s) produced 0 URLs`, { empty, sections, total });
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
serverLogger.info("sitemap: built", { sections, total });
|
|
482
|
+
}
|
|
334
483
|
return [
|
|
335
|
-
...
|
|
484
|
+
...staticUrls,
|
|
336
485
|
...categoryUrls,
|
|
337
486
|
...brandUrls,
|
|
338
487
|
...bundleUrls,
|
|
@@ -36,6 +36,17 @@ function getBoolOpt(baseOpts, key, fallback) {
|
|
|
36
36
|
return false;
|
|
37
37
|
return fallback;
|
|
38
38
|
}
|
|
39
|
+
function getStringOpt(baseOpts, key) {
|
|
40
|
+
const value = baseOpts[key];
|
|
41
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
42
|
+
}
|
|
43
|
+
function getStringArrayOpt(baseOpts, key) {
|
|
44
|
+
const value = baseOpts[key];
|
|
45
|
+
if (!Array.isArray(value))
|
|
46
|
+
return undefined;
|
|
47
|
+
const strings = value.filter((v) => typeof v === "string" && v.length > 0);
|
|
48
|
+
return strings.length > 0 ? strings : undefined;
|
|
49
|
+
}
|
|
39
50
|
const LISTERS = {
|
|
40
51
|
products: (m, o) => productRepository.list(m, o),
|
|
41
52
|
categories: (m) => categoriesRepository.list(m),
|
|
@@ -52,7 +63,14 @@ const LISTERS = {
|
|
|
52
63
|
payouts: (m) => payoutRepository.list(m),
|
|
53
64
|
blogPosts: (m) => blogRepository.listAll(m),
|
|
54
65
|
events: (m) => eventRepository.list(m),
|
|
55
|
-
|
|
66
|
+
// Forwards opts so `baseOpts.search` reaches the repository's token search.
|
|
67
|
+
// This was `(m) => faqsRepository.list(m)` — the second argument was dropped,
|
|
68
|
+
// which made FAQ token search structurally unreachable through the Function
|
|
69
|
+
// even though the repository has implemented it all along.
|
|
70
|
+
faqs: (m, o) => faqsRepository.list(m, {
|
|
71
|
+
search: getStringOpt(o, "search"),
|
|
72
|
+
tags: getStringArrayOpt(o, "tags"),
|
|
73
|
+
}),
|
|
56
74
|
notifications: (m) => notificationRepository.list(m),
|
|
57
75
|
scammers: (m) => scammerRepository.listAll(m),
|
|
58
76
|
sublistingCategories: (m) => categoriesRepository.list({
|
|
@@ -2469,6 +2469,20 @@ export const ACTIONS = {
|
|
|
2469
2469
|
description: "Advance from address selection to the payment step.",
|
|
2470
2470
|
kind: "primary",
|
|
2471
2471
|
},
|
|
2472
|
+
"continue-to-payment": {
|
|
2473
|
+
iconKey: "cart",
|
|
2474
|
+
id: "checkout.continue-to-payment",
|
|
2475
|
+
label: "Continue to payment",
|
|
2476
|
+
description: "Advance from the add-ons & fees step to the payment step.",
|
|
2477
|
+
kind: "primary",
|
|
2478
|
+
},
|
|
2479
|
+
back: {
|
|
2480
|
+
iconKey: "back",
|
|
2481
|
+
id: "checkout.back",
|
|
2482
|
+
label: "Back",
|
|
2483
|
+
description: "Return to the previous checkout step. Safe at any point before payment — add-on selections are persisted to the cart as they are made, so nothing is lost.",
|
|
2484
|
+
kind: "ghost",
|
|
2485
|
+
},
|
|
2472
2486
|
"verify-otp": {
|
|
2473
2487
|
iconKey: "verify",
|
|
2474
2488
|
id: "checkout.verify-otp",
|
|
@@ -4,8 +4,30 @@
|
|
|
4
4
|
* directly, unlike `checkout/actions.ts` whose module graph pulls in
|
|
5
5
|
* `server-only` guards that fail outside a real server-action test harness.
|
|
6
6
|
*/
|
|
7
|
-
import type { CartItemDocument } from "../../../features/cart/schemas/firestore";
|
|
7
|
+
import type { CartItemDocument, CartLineKind } from "../../../features/cart/schemas/firestore";
|
|
8
8
|
import type { ProductDocument } from "../../../features/products/schemas/firestore";
|
|
9
|
+
/**
|
|
10
|
+
* Exactly the fields `unitPriceFor` reads.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately narrower than `CartItemDocument`, which a client cannot satisfy:
|
|
13
|
+
* `checkoutDeadline` is a `Date` on the document and a string once the cart has
|
|
14
|
+
* been through `JSON.parse`. Without this seam the checkout page would have to
|
|
15
|
+
* hand-roll a seventh copy of the pricing rule — the exact thing the docstring
|
|
16
|
+
* below spends a paragraph forbidding. `CartItemDocument` is structurally
|
|
17
|
+
* assignable to it, so every existing server call site is unaffected.
|
|
18
|
+
*/
|
|
19
|
+
export interface PricedCartLine {
|
|
20
|
+
price: number;
|
|
21
|
+
quantity: number;
|
|
22
|
+
lockedPrice?: number;
|
|
23
|
+
lineKind?: CartLineKind;
|
|
24
|
+
bundleCategorySlug?: string;
|
|
25
|
+
bundleProductIds?: string[];
|
|
26
|
+
groupMembers?: Array<{
|
|
27
|
+
unitPrice: number;
|
|
28
|
+
quantity: number;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
9
31
|
/**
|
|
10
32
|
* The single source of truth for "what do we charge for ONE COPY of this line".
|
|
11
33
|
*
|
|
@@ -38,13 +60,13 @@ import type { ProductDocument } from "../../../features/products/schemas/firesto
|
|
|
38
60
|
* for an accepted offer while the cart displayed the negotiated one. Call
|
|
39
61
|
* `lineTotalFor` and let this function stay the only definition.
|
|
40
62
|
*/
|
|
41
|
-
export declare function unitPriceFor(item:
|
|
63
|
+
export declare function unitPriceFor(item: PricedCartLine, product: ProductDocument | null): number;
|
|
42
64
|
/**
|
|
43
65
|
* What this line contributes to a subtotal: one copy's price × the number of
|
|
44
66
|
* copies. THE call site should use this rather than multiplying `unitPriceFor`
|
|
45
67
|
* itself — that multiplication is where the six hand-rolled copies diverged.
|
|
46
68
|
*/
|
|
47
|
-
export declare function lineTotalFor(item:
|
|
69
|
+
export declare function lineTotalFor(item: PricedCartLine, product: ProductDocument | null): number;
|
|
48
70
|
/** One taxable slice of a line. A single-product line has exactly one. */
|
|
49
71
|
export interface LineTaxComponent {
|
|
50
72
|
productId: string;
|
|
@@ -6,11 +6,11 @@ export declare const CHECKOUT_DEFAULT_COMMISSIONS: {
|
|
|
6
6
|
readonly codDepositPercent: 10;
|
|
7
7
|
readonly codHandlingFeeMin: 200;
|
|
8
8
|
readonly codHandlingFeePercent: 10;
|
|
9
|
-
readonly whatsappNotifyFeeEnabled:
|
|
9
|
+
readonly whatsappNotifyFeeEnabled: true;
|
|
10
10
|
readonly whatsappNotifyFee: 10;
|
|
11
|
-
readonly giftWrapFeeEnabled:
|
|
11
|
+
readonly giftWrapFeeEnabled: true;
|
|
12
12
|
readonly giftWrapFee: 49;
|
|
13
|
-
readonly shipmentProtectionFeeEnabled:
|
|
13
|
+
readonly shipmentProtectionFeeEnabled: true;
|
|
14
14
|
readonly shipmentProtectionFeePercent: 2;
|
|
15
15
|
readonly shipmentProtectionFeeMin: 30;
|
|
16
16
|
readonly sellerShippingFixed: 50;
|
|
@@ -10,11 +10,14 @@ export const CHECKOUT_DEFAULT_COMMISSIONS = {
|
|
|
10
10
|
codDepositPercent: 10,
|
|
11
11
|
codHandlingFeeMin: 200,
|
|
12
12
|
codHandlingFeePercent: 10,
|
|
13
|
-
|
|
13
|
+
// Mirrors the SiteSettingsDocument defaults, which enable all three add-ons.
|
|
14
|
+
// Consequence of the mirror: if the settings read fails, an add-on already
|
|
15
|
+
// ticked on the cart document is still billed rather than silently dropped.
|
|
16
|
+
whatsappNotifyFeeEnabled: true,
|
|
14
17
|
whatsappNotifyFee: 10,
|
|
15
|
-
giftWrapFeeEnabled:
|
|
18
|
+
giftWrapFeeEnabled: true,
|
|
16
19
|
giftWrapFee: 49,
|
|
17
|
-
shipmentProtectionFeeEnabled:
|
|
20
|
+
shipmentProtectionFeeEnabled: true,
|
|
18
21
|
shipmentProtectionFeePercent: 2,
|
|
19
22
|
shipmentProtectionFeeMin: 30,
|
|
20
23
|
sellerShippingFixed: 50,
|
package/dist/client.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export type { SurfaceErrorOptions } from "./client/api/surface-error";
|
|
|
11
11
|
export { reportClientError, } from "./client/observability/reportClientError";
|
|
12
12
|
export type { ClientErrorPayload } from "./client/observability/reportClientError";
|
|
13
13
|
export { installClientErrorReporter, useClientErrorReporter, } from "./client/observability/installClientErrorReporter";
|
|
14
|
+
export { setErrorTracker, trackError, ErrorCategory, ErrorSeverity, } from "./monitoring/error-tracking";
|
|
15
|
+
export type { ErrorTrackerFn, ErrorContext, } from "./monitoring/error-tracking";
|
|
14
16
|
export { useApiMutation } from "./client/api/useApiMutation";
|
|
15
17
|
export type { UseApiMutationOptions } from "./client/api/useApiMutation";
|
|
16
18
|
export { useApiQuery } from "./client/api/useApiQuery";
|
|
@@ -38,6 +40,8 @@ export type { SkeletonProps } from "./ui/components/Skeleton";
|
|
|
38
40
|
export { Divider } from "./ui/components/Divider";
|
|
39
41
|
export { Tabs, TabsList, TabsTrigger, TabsContent } from "./ui/components/Tabs";
|
|
40
42
|
export type { TabsProps, TabsListProps, TabsTriggerProps, TabsContentProps } from "./ui/components/Tabs";
|
|
43
|
+
export { TabBarShell, TabBarButton, TabsNavSelect } from "./ui/components/TabBarShell";
|
|
44
|
+
export type { TabBarShellProps, TabBarButtonProps, TabsNavSelectProps } from "./ui/components/TabBarShell";
|
|
41
45
|
export { SellerProductsView } from "./features/seller/components/SellerProductsView";
|
|
42
46
|
export { SellerOrderDetailPanel } from "./features/seller/components/SellerOrdersView";
|
|
43
47
|
export { SellerPayoutDetailContent } from "./features/seller/components/SellerPayoutsView";
|
|
@@ -90,6 +94,20 @@ export { LotteryDetailView } from "./_internal/client/features/lottery/LotteryDe
|
|
|
90
94
|
export { LotteryEntriesView } from "./_internal/client/features/lottery/LotteryEntriesView";
|
|
91
95
|
export { LotteryAdminSlotView } from "./_internal/client/features/lottery/LotteryAdminSlotView";
|
|
92
96
|
export { LotteryAdminEditView } from "./_internal/client/features/lottery/LotteryAdminEditView";
|
|
97
|
+
export { lotteryConfigWriteSchema, lotterySlotWriteSchema } from "./features/lottery/schemas/config-write";
|
|
98
|
+
export { SectionForm, useSectionFormNav } from "./features/shell/SectionForm";
|
|
99
|
+
export type { SectionDef, SectionFormProps } from "./features/shell/SectionForm";
|
|
100
|
+
export { buildSectionsFromSchema } from "./features/shell/build-sections";
|
|
101
|
+
export { reportCreateSchema } from "./features/store-extensions/schemas/report-create-form";
|
|
102
|
+
export { itemRequestCreateSchema } from "./features/store-extensions/schemas/item-request-create-form";
|
|
103
|
+
export { supportTicketCreateSchema } from "./features/support/schemas/ticket-create-form";
|
|
104
|
+
export type { SupportTicketCreateValues } from "./features/support/schemas/ticket-create-form";
|
|
105
|
+
export { analyticsCardCreateSchema, ANALYTICS_CARD_TYPES } from "./features/store-extensions/schemas/analytics-forms";
|
|
106
|
+
export { QuickFormDrawer } from "./features/shell/QuickFormDrawer";
|
|
107
|
+
export type { QuickFormDrawerProps, QuickFieldDef } from "./features/shell/QuickFormDrawer";
|
|
108
|
+
export type { ItemRequestCreateValues } from "./features/store-extensions/schemas/item-request-create-form";
|
|
109
|
+
export type { ReportCreateValues } from "./features/store-extensions/schemas/report-create-form";
|
|
110
|
+
export type { LotteryConfigWriteInput } from "./features/lottery/schemas/config-write";
|
|
93
111
|
export { PrizeDrawLotteryDetailView } from "./_internal/client/features/lottery/PrizeDrawLotteryDetailView";
|
|
94
112
|
export type { LotteryConfig, LotterySlot, ClientLotterySlot, ClientLotteryConfig, LotteryPricingMode, LotteryEntryStatus } from "./features/lottery/types";
|
|
95
113
|
export { BottomSheet } from "./features/layout/index";
|
|
@@ -220,13 +238,19 @@ export type { PageViewTrackerProps } from "./features/analytics/components/PageV
|
|
|
220
238
|
export { PAGE_VIEW_ENTITY_TYPES } from "./features/analytics/types";
|
|
221
239
|
export type { PageViewEntityType } from "./features/analytics/types";
|
|
222
240
|
export { AuctionBidsTable } from "./features/auctions/components/AuctionBidsTable";
|
|
241
|
+
export { buildBidDetailFields, bidStatusBadge } from "./features/auctions/components/bid-detail-fields";
|
|
242
|
+
export { buildEventEntryDetailFields } from "./features/events/components/event-entry-detail-fields";
|
|
243
|
+
export type { EntryFieldRow } from "./features/events/components/event-entry-detail-fields";
|
|
244
|
+
export type { BidDetailViewer } from "./features/auctions/components/bid-detail-fields";
|
|
223
245
|
export type { AuctionBidsTableProps, AuctionWithBids } from "./features/auctions/components/AuctionBidsTable";
|
|
224
246
|
export { ProtectedRoute, AuthStatusPanel, ForgotPasswordView, LoginForm, RegisterForm, ResetPasswordView, VerifyEmailView } from "./features/auth/index";
|
|
225
247
|
export type { AuthGuardUser, ForgotPasswordViewProps, LoginFormProps, LoginFormValues, RegisterFormProps, RegisterFormValues, ResetPasswordViewProps, VerifyEmailViewProps, } from "./features/auth/index";
|
|
226
248
|
export { useLogout, useLogin, useGoogleLogin, useLinkGoogleAccount, useRegister, useForgotPassword, useResetPassword, useVerifyEmail, useChangeEmail } from "./features/auth/index";
|
|
227
249
|
export type { LoginCredentials, RegisterData, ForgotPasswordData, ResetPasswordData, VerifyEmailData, ChangeEmailData } from "./features/auth/index";
|
|
228
250
|
export { CartView, CartItemRow, CartGroupLineRow, CartSummary, CartPriceBreakdown, CartDrawer, CheckoutView, CheckoutSuccessView, CheckoutAddressStep, useGuestCart, useCartCount, useAddToCart, useCart, useGuestCartMerge, useCartQuery } from "./features/cart/index";
|
|
229
|
-
export { StoreAddonsPicker } from "./features/cart/index";
|
|
251
|
+
export { StoreAddonsPicker, hasAnyStoreAddon } from "./features/cart/index";
|
|
252
|
+
export { clientLineTotal } from "./features/cart/utils/line-total";
|
|
253
|
+
export type { PricedCartLine } from "./features/cart/utils/line-total";
|
|
230
254
|
export type { CartPriceBreakdownData, CartPriceBreakdownStore, StoreAddonsValue, StoreAddonsRates } from "./features/cart/index";
|
|
231
255
|
export { getCartOps, CART_OPS_CHANGE_EVENT } from "./features/cart/utils/pending-ops";
|
|
232
256
|
export type { CartOp } from "./features/cart/utils/pending-ops";
|
|
@@ -258,12 +282,16 @@ export type { AdSlotId, AdProvider, AdSlotConfig } from "./features/homepage/ad-
|
|
|
258
282
|
export { WishlistView, useGuestWishlist, useWishlistWithGuest } from "./features/wishlist/index";
|
|
259
283
|
export type { WishlistViewProps, GuestWishlistItem, WishlistItem, WishlistResponse, WishlistProductData, EnrichedWishlistItem } from "./features/wishlist/index";
|
|
260
284
|
export { WishlistCapWatcher } from "./features/wishlist/components/WishlistCapWatcher";
|
|
285
|
+
export { WishlistHeartButton } from "./features/wishlist/components/WishlistHeartButton";
|
|
286
|
+
export type { WishlistHeartButtonProps, WishlistHeartPlacement, } from "./features/wishlist/components/WishlistHeartButton";
|
|
261
287
|
export { SyncManagerMount } from "./core/components/SyncManagerMount";
|
|
262
288
|
export { useWishlistCount, useWishlistCountWithLimit, WISHLIST_CAP_EVENT } from "./features/wishlist/hooks/useWishlistCount";
|
|
263
289
|
export type { WishlistCapEventDetail } from "./features/wishlist/hooks/useWishlistCount";
|
|
264
290
|
export { getGuestWishlistItems, addToGuestWishlist, removeFromGuestWishlist, isInGuestWishlist, clearGuestWishlist, getGuestWishlistCount, getGuestWishlistByType, } from "./features/wishlist/utils/guest-wishlist";
|
|
265
291
|
export { InteractiveProductCard } from "./features/products/index";
|
|
266
292
|
export type { InteractiveProductCardProps } from "./features/products/index";
|
|
293
|
+
export { GroupedListingEditorView } from "./features/grouped/components/GroupedListingEditorView";
|
|
294
|
+
export type { GroupedListingEditorViewProps } from "./features/grouped/components/GroupedListingEditorView";
|
|
267
295
|
export { GroupedListingDetailView } from "./features/grouped/components/GroupedListingDetailView";
|
|
268
296
|
export type { GroupedListingDetailViewProps } from "./features/grouped/components/GroupedListingDetailView";
|
|
269
297
|
export { GroupMemberPicker } from "./features/products/components/GroupMemberPicker";
|
|
@@ -414,8 +442,10 @@ export type { PaymentProofReviewMessageInput } from "./features/whatsapp-bot/typ
|
|
|
414
442
|
export type { AdminNotificationDocument, ItemRequestDocument, ModerationQueueDocument, ReportDocument, CustomRoleDocument, AnalyticsCardDocument, ListingTemplateDocument, } from "./features/store-extensions/index";
|
|
415
443
|
export { CommandPalette, useCommandPaletteHotkey } from "./features/shell/index";
|
|
416
444
|
export type { CommandPaletteGroup } from "./features/shell/index";
|
|
417
|
-
export { AdminBlogEditorView, AdminBundleEditorView, AdminCarouselEditorView, AdminCategoryEditorView, AdminCouponEditorView, AdminFaqEditorView, AdminFeatureEditorView, AdminOrderEditorView, AdminPayoutMarkPaidModal, AdminAuditLogView, ViewAuditLogEntryModal, AdminProductEditorView, AdminScammerEditorView, AdminStoreEditorView, AdminSublistingCategoryEditorView, AdminSupportTicketDetailView, } from "./features/admin/index";
|
|
445
|
+
export { AdminBlogEditorView, AdminBundleEditorView, AdminCarouselEditorView, AdminCategoryEditorView, AdminCouponEditorView, AdminFaqEditorView, AdminFeatureEditorView, AdminOrderEditorView, AdminPayoutMarkPaidModal, AdminAuditLogView, ViewAuditLogEntryModal, AdminProductEditorView, AdminScammerEditorView, AdminEmployeeEditorView, AdminNavEditorView, AdminUserEditorView, AdminStoreEditorView, AdminSublistingCategoryEditorView, AdminSupportTicketDetailView, } from "./features/admin/index";
|
|
418
446
|
export type { AdminStoreEditorViewProps, AdminPayoutMarkPaidModalProps, AdminAuditLogViewProps, AuditLogEntryDetail, ViewAuditLogEntryModalProps } from "./features/admin/index";
|
|
447
|
+
export type { NavItemData } from "./features/admin/index";
|
|
448
|
+
export { PageLoader } from "./ui/index";
|
|
419
449
|
export { ADMIN_CHECKOUT_BYPASS_FLAG_KEY } from "./features/admin/schemas/firestore";
|
|
420
450
|
export { SpinWheelView, EventRaffleEntryForm } from "./features/events/index";
|
|
421
451
|
export { Card, CardBody } from "./ui/index";
|