@mohasinac/appkit 2.7.58 → 2.8.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/filters/filter-load-options.d.ts +4 -5
- package/dist/_internal/server/features/auctions/og.js +8 -32
- package/dist/_internal/server/features/blog/og.js +10 -49
- package/dist/_internal/server/features/checkout/actions.js +6 -0
- package/dist/_internal/server/features/classified/og.js +9 -51
- package/dist/_internal/server/features/digital-code/actions.d.ts +11 -0
- package/dist/_internal/server/features/digital-code/actions.js +30 -0
- package/dist/_internal/server/features/digital-code/index.d.ts +1 -0
- package/dist/_internal/server/features/digital-code/index.js +1 -0
- package/dist/_internal/server/features/digital-code/og.js +9 -51
- package/dist/_internal/server/features/events/og.js +10 -49
- package/dist/_internal/server/features/item-requests/data.d.ts +17 -0
- package/dist/_internal/server/features/item-requests/data.js +20 -0
- package/dist/_internal/server/features/item-requests/index.d.ts +2 -0
- package/dist/_internal/server/features/item-requests/index.js +2 -0
- package/dist/_internal/server/features/item-requests/og.d.ts +40 -0
- package/dist/_internal/server/features/item-requests/og.js +136 -0
- package/dist/_internal/server/features/live/actions.d.ts +5 -0
- package/dist/_internal/server/features/live/actions.js +24 -0
- package/dist/_internal/server/features/live/index.d.ts +1 -0
- package/dist/_internal/server/features/live/index.js +1 -0
- package/dist/_internal/server/features/live/og.js +9 -51
- package/dist/_internal/server/features/media/contextGuards.js +19 -8
- package/dist/_internal/server/features/pre-orders/og.js +8 -32
- package/dist/_internal/server/features/prize-draws/data.d.ts +17 -0
- package/dist/_internal/server/features/prize-draws/data.js +20 -0
- package/dist/_internal/server/features/prize-draws/index.d.ts +2 -0
- package/dist/_internal/server/features/prize-draws/index.js +2 -0
- package/dist/_internal/server/features/prize-draws/og.d.ts +30 -0
- package/dist/_internal/server/features/prize-draws/og.js +50 -0
- package/dist/_internal/server/features/products/og.js +8 -33
- package/dist/_internal/server/features/scams/og.js +1 -1
- package/dist/_internal/server/features/seo/og-layout.d.ts +42 -0
- package/dist/_internal/server/features/seo/og-layout.js +69 -0
- package/dist/_internal/server/features/stores/og.js +8 -41
- package/dist/_internal/server/features/sublisting-categories/og.js +11 -42
- package/dist/_internal/shared/actions/bulk-helpers.d.ts +3 -0
- package/dist/_internal/shared/actions/bulk-helpers.js +19 -0
- package/dist/_internal/shared/config/schema.d.ts +4 -4
- package/dist/client.d.ts +13 -6
- package/dist/client.js +9 -3
- package/dist/configs/next.js +11 -0
- package/dist/constants/index.d.ts +4 -0
- package/dist/constants/index.js +2 -0
- package/dist/constants/notification-types.d.ts +20 -0
- package/dist/constants/notification-types.js +37 -0
- package/dist/constants/pagination-presets.d.ts +39 -0
- package/dist/constants/pagination-presets.js +38 -0
- package/dist/errors/messages.d.ts +0 -4
- package/dist/errors/messages.js +0 -4
- package/dist/features/account/components/AddressesIndexListing.js +3 -4
- package/dist/features/account/components/UserOffersPanel.js +1 -1
- package/dist/features/account/components/UserSidebar.js +14 -10
- package/dist/features/account/components/UserSupportView.d.ts +1 -2
- package/dist/features/account/components/UserSupportView.js +9 -1
- package/dist/features/admin/actions/admin-actions.js +16 -1
- package/dist/features/admin/components/AdminAllEventEntriesView.d.ts +2 -3
- package/dist/features/admin/components/AdminAllEventEntriesView.js +50 -89
- package/dist/features/admin/components/AdminBidsView.d.ts +2 -3
- package/dist/features/admin/components/AdminBidsView.js +64 -104
- package/dist/features/admin/components/AdminBlogView.d.ts +3 -7
- package/dist/features/admin/components/AdminBlogView.js +53 -88
- package/dist/features/admin/components/AdminBrandEditorView.js +14 -17
- package/dist/features/admin/components/AdminBrandsView.d.ts +2 -3
- package/dist/features/admin/components/AdminBrandsView.js +85 -89
- package/dist/features/admin/components/AdminBundlesView.js +68 -130
- package/dist/features/admin/components/AdminCarouselView.d.ts +2 -2
- package/dist/features/admin/components/AdminCarouselView.js +22 -70
- package/dist/features/admin/components/AdminCartsView.d.ts +2 -3
- package/dist/features/admin/components/AdminCartsView.js +39 -89
- package/dist/features/admin/components/AdminCategoriesView.d.ts +3 -3
- package/dist/features/admin/components/AdminCategoriesView.js +97 -96
- package/dist/features/admin/components/AdminCategoryEditorView.js +2 -6
- package/dist/features/admin/components/AdminClassifiedView.d.ts +3 -0
- package/dist/features/admin/components/AdminClassifiedView.js +44 -0
- package/dist/features/admin/components/AdminContactView.d.ts +2 -2
- package/dist/features/admin/components/AdminContactView.js +105 -130
- package/dist/features/admin/components/AdminCouponEditorView.js +14 -17
- package/dist/features/admin/components/AdminCouponsView.d.ts +3 -6
- package/dist/features/admin/components/AdminCouponsView.js +69 -97
- package/dist/features/admin/components/AdminDigitalCodesView.d.ts +3 -0
- package/dist/features/admin/components/AdminDigitalCodesView.js +51 -0
- package/dist/features/admin/components/AdminFaqEditorView.js +14 -17
- package/dist/features/admin/components/AdminFaqsView.d.ts +4 -4
- package/dist/features/admin/components/AdminFaqsView.js +79 -86
- package/dist/features/admin/components/AdminFeatureEditorView.js +7 -9
- package/dist/features/admin/components/AdminFeaturesView.d.ts +2 -3
- package/dist/features/admin/components/AdminFeaturesView.js +57 -70
- package/dist/features/admin/components/AdminGroupedListingsView.d.ts +3 -0
- package/dist/features/admin/components/AdminGroupedListingsView.js +43 -0
- package/dist/features/admin/components/AdminHistoryView.d.ts +2 -3
- package/dist/features/admin/components/AdminHistoryView.js +35 -52
- package/dist/features/admin/components/AdminListingScaffold.d.ts +2 -2
- package/dist/features/admin/components/AdminListingScaffold.js +3 -3
- package/dist/features/admin/components/AdminLiveView.d.ts +3 -0
- package/dist/features/admin/components/AdminLiveView.js +50 -0
- package/dist/features/admin/components/AdminNewsletterView.d.ts +2 -2
- package/dist/features/admin/components/AdminNewsletterView.js +68 -108
- package/dist/features/admin/components/AdminNotificationsView.d.ts +2 -3
- package/dist/features/admin/components/AdminNotificationsView.js +67 -99
- package/dist/features/admin/components/AdminOrderEditorView.js +10 -10
- package/dist/features/admin/components/AdminOrdersView.d.ts +2 -3
- package/dist/features/admin/components/AdminOrdersView.js +93 -113
- package/dist/features/admin/components/AdminPayoutsView.d.ts +2 -3
- package/dist/features/admin/components/AdminPayoutsView.js +51 -97
- package/dist/features/admin/components/AdminPrizeDrawsView.d.ts +2 -3
- package/dist/features/admin/components/AdminPrizeDrawsView.js +41 -83
- package/dist/features/admin/components/AdminProductEditorView.js +3 -7
- package/dist/features/admin/components/AdminProductsView.d.ts +4 -4
- package/dist/features/admin/components/AdminProductsView.js +166 -167
- package/dist/features/admin/components/AdminReturnRequestsView.d.ts +1 -1
- package/dist/features/admin/components/AdminReturnRequestsView.js +64 -66
- package/dist/features/admin/components/AdminReviewsView.d.ts +3 -7
- package/dist/features/admin/components/AdminReviewsView.js +94 -116
- package/dist/features/admin/components/AdminScammersView.d.ts +2 -3
- package/dist/features/admin/components/AdminScammersView.js +53 -103
- package/dist/features/admin/components/AdminSectionsView.js +1 -1
- package/dist/features/admin/components/AdminSessionsView.d.ts +2 -3
- package/dist/features/admin/components/AdminSessionsView.js +62 -95
- package/dist/features/admin/components/AdminStoreAddressesView.d.ts +1 -1
- package/dist/features/admin/components/AdminStoreAddressesView.js +39 -53
- package/dist/features/admin/components/AdminStoreEditorView.js +21 -8
- package/dist/features/admin/components/AdminStoresView.d.ts +2 -3
- package/dist/features/admin/components/AdminStoresView.js +67 -105
- package/dist/features/admin/components/AdminSublistingCategoriesView.d.ts +1 -1
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +29 -49
- package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +17 -20
- package/dist/features/admin/components/AdminSupportTicketDetailView.d.ts +10 -1
- package/dist/features/admin/components/AdminSupportTicketDetailView.js +191 -5
- package/dist/features/admin/components/AdminSupportTicketsView.d.ts +2 -3
- package/dist/features/admin/components/AdminSupportTicketsView.js +65 -102
- package/dist/features/admin/components/AdminTeamView.d.ts +2 -2
- package/dist/features/admin/components/AdminTeamView.js +42 -85
- package/dist/features/admin/components/AdminUserEditorView.d.ts +11 -1
- package/dist/features/admin/components/AdminUserEditorView.js +80 -6
- package/dist/features/admin/components/AdminUsersView.d.ts +2 -3
- package/dist/features/admin/components/AdminUsersView.js +108 -106
- package/dist/features/admin/components/AdminViewCards.d.ts +1 -1
- package/dist/features/admin/components/AdminWishlistsView.d.ts +2 -3
- package/dist/features/admin/components/AdminWishlistsView.js +36 -62
- package/dist/features/admin/components/DataListingView.d.ts +122 -0
- package/dist/features/admin/components/DataListingView.js +66 -0
- package/dist/features/admin/components/index.d.ts +10 -4
- package/dist/features/admin/components/index.js +6 -2
- package/dist/features/admin/constants/filter-tabs.d.ts +23 -17
- package/dist/features/admin/constants/filter-tabs.js +21 -17
- package/dist/features/admin/hooks/useAdminListing.d.ts +59 -0
- package/dist/features/admin/hooks/useAdminListing.js +71 -0
- package/dist/features/admin/schemas/firestore.js +6 -7
- package/dist/features/auctions/server.d.ts +0 -1
- package/dist/features/auctions/server.js +0 -1
- package/dist/features/auth/actions/realtime-token-actions.js +1 -1
- package/dist/features/auth/repository/user.repository.js +1 -1
- package/dist/features/auth/schemas/firestore.d.ts +1 -0
- package/dist/features/blog/components/BlogIndexListing.js +3 -6
- package/dist/features/cart/repository/cart.repository.d.ts +4 -1
- package/dist/features/cart/repository/cart.repository.js +12 -0
- package/dist/features/categories/components/CategoriesIndexListing.js +3 -6
- package/dist/features/checkout/hooks/useCheckoutApi.d.ts +0 -2
- package/dist/features/checkout/index.d.ts +1 -1
- package/dist/features/events/components/AdminEventsView.d.ts +3 -3
- package/dist/features/events/components/AdminEventsView.js +50 -86
- package/dist/features/events/components/EventOfferCard.d.ts +19 -0
- package/dist/features/events/components/EventOfferCard.js +29 -0
- package/dist/features/events/components/EventRaffleEntryForm.d.ts +25 -0
- package/dist/features/events/components/EventRaffleEntryForm.js +37 -0
- package/dist/features/events/components/EventRafflesSection.d.ts +1 -4
- package/dist/features/events/components/EventRafflesSection.js +17 -6
- package/dist/features/events/components/EventSaleBanner.d.ts +21 -0
- package/dist/features/events/components/EventSaleBanner.js +18 -0
- package/dist/features/events/components/EventsIndexListing.js +3 -4
- package/dist/features/events/components/index.d.ts +6 -0
- package/dist/features/events/components/index.js +4 -0
- package/dist/features/events/repository/event-entry.repository.d.ts +5 -0
- package/dist/features/events/repository/event-entry.repository.js +7 -0
- package/dist/features/filters/AsyncFacetSection.d.ts +1 -1
- package/dist/features/homepage/components/AnnouncementBar.d.ts +4 -1
- package/dist/features/homepage/components/AnnouncementBar.js +51 -4
- package/dist/features/homepage/components/FAQSection.d.ts +0 -5
- package/dist/features/homepage/components/MarketplaceHomepageView.d.ts +3 -1
- package/dist/features/homepage/components/MarketplaceHomepageView.js +2 -2
- package/dist/features/homepage/components/index.d.ts +1 -1
- package/dist/features/homepage/components/index.js +1 -1
- package/dist/features/homepage/lib/live-stats.js +1 -1
- package/dist/features/homepage/lib/section-renderer.d.ts +2 -2
- package/dist/features/homepage/lib/section-renderer.js +2 -2
- package/dist/features/homepage/schemas/firestore.d.ts +0 -2
- package/dist/features/layout/index.d.ts +0 -2
- package/dist/features/layout/index.js +0 -1
- package/dist/features/orders/repository/orders.repository.d.ts +0 -1
- package/dist/features/orders/repository/orders.repository.js +0 -1
- package/dist/features/orders/server.d.ts +1 -1
- package/dist/features/orders/server.js +1 -1
- package/dist/features/pre-orders/server.d.ts +0 -1
- package/dist/features/pre-orders/server.js +0 -1
- package/dist/features/products/components/GroupSettingsPanel.js +65 -49
- package/dist/features/products/components/PrizeDrawItemsEditor.js +2 -2
- package/dist/features/products/components/PrizeDrawsSection.d.ts +1 -4
- package/dist/features/products/components/PrizeDrawsSection.js +17 -6
- package/dist/features/products/components/PrizeRevealModal.js +1 -1
- package/dist/features/products/components/ProductCardMetadataSection.d.ts +11 -0
- package/dist/features/products/components/ProductCardMetadataSection.js +25 -0
- package/dist/features/products/components/ProductDetailPageView.js +3 -1
- package/dist/features/products/components/ProductFeaturesSelector.js +1 -1
- package/dist/features/products/components/ProductGradingTab.d.ts +13 -0
- package/dist/features/products/components/ProductGradingTab.js +25 -0
- package/dist/features/products/components/ProductGrid.js +14 -2
- package/dist/features/products/components/ProductTabsShell.d.ts +5 -1
- package/dist/features/products/components/ProductTabsShell.js +6 -1
- package/dist/features/products/components/index.d.ts +4 -0
- package/dist/features/products/components/index.js +3 -0
- package/dist/features/products/constants/action-defs.d.ts +5 -0
- package/dist/features/products/constants/action-defs.js +52 -32
- package/dist/features/products/constants/sieve.d.ts +24 -4
- package/dist/features/products/constants/sieve.js +20 -11
- package/dist/features/products/repository/products.repository.d.ts +0 -2
- package/dist/features/products/repository/products.repository.js +0 -2
- package/dist/features/products/schemas/firestore.d.ts +17 -0
- package/dist/features/products/schemas/product-features.validators.d.ts +2 -2
- package/dist/features/products/schemas/product-templates.d.ts +2 -4
- package/dist/features/products/server.d.ts +1 -1
- package/dist/features/products/server.js +1 -1
- package/dist/features/products/types/index.d.ts +4 -0
- package/dist/features/promotions/components/CouponCard.js +5 -5
- package/dist/features/promotions/components/CouponsIndexListing.js +3 -2
- package/dist/features/promotions/server.d.ts +0 -1
- package/dist/features/promotions/server.js +0 -1
- package/dist/features/reviews/components/ReviewsIndexListing.js +3 -4
- package/dist/features/reviews/repository/reviews.repository.d.ts +0 -1
- package/dist/features/reviews/repository/reviews.repository.js +0 -1
- package/dist/features/reviews/server.d.ts +1 -1
- package/dist/features/reviews/server.js +1 -1
- package/dist/features/search/api/route.js +44 -1
- package/dist/features/search/components/Search.js +2 -0
- package/dist/features/search/hooks/useNavSuggestions.d.ts +5 -1
- package/dist/features/search/hooks/useNavSuggestions.js +31 -4
- package/dist/features/seller/components/BrandInlineSelect.js +2 -2
- package/dist/features/seller/components/CategoryInlineSelect.js +2 -2
- package/dist/features/seller/components/SellerAddressesView.js +10 -20
- package/dist/features/seller/components/SellerAuctionsView.d.ts +3 -3
- package/dist/features/seller/components/SellerAuctionsView.js +67 -106
- package/dist/features/seller/components/SellerBidsView.js +6 -6
- package/dist/features/seller/components/SellerBundlesView.js +72 -105
- package/dist/features/seller/components/SellerClassifiedView.js +74 -105
- package/dist/features/seller/components/SellerCouponEditorView.js +1 -1
- package/dist/features/seller/components/SellerCouponsView.d.ts +2 -2
- package/dist/features/seller/components/SellerCouponsView.js +51 -96
- package/dist/features/seller/components/SellerDigitalCodesView.js +70 -103
- package/dist/features/seller/components/SellerGroupedListingsView.js +34 -54
- package/dist/features/seller/components/SellerLiveView.js +70 -99
- package/dist/features/seller/components/SellerOffersPanel.js +1 -1
- package/dist/features/seller/components/SellerOffersView.d.ts +2 -2
- package/dist/features/seller/components/SellerOffersView.js +37 -70
- package/dist/features/seller/components/SellerOrdersView.d.ts +2 -2
- package/dist/features/seller/components/SellerOrdersView.js +10 -24
- package/dist/features/seller/components/SellerPayoutMethodsView.js +12 -24
- package/dist/features/seller/components/SellerPayoutsView.d.ts +2 -2
- package/dist/features/seller/components/SellerPayoutsView.js +34 -69
- package/dist/features/seller/components/SellerPreOrdersView.d.ts +2 -2
- package/dist/features/seller/components/SellerPreOrdersView.js +55 -97
- package/dist/features/seller/components/SellerPrizeDrawsView.d.ts +2 -2
- package/dist/features/seller/components/SellerPrizeDrawsView.js +55 -97
- package/dist/features/seller/components/SellerProductShell.d.ts +1 -1
- package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +1 -1
- package/dist/features/seller/components/SellerProductsFilterDrawer.js +3 -6
- package/dist/features/seller/components/SellerProductsView.d.ts +2 -2
- package/dist/features/seller/components/SellerProductsView.js +24 -32
- package/dist/features/seller/components/SellerShippingConfigsView.js +12 -24
- package/dist/features/seller/components/SellerSidebar.d.ts +0 -4
- package/dist/features/seller/components/SellerSidebar.js +0 -2
- package/dist/features/seller/components/SellerStoreCategoriesView.js +15 -34
- package/dist/features/seller/components/SellerTemplatesView.js +27 -43
- package/dist/features/seller/components/SellersListView.d.ts +1 -2
- package/dist/features/seller/components/analytics/SellerAnalyticsStats.d.ts +5 -0
- package/dist/features/seller/components/analytics/SellerAnalyticsStats.js +2 -8
- package/dist/features/seller/components/index.d.ts +0 -3
- package/dist/features/seller/components/index.js +0 -2
- package/dist/features/seller/server.d.ts +0 -1
- package/dist/features/seller/server.js +0 -1
- package/dist/features/shell/FormShell.d.ts +1 -1
- package/dist/features/shell/FormShell.js +4 -1
- package/dist/features/shell/field-groups/ImageFieldGroup.d.ts +18 -0
- package/dist/features/shell/field-groups/ImageFieldGroup.js +15 -0
- package/dist/features/shell/field-groups/SeoFieldGroup.d.ts +22 -0
- package/dist/features/shell/field-groups/SeoFieldGroup.js +16 -0
- package/dist/features/shell/field-groups/StatusFieldGroup.d.ts +35 -0
- package/dist/features/shell/field-groups/StatusFieldGroup.js +16 -0
- package/dist/features/shell/field-groups/TitleDescriptionGroup.d.ts +40 -0
- package/dist/features/shell/field-groups/TitleDescriptionGroup.js +16 -0
- package/dist/features/shell/field-groups/index.d.ts +13 -0
- package/dist/features/shell/field-groups/index.js +9 -0
- package/dist/features/shell/index.d.ts +2 -0
- package/dist/features/shell/index.js +1 -0
- package/dist/features/stores/components/StoreCapabilitiesGuideView.d.ts +1 -2
- package/dist/features/stores/components/StoreFinanceGuideView.d.ts +1 -2
- package/dist/features/stores/components/StoreHeader.js +2 -1
- package/dist/features/stores/components/StoreListingsGuideView.d.ts +1 -2
- package/dist/features/stores/components/StoreOrdersGuideView.d.ts +1 -2
- package/dist/features/stores/components/StoreReviewsListing.js +3 -4
- package/dist/features/stores/components/StoreScopedSearch.d.ts +16 -0
- package/dist/features/stores/components/StoreScopedSearch.js +27 -0
- package/dist/features/stores/components/StoreSettingsGuideView.d.ts +1 -2
- package/dist/features/stores/components/StoresIndexListing.js +3 -4
- package/dist/features/stores/server.d.ts +0 -1
- package/dist/features/stores/server.js +0 -1
- package/dist/features/support/schemas/firestore.d.ts +22 -1
- package/dist/features/support/schemas/firestore.js +10 -0
- package/dist/features/wishlist/server.d.ts +0 -1
- package/dist/features/wishlist/server.js +0 -1
- package/dist/index.d.ts +11 -33
- package/dist/index.js +17 -62
- package/dist/next/routing/route-map.d.ts +8 -0
- package/dist/next/routing/route-map.js +4 -0
- package/dist/react/contexts/SessionContext.d.ts +2 -0
- package/dist/react/contexts/SessionContext.js +2 -0
- package/dist/react/hooks/useEntityDelete.d.ts +15 -0
- package/dist/react/hooks/useEntityDelete.js +39 -0
- package/dist/react/hooks/useListingTypeFlags.d.ts +32 -0
- package/dist/react/hooks/useListingTypeFlags.js +19 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.js +2 -0
- package/dist/repositories/index.d.ts +3 -3
- package/dist/repositories/index.js +3 -3
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/pii-redact.d.ts +8 -0
- package/dist/security/pii-redact.js +10 -1
- package/dist/seed/grouped-listings-seed-data.d.ts +4 -0
- package/dist/seed/products-preorders-seed-data.d.ts +4 -0
- package/dist/seed/products-prize-draws-seed-data.js +3 -0
- package/dist/seed/site-settings-seed-data.js +5 -5
- package/dist/seed/sub-listings-seed-data.d.ts +4 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +4 -0
- package/dist/styles.css +54 -395
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/BaseListingCard.d.ts +10 -0
- package/dist/ui/components/BaseListingCard.js +17 -1
- package/dist/ui/components/DetailPageGallery.d.ts +32 -0
- package/dist/ui/components/DetailPageGallery.js +47 -0
- package/dist/ui/components/DetailPageHero.d.ts +30 -0
- package/dist/ui/components/DetailPageHero.js +22 -0
- package/dist/ui/components/DetailPageTabs.d.ts +34 -0
- package/dist/ui/components/DetailPageTabs.js +38 -0
- package/dist/ui/components/HorizontalScroller.style.css +15 -2
- package/dist/ui/components/ListingFilterDrawer.d.ts +10 -0
- package/dist/ui/components/ListingFilterDrawer.js +8 -0
- package/dist/ui/components/ListingLayout.d.ts +11 -2
- package/dist/ui/components/ListingLayout.js +12 -6
- package/dist/ui/components/PaginatedSelect.d.ts +66 -0
- package/dist/ui/components/PaginatedSelect.js +201 -0
- package/dist/ui/components/PaginatedSelect.style.css +254 -0
- package/dist/ui/components/Semantic.d.ts +0 -4
- package/dist/ui/components/Semantic.js +0 -2
- package/dist/ui/components/SettingsSection.d.ts +47 -0
- package/dist/ui/components/SettingsSection.js +38 -0
- package/dist/ui/components/index.style.css +1 -4
- package/dist/ui/index.d.ts +14 -14
- package/dist/ui/index.js +7 -7
- package/dist/utils/id-generators.d.ts +1 -18
- package/dist/utils/id-generators.js +51 -18
- package/dist/validation/schemas.d.ts +25 -0
- package/dist/validation/schemas.js +28 -0
- package/package.json +1 -1
|
@@ -4,17 +4,22 @@ import { useState } from "react";
|
|
|
4
4
|
const STATIC_TABS = [
|
|
5
5
|
{ id: "description", label: "Description" },
|
|
6
6
|
{ id: "specs", label: "Specifications" },
|
|
7
|
+
{ id: "grading", label: "Grading" },
|
|
7
8
|
{ id: "ingredients", label: "Ingredients" },
|
|
8
9
|
{ id: "howToUse", label: "How to Use" },
|
|
9
10
|
{ id: "reviews", label: "Reviews" },
|
|
11
|
+
// W1-34 — Q&A tab; consumers pass `qaContent` to surface it.
|
|
12
|
+
{ id: "qa", label: "Q&A" },
|
|
10
13
|
];
|
|
11
|
-
export function ProductTabsShell({ descriptionContent, specsContent, ingredientsContent, howToUseContent, reviewsContent, customTabs = [], className = "", }) {
|
|
14
|
+
export function ProductTabsShell({ descriptionContent, specsContent, gradingContent, ingredientsContent, howToUseContent, reviewsContent, qaContent, customTabs = [], className = "", }) {
|
|
12
15
|
const staticContentMap = {
|
|
13
16
|
description: descriptionContent,
|
|
14
17
|
specs: specsContent,
|
|
18
|
+
grading: gradingContent,
|
|
15
19
|
ingredients: ingredientsContent,
|
|
16
20
|
howToUse: howToUseContent,
|
|
17
21
|
reviews: reviewsContent,
|
|
22
|
+
qa: qaContent,
|
|
18
23
|
};
|
|
19
24
|
const visibleStatic = STATIC_TABS.filter((t) => staticContentMap[t.id] != null);
|
|
20
25
|
const visibleCustom = customTabs.filter((t) => t.content != null);
|
|
@@ -54,6 +54,10 @@ export { ProductGalleryClient } from "./ProductGalleryClient";
|
|
|
54
54
|
export type { ProductGalleryClientProps } from "./ProductGalleryClient";
|
|
55
55
|
export { ProductTabsShell } from "./ProductTabsShell";
|
|
56
56
|
export type { ProductTabsShellProps, CustomTabDef } from "./ProductTabsShell";
|
|
57
|
+
export { ProductGradingTab } from "./ProductGradingTab";
|
|
58
|
+
export type { ProductGradingTabProps } from "./ProductGradingTab";
|
|
59
|
+
export { ProductCardMetadataSection } from "./ProductCardMetadataSection";
|
|
60
|
+
export type { ProductCardMetadataSectionProps } from "./ProductCardMetadataSection";
|
|
57
61
|
export { CustomFieldsEditor } from "./CustomFieldsEditor";
|
|
58
62
|
export type { CustomFieldsEditorProps } from "./CustomFieldsEditor";
|
|
59
63
|
export { CustomSectionsEditor } from "./CustomSectionsEditor";
|
|
@@ -32,6 +32,9 @@ export { MakeOfferButton } from "./MakeOfferButton";
|
|
|
32
32
|
export { RelatedProducts } from "./RelatedProducts";
|
|
33
33
|
export { ProductGalleryClient } from "./ProductGalleryClient";
|
|
34
34
|
export { ProductTabsShell } from "./ProductTabsShell";
|
|
35
|
+
// W1-34: Product detail missing sections
|
|
36
|
+
export { ProductGradingTab } from "./ProductGradingTab";
|
|
37
|
+
export { ProductCardMetadataSection } from "./ProductCardMetadataSection";
|
|
35
38
|
export { CustomFieldsEditor } from "./CustomFieldsEditor";
|
|
36
39
|
export { CustomSectionsEditor } from "./CustomSectionsEditor";
|
|
37
40
|
export { CustomSectionTabContent } from "./CustomSectionTabContent";
|
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
* Client — useAuthGate() shows LoginRequiredModal for Tier 1 (public) actions
|
|
10
10
|
* Server — checkActionAllowed() enforces the same guards on every server action
|
|
11
11
|
* Admin — ActionPermissionsManager toggles defaultEnabled via siteSettings.actionConfig
|
|
12
|
+
*
|
|
13
|
+
* Label source of truth: `ACTIONS.{RESOURCE}["..."].label` in
|
|
14
|
+
* _internal/shared/actions/action-registry.ts. `ACTION_META` derives its labels
|
|
15
|
+
* via `regLabel()` where a registry counterpart exists; entries with no
|
|
16
|
+
* counterpart keep an inline literal until a registry leaf is added (W1-5).
|
|
12
17
|
*/
|
|
13
18
|
export type ActionVariant = "primary" | "secondary" | "outline" | "ghost" | "danger" | "warning";
|
|
14
19
|
export declare const ACTION_ID: {
|
|
@@ -9,7 +9,26 @@
|
|
|
9
9
|
* Client — useAuthGate() shows LoginRequiredModal for Tier 1 (public) actions
|
|
10
10
|
* Server — checkActionAllowed() enforces the same guards on every server action
|
|
11
11
|
* Admin — ActionPermissionsManager toggles defaultEnabled via siteSettings.actionConfig
|
|
12
|
+
*
|
|
13
|
+
* Label source of truth: `ACTIONS.{RESOURCE}["..."].label` in
|
|
14
|
+
* _internal/shared/actions/action-registry.ts. `ACTION_META` derives its labels
|
|
15
|
+
* via `regLabel()` where a registry counterpart exists; entries with no
|
|
16
|
+
* counterpart keep an inline literal until a registry leaf is added (W1-5).
|
|
17
|
+
*/
|
|
18
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
19
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
20
|
+
// Label-from-registry helper (W1-5)
|
|
21
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
22
|
+
/**
|
|
23
|
+
* Returns the label for `ACTIONS[resource][id]`. The `fallback` is used only
|
|
24
|
+
* when the registry has no leaf yet — orphan IDs should be added to ACTIONS
|
|
25
|
+
* over time. Adding the fallback parameter as required ensures every call
|
|
26
|
+
* site documents what the inline label was at migration time, simplifying
|
|
27
|
+
* the eventual cleanup.
|
|
12
28
|
*/
|
|
29
|
+
function regLabel(resource, id, fallback) {
|
|
30
|
+
return ACTIONS[resource]?.[id]?.label ?? fallback;
|
|
31
|
+
}
|
|
13
32
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
14
33
|
// § 1 Product / listing actions
|
|
15
34
|
// Used by: detail pages, BulkActionsBar, BuyBar
|
|
@@ -64,49 +83,50 @@ export const ACTION_ID = {
|
|
|
64
83
|
DELETE_ACCOUNT: "delete-account",
|
|
65
84
|
};
|
|
66
85
|
export const ACTION_META = {
|
|
67
|
-
[ACTION_ID.BUY_NOW]: { id: ACTION_ID.BUY_NOW, label: "Buy Now", variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to purchase items." },
|
|
68
|
-
[ACTION_ID.ADD_TO_CART]: { id: ACTION_ID.ADD_TO_CART, label: "Add to Cart", variant: "secondary", iconName: "ShoppingCart" },
|
|
69
|
-
[ACTION_ID.ADD_TO_WISHLIST]: { id: ACTION_ID.ADD_TO_WISHLIST, label: "Add to Wishlist", variant: "ghost", iconName: "Heart", requiresAuth: true, authMessage: "You need to be signed in to save items to your wishlist." },
|
|
70
|
-
[ACTION_ID.REMOVE_FROM_WISHLIST]: { id: ACTION_ID.REMOVE_FROM_WISHLIST, label: "Remove from Wishlist", variant: "ghost", iconName: "HeartOff", requiresAuth: true, authMessage: "You need to be signed in to manage your wishlist." },
|
|
71
|
-
[ACTION_ID.MAKE_OFFER]: { id: ACTION_ID.MAKE_OFFER, label: "Make an Offer", variant: "outline", iconName: "Tag", requiresAuth: true, authMessage: "You need to be signed in to make an offer." },
|
|
72
|
-
[ACTION_ID.SHARE]: { id: ACTION_ID.SHARE, label: "Share", variant: "ghost", iconName: "Share2" },
|
|
73
|
-
[ACTION_ID.COMPARE]: { id: ACTION_ID.COMPARE, label: "Compare", variant: "secondary", iconName: "Columns" },
|
|
74
|
-
[ACTION_ID.PLACE_BID]: { id: ACTION_ID.PLACE_BID, label: "Place Bid", variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to place a bid." },
|
|
75
|
-
[ACTION_ID.BUY_NOW_AUCTION]: { id: ACTION_ID.BUY_NOW_AUCTION, label: "Buy Now", variant: "secondary", requiresAuth: true, authMessage: "You need to be signed in to purchase items." },
|
|
76
|
-
[ACTION_ID.WATCH_AUCTION]: { id: ACTION_ID.WATCH_AUCTION, label: "Watch", variant: "ghost", iconName: "Eye", requiresAuth: true, authMessage: "You need to be signed in to watch auctions." },
|
|
77
|
-
[ACTION_ID.UNWATCH_AUCTION]: { id: ACTION_ID.UNWATCH_AUCTION, label: "Unwatch", variant: "ghost", iconName: "EyeOff", requiresAuth: true, authMessage: "You need to be signed in to manage your watchlist." },
|
|
78
|
-
[ACTION_ID.RESERVE_NOW]: { id: ACTION_ID.RESERVE_NOW, label: "Reserve Now", variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to reserve a pre-order." },
|
|
79
|
-
[ACTION_ID.CANCEL_RESERVATION]: { id: ACTION_ID.CANCEL_RESERVATION, label: "Cancel Reservation", variant: "danger", iconName: "X", requiresAuth: true, authMessage: "You need to be signed in to cancel a reservation." },
|
|
86
|
+
[ACTION_ID.BUY_NOW]: { id: ACTION_ID.BUY_NOW, label: regLabel("PRODUCT", "buy-now", "Buy Now"), variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to purchase items." },
|
|
87
|
+
[ACTION_ID.ADD_TO_CART]: { id: ACTION_ID.ADD_TO_CART, label: regLabel("PRODUCT", "add-to-cart", "Add to Cart"), variant: "secondary", iconName: "ShoppingCart" },
|
|
88
|
+
[ACTION_ID.ADD_TO_WISHLIST]: { id: ACTION_ID.ADD_TO_WISHLIST, label: regLabel("PRODUCT", "add-to-wishlist", "Add to Wishlist"), variant: "ghost", iconName: "Heart", requiresAuth: true, authMessage: "You need to be signed in to save items to your wishlist." },
|
|
89
|
+
[ACTION_ID.REMOVE_FROM_WISHLIST]: { id: ACTION_ID.REMOVE_FROM_WISHLIST, label: regLabel("PRODUCT", "remove-from-wishlist", "Remove from Wishlist"), variant: "ghost", iconName: "HeartOff", requiresAuth: true, authMessage: "You need to be signed in to manage your wishlist." },
|
|
90
|
+
[ACTION_ID.MAKE_OFFER]: { id: ACTION_ID.MAKE_OFFER, label: regLabel("PRODUCT", "make-offer", "Make an Offer"), variant: "outline", iconName: "Tag", requiresAuth: true, authMessage: "You need to be signed in to make an offer." },
|
|
91
|
+
[ACTION_ID.SHARE]: { id: ACTION_ID.SHARE, label: regLabel("PRODUCT", "share", "Share"), variant: "ghost", iconName: "Share2" },
|
|
92
|
+
[ACTION_ID.COMPARE]: { id: ACTION_ID.COMPARE, label: regLabel("PRODUCT", "compare", "Compare"), variant: "secondary", iconName: "Columns" },
|
|
93
|
+
[ACTION_ID.PLACE_BID]: { id: ACTION_ID.PLACE_BID, label: regLabel("AUCTION", "place-bid", "Place Bid"), variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to place a bid." },
|
|
94
|
+
[ACTION_ID.BUY_NOW_AUCTION]: { id: ACTION_ID.BUY_NOW_AUCTION, label: regLabel("AUCTION", "buy-it-now", "Buy Now"), variant: "secondary", requiresAuth: true, authMessage: "You need to be signed in to purchase items." },
|
|
95
|
+
[ACTION_ID.WATCH_AUCTION]: { id: ACTION_ID.WATCH_AUCTION, label: regLabel("AUCTION", "watch", "Watch"), variant: "ghost", iconName: "Eye", requiresAuth: true, authMessage: "You need to be signed in to watch auctions." },
|
|
96
|
+
[ACTION_ID.UNWATCH_AUCTION]: { id: ACTION_ID.UNWATCH_AUCTION, label: regLabel("AUCTION", "unwatch", "Unwatch"), variant: "ghost", iconName: "EyeOff", requiresAuth: true, authMessage: "You need to be signed in to manage your watchlist." },
|
|
97
|
+
[ACTION_ID.RESERVE_NOW]: { id: ACTION_ID.RESERVE_NOW, label: regLabel("PRE_ORDER", "reserve-now", "Reserve Now"), variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to reserve a pre-order." },
|
|
98
|
+
[ACTION_ID.CANCEL_RESERVATION]: { id: ACTION_ID.CANCEL_RESERVATION, label: regLabel("PRE_ORDER", "cancel-reservation", "Cancel Reservation"), variant: "danger", iconName: "X", requiresAuth: true, authMessage: "You need to be signed in to cancel a reservation." },
|
|
80
99
|
// ── Checkout / navigation CTAs ────────────────────────────────────────────
|
|
81
|
-
[ACTION_ID.CHECKOUT]: { id: ACTION_ID.CHECKOUT, label: "Checkout", variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to checkout." },
|
|
82
|
-
[ACTION_ID.CONTINUE_TO_VERIFY]: { id: ACTION_ID.CONTINUE_TO_VERIFY, label: "Continue", variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to checkout." },
|
|
83
|
-
[ACTION_ID.SEND_OTP]: { id: ACTION_ID.SEND_OTP, label: "Send Code", variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to checkout." },
|
|
84
|
-
[ACTION_ID.VERIFY_OTP]: { id: ACTION_ID.VERIFY_OTP, label: "Verify & Continue", variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to checkout." },
|
|
85
|
-
[ACTION_ID.PAY_ONLINE]: { id: ACTION_ID.PAY_ONLINE, label: "Pay Online", variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to checkout." },
|
|
86
|
-
[ACTION_ID.PAY_COD]: { id: ACTION_ID.PAY_COD, label: "Cash on Delivery", variant: "secondary", requiresAuth: true, authMessage: "You need to be signed in to checkout." },
|
|
87
|
-
[ACTION_ID.APPLY_COUPON]: { id: ACTION_ID.APPLY_COUPON, label: "Apply", variant: "secondary", requiresAuth: true, authMessage: "You need to be signed in to apply a coupon." },
|
|
88
|
-
[ACTION_ID.REMOVE_COUPON]: { id: ACTION_ID.REMOVE_COUPON, label: "Remove", variant: "ghost", requiresAuth: true, authMessage: "You need to be signed in to manage coupons." },
|
|
89
|
-
[ACTION_ID.ENTER_PRIZE_DRAW]: { id: ACTION_ID.ENTER_PRIZE_DRAW, label: "Enter Draw", variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to enter a prize draw." },
|
|
100
|
+
[ACTION_ID.CHECKOUT]: { id: ACTION_ID.CHECKOUT, label: regLabel("CART", "checkout", "Checkout"), variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to checkout." },
|
|
101
|
+
[ACTION_ID.CONTINUE_TO_VERIFY]: { id: ACTION_ID.CONTINUE_TO_VERIFY, label: regLabel("CHECKOUT", "continue-to-verification", "Continue"), variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to checkout." },
|
|
102
|
+
[ACTION_ID.SEND_OTP]: { id: ACTION_ID.SEND_OTP, label: regLabel("CHECKOUT", "send-otp", "Send Code"), variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to checkout." },
|
|
103
|
+
[ACTION_ID.VERIFY_OTP]: { id: ACTION_ID.VERIFY_OTP, label: regLabel("CHECKOUT", "verify-otp", "Verify & Continue"), variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to checkout." },
|
|
104
|
+
[ACTION_ID.PAY_ONLINE]: { id: ACTION_ID.PAY_ONLINE, label: regLabel("CHECKOUT", "pay-online", "Pay Online"), variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to checkout." },
|
|
105
|
+
[ACTION_ID.PAY_COD]: { id: ACTION_ID.PAY_COD, label: regLabel("CHECKOUT", "pay-cod", "Cash on Delivery"), variant: "secondary", requiresAuth: true, authMessage: "You need to be signed in to checkout." },
|
|
106
|
+
[ACTION_ID.APPLY_COUPON]: { id: ACTION_ID.APPLY_COUPON, label: regLabel("CHECKOUT", "apply-coupon", "Apply"), variant: "secondary", requiresAuth: true, authMessage: "You need to be signed in to apply a coupon." },
|
|
107
|
+
[ACTION_ID.REMOVE_COUPON]: { id: ACTION_ID.REMOVE_COUPON, label: regLabel("CHECKOUT", "remove-coupon", "Remove"), variant: "ghost", requiresAuth: true, authMessage: "You need to be signed in to manage coupons." },
|
|
108
|
+
[ACTION_ID.ENTER_PRIZE_DRAW]: { id: ACTION_ID.ENTER_PRIZE_DRAW, label: regLabel("PRIZE_DRAW", "enter-draw", "Enter Draw"), variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to enter a prize draw." },
|
|
109
|
+
// ── Inline literals: no registry counterpart yet (orphan IDs — add to ACTIONS in a follow-up sweep) ─
|
|
90
110
|
[ACTION_ID.ENTER_RAFFLE]: { id: ACTION_ID.ENTER_RAFFLE, label: "Enter Raffle", variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to enter a raffle." },
|
|
91
111
|
[ACTION_ID.REPORT_LISTING]: { id: ACTION_ID.REPORT_LISTING, label: "Report Listing", variant: "ghost", requiresAuth: true, authMessage: "You need to be signed in to report a listing." },
|
|
92
|
-
[ACTION_ID.FOLLOW_STORE]: { id: ACTION_ID.FOLLOW_STORE, label: "Follow Store", variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to follow a store." },
|
|
112
|
+
[ACTION_ID.FOLLOW_STORE]: { id: ACTION_ID.FOLLOW_STORE, label: regLabel("STORE", "follow", "Follow Store"), variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to follow a store." },
|
|
93
113
|
// ── Reviews & social ──────────────────────────────────────────────────────
|
|
94
|
-
[ACTION_ID.WRITE_REVIEW]: { id: ACTION_ID.WRITE_REVIEW, label: "Write a Review", variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to write a review." },
|
|
114
|
+
[ACTION_ID.WRITE_REVIEW]: { id: ACTION_ID.WRITE_REVIEW, label: regLabel("USER", "write-review", "Write a Review"), variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to write a review." },
|
|
95
115
|
[ACTION_ID.MESSAGE_SELLER]: { id: ACTION_ID.MESSAGE_SELLER, label: "Message Seller", variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to message a seller." },
|
|
96
116
|
// ── Seller CTAs ───────────────────────────────────────────────────────────
|
|
97
117
|
[ACTION_ID.BECOME_SELLER]: { id: ACTION_ID.BECOME_SELLER, label: "Apply as Seller", variant: "primary", requiresAuth: true, authMessage: "You need to be signed in to apply as a seller." },
|
|
98
|
-
[ACTION_ID.REQUEST_PAYOUT]: { id: ACTION_ID.REQUEST_PAYOUT, label: "Request Payout", variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to request a payout.", requiredPermission: "seller.payouts.request" },
|
|
99
|
-
[ACTION_ID.RESPOND_TO_REVIEW]: { id: ACTION_ID.RESPOND_TO_REVIEW, label: "Respond to Review", variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to respond to a review.", requiredPermission: "seller.reviews.respond" },
|
|
118
|
+
[ACTION_ID.REQUEST_PAYOUT]: { id: ACTION_ID.REQUEST_PAYOUT, label: regLabel("STORE", "request-payout", "Request Payout"), variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to request a payout.", requiredPermission: "seller.payouts.request" },
|
|
119
|
+
[ACTION_ID.RESPOND_TO_REVIEW]: { id: ACTION_ID.RESPOND_TO_REVIEW, label: regLabel("STORE", "reply-review", "Respond to Review"), variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to respond to a review.", requiredPermission: "seller.reviews.respond" },
|
|
100
120
|
// ── User account actions ──────────────────────────────────────────────────
|
|
101
|
-
[ACTION_ID.CANCEL_ORDER]: { id: ACTION_ID.CANCEL_ORDER, label: "Cancel Order", variant: "danger", requiresAuth: true, authMessage: "You need to be signed in to cancel an order." },
|
|
102
|
-
[ACTION_ID.REQUEST_RETURN]: { id: ACTION_ID.REQUEST_RETURN, label: "Request Return", variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to request a return." },
|
|
103
|
-
[ACTION_ID.REORDER]: { id: ACTION_ID.REORDER, label: "Reorder", variant: "secondary", requiresAuth: true, authMessage: "You need to be signed in to reorder." },
|
|
104
|
-
[ACTION_ID.TRACK_ORDER]: { id: ACTION_ID.TRACK_ORDER, label: "Track Order", variant: "ghost", requiresAuth: true, authMessage: "You need to be signed in to track your order." },
|
|
121
|
+
[ACTION_ID.CANCEL_ORDER]: { id: ACTION_ID.CANCEL_ORDER, label: regLabel("USER", "cancel-order", "Cancel Order"), variant: "danger", requiresAuth: true, authMessage: "You need to be signed in to cancel an order." },
|
|
122
|
+
[ACTION_ID.REQUEST_RETURN]: { id: ACTION_ID.REQUEST_RETURN, label: regLabel("USER", "request-return", "Request Return"), variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to request a return." },
|
|
123
|
+
[ACTION_ID.REORDER]: { id: ACTION_ID.REORDER, label: regLabel("USER", "reorder", "Reorder"), variant: "secondary", requiresAuth: true, authMessage: "You need to be signed in to reorder." },
|
|
124
|
+
[ACTION_ID.TRACK_ORDER]: { id: ACTION_ID.TRACK_ORDER, label: regLabel("USER", "track-order", "Track Order"), variant: "ghost", requiresAuth: true, authMessage: "You need to be signed in to track your order." },
|
|
105
125
|
[ACTION_ID.EDIT_PROFILE]: { id: ACTION_ID.EDIT_PROFILE, label: "Edit Profile", variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to edit your profile." },
|
|
106
126
|
[ACTION_ID.ADD_ADDRESS]: { id: ACTION_ID.ADD_ADDRESS, label: "Add Address", variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to add an address." },
|
|
107
127
|
[ACTION_ID.EDIT_ADDRESS]: { id: ACTION_ID.EDIT_ADDRESS, label: "Edit Address", variant: "ghost", requiresAuth: true, authMessage: "You need to be signed in to edit an address." },
|
|
108
|
-
[ACTION_ID.DELETE_ADDRESS]: { id: ACTION_ID.DELETE_ADDRESS, label: "Delete Address", variant: "danger", requiresAuth: true, authMessage: "You need to be signed in to delete an address." },
|
|
109
|
-
[ACTION_ID.CHANGE_PASSWORD]: { id: ACTION_ID.CHANGE_PASSWORD, label: "Change Password", variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to change your password." },
|
|
128
|
+
[ACTION_ID.DELETE_ADDRESS]: { id: ACTION_ID.DELETE_ADDRESS, label: regLabel("USER", "delete-address", "Delete Address"), variant: "danger", requiresAuth: true, authMessage: "You need to be signed in to delete an address." },
|
|
129
|
+
[ACTION_ID.CHANGE_PASSWORD]: { id: ACTION_ID.CHANGE_PASSWORD, label: regLabel("USER", "update-password", "Change Password"), variant: "outline", requiresAuth: true, authMessage: "You need to be signed in to change your password." },
|
|
110
130
|
[ACTION_ID.DELETE_ACCOUNT]: { id: ACTION_ID.DELETE_ACCOUNT, label: "Delete Account", variant: "danger", requiresAuth: true, authMessage: "You need to be signed in to delete your account.", requiredPermission: "user.account.delete" },
|
|
111
131
|
};
|
|
112
132
|
// Detail page action groups — ordered top-to-bottom in the right-hand panel
|
|
@@ -2,6 +2,20 @@ export type SortOption = {
|
|
|
2
2
|
readonly value: string;
|
|
3
3
|
readonly label: string;
|
|
4
4
|
};
|
|
5
|
+
/** Time + price sorts, the common subset across most listing-type pickers. */
|
|
6
|
+
export declare const BASE_SORT_OPTIONS: readonly [{
|
|
7
|
+
readonly value: string;
|
|
8
|
+
readonly label: "Newest First";
|
|
9
|
+
}, {
|
|
10
|
+
readonly value: string;
|
|
11
|
+
readonly label: "Oldest First";
|
|
12
|
+
}, {
|
|
13
|
+
readonly value: string;
|
|
14
|
+
readonly label: "Price: Low to High";
|
|
15
|
+
}, {
|
|
16
|
+
readonly value: string;
|
|
17
|
+
readonly label: "Price: High to Low";
|
|
18
|
+
}];
|
|
5
19
|
export declare const STANDARD_SORT_OPTIONS: readonly [{
|
|
6
20
|
readonly value: string;
|
|
7
21
|
readonly label: "Newest First";
|
|
@@ -108,10 +122,13 @@ export declare const PREORDER_SORT_OPTIONS: readonly [{
|
|
|
108
122
|
}, {
|
|
109
123
|
readonly value: string;
|
|
110
124
|
readonly label: "Latest Delivery";
|
|
111
|
-
}, {
|
|
125
|
+
}, ...({
|
|
112
126
|
readonly value: string;
|
|
113
127
|
readonly label: "Newest First";
|
|
114
|
-
}
|
|
128
|
+
} | {
|
|
129
|
+
readonly value: string;
|
|
130
|
+
readonly label: "Oldest First";
|
|
131
|
+
})[], {
|
|
115
132
|
readonly value: string;
|
|
116
133
|
readonly label: "Price: Low to High";
|
|
117
134
|
}, {
|
|
@@ -124,10 +141,13 @@ export declare const PREORDER_SORT_OPTIONS: readonly [{
|
|
|
124
141
|
readonly value: string;
|
|
125
142
|
readonly label: "Lowest Deposit First";
|
|
126
143
|
}];
|
|
127
|
-
export declare const BUNDLE_SORT_OPTIONS: readonly [{
|
|
144
|
+
export declare const BUNDLE_SORT_OPTIONS: readonly [...({
|
|
128
145
|
readonly value: string;
|
|
129
146
|
readonly label: "Newest First";
|
|
130
|
-
}
|
|
147
|
+
} | {
|
|
148
|
+
readonly value: string;
|
|
149
|
+
readonly label: "Oldest First";
|
|
150
|
+
})[], {
|
|
131
151
|
readonly value: string;
|
|
132
152
|
readonly label: "Price: Low to High";
|
|
133
153
|
}, {
|
|
@@ -5,13 +5,25 @@ const LABEL_PRICE_LOW = "Price: Low to High";
|
|
|
5
5
|
const LABEL_NEWEST = "Newest First";
|
|
6
6
|
const LABEL_OLDEST = "Oldest First";
|
|
7
7
|
// ---------------------------------------------------------------------------
|
|
8
|
-
//
|
|
8
|
+
// W2-6 — Base sort options shared by standard / pre-order / bundle / prize-draw.
|
|
9
|
+
// Auctions get their own base (auctionEndDate primary) because the "Ending Soon"
|
|
10
|
+
// dimension dominates browse intent.
|
|
9
11
|
// ---------------------------------------------------------------------------
|
|
10
|
-
|
|
12
|
+
const BASE_TIME_SORTS = [
|
|
11
13
|
{ value: sortBy(PRODUCT_FIELDS.CREATED_AT), label: LABEL_NEWEST },
|
|
12
14
|
{ value: sortBy(PRODUCT_FIELDS.CREATED_AT, "ASC"), label: LABEL_OLDEST },
|
|
15
|
+
];
|
|
16
|
+
const BASE_PRICE_SORTS = [
|
|
13
17
|
{ value: sortBy(PRODUCT_FIELDS.PRICE, "ASC"), label: LABEL_PRICE_LOW },
|
|
14
18
|
{ value: sortBy(PRODUCT_FIELDS.PRICE), label: LABEL_PRICE_HIGH },
|
|
19
|
+
];
|
|
20
|
+
/** Time + price sorts, the common subset across most listing-type pickers. */
|
|
21
|
+
export const BASE_SORT_OPTIONS = [...BASE_TIME_SORTS, ...BASE_PRICE_SORTS];
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Standard Products
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
export const STANDARD_SORT_OPTIONS = [
|
|
26
|
+
...BASE_SORT_OPTIONS,
|
|
15
27
|
{ value: sortBy(PRODUCT_FIELDS.TITLE, "ASC"), label: "Name: A–Z" },
|
|
16
28
|
{ value: sortBy(PRODUCT_FIELDS.TITLE), label: "Name: Z–A" },
|
|
17
29
|
{ value: sortBy(PRODUCT_FIELDS.FEATURED), label: "Featured First" },
|
|
@@ -29,7 +41,7 @@ export const STANDARD_PUBLIC_SORT_OPTIONS = [
|
|
|
29
41
|
STANDARD_SORT_OPTIONS[9],
|
|
30
42
|
];
|
|
31
43
|
// ---------------------------------------------------------------------------
|
|
32
|
-
// Auctions
|
|
44
|
+
// Auctions — auction-specific base puts auctionEndDate primary
|
|
33
45
|
// ---------------------------------------------------------------------------
|
|
34
46
|
export const AUCTION_SORT_OPTIONS = [
|
|
35
47
|
{ value: sortBy(PRODUCT_FIELDS.AUCTION_END_DATE, "ASC"), label: "Ending Soon" },
|
|
@@ -56,9 +68,8 @@ export const AUCTION_PUBLIC_SORT_OPTIONS = [
|
|
|
56
68
|
export const PREORDER_SORT_OPTIONS = [
|
|
57
69
|
{ value: sortBy(PRODUCT_FIELDS.PRE_ORDER_DELIVERY_DATE, "ASC"), label: "Earliest Delivery" },
|
|
58
70
|
{ value: sortBy(PRODUCT_FIELDS.PRE_ORDER_DELIVERY_DATE), label: "Latest Delivery" },
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
{ value: sortBy(PRODUCT_FIELDS.PRICE), label: LABEL_PRICE_HIGH },
|
|
71
|
+
...BASE_TIME_SORTS.slice(0, 1), // Newest First
|
|
72
|
+
...BASE_PRICE_SORTS,
|
|
62
73
|
{ value: sortBy(PRODUCT_FIELDS.PRE_ORDER_CURRENT_COUNT), label: "Fewest Slots Left" },
|
|
63
74
|
{ value: sortBy(PRODUCT_FIELDS.PRE_ORDER_DEPOSIT_AMOUNT, "ASC"), label: "Lowest Deposit First" },
|
|
64
75
|
];
|
|
@@ -66,9 +77,8 @@ export const PREORDER_SORT_OPTIONS = [
|
|
|
66
77
|
// Bundles
|
|
67
78
|
// ---------------------------------------------------------------------------
|
|
68
79
|
export const BUNDLE_SORT_OPTIONS = [
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
{ value: sortBy(PRODUCT_FIELDS.PRICE), label: LABEL_PRICE_HIGH },
|
|
80
|
+
...BASE_TIME_SORTS.slice(0, 1), // Newest First
|
|
81
|
+
...BASE_PRICE_SORTS,
|
|
72
82
|
{ value: "-savingsAmount", label: "Most Savings" },
|
|
73
83
|
{ value: "-bundleItemCount", label: "Most Items" },
|
|
74
84
|
];
|
|
@@ -76,8 +86,7 @@ export const BUNDLE_SORT_OPTIONS = [
|
|
|
76
86
|
// Prize Draws
|
|
77
87
|
// ---------------------------------------------------------------------------
|
|
78
88
|
export const PRIZE_DRAW_SORT_OPTIONS = [
|
|
79
|
-
|
|
80
|
-
{ value: sortBy(PRODUCT_FIELDS.CREATED_AT, "ASC"), label: LABEL_OLDEST },
|
|
89
|
+
...BASE_TIME_SORTS,
|
|
81
90
|
{ value: sortBy(PRODUCT_FIELDS.PRIZE_REVEAL_WINDOW_START, "ASC"), label: "Reveal: Soonest" },
|
|
82
91
|
{ value: sortBy(PRODUCT_FIELDS.PRIZE_REVEAL_WINDOW_START), label: "Reveal: Furthest" },
|
|
83
92
|
{ value: sortBy(PRODUCT_FIELDS.PRICE, "ASC"), label: "Entry: Low to High" },
|
|
@@ -256,6 +256,4 @@ export declare class ProductRepository extends BaseRepository<ProductDocument> {
|
|
|
256
256
|
/** Cloud Functions: returns refs for draft products older than `cutoff` (for 30-day prune). */
|
|
257
257
|
getStaleDraftRefs(cutoff: Date): Promise<DocumentReference[]>;
|
|
258
258
|
}
|
|
259
|
-
export declare class ProductsRepository extends ProductRepository {
|
|
260
|
-
}
|
|
261
259
|
export declare const productRepository: ProductRepository;
|
|
@@ -132,6 +132,10 @@ export interface ProductDocument {
|
|
|
132
132
|
status: ProductStatus;
|
|
133
133
|
storeId: string;
|
|
134
134
|
storeName?: string;
|
|
135
|
+
/** W1-34 — denormalized seller rating (0–5) shown on product detail store card. */
|
|
136
|
+
storeRating?: number;
|
|
137
|
+
/** W1-34 — denormalized seller total review count shown alongside the rating. */
|
|
138
|
+
storeReviewCount?: number;
|
|
135
139
|
featured: boolean;
|
|
136
140
|
tags: string[];
|
|
137
141
|
specifications?: ProductSpecification[];
|
|
@@ -194,6 +198,19 @@ export interface ProductDocument {
|
|
|
194
198
|
groupParentSlug?: string;
|
|
195
199
|
groupChildSlugs?: string[];
|
|
196
200
|
groupTitle?: string;
|
|
201
|
+
/**
|
|
202
|
+
* W1-45 — optional icon shown as an overlay badge on every card whose
|
|
203
|
+
* product belongs to this group. Set once on the group parent; cards
|
|
204
|
+
* inherit it via the snapshot pipeline. Either an emoji or a media slug
|
|
205
|
+
* (rendered via `/media/<slug>`).
|
|
206
|
+
*/
|
|
207
|
+
groupIcon?: string;
|
|
208
|
+
/**
|
|
209
|
+
* W1-45 — denormalized icon from the sublisting category (`display.icon`).
|
|
210
|
+
* Mirrored onto the product snapshot at create/update time so cards can
|
|
211
|
+
* render it without an extra category lookup per row.
|
|
212
|
+
*/
|
|
213
|
+
sublistingIcon?: string;
|
|
197
214
|
/**
|
|
198
215
|
* Required since Phase 4 dropped the legacy `isAuction` / `isPreOrder`
|
|
199
216
|
* booleans. Every product document carries this; queries route through
|
|
@@ -89,8 +89,8 @@ export declare const productFeatureUpdateSchema: z.ZodObject<{
|
|
|
89
89
|
label?: string | undefined;
|
|
90
90
|
icon?: string | undefined;
|
|
91
91
|
isActive?: boolean | undefined;
|
|
92
|
-
iconColor?: string | undefined;
|
|
93
92
|
displayOrder?: number | undefined;
|
|
93
|
+
iconColor?: string | undefined;
|
|
94
94
|
productTypes?: ("auction" | "prize-draw" | "classified" | "digital-code" | "live" | "all" | "product" | "preorder")[] | undefined;
|
|
95
95
|
}, {
|
|
96
96
|
category?: "seller" | "custom" | "auction" | "condition" | "shipping" | "preorder" | "platform" | undefined;
|
|
@@ -98,8 +98,8 @@ export declare const productFeatureUpdateSchema: z.ZodObject<{
|
|
|
98
98
|
label?: string | undefined;
|
|
99
99
|
icon?: string | undefined;
|
|
100
100
|
isActive?: boolean | undefined;
|
|
101
|
-
iconColor?: string | undefined;
|
|
102
101
|
displayOrder?: number | undefined;
|
|
102
|
+
iconColor?: string | undefined;
|
|
103
103
|
productTypes?: ("auction" | "prize-draw" | "classified" | "digital-code" | "live" | "all" | "product" | "preorder")[] | undefined;
|
|
104
104
|
}>;
|
|
105
105
|
export type ProductFeatureAdminCreatePayload = z.infer<typeof productFeatureAdminCreateSchema>;
|
|
@@ -22,7 +22,5 @@ export interface ProductTemplateDocument {
|
|
|
22
22
|
createdAt: Date | string;
|
|
23
23
|
updatedAt: Date | string;
|
|
24
24
|
}
|
|
25
|
-
export
|
|
26
|
-
|
|
27
|
-
export interface ProductTemplateUpdateInput extends Partial<Omit<ProductTemplateDocument, "id" | "storeId" | "createdAt">> {
|
|
28
|
-
}
|
|
25
|
+
export type ProductTemplateCreateInput = Omit<ProductTemplateDocument, "id" | "createdAt" | "updatedAt">;
|
|
26
|
+
export type ProductTemplateUpdateInput = Partial<Omit<ProductTemplateDocument, "id" | "storeId" | "createdAt">>;
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* Server-only entry point — repositories and API route handlers.
|
|
5
5
|
*/
|
|
6
6
|
export * from "./actions";
|
|
7
|
-
export { ProductRepository,
|
|
7
|
+
export { ProductRepository, productRepository, } from "./repository/products.repository";
|
|
8
8
|
export { GET, POST } from "./api/route";
|
|
9
9
|
export { GET as productItemGET, PATCH as productItemPATCH, DELETE as productItemDELETE, } from "./api/[id]/route";
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* Server-only entry point — repositories and API route handlers.
|
|
5
5
|
*/
|
|
6
6
|
export * from "./actions";
|
|
7
|
-
export { ProductRepository,
|
|
7
|
+
export { ProductRepository, productRepository, } from "./repository/products.repository";
|
|
8
8
|
export { GET, POST } from "./api/route";
|
|
9
9
|
export { GET as productItemGET, PATCH as productItemPATCH, DELETE as productItemDELETE, } from "./api/[id]/route";
|
|
@@ -65,6 +65,10 @@ export interface ProductItem {
|
|
|
65
65
|
groupParentSlug?: string;
|
|
66
66
|
groupChildSlugs?: string[];
|
|
67
67
|
groupTitle?: string;
|
|
68
|
+
/** W1-45 — icon shown as a card overlay; emoji or `/media/<slug>`. */
|
|
69
|
+
groupIcon?: string;
|
|
70
|
+
/** W1-45 — denormalized icon from the sublisting category. */
|
|
71
|
+
sublistingIcon?: string;
|
|
68
72
|
isOnSale?: boolean;
|
|
69
73
|
isSold?: boolean;
|
|
70
74
|
inStock?: boolean;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { Pencil, Trash2, ToggleLeft, ToggleRight } from "lucide-react";
|
|
5
|
-
import { BaseListingCard, Div, Row, Span, Text } from "../../../ui";
|
|
5
|
+
import { BaseListingCard, ConfirmDeleteModal, Div, Row, Span, Text } from "../../../ui";
|
|
6
6
|
import { useLongPress } from "../../../react/hooks/useLongPress";
|
|
7
7
|
const TYPE_COLORS = {
|
|
8
8
|
percentage: { card: "bg-purple-50 border-purple-200 dark:bg-purple-950/30 dark:border-purple-800", code: "bg-purple-100 dark:bg-purple-900/40 text-purple-800 dark:text-purple-200 border-purple-300 dark:border-purple-700" },
|
|
@@ -91,6 +91,7 @@ export function CouponCard({ coupon, labels: labelsProp, onCopy, className = "",
|
|
|
91
91
|
const [copied, setCopied] = useState(false);
|
|
92
92
|
const [claiming, setClaiming] = useState(false);
|
|
93
93
|
const [busy, setBusy] = useState(null);
|
|
94
|
+
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
|
|
94
95
|
const longPress = useLongPress(() => onSelect?.(n.id, !isSelected));
|
|
95
96
|
const expiry = formatDateSafe(n.expiresAt);
|
|
96
97
|
const discountLabel = formatDiscount(n, labels);
|
|
@@ -144,11 +145,10 @@ export function CouponCard({ coupon, labels: labelsProp, onCopy, className = "",
|
|
|
144
145
|
setBusy(null);
|
|
145
146
|
}
|
|
146
147
|
};
|
|
147
|
-
const
|
|
148
|
+
const handleDeleteConfirmed = async () => {
|
|
148
149
|
if (!onDelete)
|
|
149
150
|
return;
|
|
150
|
-
|
|
151
|
-
return;
|
|
151
|
+
setDeleteConfirmOpen(false);
|
|
152
152
|
setBusy("delete");
|
|
153
153
|
try {
|
|
154
154
|
await onDelete(n.id);
|
|
@@ -161,5 +161,5 @@ export function CouponCard({ coupon, labels: labelsProp, onCopy, className = "",
|
|
|
161
161
|
? "bg-success-surface text-success"
|
|
162
162
|
: "bg-zinc-200 text-zinc-600 dark:bg-zinc-700 dark:text-zinc-300"}`, children: n.isActive ? labels.active : labels.inactive }), n.scope && (_jsx(Span, { className: "inline-flex items-center rounded-full bg-zinc-200/70 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-zinc-700 dark:bg-zinc-700/60 dark:text-zinc-200", children: n.scope }))] })), _jsxs(Div, { className: "mb-3", children: [_jsx(Text, { className: "text-2xl font-extrabold tracking-tight leading-none", children: discountLabel }), n.name && (_jsx(Text, { className: "text-sm mt-0.5 font-medium opacity-80", children: n.name }))] }), n.description && (_jsx(Text, { className: "text-xs opacity-60 mb-3", children: n.description })), _jsxs("div", { className: `flex items-center gap-2 rounded-lg border border-dashed px-3 py-2 ${colors.code}`, children: [_jsx("span", { className: "flex-1 font-mono text-sm font-bold tracking-widest uppercase select-all", children: n.code || "—" }), n.code && (_jsx("button", { type: "button", onClick: handleCopy, className: "shrink-0 rounded-md px-2.5 py-1 text-xs font-semibold transition-all hover:opacity-80 active:scale-95 bg-white/60 dark:bg-black/20 border border-current/20", "aria-label": "Copy coupon code", children: copied ? labels.copied : labels.copy }))] }), showClaim && n.code && n.isActive && (_jsx("div", { className: "mt-2", children: _jsx("button", { type: "button", onClick: handleClaim, disabled: claiming, className: "w-full rounded-md px-3 py-1.5 text-xs font-semibold transition-all active:scale-95 bg-[var(--appkit-color-primary-700)] text-[var(--appkit-color-text-on-primary,#fff)] hover:bg-[var(--appkit-color-primary-800)] disabled:opacity-50", "aria-label": `Claim coupon ${n.code} and apply at checkout`, children: claiming ? labels.claiming : labels.claim }) })), _jsxs(Row, { wrap: true, gap: "sm", className: "text-xs opacity-60 mt-2", children: [n.minOrderAmount ? (_jsxs(Span, { children: [labels.minOrder, ": \u20B9", (n.minOrderAmount / 100).toFixed(0)] })) : null, expiry && (_jsxs(Span, { children: [labels.expires, ": ", expiry] })), n.usageLimit ? (_jsxs(Span, { children: [n.usageCount, "/", n.usageLimit, " ", labels.used] })) : n.usageCount > 0 ? (_jsxs(Span, { children: [n.usageCount, " ", labels.used] })) : null] }), hasAdminActions && (_jsxs(Row, { gap: "xs", justify: "end", className: "mt-auto pt-3", children: [onEdit && (_jsx("button", { type: "button", onClick: () => onEdit(n.id), title: labels.edit, "aria-label": labels.edit, className: "rounded-lg p-1.5 text-zinc-500 dark:text-zinc-400 hover:bg-white/60 dark:hover:bg-black/30 hover:text-zinc-800 dark:hover:text-zinc-200 transition-colors", children: _jsx(Pencil, { className: "h-4 w-4" }) })), onToggleActive && (_jsx("button", { type: "button", onClick: handleToggle, disabled: busy === "toggle", title: n.isActive ? labels.deactivate : labels.activate, "aria-label": n.isActive ? labels.deactivate : labels.activate, className: "rounded-lg p-1.5 text-zinc-500 dark:text-zinc-400 hover:bg-white/60 dark:hover:bg-black/30 transition-colors disabled:opacity-50", children: n.isActive
|
|
163
163
|
? _jsx(ToggleRight, { className: "h-4 w-4 text-emerald-600 dark:text-emerald-400" })
|
|
164
|
-
: _jsx(ToggleLeft, { className: "h-4 w-4" }) })), onDelete && (_jsx("button", { type: "button", onClick:
|
|
164
|
+
: _jsx(ToggleLeft, { className: "h-4 w-4" }) })), onDelete && (_jsx("button", { type: "button", onClick: () => setDeleteConfirmOpen(true), disabled: busy === "delete", title: labels.delete, "aria-label": labels.delete, className: "rounded-lg p-1.5 text-zinc-500 dark:text-zinc-400 hover:bg-red-50 dark:hover:bg-red-950/40 hover:text-red-600 dark:hover:text-red-400 transition-colors disabled:opacity-50", children: _jsx(Trash2, { className: "h-4 w-4" }) }))] })), deleteConfirmOpen && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Coupon", message: labels.deleteConfirm, onConfirm: handleDeleteConfirmed, onClose: () => setDeleteConfirmOpen(false), isDeleting: busy === "delete" }))] }));
|
|
165
165
|
}
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useState, useCallback, useMemo } from "react";
|
|
4
4
|
import { Search, SlidersHorizontal, X } from "lucide-react";
|
|
5
5
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
|
-
import { Pagination, SortDropdown, Div, Text, Heading } from "../../../ui";
|
|
6
|
+
import { ListingFilterDrawer, Pagination, SortDropdown, Div, Text, Heading } from "../../../ui";
|
|
7
7
|
import { usePromotions } from "../hooks/usePromotions";
|
|
8
8
|
import { CouponCard } from "./CouponCard";
|
|
9
9
|
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
@@ -34,6 +34,7 @@ export function CouponsIndexListing({ initialCoupons, storeSlug, storeId, }) {
|
|
|
34
34
|
get: (key) => pendingFilters[key] ?? "",
|
|
35
35
|
set: (key, value) => setPendingFilters((p) => ({ ...p, [key]: value })),
|
|
36
36
|
}), [pendingFilters]);
|
|
37
|
+
const activeFilterCount = FILTER_KEYS.filter((k) => !!table.get(k)).length;
|
|
37
38
|
const openFilters = useCallback(() => {
|
|
38
39
|
setPendingFilters(Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
|
|
39
40
|
setFilterOpen(true);
|
|
@@ -97,5 +98,5 @@ export function CouponsIndexListing({ initialCoupons, storeSlug, storeId, }) {
|
|
|
97
98
|
minOrder: "Min. order",
|
|
98
99
|
off: "OFF",
|
|
99
100
|
freeShipping: "Free Shipping",
|
|
100
|
-
} }, coupon.id))) })), totalPages > 1 && (_jsx("div", { className: "mt-8 flex justify-center", children: _jsx(Pagination, { currentPage: table.getNumber("page", 1), totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), !isLoading && total > 0 && (_jsx(Div, { className: "mt-4 text-center", children: _jsxs(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400", children: [total, " coupon", total !== 1 ? "s" : "", " available"] }) }))] }),
|
|
101
|
+
} }, coupon.id))) })), totalPages > 1 && (_jsx("div", { className: "mt-8 flex justify-center", children: _jsx(Pagination, { currentPage: table.getNumber("page", 1), totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), !isLoading && total > 0 && (_jsx(Div, { className: "mt-4 text-center", children: _jsxs(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400", children: [total, " coupon", total !== 1 ? "s" : "", " available"] }) }))] }), _jsxs(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearPending, activeCount: activeFilterCount, children: [_jsxs(_Fragment, { children: [_jsx(Heading, { level: 6, className: "text-xs font-semibold uppercase tracking-wider text-zinc-500 dark:text-zinc-400 mb-3", children: "Discount Type" }), _jsxs("div", { className: "space-y-2", children: [COUPON_TYPES.map((t) => (_jsxs("label", { className: "flex items-center gap-2 cursor-pointer text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx("input", { type: "radio", name: "coupon-type", value: t.value, checked: pendingTable.get(TABLE_KEYS.TYPE) === t.value, onChange: () => { pendingTable.set(TABLE_KEYS.TYPE, t.value); }, className: "accent-primary" }), t.label] }, t.value))), pendingTable.get(TABLE_KEYS.TYPE) && (_jsx("button", { type: "button", onClick: () => { pendingTable.set(TABLE_KEYS.TYPE, ""); }, className: "text-xs text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300 underline", children: "Clear type" }))] })] }), _jsxs(_Fragment, { children: [_jsx(Heading, { level: 6, className: "text-xs font-semibold uppercase tracking-wider text-zinc-500 dark:text-zinc-400 mb-3", children: "Valid Date Range" }), _jsxs("div", { className: "space-y-3", children: [_jsxs(_Fragment, { children: [_jsx("label", { className: "block text-xs text-zinc-500 dark:text-zinc-400 mb-1", children: "From date" }), _jsx("input", { type: "date", value: pendingTable.get(TABLE_KEYS.DATE_FROM) || "", onChange: (e) => { pendingTable.set(TABLE_KEYS.DATE_FROM, e.target.value); }, className: "w-full rounded-lg border border-zinc-300 dark:border-slate-600 bg-white dark:bg-slate-800 px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 outline-none focus:ring-2 focus:ring-primary" })] }), _jsxs(_Fragment, { children: [_jsx("label", { className: "block text-xs text-zinc-500 dark:text-zinc-400 mb-1", children: "To date" }), _jsx("input", { type: "date", value: pendingTable.get(TABLE_KEYS.DATE_TO) || "", onChange: (e) => { pendingTable.set(TABLE_KEYS.DATE_TO, e.target.value); }, className: "w-full rounded-lg border border-zinc-300 dark:border-slate-600 bg-white dark:bg-slate-800 px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 outline-none focus:ring-2 focus:ring-primary" })] })] })] })] })] }));
|
|
101
102
|
}
|
|
@@ -4,6 +4,5 @@
|
|
|
4
4
|
* Server-only entry point for promotions repositories and API route handlers.
|
|
5
5
|
*/
|
|
6
6
|
export * from "./actions";
|
|
7
|
-
export { PromotionsRepository } from "./repository/promotions.repository";
|
|
8
7
|
export { couponsRepository } from "./repository/coupons.repository";
|
|
9
8
|
export { GET as promotionsGET, GET } from "./api/route";
|
|
@@ -4,6 +4,5 @@
|
|
|
4
4
|
* Server-only entry point for promotions repositories and API route handlers.
|
|
5
5
|
*/
|
|
6
6
|
export * from "./actions";
|
|
7
|
-
export { PromotionsRepository } from "./repository/promotions.repository";
|
|
8
7
|
export { couponsRepository } from "./repository/coupons.repository";
|
|
9
8
|
export { GET as promotionsGET, GET } from "./api/route";
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useCallback, useMemo } from "react";
|
|
4
|
-
import { X } from "lucide-react";
|
|
5
4
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
|
-
import { ListingToolbar, Pagination, Text } from "../../../ui";
|
|
5
|
+
import { ListingFilterDrawer, ListingToolbar, Pagination, Text } from "../../../ui";
|
|
7
6
|
import { ReviewCard } from "./ReviewsList";
|
|
8
7
|
import { ReviewFilters, REVIEW_PUBLIC_SORT_OPTIONS } from "./ReviewFilters";
|
|
9
8
|
import { useReviews } from "../hooks/useReviews";
|
|
@@ -103,5 +102,5 @@ export function ReviewsIndexListing({ initialData, variant = "public", }) {
|
|
|
103
102
|
value: opt.value,
|
|
104
103
|
label: SORT_OPTION_LABELS[opt.key] ?? opt.key,
|
|
105
104
|
}));
|
|
106
|
-
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search reviews by product name...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: sort, sortOptions: sortOptions, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6", children: isLoading ? (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: Array.from({ length: 6 }).map((_, i) => (_jsx("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: _jsxs("div", { className: "p-4 space-y-3", children: [_jsx("div", { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" })] }) }, i))) })) : reviews.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No reviews found." })) : view === "list" ? (_jsx("div", { className: "flex flex-col divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800", children: reviews.map((review) => (_jsx(ReviewCard, { review: review }, review.id))) })) : (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: reviews.map((review) => (_jsx(ReviewCard, { review: review }, review.id))) })) }),
|
|
105
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search reviews by product name...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: sort, sortOptions: sortOptions, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6", children: isLoading ? (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: Array.from({ length: 6 }).map((_, i) => (_jsx("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: _jsxs("div", { className: "p-4 space-y-3", children: [_jsx("div", { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" })] }) }, i))) })) : reviews.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No reviews found." })) : view === "list" ? (_jsx("div", { className: "flex flex-col divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800", children: reviews.map((review) => (_jsx(ReviewCard, { review: review }, review.id))) })) : (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: reviews.map((review) => (_jsx(ReviewCard, { review: review }, review.id))) })) }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsx(ReviewFilters, { table: pendingTable, variant: variant }) })] }));
|
|
107
106
|
}
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* Server-only entry point — repositories and API route handlers.
|
|
5
5
|
*/
|
|
6
6
|
export * from "./actions";
|
|
7
|
-
export { ReviewRepository,
|
|
7
|
+
export { ReviewRepository, reviewRepository, } from "./repository/reviews.repository";
|
|
8
8
|
export { GET as reviewsGET, GET, POST } from "./api/route";
|
|
9
9
|
export { reviewItemGET, reviewItemPATCH, reviewItemDELETE, } from "./api/[id]/route";
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* Server-only entry point — repositories and API route handlers.
|
|
5
5
|
*/
|
|
6
6
|
export * from "./actions";
|
|
7
|
-
export { ReviewRepository,
|
|
7
|
+
export { ReviewRepository, reviewRepository, } from "./repository/reviews.repository";
|
|
8
8
|
export { GET as reviewsGET, GET, POST } from "./api/route";
|
|
9
9
|
export { reviewItemGET, reviewItemPATCH, reviewItemDELETE, } from "./api/[id]/route";
|