@mohasinac/appkit 4.13.1 → 4.15.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/layout/DashboardLayoutClient.js +14 -5
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +3 -0
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +6 -0
- package/dist/_internal/client/features/lottery/LotteryDetailView.d.ts +8 -0
- package/dist/_internal/client/features/lottery/LotteryDetailView.js +4 -1
- package/dist/_internal/client/features/lottery/LotteryListView.d.ts +7 -0
- package/dist/_internal/client/features/lottery/LotteryListView.js +1 -1
- package/dist/_internal/client/features/lottery/PrizeDrawLotteryDetailView.js +4 -1
- package/dist/_internal/client/features/lottery/slot-collage-items.d.ts +15 -0
- package/dist/_internal/client/features/lottery/slot-collage-items.js +13 -0
- package/dist/_internal/server/features/auctions/actions.js +8 -2
- package/dist/_internal/server/features/bundles/data.d.ts +16 -0
- package/dist/_internal/server/features/bundles/data.js +26 -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/cart/service.d.ts +3 -3
- package/dist/_internal/server/features/checkout/actions.js +25 -0
- package/dist/_internal/server/features/checkout/locked-lines.d.ts +38 -0
- package/dist/_internal/server/features/checkout/locked-lines.js +171 -0
- package/dist/_internal/server/features/checkout/source-context.d.ts +5 -0
- package/dist/_internal/server/features/checkout/source-context.js +157 -0
- package/dist/_internal/server/features/homepage/index.d.ts +0 -1
- package/dist/_internal/server/features/homepage/index.js +7 -1
- package/dist/_internal/server/features/lottery/adapters.js +4 -0
- package/dist/_internal/server/features/offers/adapters.d.ts +103 -0
- package/dist/_internal/server/features/offers/adapters.js +88 -0
- package/dist/_internal/server/features/offers/index.d.ts +2 -0
- package/dist/_internal/server/features/offers/index.js +1 -0
- package/dist/_internal/server/features/orders/adapters.js +24 -0
- package/dist/_internal/server/features/products/data.js +15 -37
- package/dist/_internal/server/features/products/index.d.ts +1 -1
- package/dist/_internal/server/features/products/index.js +1 -1
- package/dist/_internal/server/features/products/list-public.d.ts +46 -20
- package/dist/_internal/server/features/products/list-public.js +266 -90
- package/dist/_internal/server/features/products/listing-tab-counts.d.ts +44 -0
- package/dist/_internal/server/features/products/listing-tab-counts.js +97 -0
- package/dist/_internal/server/features/site-settings/adapters.d.ts +51 -0
- package/dist/_internal/server/features/site-settings/adapters.js +75 -0
- package/dist/_internal/server/features/site-settings/index.d.ts +1 -0
- package/dist/_internal/server/features/site-settings/index.js +1 -0
- package/dist/_internal/server/features/stores/adapters.d.ts +56 -0
- package/dist/_internal/server/features/stores/adapters.js +91 -0
- package/dist/_internal/server/features/stores/index.d.ts +1 -0
- package/dist/_internal/server/features/stores/index.js +1 -0
- package/dist/_internal/server/jobs/core/auctionSettlement.js +56 -2
- package/dist/_internal/server/jobs/core/offerExpiry.js +55 -19
- package/dist/_internal/server/jobs/core/paymentReviewAutoApprove.d.ts +5 -0
- package/dist/_internal/server/jobs/core/paymentReviewAutoApprove.js +33 -1
- package/dist/_internal/server/jobs/handlers/messages.d.ts +7 -0
- package/dist/_internal/server/jobs/handlers/messages.js +10 -0
- package/dist/_internal/shared/actions/action-registry.js +17 -1
- package/dist/_internal/shared/checkout/lanes.d.ts +25 -0
- package/dist/_internal/shared/checkout/lanes.js +26 -0
- package/dist/_internal/shared/features/auctions/config.d.ts +27 -0
- package/dist/_internal/shared/features/auctions/config.js +27 -0
- package/dist/_internal/shared/features/auctions/schema.d.ts +14 -2
- package/dist/_internal/shared/features/auctions/schema.js +13 -1
- package/dist/_internal/shared/features/blog/schema.d.ts +2 -2
- package/dist/_internal/shared/features/cart/schema.d.ts +20 -15
- package/dist/_internal/shared/features/cart/schema.js +15 -0
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +32 -32
- package/dist/_internal/shared/features/emi/schedule.d.ts +24 -3
- package/dist/_internal/shared/features/emi/schedule.js +20 -5
- package/dist/_internal/shared/features/events/schema.d.ts +2 -2
- package/dist/_internal/shared/features/homepage/section-gate.d.ts +14 -0
- package/dist/_internal/shared/features/homepage/section-gate.js +51 -0
- package/dist/_internal/shared/features/offers/config.d.ts +30 -0
- package/dist/_internal/shared/features/offers/config.js +59 -0
- package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
- package/dist/_internal/shared/features/products/schema.d.ts +30 -30
- package/dist/_internal/shared/features/products/to-product-item.js +6 -0
- package/dist/_internal/shared/features/reviews/schema.d.ts +2 -2
- package/dist/_internal/shared/features/site-settings/fees.d.ts +60 -0
- package/dist/_internal/shared/features/site-settings/fees.js +39 -0
- package/dist/_internal/shared/features/site-settings/types.d.ts +40 -0
- package/dist/_internal/shared/features/site-settings/types.js +1 -0
- package/dist/_internal/shared/history/history.d.ts +88 -0
- package/dist/_internal/shared/history/history.js +198 -0
- package/dist/_internal/shared/history/index.d.ts +4 -0
- package/dist/_internal/shared/history/index.js +2 -0
- package/dist/_internal/shared/history/types.d.ts +61 -0
- package/dist/_internal/shared/history/types.js +6 -0
- package/dist/_internal/shared/listing-types/_registry.d.ts +54 -1
- package/dist/_internal/shared/listing-types/_registry.js +67 -0
- package/dist/_internal/shared/listing-types/art/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/art/config.js +5 -0
- package/dist/_internal/shared/listing-types/auction/config.d.ts +13 -0
- package/dist/_internal/shared/listing-types/auction/config.js +21 -0
- package/dist/_internal/shared/listing-types/availability.d.ts +79 -0
- package/dist/_internal/shared/listing-types/availability.js +104 -0
- package/dist/_internal/shared/listing-types/capabilities.d.ts +15 -0
- package/dist/_internal/shared/listing-types/capabilities.js +12 -0
- package/dist/_internal/shared/listing-types/classified/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/classified/config.js +5 -0
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +11 -0
- package/dist/_internal/shared/listing-types/digital-code/config.js +22 -2
- package/dist/_internal/shared/listing-types/live/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/live/config.js +5 -0
- package/dist/_internal/shared/listing-types/pre-order/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/pre-order/config.js +19 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +11 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.js +15 -0
- package/dist/_internal/shared/listing-types/standard/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/standard/config.js +5 -0
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +3 -0
- package/dist/_internal/shared/listing-types/stickers/config.js +5 -0
- package/dist/client.d.ts +20 -7
- package/dist/client.js +22 -4
- package/dist/constants/api-endpoints.d.ts +6 -0
- package/dist/constants/api-endpoints.js +2 -0
- package/dist/constants/field-names.d.ts +57 -8
- package/dist/constants/field-names.js +101 -8
- package/dist/constants/table-keys.d.ts +17 -0
- package/dist/constants/table-keys.js +17 -0
- package/dist/errors/error-codes.d.ts +13 -1
- package/dist/errors/error-codes.js +13 -1
- package/dist/errors/error-display-map.js +12 -3
- package/dist/errors/messages.d.ts +10 -2
- package/dist/errors/messages.js +10 -2
- package/dist/features/about/components/AboutView.d.ts +3 -0
- package/dist/features/about/components/AboutView.js +3 -2
- package/dist/features/about/components/PolicyPageView.d.ts +2 -1
- package/dist/features/about/components/PolicyPageView.js +61 -23
- package/dist/features/about/components/PublicProfileView.js +5 -0
- package/dist/features/about/schemas/firestore.d.ts +3 -0
- package/dist/features/account/components/UserBidsView.js +12 -4
- package/dist/features/account/components/UserOrdersView.js +7 -0
- package/dist/features/account/components/UserReturnsView.d.ts +3 -0
- package/dist/features/account/components/UserReturnsView.js +17 -1
- package/dist/features/account/components/index.d.ts +0 -2
- package/dist/features/account/components/index.js +0 -1
- package/dist/features/account/schemas/index.d.ts +2 -2
- package/dist/features/account/types/index.d.ts +21 -2
- package/dist/features/addresses/schemas/index.d.ts +4 -4
- package/dist/features/admin/components/AdminArtView.js +8 -3
- package/dist/features/admin/components/AdminAuditLogView.js +1 -0
- package/dist/features/admin/components/AdminBidsView.js +15 -2
- package/dist/features/admin/components/AdminBlogEditorView.js +65 -33
- package/dist/features/admin/components/AdminClassifiedView.js +8 -3
- package/dist/features/admin/components/AdminDigitalCodesView.js +8 -3
- package/dist/features/admin/components/AdminFeatureEditorView.js +35 -6
- package/dist/features/admin/components/AdminFeatureFlagsView.js +1 -0
- package/dist/features/admin/components/AdminLiveView.js +8 -3
- package/dist/features/admin/components/AdminNavEditorView.js +15 -5
- package/dist/features/admin/components/AdminNewsletterView.js +18 -2
- package/dist/features/admin/components/AdminOffersView.d.ts +4 -0
- package/dist/features/admin/components/AdminOffersView.js +230 -0
- package/dist/features/admin/components/AdminOrdersView.js +10 -1
- package/dist/features/admin/components/AdminPaymentMethodsView.js +24 -4
- package/dist/features/admin/components/AdminPrizeDrawsView.js +5 -0
- package/dist/features/admin/components/AdminProductsView.js +16 -29
- package/dist/features/admin/components/AdminScammerEditorView.d.ts +2 -1
- package/dist/features/admin/components/AdminScammerEditorView.js +3 -13
- package/dist/features/admin/components/AdminScammersView.js +3 -8
- package/dist/features/admin/components/AdminSectionsView.js +32 -23
- package/dist/features/admin/components/AdminSessionsView.js +17 -2
- package/dist/features/admin/components/AdminSiteSettingsView.js +31 -13
- package/dist/features/admin/components/AdminSiteView.js +6 -2
- package/dist/features/admin/components/AdminStickersView.js +8 -3
- package/dist/features/admin/components/ViewAuditLogEntryModal.js +1 -0
- package/dist/features/admin/components/index.d.ts +2 -0
- package/dist/features/admin/components/index.js +1 -0
- package/dist/features/admin/components/sections/adminSectionsTypes.d.ts +4 -2
- package/dist/features/admin/components/sections/adminSectionsTypes.js +45 -27
- package/dist/features/admin/constants/filter-tabs.d.ts +89 -0
- package/dist/features/admin/constants/filter-tabs.js +56 -0
- package/dist/features/admin/schemas/firestore.d.ts +122 -3
- package/dist/features/admin/schemas/firestore.js +1 -0
- package/dist/features/admin/schemas/homepage-section-form.d.ts +22 -0
- package/dist/features/admin/schemas/homepage-section-form.js +68 -0
- package/dist/features/admin/schemas/nav-item-form.d.ts +74 -0
- package/dist/features/admin/schemas/nav-item-form.js +72 -0
- package/dist/features/auctions/actions/bid-actions.d.ts +20 -5
- package/dist/features/auctions/actions/bid-actions.js +93 -20
- package/dist/features/auctions/components/AuctionBidsTable.d.ts +10 -1
- package/dist/features/auctions/components/AuctionBidsTable.js +22 -4
- package/dist/features/auctions/components/AuctionDetailPageView.js +11 -6
- package/dist/features/auctions/components/AuctionsListView.js +5 -6
- package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +7 -0
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +19 -2
- package/dist/features/auctions/components/PlaceBidFormClient.d.ts +1 -2
- package/dist/features/auctions/components/PlaceBidFormClient.js +8 -4
- package/dist/features/auctions/components/bid-detail-fields.d.ts +29 -0
- package/dist/features/auctions/components/bid-detail-fields.js +103 -0
- package/dist/features/auctions/repository/bid.repository.d.ts +13 -0
- package/dist/features/auctions/repository/bid.repository.js +23 -0
- package/dist/features/auctions/schemas/firestore.d.ts +17 -0
- package/dist/features/auctions/schemas/index.d.ts +12 -12
- package/dist/features/audit-log/schemas/firestore.d.ts +14 -0
- package/dist/features/audit-log/schemas/firestore.js +7 -0
- package/dist/features/auth/permissions/constants.d.ts +1 -1
- package/dist/features/auth/permissions/constants.js +10 -1
- package/dist/features/blog/actions/blog-actions.d.ts +7 -7
- package/dist/features/blog/schemas/blog-form.d.ts +80 -0
- package/dist/features/blog/schemas/blog-form.js +100 -0
- package/dist/features/blog/schemas/index.d.ts +6 -6
- package/dist/features/cart/repository/cart.repository.js +1 -0
- package/dist/features/cart/schemas/firestore.d.ts +15 -0
- package/dist/features/catalogue/schemas/validation.d.ts +4 -4
- package/dist/features/categories/components/BrandDetailPageView.js +23 -40
- package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -7
- package/dist/features/categories/components/BrandDetailTabs.js +8 -12
- package/dist/features/categories/components/BundleCollage.js +1 -1
- package/dist/features/categories/components/CategoryDetailPageView.js +53 -57
- package/dist/features/categories/components/CategoryDetailTabs.d.ts +10 -8
- package/dist/features/categories/components/CategoryDetailTabs.js +11 -16
- package/dist/features/categories/components/CategoryProductsListing.js +11 -1
- package/dist/features/categories/components/ConcernCard.js +7 -1
- package/dist/features/categories/schemas/firestore.d.ts +13 -0
- package/dist/features/categories/schemas/index.d.ts +26 -26
- package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +16 -1
- package/dist/features/classified/components/ClassifiedDetailPageView.js +23 -3
- package/dist/features/events/components/AdminEventEditorView.js +32 -54
- package/dist/features/events/components/AdminEventEntriesView.js +22 -3
- package/dist/features/events/components/AdminEventsView.js +15 -11
- package/dist/features/events/components/EventFilters.d.ts +9 -1
- package/dist/features/events/components/EventFilters.js +45 -21
- package/dist/features/events/components/EventsIndexListing.d.ts +6 -1
- package/dist/features/events/components/EventsIndexListing.js +2 -2
- package/dist/features/events/components/EventsListPageView.js +13 -4
- package/dist/features/events/repository/events.repository.d.ts +17 -0
- package/dist/features/events/repository/events.repository.js +27 -0
- package/dist/features/events/schemas/event-form.d.ts +113 -0
- package/dist/features/events/schemas/event-form.js +82 -0
- package/dist/features/events/schemas/firestore.d.ts +12 -0
- package/dist/features/events/schemas/firestore.js +12 -0
- package/dist/features/events/schemas/index.d.ts +50 -50
- package/dist/features/events/types/index.d.ts +11 -0
- package/dist/features/events/types/index.js +57 -1
- package/dist/features/faq/actions/faq-actions.d.ts +12 -12
- package/dist/features/faq/schemas/index.d.ts +8 -8
- package/dist/features/filters/FilterFacetSection.d.ts +7 -1
- package/dist/features/filters/FilterFacetSection.js +11 -3
- package/dist/features/grouped/schemas/grouped-listing-form.d.ts +101 -0
- package/dist/features/grouped/schemas/grouped-listing-form.js +89 -0
- package/dist/features/grouped/schemas/index.d.ts +4 -4
- package/dist/features/homepage/actions/homepage-section-actions.d.ts +11 -3
- package/dist/features/homepage/actions/homepage-section-actions.js +33 -1
- package/dist/features/homepage/components/AnnouncementBar.d.ts +7 -1
- package/dist/features/homepage/components/AnnouncementBar.js +3 -3
- package/dist/features/homepage/components/MarketplaceHomepageView.js +20 -6
- package/dist/features/homepage/hooks/homepage-query.d.ts +16 -0
- package/dist/features/homepage/hooks/homepage-query.js +45 -0
- package/dist/features/homepage/hooks/useFeaturedAuctions.d.ts +10 -0
- package/dist/features/homepage/hooks/useFeaturedAuctions.js +28 -8
- package/dist/features/homepage/hooks/useFeaturedPreOrders.js +17 -8
- package/dist/features/homepage/hooks/useFeaturedProducts.js +15 -8
- package/dist/features/homepage/schemas/index.d.ts +33 -2
- package/dist/features/homepage/schemas/index.js +24 -0
- package/dist/features/layout/AppLayoutShell.d.ts +11 -1
- package/dist/features/layout/AppLayoutShell.js +15 -14
- package/dist/features/layout/BackToTop.d.ts +9 -0
- package/dist/features/layout/BackToTop.js +10 -1
- package/dist/features/layout/BottomActions.js +28 -25
- package/dist/features/layout/BottomChrome.d.ts +34 -0
- package/dist/features/layout/BottomChrome.js +55 -0
- package/dist/features/layout/BottomNavLayout.d.ts +6 -0
- package/dist/features/layout/BottomNavLayout.js +7 -1
- package/dist/features/layout/BottomNavbar.js +15 -2
- package/dist/features/layout/FooterLayout.js +11 -1
- package/dist/features/layout/NavbarLayout.js +1 -1
- package/dist/features/layout/TitleBarLayout.d.ts +7 -0
- package/dist/features/layout/TitleBarLayout.js +28 -5
- package/dist/features/layout/index.d.ts +2 -0
- package/dist/features/layout/index.js +1 -0
- package/dist/features/lottery/types/index.d.ts +3 -0
- package/dist/features/media/MediaPickerModal.js +5 -1
- package/dist/features/messages/schemas/index.d.ts +2 -2
- package/dist/features/orders/components/OrderScopeTabs.d.ts +20 -0
- package/dist/features/orders/components/OrderScopeTabs.js +31 -0
- package/dist/features/orders/components/OrderStatusTimeline.d.ts +5 -1
- package/dist/features/orders/components/OrderStatusTimeline.js +39 -20
- package/dist/features/orders/constants/order-scope.d.ts +48 -0
- package/dist/features/orders/constants/order-scope.js +111 -0
- package/dist/features/orders/repository/orders.repository.d.ts +54 -7
- package/dist/features/orders/repository/orders.repository.js +121 -22
- package/dist/features/orders/schemas/firestore.d.ts +152 -0
- package/dist/features/orders/schemas/firestore.js +30 -0
- package/dist/features/orders/schemas/index.d.ts +18 -18
- package/dist/features/orders/types/index.d.ts +35 -7
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +14 -9
- package/dist/features/pre-orders/components/PreOrdersListView.js +6 -5
- package/dist/features/pre-orders/schemas/index.d.ts +1 -1
- package/dist/features/products/actions/product-actions.d.ts +14 -0
- package/dist/features/products/actions/product-actions.js +49 -11
- package/dist/features/products/api/route.d.ts +12 -0
- package/dist/features/products/api/route.js +42 -100
- package/dist/features/products/components/ArtStickersListView.js +2 -2
- package/dist/features/products/components/AuctionsIndexListing.js +13 -11
- package/dist/features/products/components/AvailabilityTabs.d.ts +11 -0
- package/dist/features/products/components/AvailabilityTabs.js +47 -0
- package/dist/features/products/components/GroupSettingsPanel.js +5 -1
- package/dist/features/products/components/MakeOfferButton.js +48 -49
- package/dist/features/products/components/PrizeDrawCollage.d.ts +20 -4
- package/dist/features/products/components/PrizeDrawCollage.js +9 -1
- package/dist/features/products/components/PrizeDrawsIndexListing.js +14 -12
- package/dist/features/products/components/PrizeDrawsListingView.js +2 -2
- package/dist/features/products/components/PrizeDrawsSection.d.ts +7 -1
- package/dist/features/products/components/PrizeDrawsSection.js +23 -18
- package/dist/features/products/components/ProductDetailPageView.d.ts +4 -1
- package/dist/features/products/components/ProductDetailPageView.js +18 -4
- package/dist/features/products/components/ProductForm.js +5 -2
- package/dist/features/products/components/ProductGrid.js +6 -1
- package/dist/features/products/components/ProductsIndexListing.js +22 -32
- package/dist/features/products/components/ProductsIndexPageView.js +6 -9
- package/dist/features/products/components/index.d.ts +2 -2
- package/dist/features/products/components/index.js +1 -1
- package/dist/features/products/config/listing-type-listing-config.d.ts +20 -0
- package/dist/features/products/config/listing-type-listing-config.js +22 -10
- package/dist/features/products/constants/action-defs.d.ts +2 -0
- package/dist/features/products/constants/action-defs.js +6 -0
- package/dist/features/products/hooks/useAvailabilityScope.d.ts +13 -0
- package/dist/features/products/hooks/useAvailabilityScope.js +19 -0
- package/dist/features/products/hooks/useProducts.d.ts +5 -0
- package/dist/features/products/hooks/useProducts.js +13 -2
- package/dist/features/products/repository/products.repository.d.ts +31 -2
- package/dist/features/products/repository/products.repository.js +53 -21
- package/dist/features/products/schemas/firestore.d.ts +17 -3
- package/dist/features/products/schemas/firestore.js +7 -2
- package/dist/features/products/schemas/index.d.ts +64 -64
- package/dist/features/products/schemas/product-features.validators.d.ts +79 -6
- package/dist/features/products/schemas/product-features.validators.js +63 -0
- package/dist/features/products/types/index.d.ts +16 -1
- package/dist/features/promotions/schemas/index.d.ts +2 -2
- package/dist/features/reviews/schemas/index.d.ts +16 -16
- package/dist/features/scams/constants/scammer-status-display.d.ts +28 -0
- package/dist/features/scams/constants/scammer-status-display.js +79 -0
- package/dist/features/search/schemas/index.d.ts +4 -4
- package/dist/features/seller/actions/offer-actions.js +57 -4
- package/dist/features/seller/components/OfferPhaseTimeline.d.ts +59 -0
- package/dist/features/seller/components/OfferPhaseTimeline.js +107 -0
- package/dist/features/seller/components/SellerArtView.js +5 -0
- package/dist/features/seller/components/SellerAuctionsView.js +13 -15
- package/dist/features/seller/components/SellerBidsView.js +11 -4
- package/dist/features/seller/components/SellerClassifiedView.js +5 -0
- package/dist/features/seller/components/SellerCouponEditorView.js +17 -17
- package/dist/features/seller/components/SellerDigitalCodesView.js +5 -0
- package/dist/features/seller/components/SellerLiveView.js +5 -0
- package/dist/features/seller/components/SellerOffersView.js +2 -1
- package/dist/features/seller/components/SellerOrdersView.js +31 -9
- package/dist/features/seller/components/SellerPayoutSettingsView.js +56 -31
- package/dist/features/seller/components/SellerPreOrdersView.js +5 -0
- package/dist/features/seller/components/SellerPrizeDrawsView.js +14 -16
- package/dist/features/seller/components/SellerProductShell.js +7 -1
- package/dist/features/seller/components/SellerProductsView.js +11 -8
- package/dist/features/seller/components/SellerStickersView.js +5 -0
- package/dist/features/seller/components/index.d.ts +0 -2
- package/dist/features/seller/components/index.js +0 -1
- package/dist/features/seller/repository/offer.repository.d.ts +142 -24
- package/dist/features/seller/repository/offer.repository.js +165 -26
- package/dist/features/seller/schemas/coupon-form.d.ts +72 -0
- package/dist/features/seller/schemas/coupon-form.js +116 -0
- package/dist/features/seller/schemas/firestore.d.ts +56 -2
- package/dist/features/seller/schemas/firestore.js +27 -0
- package/dist/features/seller/schemas/index.d.ts +2 -2
- package/dist/features/seller/schemas/offer-forms.d.ts +46 -0
- package/dist/features/seller/schemas/offer-forms.js +42 -0
- package/dist/features/seller/server.d.ts +0 -1
- package/dist/features/seller/server.js +0 -1
- package/dist/features/shell/SectionForm.d.ts +99 -0
- package/dist/features/shell/SectionForm.js +128 -0
- package/dist/features/shell/build-sections.d.ts +63 -0
- package/dist/features/shell/build-sections.js +207 -0
- package/dist/features/shell/entity-form.d.ts +109 -0
- package/dist/features/shell/entity-form.js +96 -0
- package/dist/features/shell/field-ui-meta.d.ts +115 -0
- package/dist/features/shell/field-ui-meta.js +324 -0
- package/dist/features/shell/index.d.ts +8 -0
- package/dist/features/shell/index.js +4 -0
- package/dist/features/status-history/components/StatusTimeline.d.ts +74 -0
- package/dist/features/status-history/components/StatusTimeline.js +46 -0
- package/dist/features/status-history/index.d.ts +11 -0
- package/dist/features/status-history/index.js +10 -0
- package/dist/features/store-extensions/components/ReviewDecisionModal.d.ts +27 -0
- package/dist/features/store-extensions/components/ReviewDecisionModal.js +82 -0
- package/dist/features/store-extensions/index.d.ts +12 -0
- package/dist/features/store-extensions/index.js +12 -0
- package/dist/features/store-extensions/schemas/admin-notification-form.d.ts +36 -0
- package/dist/features/store-extensions/schemas/admin-notification-form.js +114 -0
- package/dist/features/store-extensions/schemas/analytics-forms.d.ts +57 -0
- package/dist/features/store-extensions/schemas/analytics-forms.js +158 -0
- package/dist/features/store-extensions/schemas/custom-role-form.d.ts +85 -0
- package/dist/features/store-extensions/schemas/custom-role-form.js +118 -0
- package/dist/features/store-extensions/schemas/firestore.d.ts +21 -1
- package/dist/features/store-extensions/schemas/firestore.js +60 -0
- package/dist/features/store-extensions/schemas/google-config-form.d.ts +53 -0
- package/dist/features/store-extensions/schemas/google-config-form.js +105 -0
- package/dist/features/store-extensions/schemas/item-request-create-form.d.ts +28 -0
- package/dist/features/store-extensions/schemas/item-request-create-form.js +80 -0
- package/dist/features/store-extensions/schemas/listing-template-form.d.ts +78 -0
- package/dist/features/store-extensions/schemas/listing-template-form.js +87 -0
- package/dist/features/store-extensions/schemas/moderation-review-form.d.ts +49 -0
- package/dist/features/store-extensions/schemas/moderation-review-form.js +101 -0
- package/dist/features/store-extensions/schemas/payout-method-form.d.ts +153 -0
- package/dist/features/store-extensions/schemas/payout-method-form.js +155 -0
- package/dist/features/store-extensions/schemas/report-create-form.d.ts +25 -0
- package/dist/features/store-extensions/schemas/report-create-form.js +79 -0
- package/dist/features/store-extensions/schemas/report-review-form.d.ts +47 -0
- package/dist/features/store-extensions/schemas/report-review-form.js +111 -0
- package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +148 -0
- package/dist/features/store-extensions/schemas/shipping-config-form.js +104 -0
- package/dist/features/store-extensions/schemas/store-category-form.d.ts +54 -0
- package/dist/features/store-extensions/schemas/store-category-form.js +73 -0
- package/dist/features/stores/api/[storeSlug]/route.js +2 -25
- package/dist/features/stores/components/StoreAuctionsListing.js +15 -1
- package/dist/features/stores/components/StoreClassifiedsListing.js +12 -2
- package/dist/features/stores/components/StoreDetailLayoutView.js +24 -71
- package/dist/features/stores/components/StoreDigitalCodesListing.js +12 -2
- package/dist/features/stores/components/StoreLiveItemsListing.js +12 -2
- package/dist/features/stores/components/StorePreOrdersListing.js +12 -1
- package/dist/features/stores/components/StoreProductsListing.js +11 -1
- package/dist/features/stores/repository/store.repository.js +6 -0
- package/dist/features/stores/schemas/index.d.ts +6 -6
- package/dist/features/support/schemas/index.d.ts +4 -4
- package/dist/features/tester/actions/checklist-item-actions.d.ts +4 -4
- package/dist/features/tester/seed-data/offers-tester-seed-data.js +119 -3
- package/dist/features/tester/seed-data/products-tester-seed-data.js +131 -1
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +431 -1
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
- package/dist/index.d.ts +25 -12
- package/dist/index.js +26 -11
- package/dist/next/routing/route-map.d.ts +23 -3
- package/dist/next/routing/route-map.js +14 -2
- package/dist/providers/db-firebase/base.repository.d.ts +30 -0
- package/dist/providers/db-firebase/base.repository.js +50 -1
- package/dist/providers/db-firebase/index.d.ts +1 -1
- package/dist/providers/db-firebase/index.js +1 -1
- package/dist/providers/db-firebase/sieve.d.ts +25 -0
- package/dist/providers/db-firebase/sieve.js +52 -18
- package/dist/react/hooks/useUrlTable.js +10 -1
- package/dist/schemas/firestore-value.d.ts +8 -0
- package/dist/schemas/firestore-value.js +44 -0
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/index.js +1 -1
- package/dist/schemas/registry.d.ts +702 -69
- package/dist/schemas/registry.js +64 -1
- package/dist/seed/_helpers/category-forest.d.ts +2 -0
- package/dist/seed/_helpers/category-forest.js +309 -0
- package/dist/seed/_helpers/category-tree.d.ts +27 -0
- package/dist/seed/_helpers/category-tree.js +103 -0
- package/dist/seed/bids-seed-data.js +30 -0
- package/dist/seed/catalogue-seed-data.js +12 -12
- package/dist/seed/categories-seed-data.js +177 -162
- package/dist/seed/events-seed-data.js +61 -10
- package/dist/seed/homepage-sections-seed-data.js +5 -1
- package/dist/seed/offers-seed-data.js +244 -34
- package/dist/seed/orders-seed-data.js +336 -1
- package/dist/seed/products-art-seed-data.js +50 -12
- package/dist/seed/products-auctions-seed-data.js +138 -18
- package/dist/seed/products-classifieds-seed-data.js +80 -16
- package/dist/seed/products-digital-codes-seed-data.js +66 -18
- package/dist/seed/products-live-items-seed-data.js +64 -13
- package/dist/seed/products-preorders-seed-data.d.ts +0 -1
- package/dist/seed/products-preorders-seed-data.js +52 -13
- package/dist/seed/products-prize-draws-seed-data.js +63 -14
- package/dist/seed/products-standard-seed-data.js +99 -26
- package/dist/seed/products-stickers-seed-data.js +47 -12
- package/dist/seed/reviews-seed-data.js +6 -1
- package/dist/seed/site-settings-seed-data.d.ts +1 -38
- package/dist/seed/site-settings-seed-data.js +38 -76
- package/dist/seed/stores-seed-data.js +71 -1
- package/dist/seed/users-seed-data.js +15 -5
- package/dist/server-entry.d.ts +1 -2
- package/dist/server-entry.js +4 -3
- package/dist/server.d.ts +6 -3
- package/dist/server.js +13 -4
- package/dist/styles.css +78 -12
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Button.style.css +19 -4
- package/dist/ui/components/CollapsibleSection.d.ts +17 -1
- package/dist/ui/components/CollapsibleSection.js +6 -2
- package/dist/ui/components/FilterChipGroup.d.ts +25 -1
- package/dist/ui/components/FilterChipGroup.js +21 -4
- package/dist/ui/components/HandMode.style.css +47 -0
- package/dist/ui/components/Layout.d.ts +9 -2
- package/dist/ui/components/Layout.js +1 -1
- package/dist/ui/components/ListingLayout.js +8 -8
- package/dist/ui/components/ListingLayout.style.css +8 -7
- package/dist/ui/components/RecordDetailModal.d.ts +10 -1
- package/dist/ui/components/RecordDetailModal.js +2 -2
- package/dist/ui/components/StickyToolbar.d.ts +3 -1
- package/dist/ui/components/StickyToolbar.js +62 -20
- package/dist/ui/components/bottom-chrome-slot.d.ts +21 -0
- package/dist/ui/components/bottom-chrome-slot.js +29 -0
- package/dist/ui/components/index.style.css +3 -0
- package/dist/ui/forms/FormShell.d.ts +43 -13
- package/dist/ui/forms/FormShell.js +22 -11
- package/dist/ui/forms/index.d.ts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/package.json +2 -1
- package/scripts/node-esm-loader.mjs +65 -0
- package/scripts/seed-cli-loader.mjs +6 -49
- package/scripts/seed-cli.mjs +1 -1
|
@@ -7,14 +7,16 @@ export interface CategoryDetailTabsProps {
|
|
|
7
7
|
initialProductsData?: any;
|
|
8
8
|
initialBundles?: CategoryDocument[];
|
|
9
9
|
initialStores?: StoreListItem[];
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
/**
|
|
11
|
+
* tabSlug -> row count. `undefined` means the count could not be resolved,
|
|
12
|
+
* NOT zero — such a tab stays visible so a failed query can never hide real
|
|
13
|
+
* inventory (Root Cause #59).
|
|
14
|
+
*
|
|
15
|
+
* Keyed by tab id rather than by hand-named properties: the previous shape
|
|
16
|
+
* named only 6 of the 10 tabs, so classifieds / digital-codes / live / art
|
|
17
|
+
* were structurally uncountable and could never hide (Root Cause #61).
|
|
18
|
+
*/
|
|
19
|
+
counts?: Record<string, number | undefined>;
|
|
18
20
|
/** Enabled listing types (e.g. ["standard","auction","pre-order"]). When omitted, all tabs shown. */
|
|
19
21
|
enabledListingTypes?: string[];
|
|
20
22
|
/** Enabled category types (e.g. ["category","brand","bundle"]). When omitted, all tabs shown. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState } from "react";
|
|
4
|
-
import { Tabs, TabsList, TabsTrigger } from "../../../ui";
|
|
4
|
+
import { EmptyState, Tabs, TabsList, TabsTrigger } from "../../../ui";
|
|
5
5
|
import { CategoryProductsListing } from "./CategoryProductsListing";
|
|
6
6
|
import { AuctionsIndexListing } from "../../products/components/AuctionsIndexListing";
|
|
7
7
|
import { PreOrdersIndexListing } from "../../pre-orders/components/PreOrdersIndexListing";
|
|
@@ -39,17 +39,7 @@ const GENERIC_TAB_LISTING_TYPES = {
|
|
|
39
39
|
[pluginFor("art").tabSlug]: ART_STICKERS_LISTING_TYPES,
|
|
40
40
|
};
|
|
41
41
|
export function CategoryDetailTabs({ categorySlug, categoryId, initialProductsData, initialBundles = [], initialStores = [], counts, enabledListingTypes, enabledCategoryTypes, }) {
|
|
42
|
-
const countFor = (id) =>
|
|
43
|
-
switch (id) {
|
|
44
|
-
case "products": return counts?.products;
|
|
45
|
-
case "auctions": return counts?.auctions;
|
|
46
|
-
case "pre-orders": return counts?.preOrders;
|
|
47
|
-
case "prize-draws": return counts?.prizeDraws;
|
|
48
|
-
case "bundles": return counts?.bundles;
|
|
49
|
-
case "stores": return counts?.stores;
|
|
50
|
-
default: return undefined;
|
|
51
|
-
}
|
|
52
|
-
};
|
|
42
|
+
const countFor = (id) => counts?.[id];
|
|
53
43
|
const visibleTabs = CATEGORY_PAGE_TABS.filter((t) => {
|
|
54
44
|
const mapping = TAB_TYPE_MAP[t.id];
|
|
55
45
|
if (mapping) {
|
|
@@ -62,14 +52,19 @@ export function CategoryDetailTabs({ categorySlug, categoryId, initialProductsDa
|
|
|
62
52
|
return false;
|
|
63
53
|
}
|
|
64
54
|
}
|
|
65
|
-
// Hide a tab only when its count is known and explicitly zero
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
55
|
+
// Hide a tab only when its count is known and explicitly zero. `undefined`
|
|
56
|
+
// now means the count query FAILED (every tab is counted), so keeping it
|
|
57
|
+
// visible is the fail-open choice: an empty tab is a far smaller error than
|
|
58
|
+
// hiding a tab that holds real listings.
|
|
69
59
|
const count = countFor(t.id);
|
|
70
60
|
return count === undefined || count > 0;
|
|
71
61
|
});
|
|
72
62
|
const firstTabId = (visibleTabs[0]?.id ?? "products");
|
|
73
63
|
const [activeTab, setActiveTab] = useState(firstTabId);
|
|
64
|
+
// Every tab counted zero — render the empty state rather than an empty tab
|
|
65
|
+
// strip with no body beneath it.
|
|
66
|
+
if (visibleTabs.length === 0) {
|
|
67
|
+
return (_jsx(EmptyState, { title: "Nothing listed here yet", description: "This category has no active listings right now. Check back soon." }));
|
|
68
|
+
}
|
|
74
69
|
return (_jsxs(_Fragment, { children: [_jsx(Tabs, { value: activeTab, onChange: (v) => setActiveTab(v), className: "mb-6", children: _jsx(TabsList, { children: visibleTabs.map((t) => (_jsx(TabsTrigger, { value: t.id, badge: countFor(t.id), children: t.label }, t.id))) }) }), GENERIC_TAB_LISTING_TYPES[activeTab] && (_jsx(CategoryProductsListing, { categorySlug: categorySlug, categoryId: categoryId, listingTypes: GENERIC_TAB_LISTING_TYPES[activeTab], initialData: activeTab === pluginFor("standard").tabSlug ? initialProductsData : undefined })), activeTab === pluginFor("auction").tabSlug && (_jsx(AuctionsIndexListing, { categorySlug: categorySlug })), activeTab === pluginFor("pre-order").tabSlug && (_jsx(PreOrdersIndexListing, { categorySlug: categorySlug })), activeTab === pluginFor("prize-draw").tabSlug && (_jsx(PrizeDrawsIndexListing, { categorySlug: categorySlug })), activeTab === "bundles" && (_jsx(CategoryBundlesListing, { initialBundles: initialBundles })), activeTab === "stores" && (_jsx(CategoryStoresListing, { stores: initialStores }))] }));
|
|
75
70
|
}
|
|
@@ -13,6 +13,9 @@ import { ProductFilters, PRODUCT_PUBLIC_SORT_OPTIONS } from "../../products/comp
|
|
|
13
13
|
import { useGuestCart } from "../../cart/hooks/useGuestCart";
|
|
14
14
|
import { useGuestWishlist } from "../../wishlist/hooks/useGuestWishlist";
|
|
15
15
|
import { pushCartOp, pushWishlistOp } from "../../cart/utils/pending-ops";
|
|
16
|
+
import { AvailabilityTabs } from "../../products/components/AvailabilityTabs";
|
|
17
|
+
import { AVAILABILITY_VALUES } from "../../../constants/field-names";
|
|
18
|
+
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
16
19
|
const __P = {
|
|
17
20
|
p3: "p-[var(--appkit-space-3)]",
|
|
18
21
|
};
|
|
@@ -38,6 +41,12 @@ export function CategoryProductsListing({ categorySlug, categoryId, brandName, l
|
|
|
38
41
|
const localWishlist = useGuestWishlist();
|
|
39
42
|
const wishlistedIds = new Set(localWishlist.items.filter((i) => i.type === "product").map((i) => i.itemId));
|
|
40
43
|
const { pendingTable, filterActiveCount, onFilterApply, onFilterClear, onResetAll, onFilterReset } = usePendingTable(table, FILTER_KEYS);
|
|
44
|
+
// Absent means "available" — the same default `listStoreProducts`
|
|
45
|
+
// resolves server-side. These six store tabs sent NO availability
|
|
46
|
+
// param at all until 2026-08-24, while their SSR fetch did apply one,
|
|
47
|
+
// so any client refetch silently widened the list (Root Cause #30).
|
|
48
|
+
const availability = table.get(TABLE_KEYS.AVAILABILITY) ||
|
|
49
|
+
AVAILABILITY_VALUES.AVAILABLE;
|
|
41
50
|
const params = {
|
|
42
51
|
q: table.get("q") || undefined,
|
|
43
52
|
category: categoryId || undefined,
|
|
@@ -52,6 +61,7 @@ export function CategoryProductsListing({ categorySlug, categoryId, brandName, l
|
|
|
52
61
|
// sievejs parses it as a same-field OR and the Firebase adapter upgrades
|
|
53
62
|
// it to a `.where(…, "in", …)` query.
|
|
54
63
|
listingType: listingTypes.join("|"),
|
|
64
|
+
availability,
|
|
55
65
|
};
|
|
56
66
|
const { products, totalPages, page, isLoading } = useProducts(params, { initialData });
|
|
57
67
|
const commitSearch = useCallback(() => {
|
|
@@ -106,7 +116,7 @@ export function CategoryProductsListing({ categorySlug, categoryId, brandName, l
|
|
|
106
116
|
}, [localCart, showToast]);
|
|
107
117
|
return (_jsxs(Div, { className: "min-h-[200px]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: `Search in ${categorySlug.replace(/-/g, " ")}...`, onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || "-createdAt", sortOptions: PRODUCT_PUBLIC_SORT_OPTIONS, onSortChange: (v) => {
|
|
108
118
|
table.set("sort", v);
|
|
109
|
-
}, view: view === "card" ? "grid" : "list", onViewChange: (v) => handleViewToggle(v === "grid" ? "card" : "list"), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: renderCategoryProductGrid({
|
|
119
|
+
}, view: view === "card" ? "grid" : "list", onViewChange: (v) => handleViewToggle(v === "grid" ? "card" : "list"), onResetAll: resetAll, hasActiveState: hasActiveState }), _jsx(Div, { padding: "y-sm", children: _jsx(AvailabilityTabs, { types: listingTypes }) }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }) })), _jsx(Div, { padding: "y-lg", children: renderCategoryProductGrid({
|
|
110
120
|
isLoading, products: products, view,
|
|
111
121
|
getProductHref: (p) => String(ROUTES.PUBLIC.PRODUCT_DETAIL(p.slug || p.id)),
|
|
112
122
|
onWishlistToggle: handleWishlistToggle, wishlistedIds, onAddToCart: handleAddToCart,
|
|
@@ -2,5 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Button, Div, Heading, Text } from "../../../ui";
|
|
3
3
|
import { MediaImage } from "../../media/MediaImage";
|
|
4
4
|
export function ConcernCard({ concern, onClick, className = "", }) {
|
|
5
|
-
return (_jsxs(Button, { type: "button", variant: "outline", onClick: () => onClick?.(concern),
|
|
5
|
+
return (_jsxs(Button, { type: "button", variant: "outline", onClick: () => onClick?.(concern),
|
|
6
|
+
// No bare `flex` here: globals.css declares `.flex` un-layered + !important,
|
|
7
|
+
// which overrides `.appkit-button`'s own display. It is redundant anyway —
|
|
8
|
+
// the button is already a flex container. `flex-col items-center` now
|
|
9
|
+
// actually reaches the icon and label, which have been rendering
|
|
10
|
+
// side-by-side since the ripple wrapper landed (Root Cause #68).
|
|
11
|
+
className: `group flex-col items-center gap-[var(--appkit-space-3)] rounded-xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] p-[var(--appkit-space-4)] text-left shadow-sm transition hover:border-primary dark:hover:border-primary-400 hover:shadow-md ${className}`, children: [concern.display?.coverImage && (_jsx(Div, { className: "relative h-16 w-16", rounded: "full", overflow: "hidden", children: _jsx(MediaImage, { src: concern.display.coverImage, alt: concern.name, size: "thumbnail" }) })), _jsxs(Div, { children: [_jsx(Heading, { level: 3, className: "text-[var(--appkit-color-text)] group-hover:text-primary dark:group-hover:text-primary-400", size: "sm", weight: "semibold", children: concern.name }), concern.description && (_jsx(Text, { className: `mt-1`, color: "muted", truncate: 2, size: "xs", children: concern.description }))] })] }));
|
|
6
12
|
}
|
|
@@ -162,6 +162,19 @@ export interface CategoryDocument extends BaseDocument {
|
|
|
162
162
|
bundleQueryResolvedAt?: Date;
|
|
163
163
|
/** Hand-picked products list (mirror of bundleQueryRule for static rules); kept for index-friendly queries. */
|
|
164
164
|
bundleProductIds?: string[];
|
|
165
|
+
/**
|
|
166
|
+
* Categories this bundle belongs to — the union of its member products'
|
|
167
|
+
* `categorySlugs`. A bundle row has no category of its own, so without this
|
|
168
|
+
* the category page could not scope its Bundles tab at all and counted every
|
|
169
|
+
* active bundle site-wide.
|
|
170
|
+
*
|
|
171
|
+
* Denormalised at bundle create/update time and refreshed by the daily bundle
|
|
172
|
+
* stock sync. Per Root Cause #42 a mirror is never trusted alone: readers
|
|
173
|
+
* treat an ABSENT mirror as "unscoped" (show it) rather than "belongs to no
|
|
174
|
+
* category" (hide it), so a write path that forgets to set it degrades to
|
|
175
|
+
* over-inclusion instead of silently losing the bundle.
|
|
176
|
+
*/
|
|
177
|
+
bundleCategorySlugs?: string[];
|
|
165
178
|
/**
|
|
166
179
|
* Sum of member products' individual prices (decimal rupees) — the "buy
|
|
167
180
|
* separately" total the discount badge is measured against. Denormalised
|
|
@@ -106,35 +106,35 @@ export declare const bundleQueryRuleSchema: z.ZodDiscriminatedUnion<"type", [z.Z
|
|
|
106
106
|
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
107
107
|
listingType: z.ZodOptional<z.ZodEnum<["standard", "pre-order", "prize-draw"]>>;
|
|
108
108
|
}, "strip", z.ZodTypeAny, {
|
|
109
|
-
|
|
109
|
+
categorySlug?: string | undefined;
|
|
110
110
|
brandSlug?: string | undefined;
|
|
111
111
|
tags?: string[] | undefined;
|
|
112
|
-
categorySlug?: string | undefined;
|
|
113
|
-
}, {
|
|
114
112
|
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
113
|
+
}, {
|
|
114
|
+
categorySlug?: string | undefined;
|
|
115
115
|
brandSlug?: string | undefined;
|
|
116
116
|
tags?: string[] | undefined;
|
|
117
|
-
|
|
117
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
118
118
|
}>;
|
|
119
119
|
orderBy: z.ZodOptional<z.ZodEnum<["price-asc", "price-desc", "createdAt-desc"]>>;
|
|
120
120
|
limit: z.ZodNumber;
|
|
121
121
|
}, "strip", z.ZodTypeAny, {
|
|
122
122
|
type: "dynamic";
|
|
123
123
|
filter: {
|
|
124
|
-
|
|
124
|
+
categorySlug?: string | undefined;
|
|
125
125
|
brandSlug?: string | undefined;
|
|
126
126
|
tags?: string[] | undefined;
|
|
127
|
-
|
|
127
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
128
128
|
};
|
|
129
129
|
limit: number;
|
|
130
130
|
orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
|
|
131
131
|
}, {
|
|
132
132
|
type: "dynamic";
|
|
133
133
|
filter: {
|
|
134
|
-
|
|
134
|
+
categorySlug?: string | undefined;
|
|
135
135
|
brandSlug?: string | undefined;
|
|
136
136
|
tags?: string[] | undefined;
|
|
137
|
-
|
|
137
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
138
138
|
};
|
|
139
139
|
limit: number;
|
|
140
140
|
orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
|
|
@@ -260,35 +260,35 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
260
260
|
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
261
261
|
listingType: z.ZodOptional<z.ZodEnum<["standard", "pre-order", "prize-draw"]>>;
|
|
262
262
|
}, "strip", z.ZodTypeAny, {
|
|
263
|
-
|
|
263
|
+
categorySlug?: string | undefined;
|
|
264
264
|
brandSlug?: string | undefined;
|
|
265
265
|
tags?: string[] | undefined;
|
|
266
|
-
categorySlug?: string | undefined;
|
|
267
|
-
}, {
|
|
268
266
|
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
267
|
+
}, {
|
|
268
|
+
categorySlug?: string | undefined;
|
|
269
269
|
brandSlug?: string | undefined;
|
|
270
270
|
tags?: string[] | undefined;
|
|
271
|
-
|
|
271
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
272
272
|
}>;
|
|
273
273
|
orderBy: z.ZodOptional<z.ZodEnum<["price-asc", "price-desc", "createdAt-desc"]>>;
|
|
274
274
|
limit: z.ZodNumber;
|
|
275
275
|
}, "strip", z.ZodTypeAny, {
|
|
276
276
|
type: "dynamic";
|
|
277
277
|
filter: {
|
|
278
|
-
|
|
278
|
+
categorySlug?: string | undefined;
|
|
279
279
|
brandSlug?: string | undefined;
|
|
280
280
|
tags?: string[] | undefined;
|
|
281
|
-
|
|
281
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
282
282
|
};
|
|
283
283
|
limit: number;
|
|
284
284
|
orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
|
|
285
285
|
}, {
|
|
286
286
|
type: "dynamic";
|
|
287
287
|
filter: {
|
|
288
|
-
|
|
288
|
+
categorySlug?: string | undefined;
|
|
289
289
|
brandSlug?: string | undefined;
|
|
290
290
|
tags?: string[] | undefined;
|
|
291
|
-
|
|
291
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
292
292
|
};
|
|
293
293
|
limit: number;
|
|
294
294
|
orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
|
|
@@ -394,11 +394,10 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
394
394
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
395
395
|
}, z.ZodTypeAny, "passthrough">;
|
|
396
396
|
slug: string;
|
|
397
|
-
order: number;
|
|
398
|
-
position: number;
|
|
399
|
-
isFeatured: boolean;
|
|
400
397
|
isActive: boolean;
|
|
398
|
+
order: number;
|
|
401
399
|
createdBy: string;
|
|
400
|
+
isFeatured: boolean;
|
|
402
401
|
rootId: string;
|
|
403
402
|
tier: number;
|
|
404
403
|
isLeaf: boolean;
|
|
@@ -409,6 +408,7 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
409
408
|
ogImage?: string | undefined;
|
|
410
409
|
canonicalUrl?: string | undefined;
|
|
411
410
|
};
|
|
411
|
+
position: number;
|
|
412
412
|
parentIds: string[];
|
|
413
413
|
isSearchable: boolean;
|
|
414
414
|
childrenIds: string[];
|
|
@@ -466,10 +466,10 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
466
466
|
} | {
|
|
467
467
|
type: "dynamic";
|
|
468
468
|
filter: {
|
|
469
|
-
|
|
469
|
+
categorySlug?: string | undefined;
|
|
470
470
|
brandSlug?: string | undefined;
|
|
471
471
|
tags?: string[] | undefined;
|
|
472
|
-
|
|
472
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
473
473
|
};
|
|
474
474
|
limit: number;
|
|
475
475
|
orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
|
|
@@ -493,11 +493,10 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
493
493
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
494
494
|
}, z.ZodTypeAny, "passthrough">;
|
|
495
495
|
slug: string;
|
|
496
|
-
order: number;
|
|
497
|
-
position: number;
|
|
498
|
-
isFeatured: boolean;
|
|
499
496
|
isActive: boolean;
|
|
497
|
+
order: number;
|
|
500
498
|
createdBy: string;
|
|
499
|
+
isFeatured: boolean;
|
|
501
500
|
rootId: string;
|
|
502
501
|
tier: number;
|
|
503
502
|
isLeaf: boolean;
|
|
@@ -508,6 +507,7 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
508
507
|
ogImage?: string | undefined;
|
|
509
508
|
canonicalUrl?: string | undefined;
|
|
510
509
|
};
|
|
510
|
+
position: number;
|
|
511
511
|
parentIds: string[];
|
|
512
512
|
isSearchable: boolean;
|
|
513
513
|
childrenIds: string[];
|
|
@@ -565,10 +565,10 @@ export declare const categoryFirestoreSchema: z.ZodObject<{
|
|
|
565
565
|
} | {
|
|
566
566
|
type: "dynamic";
|
|
567
567
|
filter: {
|
|
568
|
-
|
|
568
|
+
categorySlug?: string | undefined;
|
|
569
569
|
brandSlug?: string | undefined;
|
|
570
570
|
tags?: string[] | undefined;
|
|
571
|
-
|
|
571
|
+
listingType?: "standard" | "pre-order" | "prize-draw" | undefined;
|
|
572
572
|
};
|
|
573
573
|
limit: number;
|
|
574
574
|
orderBy?: "price-asc" | "price-desc" | "createdAt-desc" | undefined;
|
|
@@ -3,5 +3,20 @@ export interface ClassifiedDetailPageViewProps {
|
|
|
3
3
|
slug: string;
|
|
4
4
|
/** Pre-fetched product document — dedupes with generateMetadata() via React.cache(). */
|
|
5
5
|
initialProduct?: ProductDocument | null;
|
|
6
|
+
/**
|
|
7
|
+
* Render prop for offer UI, mounted inside the contact-seller panel.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately the SAME shape `ProductDetailPageView.renderOfferAction` uses,
|
|
10
|
+
* so both detail views share one contract and both consumer pages share one
|
|
11
|
+
* snippet. Called only when all three offer gates pass: `featureFlags.offers`,
|
|
12
|
+
* the classified type's `canMakeOffer` capability, and the seller's own
|
|
13
|
+
* `allowOffers` opt-in.
|
|
14
|
+
*/
|
|
15
|
+
renderOfferAction?: (opts: {
|
|
16
|
+
productId: string;
|
|
17
|
+
price: number;
|
|
18
|
+
currency: string;
|
|
19
|
+
minOfferPercent: number;
|
|
20
|
+
}) => React.ReactNode;
|
|
6
21
|
}
|
|
7
|
-
export declare function ClassifiedDetailPageView({ slug, initialProduct }: ClassifiedDetailPageViewProps): Promise<import("react").JSX.Element>;
|
|
22
|
+
export declare function ClassifiedDetailPageView({ slug, initialProduct, renderOfferAction }: ClassifiedDetailPageViewProps): Promise<import("react").JSX.Element>;
|
|
@@ -21,6 +21,9 @@ import { computeRelatedItems } from "../../../_internal/server/features/products
|
|
|
21
21
|
import { GroupedListingsCarousel } from "../../grouped/components/GroupedListingsCarousel";
|
|
22
22
|
import { getGroupsWithItemsForProduct } from "../../../_internal/server/features/grouped/data";
|
|
23
23
|
import { ClassifiedContactSellerPanel } from "./ClassifiedContactSellerPanel";
|
|
24
|
+
import { getSiteSettingsGlobal } from "../../admin/utils/getSiteSettingsGlobal";
|
|
25
|
+
import { canMakeOffer } from "../../../_internal/shared/listing-types/capabilities";
|
|
26
|
+
import { DEFAULT_MIN_OFFER_PERCENT } from "../../../_internal/shared/features/offers/config";
|
|
24
27
|
import { ListingBottomActions } from "../../products/components/ListingBottomActions";
|
|
25
28
|
function toDescriptionHtml(raw) {
|
|
26
29
|
if (!raw)
|
|
@@ -28,7 +31,7 @@ function toDescriptionHtml(raw) {
|
|
|
28
31
|
const s = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
29
32
|
return normalizeRichTextHtml(s);
|
|
30
33
|
}
|
|
31
|
-
export async function ClassifiedDetailPageView({ slug, initialProduct }) {
|
|
34
|
+
export async function ClassifiedDetailPageView({ slug, initialProduct, renderOfferAction }) {
|
|
32
35
|
const product = initialProduct !== undefined
|
|
33
36
|
? (initialProduct ?? undefined)
|
|
34
37
|
: await getClassifiedForDetail(slug).catch(() => undefined);
|
|
@@ -52,10 +55,19 @@ export async function ClassifiedDetailPageView({ slug, initialProduct }) {
|
|
|
52
55
|
const specs = Array.isArray(p.specifications) ? p.specifications : [];
|
|
53
56
|
const customSections = Array.isArray(p.customSections) ? p.customSections : [];
|
|
54
57
|
const descriptionHtml = toDescriptionHtml(p.description);
|
|
55
|
-
const [{ relatedItems, relatedByBrand, relatedByTags, relatedByStore }, groups] = await Promise.all([
|
|
58
|
+
const [{ relatedItems, relatedByBrand, relatedByTags, relatedByStore }, groups, siteSettings] = await Promise.all([
|
|
56
59
|
computeRelatedItems(product),
|
|
57
60
|
getGroupsWithItemsForProduct(product.id),
|
|
61
|
+
getSiteSettingsGlobal().catch(() => null),
|
|
58
62
|
]);
|
|
63
|
+
// Classifieds are the one non-standard type where haggling is the norm, so
|
|
64
|
+
// `canMakeOffer` is true for them — but the seller still opts in per listing
|
|
65
|
+
// (`allowOffers`, usually alongside `classified.negotiable`).
|
|
66
|
+
const offersAvailable = siteSettings?.featureFlags?.offers !== false &&
|
|
67
|
+
canMakeOffer("classified") &&
|
|
68
|
+
p.allowOffers === true &&
|
|
69
|
+
price !== null &&
|
|
70
|
+
!!renderOfferAction;
|
|
59
71
|
return (_jsxs(Main, { children: [_jsx(HistoryTracker, { productId: String(p.id ?? p.slug ?? ""), productType: "product", snapshot: {
|
|
60
72
|
title,
|
|
61
73
|
thumb: images[0],
|
|
@@ -66,5 +78,13 @@ export async function ClassifiedDetailPageView({ slug, initialProduct }) {
|
|
|
66
78
|
id: s.id,
|
|
67
79
|
label: s.title,
|
|
68
80
|
content: _jsx(CustomSectionTabContent, { section: s }),
|
|
69
|
-
})) })), renderBuyBar: () => (
|
|
81
|
+
})) })), renderBuyBar: () => (_jsxs(Stack, { id: "classified-contact-bar", className: "p-[var(--appkit-space-5)]", border: "subtle", gap: "md", rounded: "xl", surface: "muted", children: [offersAvailable &&
|
|
82
|
+
renderOfferAction({
|
|
83
|
+
productId: String(product.id),
|
|
84
|
+
price: price,
|
|
85
|
+
currency,
|
|
86
|
+
minOfferPercent: typeof p.minOfferPercent === "number"
|
|
87
|
+
? p.minOfferPercent
|
|
88
|
+
: DEFAULT_MIN_OFFER_PERCENT,
|
|
89
|
+
}), _jsx(ClassifiedContactSellerPanel, { productId: String(product.id), onContactSeller: startClassifiedConversationAction })] })), renderRelated: () => (_jsxs(Stack, { gap: "xl", children: [_jsx(GroupedListingsCarousel, { groups: groups }), _jsx(RelatedItemsSection, { relatedItems: relatedItems, relatedByBrand: relatedByBrand, relatedByTags: relatedByTags, relatedByStore: relatedByStore, categoryLabel: categoryName || category || undefined, brandLabel: brand, storeLabel: storeName ?? undefined })] })) }), _jsx(ListingBottomActions, { listingType: "classified", anchorId: "classified-contact-bar", price: price, currency: currency })] })] }));
|
|
70
90
|
}
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { normalizeError } from "../../../errors/normalize";
|
|
4
4
|
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
5
|
-
import React, { useEffect
|
|
6
|
-
import { z } from "zod";
|
|
5
|
+
import React, { useEffect } from "react";
|
|
7
6
|
import { useQuery } from "@tanstack/react-query";
|
|
8
7
|
import { Alert, Button, Div, Grid, Heading, Input, Label, RichTextEditor, Row, Select, Stack, StackedViewShell, TagInput, Text, Textarea, Toggle, } from "../../../ui";
|
|
9
8
|
import { FormShellContext, useFormShellState, applyZodIssues, FormErrorSummary } from "../../../ui/forms";
|
|
10
9
|
import { apiClient } from "../../../http";
|
|
11
10
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
12
|
-
import {
|
|
11
|
+
import { SectionForm, useSectionFormNav } from "../../shell";
|
|
12
|
+
import { eventDraftSchema } from "../schemas/event-form";
|
|
13
13
|
import { ProductInlineSelect } from "../../seller/components/ProductInlineSelect";
|
|
14
14
|
import { CouponInlineSelect } from "../../seller/components/CouponInlineSelect";
|
|
15
15
|
// Covers the cross-type required fields plus the two conditional rules the
|
|
@@ -19,27 +19,6 @@ import { CouponInlineSelect } from "../../seller/components/CouponInlineSelect";
|
|
|
19
19
|
// form-builder arrays, raffle/spin config) are deliberately left unvalidated
|
|
20
20
|
// — modeling their full conditional shape correctly would need much deeper
|
|
21
21
|
// per-type domain rules than this pass is scoped for.
|
|
22
|
-
const eventDraftSchema = z.object({
|
|
23
|
-
type: z.string(),
|
|
24
|
-
title: z.string().min(1, "Title is required"),
|
|
25
|
-
startsAt: z.string().min(1, "Start date is required"),
|
|
26
|
-
endsAt: z.string().min(1, "End date is required"),
|
|
27
|
-
couponId: z.string(),
|
|
28
|
-
displayCode: z.string(),
|
|
29
|
-
pollOptions: z.array(z.object({ id: z.string(), label: z.string() })),
|
|
30
|
-
}).passthrough().superRefine((v, ctx) => {
|
|
31
|
-
if (v.type === "offer") {
|
|
32
|
-
if (!v.couponId.trim()) {
|
|
33
|
-
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["couponId"], message: "Coupon is required for offer events" });
|
|
34
|
-
}
|
|
35
|
-
if (!v.displayCode.trim()) {
|
|
36
|
-
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["displayCode"], message: "Display code is required for offer events" });
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
if (v.type === "poll" && v.pollOptions.filter((o) => o.label.trim()).length < 2) {
|
|
40
|
-
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["pollOptions"], message: "Poll events require at least 2 options" });
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
22
|
const __P = {
|
|
44
23
|
p4: "p-[var(--appkit-space-4)]",
|
|
45
24
|
};
|
|
@@ -226,7 +205,6 @@ export function AdminEventEditorView({ eventId, onSaved, embedded, allowedTypes,
|
|
|
226
205
|
const isEdit = Boolean(eventId);
|
|
227
206
|
const [draft, setDraft] = React.useState(DEFAULT_DRAFT);
|
|
228
207
|
const [slugManual, setSlugManual] = React.useState(false);
|
|
229
|
-
const [currentStep, setCurrentStep] = React.useState(0);
|
|
230
208
|
const [saveMessage, setSaveMessage] = React.useState(null);
|
|
231
209
|
const [triggerMessage, setTriggerMessage] = React.useState(null);
|
|
232
210
|
const [raffleWinnerName, setRaffleWinnerName] = React.useState("");
|
|
@@ -358,44 +336,49 @@ export function AdminEventEditorView({ eventId, onSaved, embedded, allowedTypes,
|
|
|
358
336
|
});
|
|
359
337
|
const isLoading = saveMutation.isPending || eventQuery.isLoading;
|
|
360
338
|
// --- steps ---
|
|
361
|
-
|
|
339
|
+
/**
|
|
340
|
+
* Sections, not steps — every field reachable at once, one submit at the
|
|
341
|
+
* bottom. The old wizard gated Settings behind Details validating, so a
|
|
342
|
+
* missing end date made an event's poll options unreachable.
|
|
343
|
+
*
|
|
344
|
+
* Ids match the schema's `section` annotations exactly, which is what lets
|
|
345
|
+
* `<FormErrorSummary>` jump to the right panel.
|
|
346
|
+
*/
|
|
347
|
+
const sections = [
|
|
362
348
|
{
|
|
349
|
+
id: "details",
|
|
350
|
+
required: true,
|
|
351
|
+
quick: true,
|
|
363
352
|
label: "Details",
|
|
364
353
|
fields: ["type", "title", "slug", "description", "startsAt", "endsAt", "tags"],
|
|
365
|
-
validate:
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
if (!values.startsAt)
|
|
369
|
-
return "Start date is required";
|
|
370
|
-
if (!values.endsAt)
|
|
371
|
-
return "End date is required";
|
|
372
|
-
return null;
|
|
373
|
-
},
|
|
354
|
+
// The per-step `validate` is gone: every rule it stated is already in
|
|
355
|
+
// eventDraftSchema (title/startsAt/endsAt are .min(1)), and it only ever
|
|
356
|
+
// acted as a gate to the next step.
|
|
374
357
|
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Event Details" }), !isEdit && (_jsx(Select, { label: "Event type", value: values.type, options: allowedTypes ? EVENT_TYPE_OPTIONS.filter((o) => allowedTypes.includes(o.value)) : EVENT_TYPE_OPTIONS, onChange: (e) => onChange({ type: e.target.value }) })), _jsx(Input, { label: "Title", value: values.title, onChange: (e) => {
|
|
375
358
|
const v = e.target.value;
|
|
376
359
|
onChange({ title: v, ...(!slugManual && { slug: toEventSlug(v) }) });
|
|
377
360
|
}, placeholder: "Charizard Flash Sale 2026", required: true }), _jsx(Input, { label: "Slug", value: values.slug, onChange: (e) => { setSlugManual(true); onChange({ slug: e.target.value }); }, placeholder: "event-charizard-flash-sale-2026", helperText: "Auto-generated from title. Must start with 'event-'." }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { children: "Description" }), _jsx(RichTextEditor, { value: values.description, onChange: (v) => onChange({ description: v }), minHeightClassName: "min-h-[120px]", placeholder: "Describe this event\u2026" })] }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Input, { label: "Starts at", type: "datetime-local", value: values.startsAt, onChange: (e) => onChange({ startsAt: e.target.value }), required: true }), _jsx(Input, { label: "Ends at", type: "datetime-local", value: values.endsAt, onChange: (e) => onChange({ endsAt: e.target.value }), required: true })] }), _jsx(TagInput, { label: "Tags", value: values.tags, onChange: (t) => onChange({ tags: t }), placeholder: "e.g. pokemon, sale, 2026" })] })),
|
|
378
361
|
},
|
|
379
362
|
{
|
|
363
|
+
id: "media",
|
|
380
364
|
label: "Media",
|
|
365
|
+
// <Collapse> unmounts its children — without this, collapsing the
|
|
366
|
+
// section mid-upload discards the transfer.
|
|
367
|
+
keepMounted: true,
|
|
381
368
|
fields: ["coverImageUrl"],
|
|
382
369
|
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Media" }), _jsx(Input, { label: "Cover Image URL (optional)", value: values.coverImageUrl, onChange: (e) => onChange({ coverImageUrl: e.target.value }), placeholder: "https://\u2026", helperText: "Direct link to the event cover image." })] })),
|
|
383
370
|
},
|
|
384
371
|
{
|
|
372
|
+
id: "settings",
|
|
385
373
|
label: "Settings",
|
|
386
374
|
fields: ["status", "allowGuestParticipation", "discountPercent", "saleBannerText", "couponId", "displayCode", "offerBannerText", "pollOptions", "resultsVisibility", "allowMultiSelect", "allowComment", "maxEntriesPerUser", "hasLeaderboard", "hasPointSystem", "pointsLabel", "entryReviewRequired", "surveyFields", "anonymous", "feedbackFields"],
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
if (values.type === "offer" && !values.displayCode.trim())
|
|
391
|
-
return "Display code is required for offer events";
|
|
392
|
-
if (values.type === "poll" && values.pollOptions.filter((o) => o.label.trim()).length < 2)
|
|
393
|
-
return "Poll events require at least 2 options";
|
|
394
|
-
return null;
|
|
395
|
-
},
|
|
375
|
+
// Same: the offer-coupon, offer-display-code and poll-minimum-options
|
|
376
|
+
// rules are all stated in eventDraftSchema's superRefine, which now
|
|
377
|
+
// surfaces them inline on the field instead of as a step-blocking banner.
|
|
396
378
|
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Event Settings" }), isEdit && (_jsx(Select, { label: "Status", value: values.status, options: EVENT_STATUS_OPTIONS, onChange: (e) => onChange({ status: e.target.value }) })), values.createdBy && (_jsxs(Stack, { gap: "none", children: [_jsx(Text, { size: "sm", weight: "medium", className: "mb-1", children: "Created by" }), _jsx(Text, { size: "sm", color: "muted", children: values.createdBy })] })), _jsxs(Stack, { gap: "xs", surface: "muted", rounded: "lg", border: "default", padding: "sm", children: [_jsx(Toggle, { checked: values.allowGuestParticipation, onChange: (v) => onChange({ allowGuestParticipation: v }), label: "Allow guest participation (no login required)" }), _jsx(Text, { size: "xs", color: "muted", children: "When enabled, unauthenticated visitors can participate in this event (poll vote, survey/feedback response, raffle entry, or wheel spin), identified by a hashed IP address instead of an account. Applies uniformly to whatever entry mechanism this event type uses." })] }), values.type === "sale" && (_jsxs(Stack, { gap: "xs", surface: "muted", rounded: "lg", border: "default", padding: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Sale configuration" }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Input, { label: "Discount %", type: "number", value: values.discountPercent, onChange: (e) => onChange({ discountPercent: e.target.value }), placeholder: "10" }), _jsx(Input, { label: "Banner text (optional)", value: values.saleBannerText, onChange: (e) => onChange({ saleBannerText: e.target.value }), placeholder: "Limited time \u2014 ends Sunday!" })] })] })), values.type === "offer" && (_jsxs(Stack, { gap: "xs", surface: "muted", rounded: "lg", border: "default", padding: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Offer configuration" }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsxs(Div, { children: [_jsx(Text, { size: "sm", weight: "medium", className: "mb-1", children: "Coupon" }), _jsx(CouponInlineSelect, { scope: "admin", value: values.couponId, onChange: (id) => onChange({ couponId: id ?? "" }), placeholder: "Search coupons\u2026", allowCreate: false })] }), _jsx(Input, { label: "Display code", value: values.displayCode, onChange: (e) => onChange({ displayCode: e.target.value }), placeholder: "CHARIZARD25", required: true })] }), _jsx(Input, { label: "Banner text (optional)", value: values.offerBannerText, onChange: (e) => onChange({ offerBannerText: e.target.value }), placeholder: "Use CHARIZARD25 at checkout" })] })), values.type === "poll" && (_jsxs(Stack, { gap: "md", rounded: "xl", border: "default", padding: "md", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Poll configuration" }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Options (minimum 2)" }), values.pollOptions.map((opt, idx) => (_jsxs(Row, { gap: "xs", children: [_jsx(Div, { className: "flex-1", children: _jsx(Input, { value: opt.label, onChange: (e) => onChange({ pollOptions: values.pollOptions.map((o) => o.id === opt.id ? { ...o, label: e.target.value } : o) }), placeholder: `Option ${idx + 1}` }) }), values.pollOptions.length > 2 && (_jsx(Button, { variant: "ghost", type: "button", onClick: () => onChange({ pollOptions: values.pollOptions.filter((o) => o.id !== opt.id) }), className: CLS_REMOVE_BTN_PX2, "aria-label": "Remove option", children: "\u00D7" }))] }, opt.id))), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onChange({ pollOptions: [...values.pollOptions, { id: `opt${Date.now()}`, label: "" }] }), children: "+ Add option" })] }), _jsx(Select, { label: "Results visibility", value: values.resultsVisibility, options: POLL_VISIBILITY_OPTIONS, onChange: (e) => onChange({ resultsVisibility: e.target.value }) }), _jsxs(Stack, { gap: "sm", children: [_jsx(Toggle, { checked: values.allowMultiSelect, onChange: (v) => onChange({ allowMultiSelect: v }), label: "Allow multi-select" }), _jsx(Toggle, { checked: values.allowComment, onChange: (v) => onChange({ allowComment: v }), label: "Allow comment with vote" })] })] })), values.type === "survey" && (_jsxs(Stack, { gap: "md", rounded: "xl", border: "default", padding: "md", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Survey configuration" }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Input, { label: "Max entries per user", type: "number", value: values.maxEntriesPerUser, onChange: (e) => onChange({ maxEntriesPerUser: e.target.value }), placeholder: "1" }), values.hasPointSystem && (_jsx(Input, { label: "Points label", value: values.pointsLabel, onChange: (e) => onChange({ pointsLabel: e.target.value }), placeholder: "Points" }))] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Toggle, { checked: values.requireLogin, onChange: (v) => onChange({ requireLogin: v }), label: "Require login to participate" }), _jsx(Toggle, { checked: values.hasLeaderboard, onChange: (v) => onChange({ hasLeaderboard: v }), label: "Show leaderboard" }), _jsx(Toggle, { checked: values.hasPointSystem, onChange: (v) => onChange({ hasPointSystem: v }), label: "Enable point system" }), _jsx(Toggle, { checked: values.entryReviewRequired, onChange: (v) => onChange({ entryReviewRequired: v }), label: "Require employee review before entry is approved" })] }), _jsx(FormFieldBuilder, { fields: values.surveyFields, setFields: (f) => onChange({ surveyFields: f }) })] })), values.type === "feedback" && (_jsxs(Stack, { gap: "md", rounded: "xl", border: "default", padding: "md", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Feedback configuration" }), _jsx(Toggle, { checked: values.anonymous, onChange: (v) => onChange({ anonymous: v }), label: "Allow anonymous submissions" }), _jsx(FormFieldBuilder, { fields: values.feedbackFields, setFields: (f) => onChange({ feedbackFields: f }) })] }))] })),
|
|
397
379
|
},
|
|
398
380
|
{
|
|
381
|
+
id: "raffle",
|
|
399
382
|
label: "Raffle / Spin",
|
|
400
383
|
fields: ["hasRaffle", "raffleType", "raffleTopN", "rafflePrize", "rafflePrizeCouponId", "rafflePrizeProductIds", "spinPrizes", "spinMaxPerUser", "spinWindowStart", "spinWindowEnd"],
|
|
401
384
|
render: ({ values, onChange }) => {
|
|
@@ -407,16 +390,11 @@ export function AdminEventEditorView({ eventId, onSaved, embedded, allowedTypes,
|
|
|
407
390
|
},
|
|
408
391
|
];
|
|
409
392
|
const alertSection = eventQuery.error ? (_jsx(Alert, { variant: "error", title: "Could not load event", children: eventQuery.error instanceof Error ? eventQuery.error.message : "Unknown error" })) : null;
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
return map;
|
|
416
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
417
|
-
}, [steps.length]);
|
|
418
|
-
const wizardShellCtx = useMemo(() => ({ ...shellCtx, fieldToStepIndex, goToStep: (n) => setCurrentStep(n) }), [shellCtx, fieldToStepIndex, setCurrentStep]);
|
|
419
|
-
const formContent = (_jsxs(Stack, { gap: "sm", children: [alertSection, _jsxs(FormShellContext.Provider, { value: wizardShellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: () => { saveMutation.mutate(); }, formId: "admin-event", currentStep: currentStep, onStepChange: setCurrentStep, completeLabel: isEdit ? "Save Changes" : "Create Event", isLoading: isLoading })] }), saveMessage && (_jsx(Alert, { variant: saveMessage.toLowerCase().includes("fail") || saveMessage.toLowerCase().includes("error") ? "error" : "success", title: "Save status", children: saveMessage }))] }));
|
|
393
|
+
// Replaces the hand-rolled fieldToStepIndex + goToStep pair. The hook owns
|
|
394
|
+
// the expand-then-scroll ordering a raw setState cannot: a collapsed panel
|
|
395
|
+
// must MOUNT before scrollIntoView and focus can reach the offending field.
|
|
396
|
+
const { openIds, setOpenIds, goToSection, fieldToSectionIndex, sectionMeta } = useSectionFormNav(sections, draft);
|
|
397
|
+
const formContent = (_jsxs(Stack, { gap: "sm", children: [alertSection, _jsxs(FormShellContext.Provider, { value: shellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(SectionForm, { sections: sections, values: draft, onChange: update, onSubmit: () => { saveMutation.mutate(); }, schema: eventDraftSchema, openIds: openIds, onOpenChange: setOpenIds, submitLabel: isEdit ? "Save Changes" : "Create Event", isLoading: isLoading })] }), saveMessage && (_jsx(Alert, { variant: saveMessage.toLowerCase().includes("fail") || saveMessage.toLowerCase().includes("error") ? "error" : "success", title: "Save status", children: saveMessage }))] }));
|
|
420
398
|
if (embedded) {
|
|
421
399
|
return _jsx(Div, { className: `${__O.yAuto} ${__P.p4}`, children: formContent });
|
|
422
400
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useApiMutation, sieveFilter, SIEVE_OP, sortBy } from "@mohasinac/appkit/client";
|
|
4
|
-
import React from "react";
|
|
4
|
+
import React, { useState } from "react";
|
|
5
5
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
6
|
-
import { Alert, Button, Div, Input, Row, Select, Stack, Text, useToast } from "../../../ui";
|
|
6
|
+
import { Alert, Button, Div, Input, Row, Select, Stack, Text, useToast, RecordDetailModal, } from "../../../ui";
|
|
7
7
|
import { apiClient } from "../../../http";
|
|
8
8
|
import { normalizeError } from "../../../errors/normalize";
|
|
9
9
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
@@ -128,6 +128,10 @@ export function AdminEventEntriesView({ eventId, entriesEndpoint, entryReviewEnd
|
|
|
128
128
|
},
|
|
129
129
|
];
|
|
130
130
|
const eventTitle = statsQuery.data?.event?.title;
|
|
131
|
+
// Approve / Waitlist / Cancel were offered on an entry the admin could never
|
|
132
|
+
// read — the poll vote, the comment and the survey answers were all invisible
|
|
133
|
+
// (Root Cause #56, "acting blind"). The row already carries the whole entry.
|
|
134
|
+
const [detail, setDetail] = useState(null);
|
|
131
135
|
const config = {
|
|
132
136
|
portal: "admin",
|
|
133
137
|
title: eventTitle ? `${eventTitle} Entries` : "Event Entries",
|
|
@@ -139,6 +143,7 @@ export function AdminEventEntriesView({ eventId, entriesEndpoint, entryReviewEnd
|
|
|
139
143
|
endpoint: resolvedEntriesEndpoint,
|
|
140
144
|
sortOptions: [{ value: sortBy("submittedAt", "DESC"), label: "Most recent" }],
|
|
141
145
|
columns,
|
|
146
|
+
onRowClick: (row) => setDetail(row),
|
|
142
147
|
mapRows: (response) => response.items ?? [],
|
|
143
148
|
getTotal: (response) => response.total ?? (response.items ?? []).length,
|
|
144
149
|
buildFilters: (state) => state.reviewStatus ? sieveFilter("reviewStatus", SIEVE_OP.EQ, state.reviewStatus) : undefined,
|
|
@@ -146,5 +151,19 @@ export function AdminEventEntriesView({ eventId, entriesEndpoint, entryReviewEnd
|
|
|
146
151
|
toolbarExtra: eventId ? (_jsx(Button, { variant: "ghost", action: ACTIONS.ADMIN["export-event-entries"], onClick: handleExportReport })) : undefined,
|
|
147
152
|
renderAboveContent: () => (_jsxs(Stack, { gap: "3", className: "px-[var(--appkit-space-3)] pb-[var(--appkit-space-2)]", children: [!eventId ? (_jsx(Alert, { variant: "warning", title: "Missing event id", children: "Event id is required to load entries." })) : null, statsQuery.error ? (_jsx(Alert, { variant: "error", title: "Could not load event stats", children: statsQuery.error instanceof Error ? statsQuery.error.message : "Unknown error" })) : null, _jsxs(Div, { layout: "grid", gap: "3", className: "grid-cols-1 sm:grid-cols-3", children: [_jsx(Alert, { variant: "info", title: "Total entries", children: String(statsQuery.data?.stats?.totalEntries ?? 0) }), _jsx(Alert, { variant: "success", title: "Approved", children: String(statsQuery.data?.stats?.approvedEntries ?? 0) }), _jsx(Alert, { variant: "warning", title: "Flagged", children: String(statsQuery.data?.stats?.flaggedEntries ?? 0) })] })] })),
|
|
148
153
|
};
|
|
149
|
-
return _jsx(DataListingView, { config: config })
|
|
154
|
+
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(RecordDetailModal, { isOpen: detail !== null, onClose: () => setDetail(null), title: detail?.userDisplayName || detail?.userEmail || "Entry", badges: detail ? [{ label: detail.reviewStatus }] : undefined, description: detail?.pollComment, fields: detail
|
|
155
|
+
? [
|
|
156
|
+
{ label: "Entrant", value: detail.userDisplayName ?? detail.userId ?? "—" },
|
|
157
|
+
{ label: "Email", value: detail.userEmail ?? "—" },
|
|
158
|
+
{ label: "Review status", value: detail.reviewStatus },
|
|
159
|
+
{ label: "Points", value: detail.points != null ? String(detail.points) : "—" },
|
|
160
|
+
{ label: "Raffle eligible", value: detail.raffleEligible ? "Yes" : "No" },
|
|
161
|
+
{ label: "Poll votes", value: detail.pollVotes?.join(", ") || "—" },
|
|
162
|
+
{ label: "Reviewed by", value: detail.reviewedBy ?? "—" },
|
|
163
|
+
{ label: "Review note", value: detail.reviewNote ?? "—" },
|
|
164
|
+
{ label: "Entry ID", value: detail.id },
|
|
165
|
+
]
|
|
166
|
+
: undefined,
|
|
167
|
+
// The survey/feedback answers — the actual submission being judged.
|
|
168
|
+
metadata: detail?.formResponses })] }));
|
|
150
169
|
}
|