@mohasinac/appkit 4.27.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/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 +2 -2
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +138 -1
- 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/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
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: Support tickets had THREE validation rules in three places that did not
|
|
3
|
+
* agree. `/user/support/new` hand-rolled a `canSubmit` boolean;
|
|
4
|
+
* `UserSupportView`'s drawer checked nothing at all; and
|
|
5
|
+
* `POST /api/support/tickets` declared its own inline schema.
|
|
6
|
+
* WHAT: One schema for both surfaces AND the route.
|
|
7
|
+
*
|
|
8
|
+
* ## The page was STRICTER than the route, which is the interesting part
|
|
9
|
+
*
|
|
10
|
+
* `/user/support/new` required an `orderId` when the category is
|
|
11
|
+
* `order_issue` — a real rule, since an order complaint with no order is
|
|
12
|
+
* unactionable and support has to go back and ask. The route never enforced
|
|
13
|
+
* it, and the drawer never enforced anything, so the same ticket was
|
|
14
|
+
* acceptable or not depending on which surface the user happened to open.
|
|
15
|
+
*
|
|
16
|
+
* That rule is a `.superRefine` here, so it now holds on all three. Deleting
|
|
17
|
+
* it to "match the route" would have been the easy read of consolidation and
|
|
18
|
+
* the wrong one: the stricter rule was the correct one.
|
|
19
|
+
*
|
|
20
|
+
* EXPORTS: supportTicketCreateSchema, type SupportTicketCreateValues
|
|
21
|
+
*
|
|
22
|
+
* @tag domain:support
|
|
23
|
+
* @tag layer:schema
|
|
24
|
+
* @tag pattern:none
|
|
25
|
+
* @tag access:isomorphic
|
|
26
|
+
* @tag consumers:/user/support/new,UserSupportView,/api/support/tickets
|
|
27
|
+
* @tag sideEffects:none
|
|
28
|
+
*/
|
|
29
|
+
import { z } from "zod";
|
|
30
|
+
import { annotate } from "../../shell/field-ui-meta";
|
|
31
|
+
import { TicketCategoryValues } from "./firestore";
|
|
32
|
+
/*
|
|
33
|
+
* `Object.values(...)` rather than `z.enum(TicketCategoryValues)`. The object
|
|
34
|
+
* form of `z.enum` is Zod 4 syntax, and appkit compiles against zod 3 while
|
|
35
|
+
* the app is on 4 — the two-zod split this repo carries. The tuple form works
|
|
36
|
+
* in both, and still DERIVES from the one map, so a twelfth category cannot be
|
|
37
|
+
* omitted here (Root Cause #61).
|
|
38
|
+
*/
|
|
39
|
+
const CATEGORY_TUPLE = Object.values(TicketCategoryValues);
|
|
40
|
+
/**
|
|
41
|
+
* 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
|
|
42
|
+
* by schema instance and every zod wrapper returns a new one.
|
|
43
|
+
*/
|
|
44
|
+
export const supportTicketCreateSchema = z
|
|
45
|
+
.object({
|
|
46
|
+
category: annotate(z.enum(CATEGORY_TUPLE), {
|
|
47
|
+
section: "ticket",
|
|
48
|
+
sectionLabel: "What do you need help with?",
|
|
49
|
+
sectionRequired: true,
|
|
50
|
+
quick: true,
|
|
51
|
+
order: 1,
|
|
52
|
+
row: "pair",
|
|
53
|
+
}),
|
|
54
|
+
subject: annotate(z
|
|
55
|
+
.string()
|
|
56
|
+
.min(3, "Give the ticket a subject of at least 3 characters.")
|
|
57
|
+
.max(200, "Keep the subject under 200 characters."), { section: "ticket", quick: true, order: 2, row: "full" }),
|
|
58
|
+
description: annotate(z
|
|
59
|
+
.string()
|
|
60
|
+
.min(10, "Describe the problem in at least 10 characters.")
|
|
61
|
+
.max(5000, "Keep the description under 5000 characters."), { section: "ticket", quick: true, order: 3, row: "full", kind: "textarea" }),
|
|
62
|
+
orderId: annotate(z.string().max(120).optional(), {
|
|
63
|
+
section: "ticket",
|
|
64
|
+
order: 4,
|
|
65
|
+
row: "pair",
|
|
66
|
+
help: "Required when the category is an order issue.",
|
|
67
|
+
}),
|
|
68
|
+
})
|
|
69
|
+
.superRefine((v, ctx) => {
|
|
70
|
+
/*
|
|
71
|
+
* The rule only `/user/support/new` enforced. An order complaint with no
|
|
72
|
+
* order id cannot be actioned — support has to reply asking for it, which
|
|
73
|
+
* is a round trip the form can prevent.
|
|
74
|
+
*/
|
|
75
|
+
if (v.category === TicketCategoryValues.ORDER_ISSUE && !v.orderId?.trim()) {
|
|
76
|
+
ctx.addIssue({
|
|
77
|
+
code: z.ZodIssueCode.custom,
|
|
78
|
+
path: ["orderId"],
|
|
79
|
+
message: "Which order is this about? An order id is required.",
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* @tag sideEffects:none
|
|
24
24
|
*/
|
|
25
25
|
import { PRODUCT_FIELDS } from "../../../constants/field-names";
|
|
26
|
-
import {
|
|
26
|
+
import { buildSearchTxt } from "../../../utils/search-txt";
|
|
27
27
|
import { seedExtMedia } from "../../../seed/_helpers/media";
|
|
28
28
|
import { testDataExpiresAt } from "./tester-ttl";
|
|
29
29
|
const TESTER_STORE_ID = "store-tester-sandbox";
|
|
@@ -42,7 +42,7 @@ function withTokens(p) {
|
|
|
42
42
|
storeId: TESTER_STORE_ID,
|
|
43
43
|
storeName: TESTER_STORE_NAME,
|
|
44
44
|
...p,
|
|
45
|
-
|
|
45
|
+
searchTxt: buildSearchTxt([p.title, p.description, p.brand, p.brandSlug, p.categoryNames, p.tags]),
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
// Staggered, incrementing-id auction fixtures so testers can watch a live
|
|
@@ -174,6 +174,29 @@ const rawTesterChecklistItems = [
|
|
|
174
174
|
{ key: "browse-categories", label: "Browsing categories shows relevant products", href: "/categories" },
|
|
175
175
|
{ key: "search", label: "Search returns relevant results", href: "/search" },
|
|
176
176
|
{ key: "filters", label: "Search/listing filters (price, brand, condition) work correctly" },
|
|
177
|
+
{
|
|
178
|
+
key: "homepage-prize-draws-section",
|
|
179
|
+
label: "The homepage shows a \"Prize Draws\" strip with real cards — NOT an empty gap and NOT a \"Something went wrong\" block",
|
|
180
|
+
description: "This section crashed the entire homepage in production (React error 441) until 2026-08-26. Scroll the whole homepage: every strip should render or be cleanly absent. If any single strip is replaced by an error message while the rest of the page is fine, that is the section boundary doing its job — report which strip.",
|
|
181
|
+
href: "/",
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
key: "homepage-event-raffles-section",
|
|
185
|
+
label: "If there are active raffle events, the homepage shows a \"Live Raffles & Spin Wheels\" strip",
|
|
186
|
+
description: "This section silently rendered nothing in production — it looked exactly like \"no active raffles\". Cross-check against /events: if an event with a raffle is active there but no strip appears on the homepage, that is a bug.",
|
|
187
|
+
href: "/",
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
key: "listing-no-missing-message",
|
|
191
|
+
label: "Open the browser console on /products and confirm there are NO \"MISSING_MESSAGE\" errors",
|
|
192
|
+
description: "Press F12 → Console tab, then load the page. A missing translation key logs 'MISSING_MESSAGE: <key>' and renders the raw key text instead of a readable label. Report the exact key name if you see one.",
|
|
193
|
+
href: "/products",
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
key: "product-filter-status-labels",
|
|
197
|
+
label: "In an admin/seller listing's filter drawer, every Status option reads as words (Published / Draft / In Review / Archived) — never a raw key like \"filters.statusInReview\"",
|
|
198
|
+
href: "/products",
|
|
199
|
+
},
|
|
177
200
|
{ key: "pagination", label: "Pagination / infinite scroll works on listing pages" },
|
|
178
201
|
{
|
|
179
202
|
key: "compare-custom-fields",
|
|
@@ -1486,7 +1509,7 @@ const rawTesterChecklistItems = [
|
|
|
1486
1509
|
{
|
|
1487
1510
|
key: "store-feature-edit-page-exists",
|
|
1488
1511
|
label: "A store feature badge can be edited on its own page, not only in a drawer",
|
|
1489
|
-
description: "ROUTES.STORE.FEATURES_EDIT
|
|
1512
|
+
description: "ROUTES.STORE.FEATURES_EDIT used to point at /store/features/[id]/edit with no page behind it. The page exists now, but nothing links to it yet — so open a badge's edit page directly by URL and confirm it loads with that badge's current values, not an empty form.",
|
|
1490
1513
|
href: "/store/features",
|
|
1491
1514
|
},
|
|
1492
1515
|
{
|
|
@@ -1790,6 +1813,12 @@ const rawTesterChecklistItems = [
|
|
|
1790
1813
|
pageLabel: "Become a Seller & Store Setup",
|
|
1791
1814
|
href: "/user/become-seller",
|
|
1792
1815
|
cases: [
|
|
1816
|
+
{
|
|
1817
|
+
key: "sell-redirect",
|
|
1818
|
+
label: "Visiting /sell redirects to the Become a Seller page — it must NOT show \"Something went wrong\"",
|
|
1819
|
+
description: "In production this returned a 200 carrying an error instead of redirecting, so the whole seller-onboarding entry point was dead while looking healthy to monitoring. Type /sell in the address bar directly; the URL should end up on /user/become-seller.",
|
|
1820
|
+
href: "/sell",
|
|
1821
|
+
},
|
|
1793
1822
|
{ key: "apply-seller", label: "Applying to become a seller works", href: "/user/become-seller" },
|
|
1794
1823
|
{ key: "store-setup", label: "Setting up store name/description/logo works" },
|
|
1795
1824
|
{ key: "store-address", label: "Adding a pickup address for the store works" },
|
|
@@ -2688,6 +2717,12 @@ const rawTesterChecklistItems = [
|
|
|
2688
2717
|
cases: [
|
|
2689
2718
|
{ key: "carousel-loops", label: "Homepage carousels (Shop by Category, Top Brands, Featured Products, Live Auctions, Reserve Before It Ships, Verified Stores, Tournaments & Events, Collector Reviews) loop back to the first item after reaching the last instead of getting stuck at the end", href: "/" },
|
|
2690
2719
|
{ key: "carousel-no-flicker", label: "Homepage carousel auto-scroll does not flash/flicker when looping back to the first item" },
|
|
2720
|
+
{
|
|
2721
|
+
key: "hero-carousel-video-plays",
|
|
2722
|
+
label: "The hero carousel slide with a video background actually PLAYS the video — not a blank/black panel",
|
|
2723
|
+
description: "Open the browser console (F12 → Console) while the homepage loads. There must be no 'Load of media resource … failed' or 404 for a .mp4. If the slide is blank, note the failing URL from the console's Network tab.",
|
|
2724
|
+
href: "/",
|
|
2725
|
+
},
|
|
2691
2726
|
{ key: "carousel-pause-on-interaction", label: "Homepage carousel auto-scroll pauses while hovering, touching, keyboard-focusing (Tab + arrow keys), or scrolling it, and resumes afterward" },
|
|
2692
2727
|
{ key: "carousel-arrows-work", label: "Homepage carousel prev/next arrow buttons work and wrap around at both ends" },
|
|
2693
2728
|
{ key: "hero-banner-loops", label: "Hero banner at the top of the homepage rotates through all slides and loops back to the first without getting stuck" },
|
|
@@ -3690,6 +3725,108 @@ const rawTesterChecklistItems = [
|
|
|
3690
3725
|
version: 2,
|
|
3691
3726
|
previousVersionId: "checklist-admin-bug-hunter-rewards-demo-fixture",
|
|
3692
3727
|
},
|
|
3728
|
+
...group("page-wiring", "Page Wiring & Reachability", [
|
|
3729
|
+
{
|
|
3730
|
+
pageKey: "drawer-pages",
|
|
3731
|
+
pageLabel: "Editors that are also pages",
|
|
3732
|
+
href: "/admin/team",
|
|
3733
|
+
cases: [
|
|
3734
|
+
{
|
|
3735
|
+
key: "page-drawer-opens-already-open",
|
|
3736
|
+
label: "Opening an editor page directly shows the panel ALREADY OPEN",
|
|
3737
|
+
description: "Go to /admin/team/new by URL. The invite panel must already be open — not a blank page you have to click into. Close it and you should land back on /admin/team, not on a dead route. Same for /admin/navigation/new and /admin/tester-checklist/new.",
|
|
3738
|
+
},
|
|
3739
|
+
{
|
|
3740
|
+
key: "page-drawer-deep-link-survives-reload",
|
|
3741
|
+
label: "A deep link to an editor survives a reload",
|
|
3742
|
+
description: "Open a team member's edit page, then reload. The panel is still open, on the same record. This is the whole reason these pages exist — a drawer alone cannot be bookmarked, shared with a colleague, or reopened after a crash.",
|
|
3743
|
+
},
|
|
3744
|
+
],
|
|
3745
|
+
},
|
|
3746
|
+
{
|
|
3747
|
+
pageKey: "detail-pages",
|
|
3748
|
+
pageLabel: "Record detail pages",
|
|
3749
|
+
href: "/admin/bids",
|
|
3750
|
+
cases: [
|
|
3751
|
+
{
|
|
3752
|
+
key: "detail-page-matches-list-modal",
|
|
3753
|
+
label: "A bid's detail PAGE shows the same fields as the list's modal",
|
|
3754
|
+
description: "Open a bid from /admin/bids (a modal opens) and note the fields. Now open /admin/bids/{id}/view directly. The fields must be identical — both are built by one buildBidDetailFields, so any difference means a second copy has appeared and the two will drift.",
|
|
3755
|
+
},
|
|
3756
|
+
{
|
|
3757
|
+
key: "detail-page-hides-identity-per-portal",
|
|
3758
|
+
label: "The buyer's own bid page does NOT reveal other bidders",
|
|
3759
|
+
description: "Open the same bid at /admin/bids/{id}/view and at /user/bids/{id}/view. The buyer view must not show the other bidder's identity. One `viewer` argument decides this, in one place — if the buyer view leaks a name, that argument is being ignored somewhere.",
|
|
3760
|
+
},
|
|
3761
|
+
],
|
|
3762
|
+
},
|
|
3763
|
+
{
|
|
3764
|
+
pageKey: "data-loss",
|
|
3765
|
+
pageLabel: "Saves that used to destroy data",
|
|
3766
|
+
href: "/admin/lotteries",
|
|
3767
|
+
cases: [
|
|
3768
|
+
{
|
|
3769
|
+
key: "lottery-edit-preserves-bookings",
|
|
3770
|
+
label: "🛑 Editing a lottery does NOT wipe slots people already pulled",
|
|
3771
|
+
description: "On a seeded lottery, pull/book a slot first. Then open the admin lottery editor, change something unrelated (rename a different slot), and save. Reopen: the booked slot must STILL be booked, with the same buyer name and lottery number. Before this wave the editor sent isBooked:false for every slot and the event PATCH let it through, so the first save erased every purchased slot — with a success message and no error anywhere.",
|
|
3772
|
+
},
|
|
3773
|
+
{
|
|
3774
|
+
key: "lottery-booked-slot-cannot-be-deleted",
|
|
3775
|
+
label: "Removing a slot somebody already pulled is refused, by number",
|
|
3776
|
+
description: "In the same editor, try to delete the slot that has been booked. The save must fail and name that slot number. It is a conflict, not a form error — the correct next action is to reopen the pull, not to fix a field.",
|
|
3777
|
+
},
|
|
3778
|
+
{
|
|
3779
|
+
key: "admin-grouped-listing-title-actually-saves",
|
|
3780
|
+
label: "🛑 An admin renaming a grouped listing actually persists it",
|
|
3781
|
+
description: "Edit a grouped listing's title at /admin/grouped-listings/{id}/edit, save, then RELOAD. The new title must still be there. Reloading is the only way to tell: the old admin PATCH accepted productIds only and silently dropped everything else, so it returned a perfectly normal 200 and wrote nothing.",
|
|
3782
|
+
href: "/admin/grouped-listings",
|
|
3783
|
+
},
|
|
3784
|
+
{
|
|
3785
|
+
key: "store-address-landmark-survives-edit",
|
|
3786
|
+
label: "🛑 A store address keeps its landmark through an edit",
|
|
3787
|
+
description: "Create a store pickup address from the /store/addresses drawer WITH a landmark filled in. Now edit that address at /store/addresses/{id}/edit, change anything else, and save. The landmark must still be set. The shared address form had no landmark field, so it sent undefined and dropped it on every edit.",
|
|
3788
|
+
href: "/store/addresses",
|
|
3789
|
+
},
|
|
3790
|
+
],
|
|
3791
|
+
},
|
|
3792
|
+
{
|
|
3793
|
+
pageKey: "reachability",
|
|
3794
|
+
pageLabel: "Everything built is reachable",
|
|
3795
|
+
href: "/admin",
|
|
3796
|
+
cases: [
|
|
3797
|
+
{
|
|
3798
|
+
key: "lottery-can-be-created-without-seeding",
|
|
3799
|
+
label: "An admin can create a lottery end to end, with no seed script",
|
|
3800
|
+
description: "Create an event of type Lottery from /admin/events/new (the type must be offered — it was missing from the picker entirely), then configure its slots from /admin/lotteries/{id}/edit, then pull a slot as a buyer. Until this wave lottery events could ONLY come from `npm run seed`.",
|
|
3801
|
+
href: "/admin/events/new",
|
|
3802
|
+
},
|
|
3803
|
+
{
|
|
3804
|
+
key: "carousel-can-be-renamed",
|
|
3805
|
+
label: "A named carousel can be renamed after it is created",
|
|
3806
|
+
description: "Open /admin/carousels, pick a carousel, use Edit carousel, change its name and status, save. There was no edit path at all: the group editor was create-only, so a carousel's name was fixed for its whole life.",
|
|
3807
|
+
href: "/admin/carousels",
|
|
3808
|
+
},
|
|
3809
|
+
{
|
|
3810
|
+
key: "grouped-listing-members-editable-from-its-own-page",
|
|
3811
|
+
label: "A grouped listing's MEMBERS can be picked while creating it",
|
|
3812
|
+
description: "Create a group at /store/grouped-listings/new and add products in the same form. Previously productIds was hardcoded to an empty array, so a group could only ever be created empty and filled in from somewhere else. Check the minimum-active-members and cover-image fields are present too — neither had an input anywhere.",
|
|
3813
|
+
href: "/store/grouped-listings/new",
|
|
3814
|
+
},
|
|
3815
|
+
{
|
|
3816
|
+
key: "public-nav-and-footer-resolve",
|
|
3817
|
+
label: "Every header, sidebar-support and footer link opens a real page",
|
|
3818
|
+
description: "Walk the public header nav, the sidebar support links and every footer column. All 55 hrefs must land on a real page. No audit checked ANY of them until this wave — the nav audit only ever looked at the three portal sidebars.",
|
|
3819
|
+
href: "/",
|
|
3820
|
+
},
|
|
3821
|
+
{
|
|
3822
|
+
key: "user-tester-hub-reachable-from-user-sidebar",
|
|
3823
|
+
label: "A tester reaches the Tester Hub from their OWN sidebar",
|
|
3824
|
+
description: "As a user with the tester flag, open /user and find Tester Hub in the sidebar under Testing. The group is injected at runtime and is empty for non-testers — confirm a NON-tester account does not see it.",
|
|
3825
|
+
href: "/user",
|
|
3826
|
+
},
|
|
3827
|
+
],
|
|
3828
|
+
},
|
|
3829
|
+
]),
|
|
3693
3830
|
];
|
|
3694
3831
|
const defaultPhases = assignDefaultPhases(rawTesterChecklistItems);
|
|
3695
3832
|
export const testerChecklistSeedData = rawTesterChecklistItems.map((item, index) => ({
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { MouseEvent } from "react";
|
|
2
|
+
/** The heart renders a <button>, so handlers get the real element type. */
|
|
3
|
+
type HeartMouseEvent = MouseEvent<HTMLButtonElement>;
|
|
4
|
+
/**
|
|
5
|
+
* Where the heart sits, which decides its box — never passed as a raw size.
|
|
6
|
+
*
|
|
7
|
+
* - `card` — the only affordance in its corner of a product card. 44px, the
|
|
8
|
+
* minimum comfortable tap target.
|
|
9
|
+
* - `inline` — sits in a row beside a title or price. 40px.
|
|
10
|
+
* - `detail` — a product detail page's standalone control. 48px.
|
|
11
|
+
*/
|
|
12
|
+
declare const PLACEMENT_SIZE: {
|
|
13
|
+
readonly inline: "md";
|
|
14
|
+
readonly card: "touch";
|
|
15
|
+
readonly detail: "lg";
|
|
16
|
+
};
|
|
17
|
+
export type WishlistHeartPlacement = keyof typeof PLACEMENT_SIZE;
|
|
18
|
+
export interface WishlistHeartButtonProps {
|
|
19
|
+
inWishlist: boolean;
|
|
20
|
+
isLoading?: boolean;
|
|
21
|
+
onToggle: (e: HeartMouseEvent) => void | Promise<void>;
|
|
22
|
+
addLabel: string;
|
|
23
|
+
removeLabel: string;
|
|
24
|
+
/** See PLACEMENT_SIZE. */
|
|
25
|
+
size?: WishlistHeartPlacement;
|
|
26
|
+
/**
|
|
27
|
+
* `overlay` floats above product imagery and needs its own backdrop;
|
|
28
|
+
* `plain` sits on an ordinary surface.
|
|
29
|
+
*/
|
|
30
|
+
variant?: "overlay" | "plain";
|
|
31
|
+
className?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The ONE wishlist heart.
|
|
35
|
+
*
|
|
36
|
+
* WHY: there were seven render sites using THREE different glyph technologies —
|
|
37
|
+
* an inline `<svg>` (product grid card), lucide `<Heart>` at two different sizes
|
|
38
|
+
* (auction card list vs grid), and the text characters `♥`/`♡` (product list
|
|
39
|
+
* row, both pre-order card layouts, and baked into the detail page's label
|
|
40
|
+
* strings). Text glyphs cannot be sized by `w-*`/`h-*` at all and fall back to a
|
|
41
|
+
* platform font, which is literally the "the wishlist icon is very small"
|
|
42
|
+
* report. The auction card's lucide heart was 14px inside a `md` Button whose
|
|
43
|
+
* min-height is ~44px, so the largest tap target carried the smallest glyph.
|
|
44
|
+
*
|
|
45
|
+
* Built on `IconButton`, not `Button`: `.appkit-button--sm` sets
|
|
46
|
+
* `min-height: 36px` and, under `important: true`, beats a caller's `h-8`, so
|
|
47
|
+
* the product card's heart rendered as a 32x36 ellipse under `rounded-full`.
|
|
48
|
+
* `IconButton` boxes are true squares.
|
|
49
|
+
*
|
|
50
|
+
* 🛑 It owns NO auth modal. `useAuthGate` is the single gate (Rule #7) and the
|
|
51
|
+
* caller wraps `onToggle` in `requireAuth`. The predecessor this replaces kept
|
|
52
|
+
* its own `LoginRequiredModal` and would have raced the gate's.
|
|
53
|
+
*/
|
|
54
|
+
export declare function WishlistHeartButton({ inWishlist, isLoading, onToggle, addLabel, removeLabel, size, variant, className, }: WishlistHeartButtonProps): import("react").JSX.Element;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { IconButton, Icon } from "../../../ui";
|
|
4
|
+
import { ICON_BUTTON_ICON_SIZE } from "../../../ui/components/IconButton";
|
|
5
|
+
/**
|
|
6
|
+
* Where the heart sits, which decides its box — never passed as a raw size.
|
|
7
|
+
*
|
|
8
|
+
* - `card` — the only affordance in its corner of a product card. 44px, the
|
|
9
|
+
* minimum comfortable tap target.
|
|
10
|
+
* - `inline` — sits in a row beside a title or price. 40px.
|
|
11
|
+
* - `detail` — a product detail page's standalone control. 48px.
|
|
12
|
+
*/
|
|
13
|
+
const PLACEMENT_SIZE = {
|
|
14
|
+
inline: "md",
|
|
15
|
+
card: "touch",
|
|
16
|
+
detail: "lg",
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* The ONE wishlist heart.
|
|
20
|
+
*
|
|
21
|
+
* WHY: there were seven render sites using THREE different glyph technologies —
|
|
22
|
+
* an inline `<svg>` (product grid card), lucide `<Heart>` at two different sizes
|
|
23
|
+
* (auction card list vs grid), and the text characters `♥`/`♡` (product list
|
|
24
|
+
* row, both pre-order card layouts, and baked into the detail page's label
|
|
25
|
+
* strings). Text glyphs cannot be sized by `w-*`/`h-*` at all and fall back to a
|
|
26
|
+
* platform font, which is literally the "the wishlist icon is very small"
|
|
27
|
+
* report. The auction card's lucide heart was 14px inside a `md` Button whose
|
|
28
|
+
* min-height is ~44px, so the largest tap target carried the smallest glyph.
|
|
29
|
+
*
|
|
30
|
+
* Built on `IconButton`, not `Button`: `.appkit-button--sm` sets
|
|
31
|
+
* `min-height: 36px` and, under `important: true`, beats a caller's `h-8`, so
|
|
32
|
+
* the product card's heart rendered as a 32x36 ellipse under `rounded-full`.
|
|
33
|
+
* `IconButton` boxes are true squares.
|
|
34
|
+
*
|
|
35
|
+
* 🛑 It owns NO auth modal. `useAuthGate` is the single gate (Rule #7) and the
|
|
36
|
+
* caller wraps `onToggle` in `requireAuth`. The predecessor this replaces kept
|
|
37
|
+
* its own `LoginRequiredModal` and would have raced the gate's.
|
|
38
|
+
*/
|
|
39
|
+
export function WishlistHeartButton({ inWishlist, isLoading = false, onToggle, addLabel, removeLabel, size = "inline", variant = "plain", className = "", }) {
|
|
40
|
+
const label = inWishlist ? removeLabel : addLabel;
|
|
41
|
+
const box = PLACEMENT_SIZE[size];
|
|
42
|
+
return (_jsx(IconButton, { type: "button", "aria-label": label, title: label, size: box, variant: "ghost", rounded: "full", disabled: isLoading, "aria-pressed": inWishlist, onClick: (e) => void onToggle(e), className: [
|
|
43
|
+
"transition-colors duration-150",
|
|
44
|
+
variant === "overlay"
|
|
45
|
+
? "bg-[var(--appkit-color-surface-elevated)]/90 shadow-sm backdrop-blur-sm"
|
|
46
|
+
: "",
|
|
47
|
+
isLoading ? "opacity-50" : "",
|
|
48
|
+
className,
|
|
49
|
+
]
|
|
50
|
+
.filter(Boolean)
|
|
51
|
+
.join(" "), icon: _jsx(Icon, { name: "wishlist", size: ICON_BUTTON_ICON_SIZE[box], filled: inWishlist, tone: inWishlist ? "error" : "muted" }) }));
|
|
52
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { WishlistCard, WishlistPage } from "./WishlistPage";
|
|
2
|
-
export {
|
|
2
|
+
export { WishlistHeartButton } from "./WishlistHeartButton";
|
|
3
|
+
export type { WishlistHeartButtonProps, WishlistHeartPlacement } from "./WishlistHeartButton";
|
|
3
4
|
export { WishlistView } from "./WishlistView";
|
|
4
5
|
export type { WishlistViewProps, WishlistTab } from "./WishlistView";
|
|
5
6
|
export { WishlistCapWatcher } from "./WishlistCapWatcher";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { WishlistCard, WishlistPage } from "./WishlistPage";
|
|
2
|
-
export {
|
|
2
|
+
export { WishlistHeartButton } from "./WishlistHeartButton";
|
|
3
3
|
export { WishlistView } from "./WishlistView";
|
|
4
4
|
export { WishlistCapWatcher } from "./WishlistCapWatcher";
|
package/dist/index.d.ts
CHANGED
|
@@ -1755,6 +1755,10 @@ export { EVENTS_COLLECTION } from "./features/events/index";
|
|
|
1755
1755
|
export { EVENT_ADMIN_SORT_OPTIONS } from "./features/events/index";
|
|
1756
1756
|
export { EVENT_ENTRIES_COLLECTION } from "./features/events/index";
|
|
1757
1757
|
export { LOTTERY_ENTRIES_COLLECTION } from "./features/lottery/schemas/firestore";
|
|
1758
|
+
export { supportTicketCreateSchema } from "./features/support/schemas/ticket-create-form";
|
|
1759
|
+
export type { SupportTicketCreateValues } from "./features/support/schemas/ticket-create-form";
|
|
1760
|
+
export { lotteryConfigWriteSchema, lotterySlotWriteSchema, mergeLotteryConfig } from "./features/lottery/schemas/config-write";
|
|
1761
|
+
export type { LotteryConfigWriteInput, LotteryMergeResult } from "./features/lottery/schemas/config-write";
|
|
1758
1762
|
export { lotteryEntriesSeedData } from "./seed/index";
|
|
1759
1763
|
export { LOTTERY_ENTRY_FIELDS } from "./features/lottery/schemas/firestore";
|
|
1760
1764
|
export { EVENT_ENTRY_FIELDS } from "./features/events/index";
|
|
@@ -1839,6 +1843,7 @@ export type { EventListResponse } from "./features/events/index";
|
|
|
1839
1843
|
export type { EventParticipateViewProps } from "./features/events/index";
|
|
1840
1844
|
export type { EventStatus } from "./features/events/index";
|
|
1841
1845
|
export type { EventType } from "./features/events/index";
|
|
1846
|
+
export { ALL_EVENT_TYPES, ALL_EVENT_STATUSES } from "./features/events/index";
|
|
1842
1847
|
export type { EventUpdateInput } from "./features/events/index";
|
|
1843
1848
|
export type { FeedbackConfig } from "./features/events/index";
|
|
1844
1849
|
export type { FormFieldType } from "./features/events/index";
|
|
@@ -3018,7 +3023,7 @@ export { sendWhatsAppBusinessMessage, syncProductsToCatalog, buildPurchaseAnnoun
|
|
|
3018
3023
|
export type { WaBusinessSendInput, CatalogSyncProduct, CatalogSyncInput, CatalogSyncResult, PurchaseAnnouncementInput } from "./features/whatsapp-bot/index";
|
|
3019
3024
|
export { WishlistCard } from "./features/wishlist/index";
|
|
3020
3025
|
export { WishlistPage } from "./features/wishlist/index";
|
|
3021
|
-
export {
|
|
3026
|
+
export { WishlistHeartButton } from "./features/wishlist/index";
|
|
3022
3027
|
export { WishlistView } from "./features/wishlist/index";
|
|
3023
3028
|
export { buildWishlistColumns } from "./features/wishlist/index";
|
|
3024
3029
|
export { useUserWishlist } from "./features/wishlist/index";
|
|
@@ -3091,6 +3096,8 @@ export { ToastProvider, StarRating, StepperNav, ViewToggle, PriceDisplay, Summar
|
|
|
3091
3096
|
export { CountdownDisplay, ItemRow, HorizontalScroller } from "./ui/index";
|
|
3092
3097
|
export { CardBody, MenuTrigger, MenuContent, MenuSeparator, RoleBadge, SkipToMain } from "./ui/index";
|
|
3093
3098
|
export { Tabs, TabsList, TabsTrigger, TabsContent, PasswordStrengthIndicator, TablePagination } from "./ui/index";
|
|
3099
|
+
export { TabBarShell, TabBarButton, TabsNavSelect } from "./ui/index";
|
|
3100
|
+
export type { TabBarShellProps, TabBarButtonProps, TabsNavSelectProps } from "./ui/index";
|
|
3094
3101
|
export { Stack, classNames, mergeTailwindClasses, SideModal, SideDrawer, RichText, RichTextRenderer } from "./ui/index";
|
|
3095
3102
|
export type { RichTextRendererProps } from "./ui/index";
|
|
3096
3103
|
export { SlottedListingView, DetailViewShell, StackedViewShell } from "./ui/index";
|
|
@@ -3132,7 +3139,7 @@ export { formatMonthYear } from "./utils/date.formatter";
|
|
|
3132
3139
|
export { generateMediaFilename } from "./utils/id-generators";
|
|
3133
3140
|
export { deriveContextTypeFromFilename } from "./utils/id-generators";
|
|
3134
3141
|
export type { MediaFilenameContext } from "./utils/id-generators";
|
|
3135
|
-
export { resolveMediaUrl, FIREBASE_STORAGE_HOST, GCS_HOST } from "./utils/media-url";
|
|
3142
|
+
export { resolveMediaUrl, resolveVideoUrl, FIREBASE_STORAGE_HOST, GCS_HOST } from "./utils/media-url";
|
|
3136
3143
|
export { generateFAQId } from "./utils/id-generators";
|
|
3137
3144
|
export type { GenerateFAQIdInput } from "./utils/id-generators";
|
|
3138
3145
|
export { generateCroppedImageFilename } from "./utils/id-generators";
|
|
@@ -3245,7 +3252,7 @@ export { TABLE_KEYS, VIEW_MODE } from "./constants/table-keys";
|
|
|
3245
3252
|
export type { TableKey, ViewMode } from "./constants/table-keys";
|
|
3246
3253
|
export { SIEVE_OP, SIEVE_PIPE_OPS, sieveFilter, sieveMultiEq, expandSieveParam, sieveAnd, } from "./utils/sieve-builder";
|
|
3247
3254
|
export type { SieveOp } from "./utils/sieve-builder";
|
|
3248
|
-
export {
|
|
3255
|
+
export { buildSearchTxt, parseSearchTxtQuery, matchesAllSearchTerms, normalizeSearchText, type SearchTxtOptions, } from "./utils/search-txt";
|
|
3249
3256
|
export { ActionPermissionsManager } from "./features/site-settings/components/ActionPermissionsManager";
|
|
3250
3257
|
export type { ActionPermissionsManagerProps } from "./features/site-settings/components/ActionPermissionsManager";
|
|
3251
3258
|
export { NavPermissionsManager } from "./features/site-settings/components/NavPermissionsManager";
|
package/dist/index.js
CHANGED
|
@@ -3313,6 +3313,10 @@ export { EVENT_ADMIN_SORT_OPTIONS } from "./features/events/index";
|
|
|
3313
3313
|
export { EVENT_ENTRIES_COLLECTION } from "./features/events/index";
|
|
3314
3314
|
// LOTTERY_ENTRIES_COLLECTION - New lotteryEntries collection constant.
|
|
3315
3315
|
export { LOTTERY_ENTRIES_COLLECTION } from "./features/lottery/schemas/firestore";
|
|
3316
|
+
export { supportTicketCreateSchema } from "./features/support/schemas/ticket-create-form";
|
|
3317
|
+
// The lotteryConfig WRITE contract + the booking-preserving merge. The only
|
|
3318
|
+
// sanctioned way to write lotteryConfig — see the schema module's header.
|
|
3319
|
+
export { lotteryConfigWriteSchema, lotterySlotWriteSchema, mergeLotteryConfig } from "./features/lottery/schemas/config-write";
|
|
3316
3320
|
// lotteryEntriesSeedData - Seed data for the lotteryEntries collection.
|
|
3317
3321
|
export { lotteryEntriesSeedData } from "./seed/index";
|
|
3318
3322
|
// [SCHEMA]-Schema / data-shape constant â€" Zod validator, default-value object, or Firestore collection/field name constant.
|
|
@@ -3445,6 +3449,11 @@ export { useEventLeaderboard } from "./features/events/index";
|
|
|
3445
3449
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
3446
3450
|
// useEvents - React hook for use events.
|
|
3447
3451
|
export { useEvents } from "./features/events/index";
|
|
3452
|
+
// ALL_EVENT_TYPES / ALL_EVENT_STATUSES - derived from a `Record<Union, true>`,
|
|
3453
|
+
// so a union member missing from either is a COMPILE error rather than a
|
|
3454
|
+
// silently short list. Exported because consumers were hand-writing their own
|
|
3455
|
+
// copies and drifting (Root Cause #61).
|
|
3456
|
+
export { ALL_EVENT_TYPES, ALL_EVENT_STATUSES } from "./features/events/index";
|
|
3448
3457
|
// ./features/events/server
|
|
3449
3458
|
// [SERVER-ONLY]-Server-only â€" uses Node.js, Next.js server internals, or third-party server SDKs (auth, email, payment, shipping).
|
|
3450
3459
|
// adminGetEventById - Shared export for admin get event by id.
|
|
@@ -5387,8 +5396,10 @@ export { WishlistCard } from "./features/wishlist/index";
|
|
|
5387
5396
|
// WishlistPage - Component for wishlist page.
|
|
5388
5397
|
export { WishlistPage } from "./features/wishlist/index";
|
|
5389
5398
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
5390
|
-
//
|
|
5391
|
-
|
|
5399
|
+
// WishlistHeartButton - the single wishlist heart. Replaced
|
|
5400
|
+
// WishlistToggleButton, which was dead code with its own competing
|
|
5401
|
+
// LoginRequiredModal; see the component for the full rationale.
|
|
5402
|
+
export { WishlistHeartButton } from "./features/wishlist/index";
|
|
5392
5403
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
5393
5404
|
// WishlistView - Component for wishlist view.
|
|
5394
5405
|
export { WishlistView } from "./features/wishlist/index";
|
|
@@ -5487,6 +5498,8 @@ export { ToastProvider, StarRating, StepperNav, ViewToggle, PriceDisplay, Summar
|
|
|
5487
5498
|
export { CountdownDisplay, ItemRow, HorizontalScroller } from "./ui/index";
|
|
5488
5499
|
export { CardBody, MenuTrigger, MenuContent, MenuSeparator, RoleBadge, SkipToMain } from "./ui/index";
|
|
5489
5500
|
export { Tabs, TabsList, TabsTrigger, TabsContent, PasswordStrengthIndicator, TablePagination } from "./ui/index";
|
|
5501
|
+
// TabBarShell - rail + overflow scroll arrows around a role="tablist"; TabBarButton / TabsNavSelect - its two trigger flavours
|
|
5502
|
+
export { TabBarShell, TabBarButton, TabsNavSelect } from "./ui/index";
|
|
5490
5503
|
export { Stack, classNames, mergeTailwindClasses, SideModal, SideDrawer, RichText, RichTextRenderer } from "./ui/index";
|
|
5491
5504
|
export { SlottedListingView, DetailViewShell, StackedViewShell } from "./ui/index";
|
|
5492
5505
|
export { buildColumns, createColumnBuilder } from "./ui/index";
|
|
@@ -5537,7 +5550,7 @@ export { formatCurrency, formatFileSize } from "./utils/number.formatter";
|
|
|
5537
5550
|
export { formatMonthYear } from "./utils/date.formatter";
|
|
5538
5551
|
export { generateMediaFilename } from "./utils/id-generators"; // generateProductImageFilename already exported from "./utils/id-generators";
|
|
5539
5552
|
export { deriveContextTypeFromFilename } from "./utils/id-generators";
|
|
5540
|
-
export { resolveMediaUrl, FIREBASE_STORAGE_HOST, GCS_HOST } from "./utils/media-url";
|
|
5553
|
+
export { resolveMediaUrl, resolveVideoUrl, FIREBASE_STORAGE_HOST, GCS_HOST } from "./utils/media-url";
|
|
5541
5554
|
export { generateFAQId } from "./utils/id-generators";
|
|
5542
5555
|
export { generateCroppedImageFilename } from "./utils/id-generators";
|
|
5543
5556
|
// Messages / Conversations feature schemas
|
|
@@ -5655,7 +5668,9 @@ export { SORT_DIR, sortBy } from "./constants/sort";
|
|
|
5655
5668
|
export { TABLE_KEYS, VIEW_MODE } from "./constants/table-keys";
|
|
5656
5669
|
// ── Sieve query builder ───────────────────────────────────────────────────────
|
|
5657
5670
|
export { SIEVE_OP, SIEVE_PIPE_OPS, sieveFilter, sieveMultiEq, expandSieveParam, sieveAnd, } from "./utils/sieve-builder";
|
|
5658
|
-
|
|
5671
|
+
// searchTxt — normalized edge-n-gram search field. Supersedes search-tokens;
|
|
5672
|
+
// see appkit/src/utils/search-txt.ts for why it is an array and not a string.
|
|
5673
|
+
export { buildSearchTxt, parseSearchTxtQuery, matchesAllSearchTerms, normalizeSearchText, } from "./utils/search-txt";
|
|
5659
5674
|
// [CLIENT-ONLY] — Admin panel components for action/nav permission management.
|
|
5660
5675
|
export { ActionPermissionsManager } from "./features/site-settings/components/ActionPermissionsManager";
|
|
5661
5676
|
export { NavPermissionsManager } from "./features/site-settings/components/NavPermissionsManager";
|
|
@@ -23,12 +23,46 @@ export var ErrorCategory;
|
|
|
23
23
|
ErrorCategory["UNKNOWN"] = "unknown";
|
|
24
24
|
})(ErrorCategory || (ErrorCategory = {}));
|
|
25
25
|
const TRACKER_KEY = "__mohasinac_error_tracker__";
|
|
26
|
+
/**
|
|
27
|
+
* Default sink — structured, severity-tagged JSON on the server.
|
|
28
|
+
*
|
|
29
|
+
* `setErrorTracker()` is exported so an app can install Sentry or similar, and
|
|
30
|
+
* its only reference anywhere in this repo was its own doc comment: nothing ever
|
|
31
|
+
* called it. So every tracked error went out as a plain `console.error` string,
|
|
32
|
+
* which Cloud Logging files as unparsed DEFAULT severity — invisible to any
|
|
33
|
+
* severity filter or alert.
|
|
34
|
+
*
|
|
35
|
+
* Emitting `{severity, message, stack}` fixes that with no dependency and no
|
|
36
|
+
* DSN: GCP Error Reporting automatically ingests ERROR-severity log entries
|
|
37
|
+
* that carry a stack trace.
|
|
38
|
+
*
|
|
39
|
+
* The formatting is inlined rather than delegated to `serverLogger` on purpose.
|
|
40
|
+
* This module is re-exported from `client.ts`, and `server-logger` imports
|
|
41
|
+
* `next/server` — importing it here would pull server-only code along every
|
|
42
|
+
* client import chain, which is how Root Cause #24 gets reproduced. Eight lines
|
|
43
|
+
* of duplicated shape is the cheaper trade.
|
|
44
|
+
*/
|
|
45
|
+
function defaultTracker(error, category, severity, context) {
|
|
46
|
+
const isError = error instanceof Error;
|
|
47
|
+
const message = isError ? error.message : error;
|
|
48
|
+
// In a browser there is no log collector to parse JSON, and a readable console
|
|
49
|
+
// entry is worth more to whoever is looking at it.
|
|
50
|
+
if (typeof window !== "undefined") {
|
|
51
|
+
console.error(`[${severity.toUpperCase()}][${category}] ${message}`, context);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
console.error(JSON.stringify({
|
|
55
|
+
severity: "ERROR",
|
|
56
|
+
message,
|
|
57
|
+
category,
|
|
58
|
+
errorSeverity: severity,
|
|
59
|
+
timestamp: new Date().toISOString(),
|
|
60
|
+
...(isError && error.stack ? { stack: error.stack } : {}),
|
|
61
|
+
...(context ? { context } : {}),
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
26
64
|
function getTracker() {
|
|
27
|
-
return
|
|
28
|
-
((error, category, severity, context) => {
|
|
29
|
-
const msg = error instanceof Error ? error.message : error;
|
|
30
|
-
console.error(`[${severity.toUpperCase()}][${category}] ${msg}`, context);
|
|
31
|
-
}));
|
|
65
|
+
return globalThis[TRACKER_KEY] ?? defaultTracker;
|
|
32
66
|
}
|
|
33
67
|
/** Override the default console-based tracker with a custom implementation. */
|
|
34
68
|
export function setErrorTracker(fn) {
|