@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
|
@@ -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",
|
|
@@ -729,39 +752,124 @@ const rawTesterChecklistItems = [
|
|
|
729
752
|
href: "/cart",
|
|
730
753
|
cases: [
|
|
731
754
|
{ key: "update-qty", label: "Updating item quantity in cart recalculates the total" },
|
|
755
|
+
// ── Grouped & bundle cart lines ──────────────────────────────────
|
|
756
|
+
// Fixtures backing these: product-tester-standard-1/2/3 (three members
|
|
757
|
+
// of one group, deliberately spanning two GST rates),
|
|
758
|
+
// product-tester-group-soldout (blocked member),
|
|
759
|
+
// product-tester-crossstore-a/b (a group spanning two sellers),
|
|
760
|
+
// bundle-tester-sandbox (a priced, all-or-nothing bundle).
|
|
761
|
+
{
|
|
762
|
+
key: "group-picker-opens",
|
|
763
|
+
label: "On a product that belongs to a group, the \"Part of: …\" strip has a \"Pick items →\" control that opens a picker with a Qty column and a +/- stepper on each member",
|
|
764
|
+
description: "Before this existed the panel was navigation only — the buyer had to open each member separately and add it as its own cart line.",
|
|
765
|
+
href: "/products/product-tester-standard-1",
|
|
766
|
+
},
|
|
732
767
|
{
|
|
733
|
-
key: "group-picker-
|
|
734
|
-
label: "
|
|
735
|
-
description: "Use the Test Gadget page. Set two different members to different quantities, check the running total in the picker footer, then add. The cart should show a single line, not three.",
|
|
768
|
+
key: "group-picker-running-total",
|
|
769
|
+
label: "Changing any member's quantity updates the picker's running total (\"N items · ₹X\") immediately, and \"Add selected to cart\" stays disabled while nothing is selected",
|
|
736
770
|
href: "/products/product-tester-standard-1",
|
|
737
771
|
},
|
|
738
772
|
{
|
|
739
|
-
key: "group-
|
|
740
|
-
label: "A
|
|
741
|
-
|
|
742
|
-
|
|
773
|
+
key: "group-picker-stock-cap",
|
|
774
|
+
label: "A member's + button stops at that member's available stock — it cannot be pushed past it",
|
|
775
|
+
href: "/products/product-tester-standard-1",
|
|
776
|
+
},
|
|
777
|
+
{
|
|
778
|
+
key: "group-picker-blocked-member",
|
|
779
|
+
label: "A sold-out member shows a reason chip (e.g. \"Sold\" / \"Out of stock\") in place of its stepper and cannot be selected",
|
|
780
|
+
description: "Test Part — Sold Out is seeded into the tester group specifically for this. The rest of the group must stay selectable around it.",
|
|
781
|
+
href: "/products/product-tester-group-soldout",
|
|
782
|
+
},
|
|
783
|
+
{
|
|
784
|
+
key: "group-picker-one-line",
|
|
785
|
+
label: "\"Add selected to cart\" with two or more members creates ONE cart line, not one line per product",
|
|
786
|
+
description: "Pick 2 of one member and 1 of another, then open the cart: a single line reading \"N items\", not three separate rows.",
|
|
787
|
+
href: "/products/product-tester-standard-1",
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
key: "group-picker-single-member-plain-line",
|
|
791
|
+
label: "Selecting exactly ONE member produces an ordinary product line (with a normal quantity stepper), not a grouped line",
|
|
792
|
+
description: "1 item × qty N is already what a normal cart line means, so it deliberately does not become a group line.",
|
|
793
|
+
href: "/products/product-tester-standard-1",
|
|
743
794
|
},
|
|
744
795
|
{
|
|
745
796
|
key: "group-picker-cross-store",
|
|
746
|
-
label: "A group whose members belong to
|
|
797
|
+
label: "A group whose members belong to DIFFERENT sellers renders read-only — no Qty column, no \"Add selected\" button — with an explanation, rather than a button that always fails",
|
|
798
|
+
description: "Use the Test Cross-Store Set. Its two members sit in different stores on purpose.",
|
|
799
|
+
href: "/products/product-tester-crossstore-a",
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
key: "group-picker-guest",
|
|
803
|
+
label: "A signed-out visitor using the picker is shown the login prompt rather than silently losing the selection",
|
|
747
804
|
href: "/products/product-tester-standard-1",
|
|
748
805
|
},
|
|
806
|
+
{
|
|
807
|
+
key: "group-line-expands-in-cart",
|
|
808
|
+
label: "A grouped cart line in the cart expands to list its members with a thumbnail, unit price and its own +/- stepper each",
|
|
809
|
+
href: "/cart",
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
key: "group-line-no-line-level-stepper",
|
|
813
|
+
label: "A grouped line has NO line-level quantity stepper — only the per-member ones",
|
|
814
|
+
description: "The member quantities carry the whole selection; a second multiplier on top would double every price, tax and stock decrement.",
|
|
815
|
+
href: "/cart",
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
key: "group-line-member-edit-recalculates",
|
|
819
|
+
label: "Changing one member's quantity in the cart updates that line's total AND the seller-group subtotal above it",
|
|
820
|
+
href: "/cart",
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
key: "group-line-remove-member",
|
|
824
|
+
label: "Removing one member from a grouped line leaves the rest of the line intact; removing the LAST member removes the whole line",
|
|
825
|
+
href: "/cart",
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
key: "group-line-link-target",
|
|
829
|
+
label: "Clicking a grouped or bundle line's title in the cart lands on a real page — never a 404",
|
|
830
|
+
description: "A bundle line goes to /bundles/{slug}, a grouped-listing line to /groups/{slug}, a product-group line to its parent product. It used to point at /products/{categoryId}, which never existed.",
|
|
831
|
+
href: "/cart",
|
|
832
|
+
},
|
|
749
833
|
{
|
|
750
834
|
key: "bundle-copies-stepper",
|
|
751
835
|
label: "A bundle page has a \"Copies\" +/- stepper and BOTH \"Buy now\" and \"Add to cart\" — Add to cart stays on the page, Buy now goes to checkout",
|
|
752
|
-
description: "A bundle is all-or-nothing: there must be no per-member quantity controls on the bundle page, only the copies stepper.",
|
|
836
|
+
description: "A bundle is all-or-nothing: there must be no per-member quantity controls anywhere on the bundle page, only the copies stepper.",
|
|
753
837
|
href: "/bundles/bundle-tester-sandbox",
|
|
754
838
|
},
|
|
755
839
|
{
|
|
756
|
-
key: "bundle-line-
|
|
757
|
-
label: "A bundle in the cart
|
|
840
|
+
key: "bundle-line-in-cart",
|
|
841
|
+
label: "A bundle in the cart lists its members READ-ONLY and offers a copies stepper; raising copies multiplies the bundle's discounted price, never the sum of the members' individual prices",
|
|
842
|
+
description: "Test Bundle is ₹199 while its members list at ₹199 + ₹149. Two copies must read ₹398, not ₹696.",
|
|
758
843
|
href: "/cart",
|
|
759
844
|
},
|
|
845
|
+
{
|
|
846
|
+
key: "bundle-cross-store-rejected",
|
|
847
|
+
label: "Saving a bundle whose items come from two different sellers is refused with a clear message naming how many sellers they span",
|
|
848
|
+
description: "Build a bundle mixing Test Cross-Store Set — Seller A with any Tester Sandbox product and save. Applies to both creating and editing, on the admin and the seller bundle editors. A bundle's storeId is a single value and is what decides which seller gets the order, the shipment and the payout — so a two-seller bundle would pay only one of them.",
|
|
849
|
+
href: "/store/bundles/new",
|
|
850
|
+
},
|
|
760
851
|
{
|
|
761
852
|
key: "grouped-listing-page-picker",
|
|
762
|
-
label: "A grouped listing has its own page with the same picker, reachable from the \"Pick items from this group →\" button on a group carousel",
|
|
853
|
+
label: "A grouped listing has its own public page with the same picker, reachable from the \"Pick items from this group →\" button on a group carousel",
|
|
763
854
|
href: "/groups/group-beyblade-original-lineage",
|
|
764
855
|
},
|
|
856
|
+
{
|
|
857
|
+
key: "group-lane-gate",
|
|
858
|
+
label: "While an unpaid won auction or accepted offer is sitting in the cart, adding a group selection is refused with the same lane message as any other add",
|
|
859
|
+
description: "This path used to bypass the gate entirely, so a buyer could keep shopping around an obligation they had already committed to.",
|
|
860
|
+
href: "/products/product-tester-standard-1",
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
key: "group-checkout-order-rows",
|
|
864
|
+
label: "After checking out a grouped or bundle line, the order shows one row PER MEMBER under a single group header, and the line totals add up to the order total",
|
|
865
|
+
description: "Rows are expanded so each carries its own HSN code and GST rate — a collapsed row can only carry one of each, which is why bundles previously showed none.",
|
|
866
|
+
href: "/user/orders",
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
key: "group-checkout-stock",
|
|
870
|
+
label: "Checking out a grouped line decrements each member by (its per-copy quantity × the number of copies), not by one each",
|
|
871
|
+
href: "/user/orders",
|
|
872
|
+
},
|
|
765
873
|
{ key: "apply-coupon", label: "Applying a coupon code at checkout works" },
|
|
766
874
|
{ key: "remove-coupon", label: "Removing an already-applied coupon from the cart recalculates the total back down" },
|
|
767
875
|
{ key: "remove-item", label: "Removing an item from the cart works" },
|
|
@@ -1401,7 +1509,7 @@ const rawTesterChecklistItems = [
|
|
|
1401
1509
|
{
|
|
1402
1510
|
key: "store-feature-edit-page-exists",
|
|
1403
1511
|
label: "A store feature badge can be edited on its own page, not only in a drawer",
|
|
1404
|
-
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.",
|
|
1405
1513
|
href: "/store/features",
|
|
1406
1514
|
},
|
|
1407
1515
|
{
|
|
@@ -1705,6 +1813,12 @@ const rawTesterChecklistItems = [
|
|
|
1705
1813
|
pageLabel: "Become a Seller & Store Setup",
|
|
1706
1814
|
href: "/user/become-seller",
|
|
1707
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
|
+
},
|
|
1708
1822
|
{ key: "apply-seller", label: "Applying to become a seller works", href: "/user/become-seller" },
|
|
1709
1823
|
{ key: "store-setup", label: "Setting up store name/description/logo works" },
|
|
1710
1824
|
{ key: "store-address", label: "Adding a pickup address for the store works" },
|
|
@@ -2603,6 +2717,12 @@ const rawTesterChecklistItems = [
|
|
|
2603
2717
|
cases: [
|
|
2604
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: "/" },
|
|
2605
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
|
+
},
|
|
2606
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" },
|
|
2607
2727
|
{ key: "carousel-arrows-work", label: "Homepage carousel prev/next arrow buttons work and wrap around at both ends" },
|
|
2608
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" },
|
|
@@ -3605,6 +3725,108 @@ const rawTesterChecklistItems = [
|
|
|
3605
3725
|
version: 2,
|
|
3606
3726
|
previousVersionId: "checklist-admin-bug-hunter-rewards-demo-fixture",
|
|
3607
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
|
+
]),
|
|
3608
3830
|
];
|
|
3609
3831
|
const defaultPhases = assignDefaultPhases(rawTesterChecklistItems);
|
|
3610
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) {
|