@mohasinac/appkit 2.7.56 → 2.7.58
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.d.ts +7 -1
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +8 -2
- package/dist/_internal/shared/actions/action-registry.js +31 -5
- package/dist/client.d.ts +2 -4
- package/dist/client.js +2 -3
- package/dist/configs/tailwind.d.ts +16 -3
- package/dist/configs/tailwind.js +18 -5
- package/dist/constants/field-names.d.ts +3 -0
- package/dist/constants/field-names.js +3 -0
- package/dist/features/about/components/FAQPageView.js +2 -2
- package/dist/features/about/components/FeesView.js +1 -1
- package/dist/features/about/components/PolicyPageView.js +1 -1
- package/dist/features/about/components/PublicProfileView.js +1 -1
- package/dist/features/account/components/AddressBook.js +1 -1
- package/dist/features/account/components/AddressesIndexListing.js +1 -1
- package/dist/features/account/components/BuyerAccountGuideView.js +7 -7
- package/dist/features/account/components/BuyerAuctionsGuideView.js +7 -7
- package/dist/features/account/components/BuyerOrdersGuideView.js +6 -6
- package/dist/features/account/components/BuyerShoppingGuideView.js +7 -7
- package/dist/features/account/components/MessagesView.js +1 -1
- package/dist/features/account/components/NotificationPreferencesPanel.js +12 -3
- package/dist/features/account/components/UserOffersPanel.js +2 -2
- package/dist/features/account/components/UserSidebar.js +3 -3
- package/dist/features/account/components/UserSupportView.js +5 -5
- package/dist/features/admin/components/AdminAdsView.js +1 -1
- package/dist/features/admin/components/AdminAllEventEntriesView.js +2 -2
- package/dist/features/admin/components/AdminAnalyticsGuideView.js +3 -3
- package/dist/features/admin/components/AdminBidsView.js +6 -2
- package/dist/features/admin/components/AdminBlogView.js +7 -2
- package/dist/features/admin/components/AdminBrandsView.js +7 -2
- package/dist/features/admin/components/AdminBundleEditorView.js +13 -9
- package/dist/features/admin/components/AdminBundlesView.js +4 -2
- package/dist/features/admin/components/AdminCarouselEditorView.js +7 -8
- package/dist/features/admin/components/AdminCarouselView.js +6 -4
- package/dist/features/admin/components/AdminCartsView.js +1 -1
- package/dist/features/admin/components/AdminCatalogGuideView.js +5 -5
- package/dist/features/admin/components/AdminCategoriesView.js +7 -2
- package/dist/features/admin/components/AdminContactEditorView.js +2 -2
- package/dist/features/admin/components/AdminContactView.js +4 -2
- package/dist/features/admin/components/AdminContentGuideView.js +6 -6
- package/dist/features/admin/components/AdminCouponsView.js +4 -2
- package/dist/features/admin/components/AdminEmployeeEditorView.js +1 -1
- package/dist/features/admin/components/AdminFaqsView.js +4 -2
- package/dist/features/admin/components/AdminFeatureFlagsView.js +1 -1
- package/dist/features/admin/components/AdminFeaturesView.js +5 -1
- package/dist/features/admin/components/AdminGuideHubView.js +1 -1
- package/dist/features/admin/components/AdminHistoryView.js +1 -1
- package/dist/features/admin/components/AdminListingScaffold.js +1 -1
- package/dist/features/admin/components/AdminMediaView.js +10 -5
- package/dist/features/admin/components/AdminNavigationView.js +1 -1
- package/dist/features/admin/components/AdminNewsletterView.js +4 -2
- package/dist/features/admin/components/AdminNotificationsView.js +7 -2
- package/dist/features/admin/components/AdminOrdersGuideView.js +5 -5
- package/dist/features/admin/components/AdminOrdersView.js +11 -2
- package/dist/features/admin/components/AdminPayoutsView.js +6 -2
- package/dist/features/admin/components/AdminPrizeDrawsView.js +4 -0
- package/dist/features/admin/components/AdminProductsView.js +14 -2
- package/dist/features/admin/components/AdminReturnRequestsView.js +1 -1
- package/dist/features/admin/components/AdminReviewsView.js +7 -2
- package/dist/features/admin/components/AdminScammerEditorView.js +3 -3
- package/dist/features/admin/components/AdminScammersView.js +5 -5
- package/dist/features/admin/components/AdminSectionsView.js +2 -2
- package/dist/features/admin/components/AdminSessionsView.js +6 -2
- package/dist/features/admin/components/AdminSidebar.js +3 -3
- package/dist/features/admin/components/AdminSiteSettingsView.js +1 -1
- package/dist/features/admin/components/AdminStoreAddressesView.js +1 -1
- package/dist/features/admin/components/AdminStoreEditorView.js +1 -1
- package/dist/features/admin/components/AdminStoresGuideView.js +6 -6
- package/dist/features/admin/components/AdminStoresView.js +7 -2
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +3 -1
- package/dist/features/admin/components/AdminSupportTicketDetailView.js +4 -4
- package/dist/features/admin/components/AdminSupportTicketsView.js +8 -8
- package/dist/features/admin/components/AdminTeamGuideView.js +4 -4
- package/dist/features/admin/components/AdminTeamView.js +4 -2
- package/dist/features/admin/components/AdminTrustGuideView.js +5 -5
- package/dist/features/admin/components/AdminUserEditorView.js +2 -2
- package/dist/features/admin/components/AdminUsersGuideView.js +5 -5
- package/dist/features/admin/components/AdminUsersView.js +6 -2
- package/dist/features/admin/components/AdminViewCards.js +3 -3
- package/dist/features/admin/components/AdminWishlistsView.js +1 -1
- package/dist/features/admin/components/DataTable.js +1 -1
- package/dist/features/admin/constants/filter-tabs.d.ts +9 -0
- package/dist/features/admin/constants/filter-tabs.js +3 -0
- package/dist/features/auctions/components/AuctionBidsTable.js +1 -1
- package/dist/features/auctions/components/AuctionBottomActions.d.ts +7 -0
- package/dist/features/auctions/components/AuctionBottomActions.js +24 -0
- package/dist/features/auctions/components/AuctionDetailPageView.js +7 -7
- package/dist/features/auctions/components/AuctionsListView.js +1 -1
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +2 -2
- package/dist/features/auctions/components/MarketplaceAuctionGrid.js +1 -1
- package/dist/features/auctions/components/PlaceBidFormClient.js +1 -1
- package/dist/features/auth/components/LoginForm.js +1 -1
- package/dist/features/auth/components/VerifyEmailView.js +2 -2
- package/dist/features/before-after/components/BeforeAfterGallery.js +1 -1
- package/dist/features/blog/components/BlogFeaturedCard.js +1 -1
- package/dist/features/blog/components/BlogIndexListing.js +1 -1
- package/dist/features/blog/components/BlogListView.js +2 -2
- package/dist/features/blog/components/BlogPostView.js +8 -8
- package/dist/features/cart/components/CartDrawer.js +2 -2
- package/dist/features/cart/repository/cart.repository.js +11 -4
- package/dist/features/cart/schemas/firestore.d.ts +3 -0
- package/dist/features/categories/components/BrandDetailPageView.js +1 -1
- package/dist/features/categories/components/CategoriesIndexListing.js +1 -1
- package/dist/features/categories/components/CategoryDetailPageView.js +39 -3
- package/dist/features/categories/components/CategoryDetailTabs.d.ts +4 -1
- package/dist/features/categories/components/CategoryDetailTabs.js +7 -2
- package/dist/features/categories/components/CategoryGrid.js +1 -1
- package/dist/features/categories/components/CategoryProductsView.js +1 -1
- package/dist/features/categories/components/CategoryStoresListing.d.ts +5 -0
- package/dist/features/categories/components/CategoryStoresListing.js +11 -0
- package/dist/features/categories/components/CategoryTableColumns.js +2 -2
- package/dist/features/categories/components/CategoryTree.js +1 -1
- package/dist/features/categories/components/index.d.ts +2 -0
- package/dist/features/categories/components/index.js +1 -0
- package/dist/features/checkout/components/CheckoutStepper.js +2 -2
- package/dist/features/classified/components/ClassifiedIndexListing.js +2 -0
- package/dist/features/classified/components/ClassifiedListView.js +1 -1
- package/dist/features/collections/components/CollectionCard.js +1 -1
- package/dist/features/contact/components/ContactInfoSidebar.js +1 -1
- package/dist/features/copilot/components/AdminCopilotView.js +2 -2
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +2 -0
- package/dist/features/digital-codes/components/DigitalCodesListView.js +1 -1
- package/dist/features/events/components/AdminEventsView.js +5 -1
- package/dist/features/events/components/EventCard.js +1 -1
- package/dist/features/events/components/EventPollWidget.js +3 -3
- package/dist/features/events/components/EventStatusBadge.js +5 -5
- package/dist/features/events/components/EventsIndexListing.js +1 -1
- package/dist/features/events/components/EventsListView.js +2 -2
- package/dist/features/events/components/SpinWheelView.js +5 -3
- package/dist/features/faq/components/FAQAccordion.js +2 -2
- package/dist/features/filters/AsyncFacetSection.js +3 -3
- package/dist/features/filters/FilterFacetSection.js +5 -5
- package/dist/features/filters/RangeFilter.js +1 -1
- package/dist/features/forms/Input.js +5 -5
- package/dist/features/forms/Select.js +3 -3
- package/dist/features/forms/Slider.js +1 -1
- package/dist/features/forms/Textarea.js +3 -3
- package/dist/features/forms/utils.d.ts +2 -2
- package/dist/features/forms/utils.js +2 -2
- package/dist/features/history/hooks/useHistory.js +23 -10
- package/dist/features/homepage/components/AdvertisementBanner.js +2 -2
- package/dist/features/homepage/components/CharacterHotspotForm.js +2 -2
- package/dist/features/homepage/components/FeaturedResultsSection.js +1 -1
- package/dist/features/homepage/components/HeroSection.js +1 -1
- package/dist/features/homepage/components/NewsletterSection.js +1 -1
- package/dist/features/homepage/components/SectionCarousel.js +1 -1
- package/dist/features/layout/BottomActions.js +2 -2
- package/dist/features/layout/ListingLayout.js +3 -3
- package/dist/features/layout/TitleBarLayout.js +1 -1
- package/dist/features/live/components/LiveItemsIndexListing.js +2 -0
- package/dist/features/live/components/LiveItemsListView.js +1 -1
- package/dist/features/media/index.d.ts +2 -0
- package/dist/features/media/index.js +1 -0
- package/dist/features/media/modals/ImageCropModal.js +1 -1
- package/dist/features/media/modals/ImageEditor.d.ts +12 -0
- package/dist/features/media/modals/ImageEditor.js +73 -0
- package/dist/features/media/upload/ImageUpload.d.ts +5 -1
- package/dist/features/media/upload/ImageUpload.js +33 -8
- package/dist/features/media/upload/MediaUploadField.d.ts +5 -1
- package/dist/features/media/upload/MediaUploadField.js +26 -12
- package/dist/features/orders/components/OrdersList.js +12 -12
- package/dist/features/orders/components/RefundHistoryTable.js +2 -2
- package/dist/features/orders/components/RefundRequestView.js +3 -3
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +1 -1
- package/dist/features/pre-orders/components/PreOrderActionsClient.js +1 -1
- package/dist/features/pre-orders/components/PreOrderBadge.js +5 -5
- package/dist/features/pre-orders/components/PreOrderBottomActions.d.ts +5 -0
- package/dist/features/pre-orders/components/PreOrderBottomActions.js +22 -0
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +5 -5
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +47 -0
- package/dist/features/pre-orders/components/PreOrdersListView.js +1 -1
- package/dist/features/pre-orders/components/PreorderCard.js +3 -3
- package/dist/features/products/components/AuctionsIndexListing.js +23 -0
- package/dist/features/products/components/BidHistory.js +2 -2
- package/dist/features/products/components/CompareOverlay.js +1 -1
- package/dist/features/products/components/CustomFieldsEditor.js +1 -1
- package/dist/features/products/components/CustomSectionTabContent.js +1 -1
- package/dist/features/products/components/CustomSectionsEditor.js +1 -1
- package/dist/features/products/components/GroupSettingsPanel.js +2 -2
- package/dist/features/products/components/MakeOfferButton.js +2 -2
- package/dist/features/products/components/PrizeDrawBottomActions.d.ts +6 -0
- package/dist/features/products/components/PrizeDrawBottomActions.js +24 -0
- package/dist/features/products/components/PrizeDrawDetailPageView.js +5 -7
- package/dist/features/products/components/PrizeDrawEntryActions.js +5 -18
- package/dist/features/products/components/PrizeDrawItemsEditor.js +3 -3
- package/dist/features/products/components/PrizeRevealModal.js +7 -4
- package/dist/features/products/components/ProductDetailActions.d.ts +6 -1
- package/dist/features/products/components/ProductDetailActions.js +36 -6
- package/dist/features/products/components/ProductDetailPageView.js +19 -18
- package/dist/features/products/components/ProductFeaturesSelector.js +1 -1
- package/dist/features/products/components/ProductGalleryClient.js +1 -1
- package/dist/features/products/components/ProductGrid.js +8 -8
- package/dist/features/products/components/ProductTabs.js +1 -1
- package/dist/features/products/components/ProductTabsShell.js +1 -1
- package/dist/features/products/components/ProductsIndexListing.js +47 -0
- package/dist/features/products/components/RelatedProducts.js +1 -1
- package/dist/features/products/components/ShowGroupSection.js +1 -1
- package/dist/features/products/components/SublistingCarouselSection.js +1 -1
- package/dist/features/products/components/SublistingCategorySelect.js +1 -1
- package/dist/features/products/components/index.d.ts +0 -2
- package/dist/features/products/components/index.js +0 -1
- package/dist/features/products/constants/action-defs.d.ts +7 -0
- package/dist/features/products/constants/action-defs.js +14 -0
- package/dist/features/products/constants/listing-tabs.d.ts +6 -0
- package/dist/features/products/constants/listing-tabs.js +1 -0
- package/dist/features/promotions/components/CouponCard.js +3 -3
- package/dist/features/promotions/components/CouponsIndexListing.js +2 -2
- package/dist/features/promotions/components/PromotionsView.js +1 -1
- package/dist/features/reviews/components/ReviewDetailPageView.js +1 -1
- package/dist/features/reviews/components/ReviewDetailShell.js +4 -4
- package/dist/features/reviews/components/ReviewModal.js +2 -2
- package/dist/features/reviews/components/ReviewSummary.js +1 -1
- package/dist/features/reviews/components/ReviewsIndexListing.js +1 -1
- package/dist/features/reviews/components/ReviewsList.js +1 -1
- package/dist/features/seller/components/SellerAddressesView.js +4 -3
- package/dist/features/seller/components/SellerAnalyticsAlertsView.js +2 -2
- package/dist/features/seller/components/SellerAuctionsView.js +11 -4
- package/dist/features/seller/components/SellerBidsView.js +22 -7
- package/dist/features/seller/components/SellerBundlesView.js +11 -4
- package/dist/features/seller/components/SellerClassifiedView.js +12 -5
- package/dist/features/seller/components/SellerCouponEditorView.js +2 -2
- package/dist/features/seller/components/SellerCouponsView.js +13 -4
- package/dist/features/seller/components/SellerDigitalCodesView.js +11 -4
- package/dist/features/seller/components/SellerFeaturesView.js +1 -1
- package/dist/features/seller/components/SellerGoogleReviewsView.js +10 -5
- package/dist/features/seller/components/SellerGroupedListingsView.js +2 -0
- package/dist/features/seller/components/SellerLiveView.js +13 -6
- package/dist/features/seller/components/SellerOffersPanel.js +2 -2
- package/dist/features/seller/components/SellerOffersView.js +2 -2
- package/dist/features/seller/components/SellerOrdersView.js +41 -18
- package/dist/features/seller/components/SellerPayoutMethodsView.js +14 -5
- package/dist/features/seller/components/SellerPayoutsView.js +2 -2
- package/dist/features/seller/components/SellerPreOrdersView.js +7 -2
- package/dist/features/seller/components/SellerPrizeDrawsView.js +7 -2
- package/dist/features/seller/components/SellerProductShell.js +27 -9
- package/dist/features/seller/components/SellerProductsCards.js +2 -1
- package/dist/features/seller/components/SellerProductsView.js +22 -9
- package/dist/features/seller/components/SellerReviewsView.js +9 -1
- package/dist/features/seller/components/SellerShippingConfigsView.js +15 -6
- package/dist/features/seller/components/SellerSidebar.js +2 -2
- package/dist/features/seller/components/SellerStoreCategoriesView.js +11 -4
- package/dist/features/seller/components/SellerTemplatesView.js +20 -7
- package/dist/features/seller/components/analytics/SellerTopProducts.js +1 -1
- package/dist/features/shell/StepForm.js +9 -3
- package/dist/features/site-settings/components/ActionPermissionsManager.js +1 -1
- package/dist/features/site-settings/components/NavPermissionsManager.js +1 -1
- package/dist/features/stores/components/InteractiveStoreCard.js +1 -1
- package/dist/features/stores/components/StoreDetailLayoutView.js +1 -1
- package/dist/features/stores/components/StoreFinanceGuideView.js +2 -2
- package/dist/features/stores/components/StoreHeader.js +1 -1
- package/dist/features/stores/components/StoreListingsGuideView.js +3 -3
- package/dist/features/stores/components/StoreOrdersGuideView.js +4 -4
- package/dist/features/stores/components/StoreReviewsListing.js +1 -1
- package/dist/features/stores/components/StoreSettingsGuideView.js +2 -2
- package/dist/features/stores/components/StoresIndexListing.js +17 -1
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +4 -4
- package/dist/features/wishlist/components/WishlistPage.js +3 -3
- package/dist/features/wishlist/hooks/useWishlistToggle.js +6 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +9 -3
- package/dist/react/hooks/use-action-dispatch.d.ts +5 -0
- package/dist/react/hooks/use-action-dispatch.js +10 -0
- package/dist/seed/cart-seed-data.js +50 -3
- package/dist/seed/categories-seed-data.js +80 -16
- package/dist/seed/index.d.ts +3 -0
- package/dist/seed/index.js +3 -0
- package/dist/seed/manifest.js +15 -1
- package/dist/seed/products-classifieds-seed-data.d.ts +10 -0
- package/dist/seed/products-classifieds-seed-data.js +197 -0
- package/dist/seed/products-digital-codes-seed-data.d.ts +10 -0
- package/dist/seed/products-digital-codes-seed-data.js +204 -0
- package/dist/seed/products-live-items-seed-data.d.ts +13 -0
- package/dist/seed/products-live-items-seed-data.js +190 -0
- package/dist/styles.css +301 -3
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/index.d.ts +3 -3
- package/dist/tokens/index.js +3 -3
- package/dist/tokens/motion.d.ts +162 -0
- package/dist/tokens/motion.js +89 -0
- package/dist/ui/DataTable.js +6 -5
- package/dist/ui/components/Accordion.js +2 -1
- package/dist/ui/components/Button.style.css +15 -0
- package/dist/ui/components/Card.d.ts +5 -2
- package/dist/ui/components/Card.js +29 -11
- package/dist/ui/components/Div.d.ts +2 -16
- package/dist/ui/components/Div.js +2 -16
- package/dist/ui/components/Input.js +1 -1
- package/dist/ui/components/Layout.d.ts +9 -19
- package/dist/ui/components/Layout.js +9 -7
- package/dist/ui/components/ListingToolbar.js +1 -1
- package/dist/ui/components/Modal.js +7 -4
- package/dist/ui/components/Motion.d.ts +75 -0
- package/dist/ui/components/Motion.js +122 -0
- package/dist/ui/components/Select.js +1 -1
- package/dist/ui/components/Semantic.d.ts +81 -14
- package/dist/ui/components/Semantic.js +75 -10
- package/dist/ui/components/Semantic.style.css +261 -2
- package/dist/ui/components/SideDrawer.d.ts +1 -1
- package/dist/ui/components/SideDrawer.js +8 -6
- package/dist/ui/components/SideModal.d.ts +1 -1
- package/dist/ui/components/SideModal.js +11 -9
- package/dist/ui/components/StackedViewShell.js +6 -1
- package/dist/ui/components/StatsGrid.js +1 -1
- package/dist/ui/components/Toast.js +5 -2
- package/dist/ui/components/Typography.d.ts +44 -3
- package/dist/ui/components/Typography.js +15 -30
- package/dist/ui/components/Typography.style.css +24 -0
- package/dist/ui/components/VacationBanner.js +2 -1
- package/dist/ui/components/surface-tokens.d.ts +70 -0
- package/dist/ui/components/surface-tokens.js +68 -0
- package/dist/ui/forms/FormShell.d.ts +6 -1
- package/dist/ui/forms/FormShell.js +32 -4
- package/dist/ui/index.d.ts +9 -6
- package/dist/ui/index.js +4 -4
- package/dist/validation/schemas.d.ts +28 -28
- package/package.json +3 -1
- package/dist/_internal/client/features/seller/print-center/InventoryLabel.d.ts +0 -12
- package/dist/_internal/client/features/seller/print-center/InventoryLabel.js +0 -49
- package/dist/_internal/client/features/seller/print-center/LabelDesignPicker.d.ts +0 -7
- package/dist/_internal/client/features/seller/print-center/LabelDesignPicker.js +0 -32
- package/dist/_internal/client/features/seller/print-center/OrderPackingLabel.d.ts +0 -28
- package/dist/_internal/client/features/seller/print-center/OrderPackingLabel.js +0 -33
- package/dist/_internal/client/features/seller/print-center/PhysicalLocationModal.d.ts +0 -12
- package/dist/_internal/client/features/seller/print-center/PhysicalLocationModal.js +0 -30
- package/dist/_internal/client/features/seller/print-center/PrintCenterView.d.ts +0 -12
- package/dist/_internal/client/features/seller/print-center/PrintCenterView.js +0 -102
- package/dist/_internal/client/features/seller/print-center/PrintGrid.d.ts +0 -12
- package/dist/_internal/client/features/seller/print-center/PrintGrid.js +0 -13
- package/dist/_internal/client/features/seller/print-center/StoreCard.d.ts +0 -19
- package/dist/_internal/client/features/seller/print-center/StoreCard.js +0 -30
- package/dist/_internal/client/features/seller/print-center/WebsiteCard.d.ts +0 -11
- package/dist/_internal/client/features/seller/print-center/WebsiteCard.js +0 -25
- package/dist/_internal/client/features/seller/print-center/index.d.ts +0 -11
- package/dist/_internal/client/features/seller/print-center/index.js +0 -10
- package/dist/_internal/client/features/seller/print-center/types.d.ts +0 -20
- package/dist/_internal/client/features/seller/print-center/types.js +0 -20
- package/dist/_internal/client/features/seller/print-center/useInventoryPdf.d.ts +0 -18
- package/dist/_internal/client/features/seller/print-center/useInventoryPdf.js +0 -76
- package/dist/features/account/repository/address.repository.d.ts +0 -17
- package/dist/features/account/repository/address.repository.js +0 -184
- package/dist/features/auctions/components/AuctionCard.d.ts +0 -29
- package/dist/features/auctions/components/AuctionCard.js +0 -38
- package/dist/features/categories/components/BundleAddToCartCta.d.ts +0 -16
- package/dist/features/categories/components/BundleAddToCartCta.js +0 -54
- package/dist/features/categories/components/CategoriesListView.d.ts +0 -31
- package/dist/features/categories/components/CategoriesListView.js +0 -27
- package/dist/features/products/components/AuctionsView.d.ts +0 -6
- package/dist/features/products/components/AuctionsView.js +0 -5
- package/dist/features/products/components/BuyBar.d.ts +0 -21
- package/dist/features/products/components/BuyBar.js +0 -19
- package/dist/features/products/components/PreOrdersView.d.ts +0 -6
- package/dist/features/products/components/PreOrdersView.js +0 -5
- package/dist/features/reviews/components/ReviewsListView.d.ts +0 -31
- package/dist/features/reviews/components/ReviewsListView.js +0 -16
- package/dist/features/stores/components/StoresListView.d.ts +0 -19
- package/dist/features/stores/components/StoresListView.js +0 -25
- package/dist/features/stores/repository/store-address.repository.d.ts +0 -55
- package/dist/features/stores/repository/store-address.repository.js +0 -187
- package/dist/ui/components/BulkActionsBar.d.ts +0 -18
- package/dist/ui/components/BulkActionsBar.js +0 -25
- package/dist/ui/components/CollageLightbox.d.ts +0 -18
- package/dist/ui/components/CollageLightbox.js +0 -41
- package/dist/ui/components/StickyBottomBar.d.ts +0 -22
- package/dist/ui/components/StickyBottomBar.js +0 -20
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import type { CategoryDocument } from "../schemas";
|
|
2
|
+
import type { StoreListItem } from "../../stores/types";
|
|
2
3
|
export interface CategoryDetailTabsProps {
|
|
3
4
|
categorySlug: string;
|
|
4
5
|
categoryId?: string;
|
|
5
6
|
initialProductsData?: any;
|
|
6
7
|
initialBundles?: CategoryDocument[];
|
|
8
|
+
initialStores?: StoreListItem[];
|
|
7
9
|
counts?: {
|
|
8
10
|
products?: number;
|
|
9
11
|
auctions?: number;
|
|
10
12
|
preOrders?: number;
|
|
11
13
|
prizeDraws?: number;
|
|
12
14
|
bundles?: number;
|
|
15
|
+
stores?: number;
|
|
13
16
|
};
|
|
14
17
|
/** Enabled listing types (e.g. ["standard","auction","pre-order"]). When omitted, all tabs shown. */
|
|
15
18
|
enabledListingTypes?: string[];
|
|
16
19
|
/** Enabled category types (e.g. ["category","brand","bundle"]). When omitted, all tabs shown. */
|
|
17
20
|
enabledCategoryTypes?: string[];
|
|
18
21
|
}
|
|
19
|
-
export declare function CategoryDetailTabs({ categorySlug, categoryId, initialProductsData, initialBundles, counts, enabledListingTypes, enabledCategoryTypes, }: CategoryDetailTabsProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export declare function CategoryDetailTabs({ categorySlug, categoryId, initialProductsData, initialBundles, initialStores, counts, enabledListingTypes, enabledCategoryTypes, }: CategoryDetailTabsProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -6,6 +6,7 @@ import { AuctionsIndexListing } from "../../products/components/AuctionsIndexLis
|
|
|
6
6
|
import { PreOrdersIndexListing } from "../../pre-orders/components/PreOrdersIndexListing";
|
|
7
7
|
import { PrizeDrawsIndexListing } from "../../products/components/PrizeDrawsIndexListing";
|
|
8
8
|
import { CategoryBundlesListing } from "./CategoryBundlesListing";
|
|
9
|
+
import { CategoryStoresListing } from "./CategoryStoresListing";
|
|
9
10
|
import { CATEGORY_PAGE_TABS } from "../../products/constants/listing-tabs";
|
|
10
11
|
function tabLabel(label, count) {
|
|
11
12
|
if (!count)
|
|
@@ -19,8 +20,9 @@ const TAB_TYPE_MAP = {
|
|
|
19
20
|
"pre-orders": { kind: "listing", type: "pre-order" },
|
|
20
21
|
"prize-draws": { kind: "listing", type: "prize-draw" },
|
|
21
22
|
bundles: { kind: "category", type: "bundle" },
|
|
23
|
+
stores: { kind: "entity", type: "stores" },
|
|
22
24
|
};
|
|
23
|
-
export function CategoryDetailTabs({ categorySlug, categoryId, initialProductsData, initialBundles = [], counts, enabledListingTypes, enabledCategoryTypes, }) {
|
|
25
|
+
export function CategoryDetailTabs({ categorySlug, categoryId, initialProductsData, initialBundles = [], initialStores = [], counts, enabledListingTypes, enabledCategoryTypes, }) {
|
|
24
26
|
const visibleTabs = CATEGORY_PAGE_TABS.filter((t) => {
|
|
25
27
|
const mapping = TAB_TYPE_MAP[t.id];
|
|
26
28
|
if (!mapping)
|
|
@@ -31,6 +33,8 @@ export function CategoryDetailTabs({ categorySlug, categoryId, initialProductsDa
|
|
|
31
33
|
if (mapping.kind === "category" && enabledCategoryTypes) {
|
|
32
34
|
return enabledCategoryTypes.includes(mapping.type);
|
|
33
35
|
}
|
|
36
|
+
if (mapping.kind === "entity")
|
|
37
|
+
return true;
|
|
34
38
|
return true;
|
|
35
39
|
});
|
|
36
40
|
const firstTabId = (visibleTabs[0]?.id ?? "products");
|
|
@@ -42,10 +46,11 @@ export function CategoryDetailTabs({ categorySlug, categoryId, initialProductsDa
|
|
|
42
46
|
case "pre-orders": return counts?.preOrders;
|
|
43
47
|
case "prize-draws": return counts?.prizeDraws;
|
|
44
48
|
case "bundles": return counts?.bundles;
|
|
49
|
+
case "stores": return counts?.stores;
|
|
45
50
|
default: return undefined;
|
|
46
51
|
}
|
|
47
52
|
};
|
|
48
53
|
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "flex border-b border-zinc-200 dark:border-slate-700 mb-6 overflow-x-auto", children: visibleTabs.map((t) => (_jsx("button", { type: "button", onClick: () => setActiveTab(t.id), className: `px-5 py-2.5 text-sm font-medium whitespace-nowrap transition-colors -mb-px border-b-2 ${activeTab === t.id
|
|
49
54
|
? "border-primary text-primary"
|
|
50
|
-
: "border-transparent text-zinc-500 hover:text-zinc-900 dark:hover:text-zinc-100"}`, children: tabLabel(t.label, countFor(t.id)) }, t.id))) }), activeTab === "products" && (_jsx(CategoryProductsListing, { categorySlug: categorySlug, categoryId: categoryId, initialData: initialProductsData })), activeTab === "auctions" && (_jsx(AuctionsIndexListing, { categorySlug: categorySlug })), activeTab === "pre-orders" && (_jsx(PreOrdersIndexListing, { categorySlug: categorySlug })), activeTab === "prize-draws" && (_jsx(PrizeDrawsIndexListing, { categorySlug: categorySlug })), activeTab === "bundles" && (_jsx(CategoryBundlesListing, { initialBundles: initialBundles }))] }));
|
|
55
|
+
: "border-transparent text-zinc-500 hover:text-zinc-900 dark:hover:text-zinc-100"}`, children: tabLabel(t.label, countFor(t.id)) }, t.id))) }), activeTab === "products" && (_jsx(CategoryProductsListing, { categorySlug: categorySlug, categoryId: categoryId, initialData: initialProductsData })), activeTab === "auctions" && (_jsx(AuctionsIndexListing, { categorySlug: categorySlug })), activeTab === "pre-orders" && (_jsx(PreOrdersIndexListing, { categorySlug: categorySlug })), activeTab === "prize-draws" && (_jsx(PrizeDrawsIndexListing, { categorySlug: categorySlug })), activeTab === "bundles" && (_jsx(CategoryBundlesListing, { initialBundles: initialBundles })), activeTab === "stores" && (_jsx(CategoryStoresListing, { stores: initialStores }))] }));
|
|
51
56
|
}
|
|
@@ -5,7 +5,7 @@ import { Div, Span, Text } from "../../../ui";
|
|
|
5
5
|
import { THEME_CONSTANTS } from "../../../tokens";
|
|
6
6
|
export function CategoryCard({ category, href, onClick, className = "", }) {
|
|
7
7
|
const productCount = category.metrics?.productCount ?? category.productCount ?? 0;
|
|
8
|
-
const inner = (_jsxs(Div, { className: "flex h-full flex-col", children: [_jsxs(Div, { className: "relative aspect-[4/3] w-full overflow-hidden bg-gradient-to-br from-neutral-100 to-neutral-200 dark:from-zinc-800 dark:to-zinc-700 flex-shrink-0", children: [category.display?.coverImage ? (_jsx(Div, { role: "img", "aria-label": category.name, className: "h-full w-full bg-center bg-cover transition-transform duration-300 group-hover:scale-105", style: { backgroundImage: `url(${category.display.coverImage})` } })) : category.display?.color ? (_jsx(Div, { className: "h-full w-full opacity-80", style: { backgroundColor: category.display.color } })) : null, category.display?.icon && (_jsx(Div, { className: "absolute inset-0 flex items-center justify-center text-4xl", children: category.display.icon })), category.isFeatured && (_jsx(Span, { className: "absolute left-2 top-2 rounded-full bg-amber-400 p-1 text-xs leading-none", children: "\u2605" }))] }), _jsxs(Div, { className: "flex flex-1 flex-col p-3.5", children: [_jsx(Text, { className: `font-semibold text-sm leading-snug ${THEME_CONSTANTS.utilities.textClamp2} text-neutral-900 dark:text-white`, children: category.name }), category.description && (_jsx(Text, { className: `mt-1 text-xs ${THEME_CONSTANTS.utilities.textClamp2} text-neutral-500 dark:text-zinc-400 flex-1`, children: category.description })), _jsxs(Div, { className: "mt-2 flex items-center justify-between gap-2", children: [_jsxs(Text, { className: "text-xs text-
|
|
8
|
+
const inner = (_jsxs(Div, { className: "flex h-full flex-col", children: [_jsxs(Div, { className: "relative aspect-[4/3] w-full overflow-hidden bg-gradient-to-br from-neutral-100 to-neutral-200 dark:from-zinc-800 dark:to-zinc-700 flex-shrink-0", children: [category.display?.coverImage ? (_jsx(Div, { role: "img", "aria-label": category.name, className: "h-full w-full bg-center bg-cover transition-transform duration-300 group-hover:scale-105", style: { backgroundImage: `url(${category.display.coverImage})` } })) : category.display?.color ? (_jsx(Div, { className: "h-full w-full opacity-80", style: { backgroundColor: category.display.color } })) : null, category.display?.icon && (_jsx(Div, { className: "absolute inset-0 flex items-center justify-center text-4xl", children: category.display.icon })), category.isFeatured && (_jsx(Span, { className: "absolute left-2 top-2 rounded-full bg-amber-400 p-1 text-xs leading-none", children: "\u2605" }))] }), _jsxs(Div, { className: "flex flex-1 flex-col p-3.5", children: [_jsx(Text, { className: `font-semibold text-sm leading-snug ${THEME_CONSTANTS.utilities.textClamp2} text-neutral-900 dark:text-white`, children: category.name }), category.description && (_jsx(Text, { className: `mt-1 text-xs ${THEME_CONSTANTS.utilities.textClamp2} text-neutral-500 dark:text-zinc-400 flex-1`, children: category.description })), _jsxs(Div, { className: "mt-2 flex items-center justify-between gap-2", children: [_jsxs(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400", children: [productCount.toLocaleString(), " ", productCount === 1 ? "item" : "items"] }), _jsxs(Span, { className: "inline-flex items-center gap-1 rounded-md border border-zinc-200 dark:border-zinc-700 px-2.5 py-1 text-xs font-medium text-zinc-600 dark:text-zinc-300 group-hover:bg-primary group-hover:border-primary group-hover:text-white transition-colors", children: ["Browse ", _jsx(ArrowRight, { className: "h-3 w-3" })] })] })] })] }));
|
|
9
9
|
const cardClass = `group relative flex flex-col overflow-hidden rounded-xl border border-neutral-200 bg-white dark:border-zinc-700 dark:bg-zinc-900 shadow-sm transition hover:shadow-md h-full ${className}`;
|
|
10
10
|
if (href) {
|
|
11
11
|
return (_jsx(Link, { href: href, className: cardClass, children: inner }));
|
|
@@ -16,6 +16,6 @@ export function CategoryProductsView({ labels = {}, table, filterVariant = "publ
|
|
|
16
16
|
}
|
|
17
17
|
table?.set("sorts", next);
|
|
18
18
|
};
|
|
19
|
-
return (_jsx(Div, { className: `min-h-screen ${className}`, children: _jsxs(Div, { className: "py-6 px-4 max-w-screen-xl mx-auto space-y-4", children: [category && renderBreadcrumbs?.(category), category && (_jsxs(Div, { children: [_jsx(Heading, { level: 1, className: "text-2xl font-bold", children: category.name }), category.description && (_jsx(Text, { className: "text-
|
|
19
|
+
return (_jsx(Div, { className: `min-h-screen ${className}`, children: _jsxs(Div, { className: "py-6 px-4 max-w-screen-xl mx-auto space-y-4", children: [category && renderBreadcrumbs?.(category), category && (_jsxs(Div, { children: [_jsx(Heading, { level: 1, className: "text-2xl font-bold", children: category.name }), category.description && (_jsx(Text, { className: "text-zinc-500 dark:text-zinc-400 mt-1", children: category.description }))] })), childCategories.length > 0 && renderChildCategories?.(childCategories), _jsx(SlottedListingView, { portal: "public", inlineToolbar: true, className: "space-y-4", renderSearch: () => renderSearch?.(search, setSearch) ?? (_jsx(Input, { value: search, onChange: (event) => setSearch(event.target.value), placeholder: "Search in category", className: "max-w-sm" })), renderSort: () => renderSort ? (renderSort(resolvedSort, handleSortChange)) : (_jsx(CategorySortSelect, { value: resolvedSort, onChange: handleSortChange, variant: filterVariant })), renderFilters: () => renderFilters?.() ??
|
|
20
20
|
(table ? _jsx(CategoryFilters, { table: table, variant: filterVariant }) : null), renderActiveFilters: renderActiveFilters, renderBulkActions: () => renderViewToggle?.(viewMode, setViewMode) ?? null, renderTable: () => renderProducts(isLoading), renderPagination: () => renderPagination?.(total) ?? null, total: total, isLoading: isLoading })] }) }));
|
|
21
21
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { InteractiveStoreCard } from "../../stores/components/InteractiveStoreCard";
|
|
4
|
+
import { ROUTES } from "../../../next";
|
|
5
|
+
import { Text } from "../../../ui";
|
|
6
|
+
export function CategoryStoresListing({ stores }) {
|
|
7
|
+
if (stores.length === 0) {
|
|
8
|
+
return (_jsx("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: _jsx(Text, { className: "text-zinc-500 dark:text-zinc-400 text-sm", children: "No stores found in this category." }) }));
|
|
9
|
+
}
|
|
10
|
+
return (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5", children: stores.map((store) => (_jsx(InteractiveStoreCard, { store: store, href: String(ROUTES.PUBLIC.STORE_DETAIL(store.storeSlug)) }, store.id))) }));
|
|
11
|
+
}
|
|
@@ -18,13 +18,13 @@ export function getCategoryTableColumns(onEdit, onDelete, labels = {}) {
|
|
|
18
18
|
{
|
|
19
19
|
key: "image",
|
|
20
20
|
header: "",
|
|
21
|
-
render: (cat) => (_jsx("div", { className: "relative w-9 h-9 rounded overflow-hidden flex-shrink-0", "data-section": "categorytablecolumns-div-270", children: cat.display?.coverImage ? (_jsx(MediaImage, { src: cat.display.coverImage, alt: "", size: "thumbnail", className: "w-full h-full object-cover" })) : (_jsx("div", { className: "w-full h-full flex items-center justify-center text-base", style: { backgroundColor: cat.display?.color ?? "#94a3b8" }, "data-section": "categorytablecolumns-div-271", children: cat.display?.icon ?? "🗂️" })) })),
|
|
21
|
+
render: (cat) => (_jsx("div", { className: "relative w-9 h-9 rounded overflow-hidden flex-shrink-0", "data-section": "categorytablecolumns-div-270", children: cat.display?.coverImage ? (_jsx(MediaImage, { src: cat.display.coverImage, alt: "", size: "thumbnail", className: "w-full h-full object-cover" })) : (_jsx("div", { className: "w-full h-full flex items-center justify-center text-base", style: { backgroundColor: cat.display?.color ?? "#94a3b8", color: "#fff" }, "data-section": "categorytablecolumns-div-271", children: cat.display?.icon ?? "🗂️" })) })),
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
key: "name",
|
|
25
25
|
header: L.colName,
|
|
26
26
|
sortable: true,
|
|
27
|
-
render: (cat) => (_jsxs("div", { style: { paddingLeft: `${cat.tier * 20}px` }, "data-section": "categorytablecolumns-div-272", children: [cat.name, cat.tier > 0 && (_jsxs(Span, { className: "text-zinc-400 text-xs ml-2", children: ["(Tier ", cat.tier, ")"] }))] })),
|
|
27
|
+
render: (cat) => (_jsxs("div", { style: { paddingLeft: `${cat.tier * 20}px` }, "data-section": "categorytablecolumns-div-272", children: [cat.name, cat.tier > 0 && (_jsxs(Span, { className: "text-zinc-400 dark:text-zinc-400 text-xs ml-2", children: ["(Tier ", cat.tier, ")"] }))] })),
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
key: "slug",
|
|
@@ -19,7 +19,7 @@ function CategoryTreeNode({ item, children = [], activeId, onSelect, depth = 0,
|
|
|
19
19
|
setExpanded((p) => !p);
|
|
20
20
|
onSelect?.(item);
|
|
21
21
|
}, className: `flex cursor-pointer items-center gap-1 rounded-md px-2 py-1.5 text-sm transition select-none
|
|
22
|
-
${isActive ? "bg-primary-50 font-semibold text-primary-700 dark:bg-primary-900/30 dark:text-primary-400" : "text-neutral-700 hover:bg-neutral-50 dark:text-zinc-300 dark:hover:bg-zinc-800"}`, style: { paddingLeft: `${8 + indent}px` }, children: [hasChildren && (_jsx(Span, { "aria-hidden": "true", className: `text-xs text-
|
|
22
|
+
${isActive ? "bg-primary-50 font-semibold text-primary-700 dark:bg-primary-900/30 dark:text-primary-400" : "text-neutral-700 hover:bg-neutral-50 dark:text-zinc-300 dark:hover:bg-zinc-800"}`, style: { paddingLeft: `${8 + indent}px` }, children: [hasChildren && (_jsx(Span, { "aria-hidden": "true", className: `text-xs text-zinc-400 dark:text-zinc-400 transition-transform duration-150 ${expanded ? "rotate-90" : ""}`, children: "\u25B6" })), !hasChildren && _jsx(Span, { className: "w-3" }), item.display?.icon && (_jsx(Span, { className: "flex-shrink-0 text-base", "aria-hidden": "true", children: item.display.icon })), _jsx(Text, { className: "flex-1 truncate", children: item.name }), item.metrics && (_jsx(Span, { className: "ml-auto flex-shrink-0 text-xs text-zinc-400 dark:text-zinc-400 tabular-nums", children: item.metrics.productCount }))] }), hasChildren && expanded && (_jsx(Div, { role: "group", children: children.map((child) => (_jsx(CategoryTreeNode, { item: child, activeId: activeId, onSelect: onSelect, depth: depth + 1 }, child.id))) }))] }));
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
25
|
* CategoryTree — hierarchical expandable navigation for categories.
|
|
@@ -34,3 +34,5 @@ export { BundleItemsPicker, defaultBundleItemsFetch, } from "./BundleItemsPicker
|
|
|
34
34
|
export type { BundleItemsPickerProps, BundleItemSearchResult, } from "./BundleItemsPicker";
|
|
35
35
|
export { CategoryBundlesListing } from "./CategoryBundlesListing";
|
|
36
36
|
export type { CategoryBundlesListingProps } from "./CategoryBundlesListing";
|
|
37
|
+
export { CategoryStoresListing } from "./CategoryStoresListing";
|
|
38
|
+
export type { CategoryStoresListingProps } from "./CategoryStoresListing";
|
|
@@ -20,3 +20,4 @@ export { BundleCollage } from "./BundleCollage";
|
|
|
20
20
|
// S-SBUNI-4 2026-05-13 — multi-select product picker for bundle editor.
|
|
21
21
|
export { BundleItemsPicker, defaultBundleItemsFetch, } from "./BundleItemsPicker";
|
|
22
22
|
export { CategoryBundlesListing } from "./CategoryBundlesListing";
|
|
23
|
+
export { CategoryStoresListing } from "./CategoryStoresListing";
|
|
@@ -8,9 +8,9 @@ export function CheckoutStepper({ steps, current }) {
|
|
|
8
8
|
const isDone = idx < currentIdx;
|
|
9
9
|
const isActive = step.id === current;
|
|
10
10
|
return (_jsxs(React.Fragment, { children: [_jsxs(Row, { className: THEME_CONSTANTS.spacing.gap["2.5"], children: [_jsx(Span, { className: `flex h-6 w-6 items-center justify-center rounded-full text-xs font-semibold ${isDone
|
|
11
|
-
? "bg-
|
|
11
|
+
? "bg-success text-white"
|
|
12
12
|
: isActive
|
|
13
13
|
? "bg-neutral-900 text-white"
|
|
14
|
-
: "bg-neutral-200 dark:bg-slate-700 text-neutral-500 dark:text-zinc-400"}`, children: isDone ? "✓" : idx + 1 }), _jsx(Span, { className: `text-sm font-medium ${isActive ? "text-neutral-900 dark:text-zinc-100" : isDone ? "text-neutral-500 dark:text-zinc-400" : "text-
|
|
14
|
+
: "bg-neutral-200 dark:bg-slate-700 text-neutral-500 dark:text-zinc-400"}`, children: isDone ? "✓" : idx + 1 }), _jsx(Span, { className: `text-sm font-medium ${isActive ? "text-neutral-900 dark:text-zinc-100" : isDone ? "text-neutral-500 dark:text-zinc-400" : "text-zinc-400 dark:text-zinc-400"}`, children: step.label })] }), idx < steps.length - 1 && (_jsx(Span, { className: "h-px flex-1 bg-neutral-200 dark:bg-slate-700" }))] }, step.id));
|
|
15
15
|
}) }));
|
|
16
16
|
}
|
|
@@ -18,6 +18,7 @@ import { InteractiveProductCard } from "../../products/components/InteractivePro
|
|
|
18
18
|
import { ClassifiedFilters } from "./ClassifiedFilters";
|
|
19
19
|
import { ACTION_ID } from "../../products/constants/action-defs";
|
|
20
20
|
import { useToast } from "../../../ui";
|
|
21
|
+
import { useBottomActions } from "../../layout";
|
|
21
22
|
const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
|
|
22
23
|
const SORT_OPTIONS = [
|
|
23
24
|
{ value: sortBy(PRODUCT_FIELDS.CREATED_AT), label: "Newest First" },
|
|
@@ -103,6 +104,7 @@ export function ClassifiedIndexListing({ initialData }) {
|
|
|
103
104
|
wishlistActions.addToWishlist(id);
|
|
104
105
|
}
|
|
105
106
|
}
|
|
107
|
+
useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [] } } : {});
|
|
106
108
|
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search classified listings\u2026", onSearchChange: setSearchInput, onSearchCommit: commitSearch, onSearchKeyDown: (e) => { if (e.key === "Enter")
|
|
107
109
|
commitSearch(); }, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: (v) => { if (v !== "table")
|
|
108
110
|
setView(v); }, onResetAll: resetAll, hasActiveState: hasActiveState, bulkMode: selection.isSelecting, bulkSelectedCount: selection.selectedCount, bulkTotalCount: products.length, onBulkSelectAll: selection.toggleAll, onBulkClear: selection.clearSelection }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [] }), 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: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6", children: isLoading ? (_jsx("div", { className: gridClass, children: Array.from({ length: 10 }).map((_, i) => (_jsxs("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: [_jsx("div", { className: "aspect-square bg-zinc-200 dark:bg-slate-700" }), _jsxs("div", { className: "p-3 space-y-2", children: [_jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-1/3" })] })] }, i))) })) : products.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No classified listings found." })) : (_jsx("div", { className: view === "list" ? "flex flex-col divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800" : gridClass, children: products.map((product) => (_jsx(InteractiveProductCard, { product: product, href: String(ROUTES.PUBLIC.CLASSIFIED_DETAIL(product.id)), variant: view === "list" ? "list" : "grid", isWishlisted: wishlistActions.isWishlisted(product.id), onToggleWishlist: handleToggleWishlist, selectable: selection.isSelecting, isSelected: selection.isSelected(product.id), onSelect: (id) => selection.toggle(id) }, product.id))) })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: onFilterClear, activeCount: filterActiveCount, hideTrigger: true, children: _jsx(ClassifiedFilters, { table: pendingTable, categoryOptions: categoryOptions }) }), _jsx(LoginRequiredModal, { isOpen: modalOpen, onClose: closeModal, message: modalMessage })] }));
|
|
@@ -39,5 +39,5 @@ export async function ClassifiedListView({ searchParams = {} }) {
|
|
|
39
39
|
const result = await productRepository
|
|
40
40
|
.list({ filters, sorts: sort, page, pageSize })
|
|
41
41
|
.catch(() => null);
|
|
42
|
-
return (_jsx(Main, { children: _jsx(Section, { className: "py-10", children: _jsxs(Container, { size: "xl", children: [_jsx(Heading, { level: 1, className: "mb-8 text-3xl font-semibold text-zinc-900", children: "Classifieds" }), _jsx(AdSlot, { id: "listing-sidebar-top", className: "mb-6" }), _jsx(ClassifiedIndexListing, { initialData: result ?? undefined }), _jsx(AdSlot, { id: "listing-sidebar-bottom", className: "mt-8" })] }) }) }));
|
|
42
|
+
return (_jsx(Main, { children: _jsx(Section, { className: "py-10", children: _jsxs(Container, { size: "xl", children: [_jsx(Heading, { level: 1, className: "mb-8 text-3xl font-semibold text-zinc-900 dark:text-zinc-50", children: "Classifieds" }), _jsx(AdSlot, { id: "listing-sidebar-top", className: "mb-6" }), _jsx(ClassifiedIndexListing, { initialData: result ?? undefined }), _jsx(AdSlot, { id: "listing-sidebar-bottom", className: "mt-8" })] }) }) }));
|
|
43
43
|
}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Div, Heading, Text, TextLink } from "../../../ui";
|
|
3
3
|
import { LAYOUT } from "../../../tokens";
|
|
4
4
|
export function CollectionCard({ collection, href }) {
|
|
5
|
-
return (_jsxs(TextLink, { href: href, className: "group relative block overflow-hidden rounded-xl bg-gray-100 dark:bg-slate-800 transition-shadow hover:shadow-lg", children: [collection.image ? (_jsx(Div, { role: "img", "aria-label": collection.title, className: `${LAYOUT.cardHeight.md} w-full bg-cover bg-center transition-transform duration-300 group-hover:scale-105`, style: { backgroundImage: `url(${collection.image})` } })) : (_jsx(Div, { className: `${LAYOUT.cardHeight.md} w-full bg-gradient-to-br from-indigo-100 to-purple-100 dark:from-indigo-900/30 dark:to-purple-900/30` })), _jsxs(Div, {
|
|
5
|
+
return (_jsxs(TextLink, { href: href, className: "group relative block overflow-hidden rounded-xl bg-gray-100 dark:bg-slate-800 transition-shadow hover:shadow-lg", children: [collection.image ? (_jsx(Div, { role: "img", "aria-label": collection.title, className: `${LAYOUT.cardHeight.md} w-full bg-cover bg-center transition-transform duration-300 group-hover:scale-105`, style: { backgroundImage: `url(${collection.image})` } })) : (_jsx(Div, { className: `${LAYOUT.cardHeight.md} w-full bg-gradient-to-br from-indigo-100 to-purple-100 dark:from-indigo-900/30 dark:to-purple-900/30` })), _jsxs(Div, { surface: "default", padding: "sm", children: [_jsx(Heading, { level: 3, className: "font-semibold text-gray-900 dark:text-zinc-100", children: collection.title }), collection.subtitle && (_jsx(Text, { className: "mt-1 text-sm text-gray-500 dark:text-zinc-400", children: collection.subtitle })), collection.productCount !== undefined && (_jsxs(Text, { className: "mt-2 text-xs text-gray-400 dark:text-zinc-500", children: [collection.productCount, " ", collection.productCount === 1 ? "item" : "items"] }))] })] }));
|
|
6
6
|
}
|
|
7
7
|
export function CollectionGrid({ collections, getHref }) {
|
|
8
8
|
return (_jsx(Div, { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: collections.map((c) => (_jsx(CollectionCard, { collection: c, href: getHref(c.slug) }, c.slug))) }));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Div, Heading, Span, Stack, Text } from "../../../ui";
|
|
3
3
|
export function ContactInfoSidebar({ infoItems, labels = {}, renderActions, }) {
|
|
4
|
-
return (_jsxs(Stack, { as: "aside", gap: "lg", children: [_jsxs(Div, { children: [_jsx(Heading, { level: 3, className: "mb-4", children: labels.title ?? "Contact Information" }), _jsx(Stack, { gap: "md", children: infoItems.map((item) => (_jsxs(Div, { className: "flex items-start gap-3", children: [_jsx(Span, { className: "text-xl flex-shrink-0 mt-0.5", children: item.icon }), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wide mb-0.5", children: item.label }), item.href ? (_jsx("a", { href: item.href, className: "text-sm text-primary-800 dark:text-primary-300 hover:underline", children: item.value })) : (_jsx(Text, { className: "text-sm", children: item.value }))] })] }, item.label))) })] }), (labels.businessHoursLabel || labels.responseTimeLabel) && (_jsxs(Stack, { gap: "sm", className: "rounded-xl border border-neutral-200 dark:border-slate-700 bg-neutral-50 dark:bg-slate-800/60 p-4", children: [labels.businessHoursLabel && labels.businessHoursValue && (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs font-semibold text-
|
|
4
|
+
return (_jsxs(Stack, { as: "aside", gap: "lg", children: [_jsxs(Div, { children: [_jsx(Heading, { level: 3, className: "mb-4", children: labels.title ?? "Contact Information" }), _jsx(Stack, { gap: "md", children: infoItems.map((item) => (_jsxs(Div, { className: "flex items-start gap-3", children: [_jsx(Span, { className: "text-xl flex-shrink-0 mt-0.5", children: item.icon }), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wide mb-0.5", children: item.label }), item.href ? (_jsx("a", { href: item.href, className: "text-sm text-primary-800 dark:text-primary-300 hover:underline", children: item.value })) : (_jsx(Text, { className: "text-sm", children: item.value }))] })] }, item.label))) })] }), (labels.businessHoursLabel || labels.responseTimeLabel) && (_jsxs(Stack, { gap: "sm", className: "rounded-xl border border-neutral-200 dark:border-slate-700 bg-neutral-50 dark:bg-slate-800/60 p-4", children: [labels.businessHoursLabel && labels.businessHoursValue && (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs font-semibold text-zinc-500 dark:text-zinc-400 uppercase tracking-wide", children: labels.businessHoursLabel }), _jsx(Text, { className: "text-sm mt-0.5", children: labels.businessHoursValue })] })), labels.responseTimeLabel && labels.responseTimeValue && (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs font-semibold text-zinc-500 dark:text-zinc-400 uppercase tracking-wide", children: labels.responseTimeLabel }), _jsx(Text, { className: "text-sm mt-0.5", children: labels.responseTimeValue })] }))] })), renderActions?.()] }));
|
|
5
5
|
}
|
|
@@ -19,7 +19,7 @@ function renderCopilotChatPanel(props) {
|
|
|
19
19
|
}
|
|
20
20
|
function renderCopilotHistoryPanel(props) {
|
|
21
21
|
const { historyQuery, conversationInput, setConversationInput, loadConversation, labels } = props;
|
|
22
|
-
return (_jsxs(Div, {
|
|
22
|
+
return (_jsxs(Div, { surface: "card", padding: "sm", className: "space-y-3", children: [_jsx(Heading, { level: 3, className: "text-sm font-semibold", children: labels?.historyTitle ?? "Conversation History" }), _jsxs("form", { className: "space-y-2", onSubmit: (e) => { e.preventDefault(); if (!conversationInput.trim())
|
|
23
23
|
return; loadConversation(conversationInput.trim()); }, children: [_jsx(Input, { label: labels?.conversationId ?? LBL_CONVERSATION_ID, value: conversationInput, onChange: (e) => setConversationInput(e.target.value), placeholder: "conv_..." }), _jsx(Button, { type: "submit", variant: "secondary", size: "sm", className: "w-full", children: labels?.loadConversation ?? "Load conversation" })] }), historyQuery.error ? (_jsx(Alert, { variant: "warning", title: "History unavailable", children: historyQuery.error instanceof Error ? historyQuery.error.message : "Could not load history" })) : null, _jsxs(Div, { className: "max-h-72 overflow-y-auto space-y-2", children: [(historyQuery.data?.messages ?? []).map((log, index) => (_jsxs(Div, { className: "rounded-lg border border-neutral-200 dark:border-slate-700 p-2", children: [_jsx(Text, { className: "text-xs font-medium text-neutral-500 dark:text-zinc-400", children: new Date(log.createdAt).toLocaleString() }), _jsxs(Text, { className: `text-sm mt-1 ${THEME_CONSTANTS.utilities.textClamp3}`, children: ["Q: ", log.prompt] }), _jsxs(Text, { className: `text-sm mt-1 ${THEME_CONSTANTS.utilities.textClamp3} text-neutral-600 dark:text-zinc-300`, children: ["A: ", log.response] })] }, `${log.createdAt}-${index}`))), !historyQuery.isLoading && (historyQuery.data?.messages?.length ?? 0) === 0 ? (_jsx(Text, { variant: "secondary", className: "text-sm", children: "No server history found for this conversation yet." })) : null] })] }));
|
|
24
24
|
}
|
|
25
25
|
export function AdminCopilotView({ endpoint, historyEndpoint = "/api/copilot/history", renderHeader, labels = {}, className = "", }) {
|
|
@@ -44,7 +44,7 @@ export function AdminCopilotView({ endpoint, historyEndpoint = "/api/copilot/his
|
|
|
44
44
|
};
|
|
45
45
|
return (_jsx(StackedViewShell, { portal: "admin", title: labels.title ?? "AI Copilot", className: className, sections: [
|
|
46
46
|
renderHeader ? (renderHeader(startNewConversation)) : (_jsxs(Div, { className: "flex items-center justify-between gap-3", children: [_jsx(Heading, { level: 2, children: labels.title ?? "AI Copilot" }), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: startNewConversation, children: labels.newConversation ?? "New Conversation" })] })),
|
|
47
|
-
_jsxs(Div, { className: "grid grid-cols-1 lg:grid-cols-[2fr,1fr] gap-4", children: [_jsxs(Div, { className: "flex flex-col rounded-xl border border-neutral-200 dark:border-slate-700 bg-white dark:bg-slate-800/60 h-[calc(100vh-300px)]", children: [_jsx(Div, { className: "border-b border-neutral-200 dark:border-slate-700 p-3", children: _jsxs(Text, { className: "text-xs font-medium text-neutral-500 dark:text-zinc-400", children: [labels.conversationId ?? LBL_CONVERSATION_ID, ": ", conversationId] }) }), _jsxs(Div, { className: "flex-1 overflow-y-auto p-4 space-y-4", children: [messages.length === 0 ? (_jsxs(Div, { className: "flex flex-col items-center justify-center h-full text-center", children: [_jsx(Text, { className: "font-medium", children: labels.noMessages ?? "No messages yet" }), _jsx(Text, { variant: "secondary", className: "text-sm mt-1", children: labels.noMessagesDesc ?? "Ask anything to get started" })] })) : null, messages.map((msg) => (_jsx(MessageBubble, { msg: msg }, msg.id))), isLoading ? (_jsx(Div, { className: "flex justify-start", children: _jsx(Div, { className: "rounded-2xl rounded-tl-sm bg-neutral-100 dark:bg-slate-700 px-4 py-2.5", children: _jsx(Span, { className: "text-sm opacity-60 animate-pulse", children: "Thinking..." }) }) })) : null, error ? (_jsx(Text, { className: "text-center text-sm text-red-500", children: labels.errorLabel ?? "An error occurred. Please try again." })) : null, _jsx("div", { ref: messagesEndRef })] }), _jsx(Div, { className: "border-t border-neutral-200 dark:border-slate-700 p-3", children: _jsxs("form", { onSubmit: handleSubmit, className: "flex gap-2", children: [_jsx("input", { type: "text", value: input, onChange: (event) => setInput(event.target.value), placeholder: labels.inputPlaceholder ?? "Ask anything...", disabled: isLoading, className: "flex-1 h-10 rounded-lg border border-neutral-200 dark:border-slate-600 bg-white dark:bg-slate-800 px-3 text-sm outline-none focus:ring-2 ring-primary/20 transition disabled:opacity-60" }), _jsx(Button, { type: "submit", variant: "primary", disabled: isLoading || !input.trim(), className: "shrink-0", children: isLoading ? labels.sendingButton ?? "Sending..." : labels.sendButton ?? "Send" })] }) })] }), _jsxs(Div, {
|
|
47
|
+
_jsxs(Div, { className: "grid grid-cols-1 lg:grid-cols-[2fr,1fr] gap-4", children: [_jsxs(Div, { className: "flex flex-col rounded-xl border border-neutral-200 dark:border-slate-700 bg-white dark:bg-slate-800/60 h-[calc(100vh-300px)]", children: [_jsx(Div, { className: "border-b border-neutral-200 dark:border-slate-700 p-3", children: _jsxs(Text, { className: "text-xs font-medium text-neutral-500 dark:text-zinc-400", children: [labels.conversationId ?? LBL_CONVERSATION_ID, ": ", conversationId] }) }), _jsxs(Div, { className: "flex-1 overflow-y-auto p-4 space-y-4", children: [messages.length === 0 ? (_jsxs(Div, { className: "flex flex-col items-center justify-center h-full text-center", children: [_jsx(Text, { className: "font-medium", children: labels.noMessages ?? "No messages yet" }), _jsx(Text, { variant: "secondary", className: "text-sm mt-1", children: labels.noMessagesDesc ?? "Ask anything to get started" })] })) : null, messages.map((msg) => (_jsx(MessageBubble, { msg: msg }, msg.id))), isLoading ? (_jsx(Div, { className: "flex justify-start", children: _jsx(Div, { className: "rounded-2xl rounded-tl-sm bg-neutral-100 dark:bg-slate-700 px-4 py-2.5", children: _jsx(Span, { className: "text-sm opacity-60 animate-pulse", children: "Thinking..." }) }) })) : null, error ? (_jsx(Text, { className: "text-center text-sm text-red-500", children: labels.errorLabel ?? "An error occurred. Please try again." })) : null, _jsx("div", { ref: messagesEndRef })] }), _jsx(Div, { className: "border-t border-neutral-200 dark:border-slate-700 p-3", children: _jsxs("form", { onSubmit: handleSubmit, className: "flex gap-2", children: [_jsx("input", { type: "text", value: input, onChange: (event) => setInput(event.target.value), placeholder: labels.inputPlaceholder ?? "Ask anything...", disabled: isLoading, className: "flex-1 h-10 rounded-lg border border-neutral-200 dark:border-slate-600 bg-white dark:bg-slate-800 px-3 text-sm outline-none focus:ring-2 ring-primary/20 transition disabled:opacity-60" }), _jsx(Button, { type: "submit", variant: "primary", disabled: isLoading || !input.trim(), className: "shrink-0", children: isLoading ? labels.sendingButton ?? "Sending..." : labels.sendButton ?? "Send" })] }) })] }), _jsxs(Div, { surface: "card", padding: "sm", className: "space-y-3", children: [_jsx(Heading, { level: 3, className: "text-sm font-semibold", children: labels.historyTitle ?? "Conversation History" }), _jsxs("form", { className: "space-y-2", onSubmit: (event) => {
|
|
48
48
|
event.preventDefault();
|
|
49
49
|
if (!conversationInput.trim())
|
|
50
50
|
return;
|
|
@@ -17,6 +17,7 @@ import { ROUTES } from "../../../next";
|
|
|
17
17
|
import { InteractiveProductCard } from "../../products/components/InteractiveProductCard";
|
|
18
18
|
import { DigitalCodeFilters } from "./DigitalCodeFilters";
|
|
19
19
|
import { ACTION_ID } from "../../products/constants/action-defs";
|
|
20
|
+
import { useBottomActions } from "../../layout";
|
|
20
21
|
const DEFAULT_SORT = sortBy(PRODUCT_FIELDS.CREATED_AT);
|
|
21
22
|
const SORT_OPTIONS = [
|
|
22
23
|
{ value: sortBy(PRODUCT_FIELDS.CREATED_AT), label: "Newest First" },
|
|
@@ -100,6 +101,7 @@ export function DigitalCodesIndexListing({ initialData }) {
|
|
|
100
101
|
wishlistActions.addToWishlist(id);
|
|
101
102
|
}
|
|
102
103
|
}
|
|
104
|
+
useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [] } } : {});
|
|
103
105
|
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search digital codes\u2026", onSearchChange: setSearchInput, onSearchCommit: commitSearch, onSearchKeyDown: (e) => { if (e.key === "Enter")
|
|
104
106
|
commitSearch(); }, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: (v) => { if (v !== "table")
|
|
105
107
|
setView(v); }, onResetAll: resetAll, hasActiveState: hasActiveState, bulkMode: selection.isSelecting, bulkSelectedCount: selection.selectedCount, bulkTotalCount: products.length, onBulkSelectAll: selection.toggleAll, onBulkClear: selection.clearSelection }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [] }), 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: page, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6", children: isLoading ? (_jsx("div", { className: gridClass, children: Array.from({ length: 10 }).map((_, i) => (_jsxs("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: [_jsx("div", { className: "aspect-square bg-zinc-200 dark:bg-slate-700" }), _jsxs("div", { className: "p-3 space-y-2", children: [_jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-1/3" })] })] }, i))) })) : products.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No digital code listings found." })) : (_jsx("div", { className: view === "list" ? "flex flex-col divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800" : gridClass, children: products.map((product) => (_jsx(InteractiveProductCard, { product: product, href: String(ROUTES.PUBLIC.DIGITAL_CODE_DETAIL(product.id)), variant: view === "list" ? "list" : "grid", isWishlisted: wishlistActions.isWishlisted(product.id), onToggleWishlist: handleToggleWishlist, selectable: selection.isSelecting, isSelected: selection.isSelected(product.id), onSelect: (id) => selection.toggle(id) }, product.id))) })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: onFilterClear, activeCount: filterActiveCount, hideTrigger: true, children: _jsx(DigitalCodeFilters, { table: pendingTable, categoryOptions: categoryOptions }) }), _jsx(LoginRequiredModal, { isOpen: modalOpen, onClose: closeModal, message: modalMessage })] }));
|
|
@@ -33,5 +33,5 @@ export async function DigitalCodesListView({ searchParams = {} }) {
|
|
|
33
33
|
const result = await productRepository
|
|
34
34
|
.list({ filters, sorts: sort, page, pageSize })
|
|
35
35
|
.catch(() => null);
|
|
36
|
-
return (_jsx(Main, { children: _jsx(Section, { className: "py-10", children: _jsxs(Container, { size: "xl", children: [_jsx(Heading, { level: 1, className: "mb-8 text-3xl font-semibold text-zinc-900", children: "Digital Codes" }), _jsx(AdSlot, { id: "listing-sidebar-top", className: "mb-6" }), _jsx(DigitalCodesIndexListing, { initialData: result ?? undefined }), _jsx(AdSlot, { id: "listing-sidebar-bottom", className: "mt-8" })] }) }) }));
|
|
36
|
+
return (_jsx(Main, { children: _jsx(Section, { className: "py-10", children: _jsxs(Container, { size: "xl", children: [_jsx(Heading, { level: 1, className: "mb-8 text-3xl font-semibold text-zinc-900 dark:text-zinc-50", children: "Digital Codes" }), _jsx(AdSlot, { id: "listing-sidebar-top", className: "mb-6" }), _jsx(DigitalCodesIndexListing, { initialData: result ?? undefined }), _jsx(AdSlot, { id: "listing-sidebar-bottom", className: "mt-8" })] }) }) }));
|
|
37
37
|
}
|
|
@@ -12,6 +12,7 @@ import { ADMIN_EVENT_STATUS_TABS } from "../../admin/constants/filter-tabs";
|
|
|
12
12
|
import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } from "../../admin/hooks/useAdminListingData";
|
|
13
13
|
import { DataTable } from "../../admin/components/DataTable";
|
|
14
14
|
import { AdminEventEditorView } from "./AdminEventEditorView";
|
|
15
|
+
import { useBottomActions } from "../../layout";
|
|
15
16
|
const PAGE_SIZE = 25;
|
|
16
17
|
const FILTER_KEYS = ["status", "type"];
|
|
17
18
|
const DEFAULT_SORT = "-startsAt";
|
|
@@ -102,7 +103,10 @@ export function AdminEventsView({ children, getRowHref, ...props }) {
|
|
|
102
103
|
if (hasChildren) {
|
|
103
104
|
return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
|
|
104
105
|
}
|
|
106
|
+
useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
|
|
107
|
+
{ id: "delete", label: "Delete Selected", variant: "secondary", onClick: () => { selection.clearSelection(); } },
|
|
108
|
+
] } } : {});
|
|
105
109
|
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search events by title or type", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: openCreatePanel, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), "Add Event"] }) }), _jsx(BulkActionBar, { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: [
|
|
106
110
|
{ id: "delete", label: "Delete Selected", variant: "secondary", onClick: () => { selection.clearSelection(); } },
|
|
107
|
-
] }), 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) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-
|
|
111
|
+
] }), 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) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx("div", { className: "mb-4 rounded-xl border border-red-200 bg-error-surface px-4 py-3 text-sm text-error dark:border-red-900/60", children: errorMessage })), view === "table" ? (_jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No events found", onRowClick: (row) => openEditPanel(row.id) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No events found", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: [_jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }), _jsx(FilterChipGroup, { label: "Type", tabs: TYPE_OPTIONS, value: pendingFilters.type ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, type: id })) })] }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] })), _jsx(SideDrawer, { isOpen: isCreateOpen || isEditOpen, onClose: closePanel, title: isCreateOpen ? "Add Event" : "Edit Event", mode: isCreateOpen ? "create" : "edit", children: (isCreateOpen || isEditOpen) && (_jsx(AdminEventEditorView, { eventId: editId ?? undefined, onSaved: closePanel, embedded: true })) })] }));
|
|
108
112
|
}
|
|
@@ -24,6 +24,6 @@ export function EventCard({ event, labels = {}, onParticipate, className = "", s
|
|
|
24
24
|
const msLeft = endsAt.getTime() - now.getTime();
|
|
25
25
|
const daysLeft = Math.max(0, Math.ceil(msLeft / (1000 * 60 * 60 * 24)));
|
|
26
26
|
const detailHref = String(ROUTES.PUBLIC.EVENT_DETAIL(event.slug ?? event.id));
|
|
27
|
-
return (_jsxs(Article, { className: `group relative flex h-full ${LAYOUT.cardHeight.event} flex-col overflow-hidden rounded-xl border bg-white shadow-sm transition-shadow hover:shadow-md dark:bg-slate-900 ${isSelected ? "border-primary outline outline-2 outline-primary" : "border-zinc-200 dark:border-slate-700"} ${className}`, onMouseDown: onSelect && !isSelected ? longPress.onMouseDown : undefined, onMouseUp: onSelect && !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: onSelect && !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: onSelect && !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: onSelect && !isSelected ? longPress.onTouchEnd : undefined, children: [onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (e) => { e.preventDefault(); onSelect(event.id, !isSelected); }, label: isSelected ? "Deselect event" : "Select event", position: "top-2 left-2", className: selectable || isSelected ? "opacity-100" : "opacity-0 group-hover:opacity-100 transition-opacity" })), _jsx(Link, { href: detailHref, className: "block flex-shrink-0", children: event.coverImageUrl ? (_jsx(Div, { className: "aspect-video overflow-hidden", children: _jsx(Div, { role: "img", "aria-label": safeTitle, className: "h-full w-full bg-cover bg-center transition-transform duration-300 group-hover:scale-105", style: { backgroundImage: `url(${event.coverImageUrl})` } }) })) : (_jsx(Div, { className: "aspect-video bg-gradient-to-br from-zinc-100 to-zinc-200 dark:from-slate-800 dark:to-slate-700 flex items-center justify-center", children: _jsx("span", { className: "text-5xl opacity-40", "aria-hidden": "true", children: TYPE_ICONS[event.type] }) })) }), _jsxs(Div, { className: "flex flex-1 flex-col p-4", children: [_jsxs(Div, { className: "flex items-start justify-between gap-2 mb-2", children: [_jsx(Span, { className: "text-lg", "aria-hidden": "true", children: TYPE_ICONS[event.type] }), _jsx(EventStatusBadge, { status: event.status })] }), _jsx(Link, { href: detailHref, className: "block", children: _jsx(Heading, { level: 3, className: "font-semibold text-gray-900 dark:text-zinc-100 text-base leading-snug mb-1 group-hover:text-primary transition-colors", children: safeTitle }) }), _jsx(RichText, { html: normalizeRichTextHtml(event.description ?? ""), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: `mb-3 ${THEME_CONSTANTS.utilities.textClamp3} text-sm text-zinc-600 dark:text-zinc-400` }), _jsxs(Div, { className: "mb-3 mt-auto flex items-center justify-between text-xs text-zinc-500 dark:text-zinc-
|
|
27
|
+
return (_jsxs(Article, { className: `group relative flex h-full ${LAYOUT.cardHeight.event} flex-col overflow-hidden rounded-xl border bg-white shadow-sm transition-shadow hover:shadow-md dark:bg-slate-900 ${isSelected ? "border-primary outline outline-2 outline-primary" : "border-zinc-200 dark:border-slate-700"} ${className}`, onMouseDown: onSelect && !isSelected ? longPress.onMouseDown : undefined, onMouseUp: onSelect && !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: onSelect && !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: onSelect && !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: onSelect && !isSelected ? longPress.onTouchEnd : undefined, children: [onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (e) => { e.preventDefault(); onSelect(event.id, !isSelected); }, label: isSelected ? "Deselect event" : "Select event", position: "top-2 left-2", className: selectable || isSelected ? "opacity-100" : "opacity-0 group-hover:opacity-100 transition-opacity" })), _jsx(Link, { href: detailHref, className: "block flex-shrink-0", children: event.coverImageUrl ? (_jsx(Div, { className: "aspect-video overflow-hidden", children: _jsx(Div, { role: "img", "aria-label": safeTitle, className: "h-full w-full bg-cover bg-center transition-transform duration-300 group-hover:scale-105", style: { backgroundImage: `url(${event.coverImageUrl})` } }) })) : (_jsx(Div, { className: "aspect-video bg-gradient-to-br from-zinc-100 to-zinc-200 dark:from-slate-800 dark:to-slate-700 flex items-center justify-center", children: _jsx("span", { className: "text-5xl opacity-40", "aria-hidden": "true", children: TYPE_ICONS[event.type] }) })) }), _jsxs(Div, { className: "flex flex-1 flex-col p-4", children: [_jsxs(Div, { className: "flex items-start justify-between gap-2 mb-2", children: [_jsx(Span, { className: "text-lg", "aria-hidden": "true", children: TYPE_ICONS[event.type] }), _jsx(EventStatusBadge, { status: event.status })] }), _jsx(Link, { href: detailHref, className: "block", children: _jsx(Heading, { level: 3, className: "font-semibold text-gray-900 dark:text-zinc-100 text-base leading-snug mb-1 group-hover:text-primary transition-colors", children: safeTitle }) }), _jsx(RichText, { html: normalizeRichTextHtml(event.description ?? ""), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: `mb-3 ${THEME_CONSTANTS.utilities.textClamp3} text-sm text-zinc-600 dark:text-zinc-400` }), _jsxs(Div, { className: "mb-3 mt-auto flex items-center justify-between text-xs text-zinc-500 dark:text-zinc-400", children: [event.status === EVENT_FIELDS.STATUS_VALUES.ACTIVE &&
|
|
28
28
|
daysLeft > 0 && _jsxs(Span, { children: ["\u23F1 ", daysLeft, "d remaining"] }), _jsxs(Span, { children: ["\uD83D\uDC65 ", event.stats.totalEntries, " ", labels.entries ?? "entries"] })] }), event.status === EVENT_FIELDS.STATUS_VALUES.ACTIVE && onParticipate ? (_jsx(Button, { type: "button", onClick: () => onParticipate(event), className: "w-full rounded-lg bg-primary py-2 text-sm font-medium text-white transition-colors hover:bg-primary-600", children: labels.participate ?? "Participate" })) : (_jsxs(TextLink, { href: detailHref, className: "inline-flex w-full items-center justify-center gap-1.5 rounded-lg border border-zinc-300 px-3 py-2 text-sm font-medium text-zinc-700 transition-colors hover:bg-zinc-100 dark:border-slate-600 dark:text-zinc-200 dark:hover:bg-slate-800", children: [labels.viewDetails ?? "View details", " \u2192"] }))] })] }));
|
|
29
29
|
}
|
|
@@ -56,13 +56,13 @@ export function EventPollWidget({ eventId, pollConfig, eventStatus, totalEntries
|
|
|
56
56
|
}
|
|
57
57
|
};
|
|
58
58
|
if (isEnded) {
|
|
59
|
-
return (_jsxs("div", { className: `rounded-xl border border-zinc-200 dark:border-zinc-700 px-5 py-4 space-y-3 ${className}`, "data-section": "eventpollwidget-div-1", children: [_jsx(Text, { className: "text-sm font-medium text-zinc-500 dark:text-zinc-400", children: "This poll has closed." }), totalEntries !== undefined && (_jsxs(Text, { className: "text-sm text-zinc-400 dark:text-zinc-
|
|
59
|
+
return (_jsxs("div", { className: `rounded-xl border border-zinc-200 dark:border-zinc-700 px-5 py-4 space-y-3 ${className}`, "data-section": "eventpollwidget-div-1", children: [_jsx(Text, { className: "text-sm font-medium text-zinc-500 dark:text-zinc-400", children: "This poll has closed." }), totalEntries !== undefined && (_jsxs(Text, { className: "text-sm text-zinc-400 dark:text-zinc-400", children: [totalEntries.toLocaleString(), " vote", totalEntries !== 1 ? "s" : "", " cast"] })), _jsx("div", { className: "space-y-2", "data-section": "eventpollwidget-div-2", children: pollConfig.options.map((opt) => (_jsx("div", { className: "rounded-lg border border-zinc-100 dark:border-zinc-800 px-4 py-2.5 text-sm text-zinc-600 dark:text-zinc-400", "data-section": "eventpollwidget-div-3", children: opt.label }, opt.id))) })] }));
|
|
60
60
|
}
|
|
61
61
|
if (pollConfig.requireLogin && !user) {
|
|
62
62
|
return (_jsxs("div", { className: `rounded-xl border border-zinc-200 dark:border-zinc-700 px-6 py-8 text-center space-y-3 ${className}`, "data-section": "eventpollwidget-div-4", children: [_jsx(Text, { className: "font-semibold text-zinc-900 dark:text-zinc-100", children: "Login to vote" }), _jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "You need an account to participate in this poll." }), _jsx("a", { href: String(ROUTES.AUTH.LOGIN), className: "inline-block rounded-xl bg-primary px-6 py-2.5 text-sm font-semibold text-white hover:bg-primary-600", children: "Log In" })] }));
|
|
63
63
|
}
|
|
64
64
|
if (isSubmitted) {
|
|
65
|
-
return (_jsxs("div", { className: `rounded-xl border border-green-200 dark:border-green-800 bg-
|
|
65
|
+
return (_jsxs("div", { className: `rounded-xl border border-green-200 dark:border-green-800 bg-success-surface px-6 py-8 text-center space-y-2 ${className}`, "data-section": "eventpollwidget-div-5", children: [_jsx(Text, { className: "font-semibold text-success", children: "Vote recorded!" }), _jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "Thanks for participating." })] }));
|
|
66
66
|
}
|
|
67
|
-
return (_jsxs("div", { className: `space-y-4 ${className}`, "data-section": "eventpollwidget-div-6", children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to vote in this poll. Please log in or create an account to continue." }), _jsx(Text, { className: "text-sm font-medium text-zinc-700 dark:text-zinc-200", children: isMulti ? "Select all that apply:" : "Choose one:" }), _jsx("div", { className: "space-y-2", "data-section": "eventpollwidget-div-7", children: pollConfig.options.map((opt) => (_jsxs("label", { className: "flex items-center gap-3 cursor-pointer rounded-lg border border-zinc-200 dark:border-zinc-700 px-4 py-3 hover:bg-zinc-50 dark:hover:bg-zinc-800 transition-colors", children: [_jsx("input", { type: isMulti ? "checkbox" : "radio", name: `poll-${eventId}`, value: opt.id, checked: selectedVotes.includes(opt.id), onChange: () => toggleVote(opt.id), className: "accent-primary" }), _jsx("span", { className: "text-sm text-zinc-700 dark:text-zinc-300", children: opt.label })] }, opt.id))) }), pollConfig.allowComment && (_jsx("textarea", { value: comment, onChange: (e) => setComment(e.target.value), placeholder: "Add a comment (optional)", rows: 3, className: "w-full rounded-lg border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-800 dark:text-zinc-200 placeholder:text-zinc-400 focus:outline-none focus:ring-2 focus:ring-primary" })), error && _jsx(Text, { className: "text-sm text-
|
|
67
|
+
return (_jsxs("div", { className: `space-y-4 ${className}`, "data-section": "eventpollwidget-div-6", children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to vote in this poll. Please log in or create an account to continue." }), _jsx(Text, { className: "text-sm font-medium text-zinc-700 dark:text-zinc-200", children: isMulti ? "Select all that apply:" : "Choose one:" }), _jsx("div", { className: "space-y-2", "data-section": "eventpollwidget-div-7", children: pollConfig.options.map((opt) => (_jsxs("label", { className: "flex items-center gap-3 cursor-pointer rounded-lg border border-zinc-200 dark:border-zinc-700 px-4 py-3 hover:bg-zinc-50 dark:hover:bg-zinc-800 transition-colors", children: [_jsx("input", { type: isMulti ? "checkbox" : "radio", name: `poll-${eventId}`, value: opt.id, checked: selectedVotes.includes(opt.id), onChange: () => toggleVote(opt.id), className: "accent-primary" }), _jsx("span", { className: "text-sm text-zinc-700 dark:text-zinc-300", children: opt.label })] }, opt.id))) }), pollConfig.allowComment && (_jsx("textarea", { value: comment, onChange: (e) => setComment(e.target.value), placeholder: "Add a comment (optional)", rows: 3, className: "w-full rounded-lg border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-800 dark:text-zinc-200 placeholder:text-zinc-400 focus:outline-none focus:ring-2 focus:ring-primary" })), error && _jsx(Text, { className: "text-sm text-error", children: error }), _jsx("button", { type: "button", onClick: handleSubmit, disabled: isLoading || selectedVotes.length === 0, className: "w-full rounded-xl bg-primary px-6 py-3 text-sm font-semibold text-white hover:bg-primary-600 disabled:opacity-60", children: isLoading ? "Submitting…" : "Submit Vote" })] }));
|
|
68
68
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Span } from "../../../ui";
|
|
3
3
|
const STATUS_MAP = {
|
|
4
|
-
draft: { label: "Draft", color: "bg-gray-100 text-gray-700" },
|
|
5
|
-
active: { label: "Active", color: "bg-
|
|
6
|
-
paused: { label: "Paused", color: "bg-
|
|
7
|
-
ended: { label: "Ended", color: "bg-
|
|
8
|
-
cancelled: { label: "Cancelled", color: "bg-
|
|
4
|
+
draft: { label: "Draft", color: "bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300" },
|
|
5
|
+
active: { label: "Active", color: "bg-success-surface text-success" },
|
|
6
|
+
paused: { label: "Paused", color: "bg-warning-surface text-warning" },
|
|
7
|
+
ended: { label: "Ended", color: "bg-error-surface text-error" },
|
|
8
|
+
cancelled: { label: "Cancelled", color: "bg-error-surface text-error" },
|
|
9
9
|
};
|
|
10
10
|
export function EventStatusBadge({ status, className = "", }) {
|
|
11
11
|
const { label, color } = STATUS_MAP[status] ?? STATUS_MAP.draft;
|
|
@@ -116,5 +116,5 @@ export function EventsIndexListing({ initialData }) {
|
|
|
116
116
|
const commitSearch = useCallback(() => {
|
|
117
117
|
table.set(TABLE_KEYS.QUERY, searchInput.trim());
|
|
118
118
|
}, [searchInput, table]);
|
|
119
|
-
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search events...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || sortBy(EVENT_FIELDS.STARTS_AT, "ASC"), sortOptions: EVENT_PUBLIC_SORT_OPTIONS, 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) => (_jsxs("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: [_jsx("div", { className: "aspect-video bg-zinc-200 dark:bg-slate-700" }), _jsxs("div", { className: "p-4 space-y-2", 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" }), _jsx("div", { className: "h-8 bg-zinc-200 dark:bg-slate-700 rounded mt-2" })] })] }, i))) })) : events.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No events 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: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })) : (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })) }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "flex items-center gap-2 text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close filters", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-
|
|
119
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search events...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || sortBy(EVENT_FIELDS.STARTS_AT, "ASC"), sortOptions: EVENT_PUBLIC_SORT_OPTIONS, 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) => (_jsxs("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: [_jsx("div", { className: "aspect-video bg-zinc-200 dark:bg-slate-700" }), _jsxs("div", { className: "p-4 space-y-2", 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" }), _jsx("div", { className: "h-8 bg-zinc-200 dark:bg-slate-700 rounded mt-2" })] })] }, i))) })) : events.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No events 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: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })) : (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })) }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "flex items-center gap-2 text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 dark:text-zinc-400 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close filters", className: "rounded-lg p-1.5 text-zinc-500 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4", children: _jsx(EventFilters, { table: pendingTable, variant: "public" }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
|
|
120
120
|
}
|
|
@@ -4,13 +4,13 @@ import { Div, Pagination, Text } from "../../../ui";
|
|
|
4
4
|
import { EventCard } from "./EventCard";
|
|
5
5
|
export function EventsListView({ events, isLoading, totalPages = 1, currentPage = 1, total = 0, onPageChange, onParticipate, emptyLabel = "No events found", slots, }) {
|
|
6
6
|
if (isLoading) {
|
|
7
|
-
return (_jsx(Div, { className: "grid gap-6 sm:grid-cols-2 lg:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Div, { className: "animate-pulse overflow-hidden rounded-xl border border-
|
|
7
|
+
return (_jsx(Div, { className: "grid gap-6 sm:grid-cols-2 lg:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Div, { className: "animate-pulse overflow-hidden rounded-xl border border-zinc-200 dark:border-zinc-700 bg-zinc-100 dark:bg-zinc-800", children: [_jsx(Div, { className: "aspect-video bg-zinc-200 dark:bg-zinc-700" }), _jsxs(Div, { className: "space-y-2 p-4", children: [_jsx(Div, { className: "h-4 w-16 rounded bg-zinc-200 dark:bg-zinc-700" }), _jsx(Div, { className: "h-5 w-full rounded bg-zinc-200 dark:bg-zinc-700" }), _jsx(Div, { className: "h-4 w-3/4 rounded bg-zinc-200 dark:bg-zinc-700" })] })] }, i))) }));
|
|
8
8
|
}
|
|
9
9
|
if (events.length === 0) {
|
|
10
10
|
if (slots?.renderEmptyState) {
|
|
11
11
|
return _jsx(_Fragment, { children: slots.renderEmptyState() });
|
|
12
12
|
}
|
|
13
|
-
return (_jsx(Text, { className: "py-12 text-center text-sm text-
|
|
13
|
+
return (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: emptyLabel }));
|
|
14
14
|
}
|
|
15
15
|
return (_jsxs(Div, { className: "space-y-8", children: [slots?.renderHeader
|
|
16
16
|
? slots.renderHeader({ total })
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useMemo, useState } from "react";
|
|
4
|
-
import { Button, ClaimCouponButton, Div, Heading, LoginRequiredModal, Span, Text } from "../../../ui";
|
|
4
|
+
import { Button, ClaimCouponButton, Div, Heading, LoginRequiredModal, Span, Text, useToast } from "../../../ui";
|
|
5
5
|
import { isAuthError } from "../../../utils/auth-error";
|
|
6
6
|
const DEFAULT_LABELS = {
|
|
7
7
|
heading: "Spin the Wheel",
|
|
@@ -22,6 +22,7 @@ export function SpinWheelView({ eventId, prizes, alreadyUsed, initialPrizeId, in
|
|
|
22
22
|
const [resultCoupon, setResultCoupon] = useState(initialCouponCode);
|
|
23
23
|
const [error, setError] = useState(null);
|
|
24
24
|
const [showLoginModal, setShowLoginModal] = useState(false);
|
|
25
|
+
const { showToast } = useToast();
|
|
25
26
|
const now = Date.now();
|
|
26
27
|
const startMs = windowStart ? new Date(windowStart).getTime() : null;
|
|
27
28
|
const endMs = windowEnd ? new Date(windowEnd).getTime() : null;
|
|
@@ -52,9 +53,10 @@ export function SpinWheelView({ eventId, prizes, alreadyUsed, initialPrizeId, in
|
|
|
52
53
|
}
|
|
53
54
|
else {
|
|
54
55
|
setError(l.errorFallback);
|
|
56
|
+
showToast(err instanceof Error ? err.message : l.errorFallback, "error");
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
|
-
}, [disabled, eventId, l.errorFallback, onSpin]);
|
|
59
|
+
}, [disabled, eventId, l.errorFallback, onSpin, showToast]);
|
|
58
60
|
const wonPrize = resultPrizeId
|
|
59
61
|
? activePrizes.find((p) => p.id === resultPrizeId)
|
|
60
62
|
: undefined;
|
|
@@ -67,5 +69,5 @@ export function SpinWheelView({ eventId, prizes, alreadyUsed, initialPrizeId, in
|
|
|
67
69
|
0% { transform: rotate(0deg); }
|
|
68
70
|
100% { transform: rotate(2160deg); }
|
|
69
71
|
}
|
|
70
|
-
` })] }), wonPrize ? (_jsxs(Div, { className: "rounded-xl border border-emerald-300 bg-
|
|
72
|
+
` })] }), wonPrize ? (_jsxs(Div, { className: "rounded-xl border border-emerald-300 bg-success-surface dark:border-emerald-700 p-4 text-center", children: [_jsx(Text, { className: "text-sm uppercase tracking-wide text-success", children: l.wonHeadline }), _jsx(Text, { className: "mt-1 text-lg font-bold text-emerald-900 dark:text-emerald-100", children: wonPrize.label }), resultCoupon ? (_jsxs(_Fragment, { children: [_jsxs(Text, { className: "mt-2 text-sm text-emerald-800 dark:text-emerald-200", children: [l.couponHint, " ", _jsx(Span, { className: "font-mono font-semibold", children: resultCoupon })] }), _jsx(Div, { className: "mt-3 flex justify-center", children: _jsx(ClaimCouponButton, { couponCode: resultCoupon, size: "sm", source: "spin" }) })] })) : null] })) : null, error ? (_jsx(Text, { className: "text-sm text-rose-600 dark:text-rose-400 text-center", children: error })) : null, _jsx(Div, { className: "flex justify-center", children: _jsx(Button, { variant: "primary", size: "lg", onClick: handleSpin, disabled: disabled, children: spinning ? l.spinningButton : l.spinButton }) }), alreadyUsed ? (_jsx(Text, { className: "text-center text-sm text-zinc-500 dark:text-zinc-400", children: l.alreadySpun })) : !inWindow ? (_jsx(Text, { className: "text-center text-sm text-zinc-500 dark:text-zinc-400", children: l.outsideWindow })) : null] }));
|
|
71
73
|
}
|
|
@@ -8,9 +8,9 @@ function FAQAccordionItem({ faq, isOpen, onToggle, renderExpandedFooter, }) {
|
|
|
8
8
|
export function FAQAccordion({ faqs, className = "", renderExpandedFooter, labels, }) {
|
|
9
9
|
const [openId, setOpenId] = useState(null);
|
|
10
10
|
if (faqs.length === 0 && labels?.noResults) {
|
|
11
|
-
return (_jsx(Div, {
|
|
11
|
+
return (_jsx(Div, { surface: "card", padding: "xl", className: "text-center", children: _jsx(Text, { className: "text-neutral-600 dark:text-zinc-300", children: labels.noResults }) }));
|
|
12
12
|
}
|
|
13
|
-
return (_jsx(Div, { className: `divide-y divide-neutral-100 dark:divide-slate-700
|
|
13
|
+
return (_jsx(Div, { surface: "card", className: `divide-y divide-neutral-100 dark:divide-slate-700 px-5 ${className}`, children: faqs.map((faq) => (_jsx(FAQAccordionItem, { faq: faq, isOpen: openId === faq.id, onToggle: () => setOpenId(openId === faq.id ? null : faq.id), renderExpandedFooter: renderExpandedFooter }, faq.id))) }));
|
|
14
14
|
}
|
|
15
15
|
export function FAQCategoryTabs({ categories, active, onSelect, labels = {}, }) {
|
|
16
16
|
return (_jsxs(Row, { wrap: true, gap: "sm", className: "scrollbar-none", children: [_jsx(Button, { onClick: () => onSelect(null), className: `rounded-full px-4 py-1.5 text-sm font-medium transition ${!active ? "bg-neutral-900 text-white" : "bg-neutral-100 dark:bg-slate-800 text-neutral-600 dark:text-zinc-300 hover:bg-neutral-200 dark:hover:bg-slate-700"}`, children: labels.all ?? "All" }), categories.map((cat) => (_jsx(Button, { onClick: () => onSelect(cat), className: `whitespace-nowrap rounded-full px-4 py-1.5 text-sm font-medium capitalize transition ${active === cat ? "bg-neutral-900 text-white" : "bg-neutral-100 dark:bg-slate-800 text-neutral-600 dark:text-zinc-300 hover:bg-neutral-200 dark:hover:bg-slate-700"}`, children: labels[cat] ?? cat.replace(/_/g, " ") }, cat)))] }));
|
|
@@ -58,8 +58,8 @@ export function AsyncFacetSection({ title, selected, onChange, loadOptions, sele
|
|
|
58
58
|
const selectedLabels = selected
|
|
59
59
|
.map((v) => labelMap.current.get(v) ?? v)
|
|
60
60
|
.slice(0, 3);
|
|
61
|
-
return (_jsxs(Div, { className: cn("p-4 border-b border-zinc-200 dark:border-slate-700 last:border-b-0", className), children: [_jsxs(Row, { gap: "xs", children: [_jsxs(Button, { type: "button", onClick: () => setCollapsed((c) => !c), variant: "ghost", size: "sm", className: "flex flex-1 items-center justify-between text-sm font-semibold text-zinc-900 dark:text-zinc-50 py-1 hover:opacity-80 transition-opacity", "aria-expanded": !collapsed, children: [_jsxs(Row, { as: Span, gap: "xs", children: [title, hasValue && (_jsx(Span, { className: "inline-flex items-center justify-center w-5 h-5 text-xs rounded-full bg-emerald-50 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300 ring-1 ring-emerald-600/20 dark:ring-emerald-400/20", children: selected.length }))] }), _jsx("svg", { className: cn("w-4 h-4 text-zinc-500 dark:text-zinc-400 transition-transform duration-200", collapsed ? "" : "rotate-180"), fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) })] }), onClear && hasValue && (_jsx(Button, { type: "button", onClick: onClear, variant: "ghost", size: "sm", className: "inline-flex items-center justify-center w-5 h-5 p-0 text-zinc-500 dark:text-zinc-400 hover:text-red-600 dark:hover:text-red-400 hover:bg-zinc-100 dark:hover:bg-slate-700 transition-colors rounded-full", "aria-label": "Clear filter", children: _jsx("svg", { className: "w-3 h-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }) }))] }), collapsed && hasValue && (_jsxs(Div, { className: "mt-2 flex flex-wrap gap-1", children: [selectedLabels.map((label) => (_jsx(Span, { className: "inline-flex items-center px-2 py-0.5 rounded-full text-xs bg-zinc-100 dark:bg-slate-700 text-zinc-700 dark:text-zinc-300 border border-zinc-200 dark:border-slate-600", children: label }, label))), selected.length > 3 && (_jsxs(Span, { className: "inline-flex items-center px-2 py-0.5 rounded-full text-xs text-zinc-400 dark:text-zinc-
|
|
61
|
+
return (_jsxs(Div, { className: cn("p-4 border-b border-zinc-200 dark:border-slate-700 last:border-b-0", className), children: [_jsxs(Row, { gap: "xs", children: [_jsxs(Button, { type: "button", onClick: () => setCollapsed((c) => !c), variant: "ghost", size: "sm", className: "flex flex-1 items-center justify-between text-sm font-semibold text-zinc-900 dark:text-zinc-50 py-1 hover:opacity-80 transition-opacity", "aria-expanded": !collapsed, children: [_jsxs(Row, { as: Span, gap: "xs", children: [title, hasValue && (_jsx(Span, { className: "inline-flex items-center justify-center w-5 h-5 text-xs rounded-full bg-emerald-50 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300 ring-1 ring-emerald-600/20 dark:ring-emerald-400/20", children: selected.length }))] }), _jsx("svg", { className: cn("w-4 h-4 text-zinc-500 dark:text-zinc-400 transition-transform duration-200", collapsed ? "" : "rotate-180"), fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) })] }), onClear && hasValue && (_jsx(Button, { type: "button", onClick: onClear, variant: "ghost", size: "sm", className: "inline-flex items-center justify-center w-5 h-5 p-0 text-zinc-500 dark:text-zinc-400 hover:text-red-600 dark:hover:text-red-400 hover:bg-zinc-100 dark:hover:bg-slate-700 transition-colors rounded-full", "aria-label": "Clear filter", children: _jsx("svg", { className: "w-3 h-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }) }))] }), collapsed && hasValue && (_jsxs(Div, { className: "mt-2 flex flex-wrap gap-1", children: [selectedLabels.map((label) => (_jsx(Span, { className: "inline-flex items-center px-2 py-0.5 rounded-full text-xs bg-zinc-100 dark:bg-slate-700 text-zinc-700 dark:text-zinc-300 border border-zinc-200 dark:border-slate-600", children: label }, label))), selected.length > 3 && (_jsxs(Span, { className: "inline-flex items-center px-2 py-0.5 rounded-full text-xs text-zinc-400 dark:text-zinc-400", children: ["+", selected.length - 3, " more"] }))] })), _jsx(Div, { className: "mt-2", children: _jsx(Input, { type: "search", placeholder: "Search\u2026", value: query, onChange: (e) => handleQueryChange(e.target.value), className: "w-full rounded-md border border-zinc-200 dark:border-slate-700 bg-white dark:bg-slate-800/60 px-2.5 py-1.5 text-xs text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-primary-500/20" }) }), !collapsed && (_jsxs(Div, { className: "mt-3 space-y-1", children: [options.map((opt) => {
|
|
62
62
|
const isSelected = selected.includes(opt.value);
|
|
63
|
-
return (_jsxs(Row, { gap: "2.5", className: "py-1 cursor-pointer group", children: [_jsx("input", { type: selectionMode === "single" ? "radio" : "checkbox", checked: isSelected, onChange: () => toggle(opt.value), "aria-label": opt.label, className: "flex-shrink-0 w-4 h-4 rounded border-zinc-300 dark:border-slate-600 cursor-pointer text-primary-600 dark:text-secondary-500" }), _jsx(Span, { className: "flex-1 text-sm text-zinc-700 dark:text-zinc-300 group-hover:text-zinc-900 dark:group-hover:text-zinc-100 transition-colors truncate", children: opt.label }), opt.count !== undefined && (_jsx(Span, { className: "text-xs text-zinc-400 dark:text-zinc-
|
|
64
|
-
}), options.length === 0 && !loading && (_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-
|
|
63
|
+
return (_jsxs(Row, { gap: "2.5", className: "py-1 cursor-pointer group", children: [_jsx("input", { type: selectionMode === "single" ? "radio" : "checkbox", checked: isSelected, onChange: () => toggle(opt.value), "aria-label": opt.label, className: "flex-shrink-0 w-4 h-4 rounded border-zinc-300 dark:border-slate-600 cursor-pointer text-primary-600 dark:text-secondary-500" }), _jsx(Span, { className: "flex-1 text-sm text-zinc-700 dark:text-zinc-300 group-hover:text-zinc-900 dark:group-hover:text-zinc-100 transition-colors truncate", children: opt.label }), opt.count !== undefined && (_jsx(Span, { className: "text-xs text-zinc-400 dark:text-zinc-400 tabular-nums flex-shrink-0", children: opt.count }))] }, opt.value));
|
|
64
|
+
}), options.length === 0 && !loading && (_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400 py-1", children: "No results" })), loading && (_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400 py-1 animate-pulse", children: "Loading\u2026" })), hasMore && !loading && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "w-full text-xs text-left text-zinc-400 dark:text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300 py-1", onClick: () => void load(query, page + 1), children: "Load more\u2026" }))] }))] }));
|
|
65
65
|
}
|