@mohasinac/appkit 2.8.1 → 2.8.3
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/classified/ClassifiedDetailView.js +7 -1
- package/dist/_internal/client/features/digital-code/CodeRevealPanel.js +4 -1
- package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.js +7 -1
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +3 -2
- package/dist/_internal/client/features/live/LiveItemDetailView.js +11 -2
- package/dist/_internal/client/scaffolds/AppShell.js +2 -1
- package/dist/_internal/client/scaffolds/DashboardScaffold.js +2 -1
- package/dist/_internal/server/features/checkout/actions.js +40 -39
- package/dist/_internal/shared/actions/action-registry.js +6 -0
- package/dist/_internal/shared/config/index.d.ts +1 -1
- package/dist/_internal/shared/config/schema.d.ts +0 -8
- package/dist/client-entry.d.ts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/configs/next.js +12 -22
- package/dist/constants/api-endpoints.d.ts +6 -0
- package/dist/constants/api-endpoints.js +2 -0
- package/dist/core/hooks/useSiteSettings.d.ts +1 -1
- package/dist/features/about/components/AboutView.js +5 -2
- package/dist/features/about/components/FAQPageView.js +3 -3
- package/dist/features/about/components/FeesView.js +13 -5
- package/dist/features/about/components/HelpPageView.js +9 -5
- package/dist/features/about/components/HowAuctionsWorkView.js +9 -5
- package/dist/features/about/components/HowCheckoutWorksView.js +9 -5
- package/dist/features/about/components/HowOffersWorkView.js +10 -5
- package/dist/features/about/components/HowOrdersWorkView.js +10 -5
- package/dist/features/about/components/HowPayoutsWorkView.js +9 -5
- package/dist/features/about/components/HowPreOrdersWorkView.js +9 -5
- package/dist/features/about/components/HowReviewsWorkView.js +9 -5
- package/dist/features/about/components/PolicyPageView.js +3 -3
- package/dist/features/about/components/PublicProfileView.js +11 -4
- package/dist/features/about/components/SecurityPrivacyView.js +8 -4
- package/dist/features/about/components/ShippingPolicyView.js +3 -2
- package/dist/features/about/components/TrackOrderView.js +2 -2
- package/dist/features/about/components/UnauthorizedView.js +3 -3
- package/dist/features/account/components/AddressBook.js +1 -1
- package/dist/features/account/components/AddressForm.js +2 -2
- package/dist/features/account/components/AddressInlineSelect.d.ts +24 -0
- package/dist/features/account/components/AddressInlineSelect.js +78 -0
- package/dist/features/account/components/AddressSelectorCreate.d.ts +2 -1
- package/dist/features/account/components/AddressSelectorCreate.js +5 -32
- package/dist/features/account/components/AddressesIndexListing.js +3 -3
- package/dist/features/account/components/ChatWindow.js +2 -1
- package/dist/features/account/components/NotificationBell.js +13 -7
- package/dist/features/account/components/NotificationPreferencesPanel.js +4 -1
- package/dist/features/account/components/UserOffersPanel.js +2 -1
- package/dist/features/account/components/UserSidebar.js +11 -7
- package/dist/features/account/components/UserSupportView.js +13 -4
- package/dist/features/account/components/index.d.ts +2 -0
- package/dist/features/account/components/index.js +1 -0
- package/dist/features/account/hooks/useAccount.d.ts +2 -2
- package/dist/features/account/hooks/useAddressSelector.d.ts +1 -1
- package/dist/features/account/hooks/useAddresses.d.ts +2 -2
- package/dist/features/account/hooks/useNotifications.d.ts +1 -1
- package/dist/features/account/hooks/useProfile.d.ts +1 -1
- package/dist/features/account/hooks/usePublicProfile.d.ts +2 -2
- package/dist/features/addresses/repository/addresses.repository.d.ts +1 -0
- package/dist/features/addresses/repository/addresses.repository.js +13 -0
- package/dist/features/admin/components/AdminAdEditorView.js +8 -5
- package/dist/features/admin/components/AdminAddressEditorView.js +5 -5
- package/dist/features/admin/components/AdminAdsView.js +10 -7
- package/dist/features/admin/components/AdminBlogEditorView.js +15 -9
- package/dist/features/admin/components/AdminBrandEditorView.js +10 -4
- package/dist/features/admin/components/AdminBrandsView.js +4 -4
- package/dist/features/admin/components/AdminBundleEditorView.js +4 -5
- package/dist/features/admin/components/AdminBundlesView.js +3 -3
- package/dist/features/admin/components/AdminCarouselEditorView.js +6 -3
- package/dist/features/admin/components/AdminCarouselView.js +6 -6
- package/dist/features/admin/components/AdminCatalogGuideView.js +2 -1
- package/dist/features/admin/components/AdminCategoriesView.js +5 -5
- package/dist/features/admin/components/AdminCategoryEditorView.js +11 -5
- package/dist/features/admin/components/AdminContactEditorView.js +8 -1
- package/dist/features/admin/components/AdminCouponEditorView.js +23 -5
- package/dist/features/admin/components/AdminEmployeeEditorView.js +7 -4
- package/dist/features/admin/components/AdminFaqEditorView.js +9 -3
- package/dist/features/admin/components/AdminFaqsView.js +4 -4
- package/dist/features/admin/components/AdminFeatureEditorView.js +7 -1
- package/dist/features/admin/components/AdminFeatureFlagsView.js +4 -1
- package/dist/features/admin/components/AdminFilterBar.js +4 -4
- package/dist/features/admin/components/AdminGroupedListingsView.js +65 -30
- package/dist/features/admin/components/AdminGuideHubView.js +4 -1
- package/dist/features/admin/components/AdminMediaView.js +4 -1
- package/dist/features/admin/components/AdminNavigationView.js +7 -4
- package/dist/features/admin/components/AdminNotificationsView.js +2 -2
- package/dist/features/admin/components/AdminOrderEditorView.js +2 -2
- package/dist/features/admin/components/AdminPageHeader.js +5 -2
- package/dist/features/admin/components/AdminPrizeDrawsView.js +5 -5
- package/dist/features/admin/components/AdminProductEditorView.js +12 -5
- package/dist/features/admin/components/AdminProductsView.js +4 -4
- package/dist/features/admin/components/AdminReviewsView.js +2 -2
- package/dist/features/admin/components/AdminScammerEditorView.js +6 -2
- package/dist/features/admin/components/AdminScammersView.js +3 -3
- package/dist/features/admin/components/AdminSectionsView.js +20 -22
- package/dist/features/admin/components/AdminSessionsManager.js +2 -1
- package/dist/features/admin/components/AdminSessionsView.js +2 -2
- package/dist/features/admin/components/AdminSidebar.js +11 -7
- package/dist/features/admin/components/AdminSiteConfigGuideView.js +2 -1
- package/dist/features/admin/components/AdminSiteSettingsView.js +5 -1
- package/dist/features/admin/components/AdminStoreAddressesView.js +2 -2
- package/dist/features/admin/components/AdminStoreEditorView.js +5 -5
- package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +3 -3
- package/dist/features/admin/components/AdminSupportTicketDetailView.js +10 -3
- package/dist/features/admin/components/AdminSupportTicketsView.js +3 -3
- package/dist/features/admin/components/AdminTrustGuideView.js +3 -3
- package/dist/features/admin/components/AdminUsersGuideView.js +3 -3
- package/dist/features/admin/components/AdminViewCards.js +12 -6
- package/dist/features/admin/components/BrandQuickCreateForm.js +2 -2
- package/dist/features/admin/components/CategoryQuickCreateForm.js +2 -2
- package/dist/features/admin/components/DashboardStats.js +9 -3
- package/dist/features/admin/components/DataListingView.js +3 -3
- package/dist/features/admin/components/DataTable.js +11 -7
- package/dist/features/admin/components/DrawerFormFooter.js +2 -2
- package/dist/features/admin/components/QuickEditMenu.js +2 -1
- package/dist/features/admin/components/analytics/AdminAnalyticsCharts.js +5 -1
- package/dist/features/admin/hooks/useAdmin.d.ts +1 -1
- package/dist/features/admin/hooks/useAdminSectionsListing.d.ts +1 -1
- package/dist/features/admin/hooks/useChat.d.ts +1 -1
- package/dist/features/auctions/components/AuctionBidsTable.js +4 -1
- package/dist/features/auctions/components/AuctionDetailPageView.js +14 -6
- package/dist/features/auctions/components/CollapsibleBidHistory.js +5 -1
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +9 -3
- package/dist/features/auctions/components/MarketplaceAuctionGrid.js +8 -2
- package/dist/features/auctions/components/PlaceBidFormClient.js +4 -1
- package/dist/features/auctions/hooks/useAuctions.d.ts +8 -8
- package/dist/features/auth/components/RegisterForm.js +2 -2
- package/dist/features/auth/components/VerifyEmailView.js +5 -2
- package/dist/features/auth/consent-otp.d.ts +2 -2
- package/dist/features/auth/hooks/useAuth.d.ts +2 -2
- package/dist/features/before-after/components/BeforeAfterSlider.js +1 -1
- package/dist/features/blog/components/BlogFeaturedCard.js +8 -1
- package/dist/features/blog/components/BlogIndexListing.js +11 -5
- package/dist/features/blog/components/BlogListView.js +11 -3
- package/dist/features/blog/components/BlogPostView.js +10 -3
- package/dist/features/cart/components/CartDrawer.js +11 -3
- package/dist/features/cart/components/CartSummary.js +2 -2
- package/dist/features/cart/components/CheckoutOtpModal.js +2 -1
- package/dist/features/cart/hooks/useCart.d.ts +1 -1
- package/dist/features/cart/hooks/useCartQuery.d.ts +1 -1
- package/dist/features/cart/hooks/useCheckoutReadQueries.d.ts +2 -2
- package/dist/features/cart/hooks/useOrder.d.ts +2 -2
- package/dist/features/categories/components/BrandDetailPageView.js +5 -2
- package/dist/features/categories/components/BrandDetailTabs.js +5 -1
- package/dist/features/categories/components/BundleDetailView.js +6 -3
- package/dist/features/categories/components/BundleDynamicRuleEditor.js +3 -1
- package/dist/features/categories/components/BundleItemsPicker.js +10 -3
- package/dist/features/categories/components/CategoriesIndexListing.js +12 -6
- package/dist/features/categories/components/CategoryBundlesListing.js +5 -2
- package/dist/features/categories/components/CategoryDetailPageView.js +6 -2
- package/dist/features/categories/components/CategoryDetailTabs.js +5 -1
- package/dist/features/categories/components/CategoryForm.js +6 -3
- package/dist/features/categories/components/CategoryGrid.js +9 -2
- package/dist/features/categories/components/CategoryProductsListing.js +10 -4
- package/dist/features/categories/components/CategorySelectorCreate.js +3 -3
- package/dist/features/categories/components/CategorySortSelect.js +1 -1
- package/dist/features/categories/components/CategoryStoresListing.js +3 -3
- package/dist/features/categories/components/CategoryTableColumns.js +10 -6
- package/dist/features/categories/components/CategoryTree.js +1 -1
- package/dist/features/categories/hooks/useCategories.d.ts +3 -3
- package/dist/features/categories/hooks/useCategorySelector.d.ts +3 -3
- package/dist/features/categories/hooks/useCategoryTree.d.ts +1 -1
- package/dist/features/checkout/hooks/useCheckoutApi.d.ts +2 -2
- package/dist/features/classified/components/ClassifiedFilters.js +2 -2
- package/dist/features/classified/components/ClassifiedIndexListing.js +9 -3
- package/dist/features/collections/components/CollectionCard.js +2 -1
- package/dist/features/collections/hooks/useCollections.d.ts +2 -2
- package/dist/features/contact/components/ContactForm.js +4 -2
- package/dist/features/contact/components/ContactInfoSidebar.js +4 -1
- package/dist/features/copilot/components/AdminCopilotView.js +13 -5
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +9 -3
- package/dist/features/events/components/AdminEventEditorView.js +62 -40
- package/dist/features/events/components/AdminEventEntriesView.js +9 -6
- package/dist/features/events/components/EventCard.js +7 -1
- package/dist/features/events/components/EventFormDrawer.js +2 -1
- package/dist/features/events/components/EventLeaderboard.js +4 -4
- package/dist/features/events/components/EventOfferCard.js +4 -1
- package/dist/features/events/components/EventParticipateView.js +3 -2
- package/dist/features/events/components/EventPollWidget.js +6 -5
- package/dist/features/events/components/EventRaffleEntryForm.js +5 -2
- package/dist/features/events/components/EventRaffleWinnerView.js +7 -1
- package/dist/features/events/components/EventRafflesSection.js +2 -2
- package/dist/features/events/components/EventSaleBanner.js +5 -2
- package/dist/features/events/components/EventsIndexListing.js +8 -2
- package/dist/features/events/components/EventsListView.js +4 -1
- package/dist/features/events/components/SpinWheelView.js +7 -2
- package/dist/features/events/hooks/useEvent.d.ts +3 -3
- package/dist/features/events/hooks/useEvents.d.ts +1 -1
- package/dist/features/events/schemas/firestore.d.ts +1 -0
- package/dist/features/events/types/index.d.ts +1 -0
- package/dist/features/faq/components/ContactCTA.js +4 -1
- package/dist/features/faq/components/FAQCategorySidebar.js +2 -2
- package/dist/features/faq/components/FAQHelpfulButtons.js +8 -5
- package/dist/features/faq/components/FAQPageContent.js +5 -5
- package/dist/features/faq/components/FAQSortDropdown.js +2 -2
- package/dist/features/faq/hooks/useFAQs.d.ts +1 -1
- package/dist/features/faq/hooks/useFaqList.d.ts +15 -15
- package/dist/features/filters/AsyncFacetSection.js +4 -2
- package/dist/features/filters/FilterFacetSection.js +14 -6
- package/dist/features/filters/RangeFilter.js +4 -2
- package/dist/features/filters/SwitchFilter.js +2 -1
- package/dist/features/forms/Checkbox.js +1 -1
- package/dist/features/forms/Radio.js +1 -1
- package/dist/features/forms/Slider.js +1 -1
- package/dist/features/homepage/components/AdSlot.js +4 -4
- package/dist/features/homepage/components/AdvertisementBanner.js +13 -4
- package/dist/features/homepage/components/AnnouncementBar.js +2 -1
- package/dist/features/homepage/components/BeforeAfterCard.js +8 -2
- package/dist/features/homepage/components/BrandsSection.js +6 -3
- package/dist/features/homepage/components/CTABannerSection.js +2 -2
- package/dist/features/homepage/components/CharacterHotspot.js +5 -2
- package/dist/features/homepage/components/CharacterHotspotForm.js +8 -4
- package/dist/features/homepage/components/CustomCardsSection.js +13 -7
- package/dist/features/homepage/components/CustomerReviewsSection.js +9 -3
- package/dist/features/homepage/components/FAQSection.js +7 -4
- package/dist/features/homepage/components/FeaturedBundlesSection.js +8 -2
- package/dist/features/homepage/components/FeaturedResultsSection.js +1 -1
- package/dist/features/homepage/components/GoogleReviewsSection.js +14 -8
- package/dist/features/homepage/components/HeroCarousel.js +1 -1
- package/dist/features/homepage/components/HomepageSkeleton.js +7 -1
- package/dist/features/homepage/components/HowItWorksInfoView.js +2 -2
- package/dist/features/homepage/components/HowItWorksSection.js +2 -2
- package/dist/features/homepage/components/NewsletterBanner.js +3 -2
- package/dist/features/homepage/components/NewsletterSection.js +5 -2
- package/dist/features/homepage/components/PromoGrid.js +4 -1
- package/dist/features/homepage/components/SectionCarousel.js +7 -4
- package/dist/features/homepage/components/SecurityHighlightsSection.js +3 -3
- package/dist/features/homepage/components/ShopByCategorySection.js +10 -4
- package/dist/features/homepage/components/SiteFeaturesSection.js +5 -2
- package/dist/features/homepage/components/SocialFeedSection.js +4 -4
- package/dist/features/homepage/components/SocialPostCard.js +6 -3
- package/dist/features/homepage/components/TrustFeaturesSection.js +5 -5
- package/dist/features/homepage/components/TrustIndicatorsSection.js +5 -2
- package/dist/features/homepage/components/WelcomeSection.js +1 -1
- package/dist/features/homepage/components/WhatsAppCommunitySection.js +3 -3
- package/dist/features/homepage/hooks/useBlogArticles.d.ts +1 -1
- package/dist/features/homepage/hooks/useFeaturedAuctions.d.ts +1 -1
- package/dist/features/homepage/hooks/useFeaturedPreOrders.d.ts +1 -1
- package/dist/features/homepage/hooks/useFeaturedProducts.d.ts +1 -1
- package/dist/features/homepage/hooks/useFeaturedStores.d.ts +1 -1
- package/dist/features/homepage/hooks/useHeroCarousel.d.ts +1 -1
- package/dist/features/homepage/hooks/useHomepageEvents.d.ts +1 -1
- package/dist/features/homepage/hooks/useHomepageReviews.d.ts +1 -1
- package/dist/features/homepage/hooks/useHomepageSections.d.ts +1 -1
- package/dist/features/homepage/hooks/useTopBrands.d.ts +1 -1
- package/dist/features/homepage/hooks/useTopCategories.d.ts +1 -1
- package/dist/features/layout/AppLayoutShell.js +2 -1
- package/dist/features/layout/BackToTop.js +1 -1
- package/dist/features/layout/BottomActions.js +4 -3
- package/dist/features/layout/BottomNavItem.js +1 -1
- package/dist/features/layout/BottomSheet.js +4 -1
- package/dist/features/layout/FooterLayout.js +1 -1
- package/dist/features/layout/NavbarLayout.js +4 -1
- package/dist/features/layout/SidebarLayout.js +5 -2
- package/dist/features/live/components/LiveItemFilters.js +2 -2
- package/dist/features/live/components/LiveItemsIndexListing.js +9 -3
- package/dist/features/loyalty/components/CoinsDisplay.js +4 -2
- package/dist/features/loyalty/hooks/useLoyaltyBalance.d.ts +1 -1
- package/dist/features/media/AvatarUpload.js +2 -2
- package/dist/features/media/MediaLightbox.js +3 -2
- package/dist/features/media/modals/VideoThumbnailSelector.js +4 -1
- package/dist/features/media/modals/VideoTrimModal.js +1 -1
- package/dist/features/media/upload/CameraCapture.js +1 -1
- package/dist/features/media/upload/ImageUpload.js +4 -1
- package/dist/features/media/upload/MediaUploadField.js +11 -2
- package/dist/features/media/upload/MediaUploadList.js +5 -1
- package/dist/features/orders/components/MarketplaceOrderCard.js +2 -2
- package/dist/features/orders/components/OrdersList.js +2 -1
- package/dist/features/orders/components/RefundHistoryTable.js +4 -1
- package/dist/features/orders/components/RefundRequestView.js +2 -1
- package/dist/features/orders/hooks/useOrders.d.ts +2 -2
- package/dist/features/payments/hooks/usePayments.d.ts +1 -1
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +5 -1
- package/dist/features/pre-orders/components/PreOrderActionsClient.js +3 -3
- package/dist/features/pre-orders/components/PreOrderBadge.js +2 -1
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +16 -7
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +32 -24
- package/dist/features/pre-orders/hooks/usePreOrders.d.ts +2 -2
- package/dist/features/products/columns/productTableColumns.js +9 -4
- package/dist/features/products/components/AuctionsIndexListing.js +9 -3
- package/dist/features/products/components/BidHistory.js +4 -4
- package/dist/features/products/components/CompareOverlay.js +10 -2
- package/dist/features/products/components/CustomFieldsEditor.js +2 -1
- package/dist/features/products/components/CustomSectionTabContent.js +2 -2
- package/dist/features/products/components/CustomSectionsEditor.js +3 -2
- package/dist/features/products/components/GroupSettingsPanel.js +34 -26
- package/dist/features/products/components/MakeOfferButton.js +6 -2
- package/dist/features/products/components/MakeOfferForm.js +2 -1
- package/dist/features/products/components/MarketplaceBundleCard.js +6 -3
- package/dist/features/products/components/MarketplacePrizeDrawCard.js +3 -2
- package/dist/features/products/components/PlaceBidForm.js +2 -1
- package/dist/features/products/components/PrizeDrawCollage.js +6 -2
- package/dist/features/products/components/PrizeDrawDetailPageView.js +6 -1
- package/dist/features/products/components/PrizeDrawItemsEditor.js +4 -2
- package/dist/features/products/components/PrizeDrawsIndexListing.js +6 -3
- package/dist/features/products/components/PrizeDrawsSection.js +2 -2
- package/dist/features/products/components/PrizeRevealModal.js +5 -1
- package/dist/features/products/components/ProductDetailPageView.js +32 -16
- package/dist/features/products/components/ProductFeatureBadges.js +9 -9
- package/dist/features/products/components/ProductForm.d.ts +11 -1
- package/dist/features/products/components/ProductForm.js +10 -5
- package/dist/features/products/components/ProductGalleryClient.js +8 -4
- package/dist/features/products/components/ProductGradingTab.js +4 -1
- package/dist/features/products/components/ProductGrid.js +35 -14
- package/dist/features/products/components/ProductInfo.js +2 -1
- package/dist/features/products/components/ProductTabs.js +2 -1
- package/dist/features/products/components/ProductTabsShell.js +5 -1
- package/dist/features/products/components/ProductsIndexListing.js +32 -24
- package/dist/features/products/components/ProductsIndexPageView.js +2 -2
- package/dist/features/products/components/RelatedProducts.js +3 -3
- package/dist/features/products/components/ShowGroupSection.js +10 -6
- package/dist/features/products/components/SublistingCarouselSection.js +7 -3
- package/dist/features/products/components/SublistingCategorySelect.d.ts +3 -1
- package/dist/features/products/components/SublistingCategorySelect.js +4 -37
- package/dist/features/products/constants/action-defs.js +3 -3
- package/dist/features/products/hooks/useProductDetail.d.ts +1 -1
- package/dist/features/products/hooks/useRelatedProducts.d.ts +1 -1
- package/dist/features/promotions/components/CouponCard.js +5 -3
- package/dist/features/promotions/components/CouponsIndexListing.js +7 -3
- package/dist/features/promotions/hooks/usePromotions.d.ts +2 -2
- package/dist/features/promotions/repository/coupons.repository.d.ts +8 -0
- package/dist/features/promotions/repository/coupons.repository.js +2 -0
- package/dist/features/reviews/components/ReviewDetailPageView.js +3 -3
- package/dist/features/reviews/components/ReviewDetailShell.js +15 -3
- package/dist/features/reviews/components/ReviewSummary.js +4 -2
- package/dist/features/reviews/components/ReviewsIndexListing.js +8 -2
- package/dist/features/reviews/components/ReviewsList.js +1 -1
- package/dist/features/reviews/hooks/useReviews.d.ts +2 -2
- package/dist/features/scams/components/ScamAwarenessModal.js +2 -2
- package/dist/features/scams/components/ScamProfileView.js +3 -3
- package/dist/features/scams/components/ScamRegistryView.js +6 -4
- package/dist/features/search/components/Search.js +9 -6
- package/dist/features/search/components/SearchFiltersRow.js +1 -1
- package/dist/features/search/components/SearchResultsSection.js +1 -1
- package/dist/features/search/hooks/useSearch.d.ts +2 -2
- package/dist/features/seller/components/CouponInlineSelect.d.ts +22 -0
- package/dist/features/seller/components/CouponInlineSelect.js +103 -0
- package/dist/features/seller/components/GroupInlineSelect.d.ts +23 -0
- package/dist/features/seller/components/GroupInlineSelect.js +80 -0
- package/dist/features/seller/components/PhysicalLocationModal.js +2 -1
- package/dist/features/seller/components/PrintCenterView.js +2 -1
- package/dist/features/seller/components/ProductInlineSelect.d.ts +24 -0
- package/dist/features/seller/components/ProductInlineSelect.js +42 -0
- package/dist/features/seller/components/QuickProductForm.js +4 -1
- package/dist/features/seller/components/SellerAddressesView.js +8 -3
- package/dist/features/seller/components/SellerAnalyticsAlertsView.js +6 -3
- package/dist/features/seller/components/SellerAnalyticsView.js +2 -2
- package/dist/features/seller/components/SellerBidsView.js +7 -7
- package/dist/features/seller/components/SellerBundlesView.js +2 -1
- package/dist/features/seller/components/SellerCouponEditorView.d.ts +2 -0
- package/dist/features/seller/components/SellerCouponEditorView.js +15 -3
- package/dist/features/seller/components/SellerCouponsView.js +1 -1
- package/dist/features/seller/components/SellerDashboardView.js +2 -2
- package/dist/features/seller/components/SellerDigitalCodesView.js +2 -2
- package/dist/features/seller/components/SellerGoogleReviewsView.js +2 -2
- package/dist/features/seller/components/SellerGroupedListingsView.js +5 -5
- package/dist/features/seller/components/SellerOrdersView.js +13 -10
- package/dist/features/seller/components/SellerPayoutMethodsView.js +5 -4
- package/dist/features/seller/components/SellerPayoutRequestView.js +5 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +5 -2
- package/dist/features/seller/components/SellerPreOrdersView.js +6 -6
- package/dist/features/seller/components/SellerPrizeDrawsView.js +6 -6
- package/dist/features/seller/components/SellerProductShell.js +1 -1
- package/dist/features/seller/components/SellerProductsCards.js +4 -1
- package/dist/features/seller/components/SellerProductsView.js +5 -5
- package/dist/features/seller/components/SellerReviewsView.js +7 -3
- package/dist/features/seller/components/SellerShippingConfigsView.js +4 -4
- package/dist/features/seller/components/SellerShippingView.js +1 -1
- package/dist/features/seller/components/SellerSidebar.js +15 -8
- package/dist/features/seller/components/SellerStoreCategoriesView.js +1 -1
- package/dist/features/seller/components/SellerStorefrontView.js +2 -2
- package/dist/features/seller/components/SellerTemplatesView.js +7 -4
- package/dist/features/seller/components/SublistingInlineSelect.d.ts +19 -0
- package/dist/features/seller/components/SublistingInlineSelect.js +83 -0
- package/dist/features/seller/components/analytics/SellerTopProducts.js +1 -1
- package/dist/features/seller/components/index.d.ts +8 -0
- package/dist/features/seller/components/index.js +4 -0
- package/dist/features/seller/hooks/useSellerPayouts.d.ts +3 -3
- package/dist/features/seller/hooks/useSellerStore.d.ts +6 -6
- package/dist/features/seller/hooks/useSellerStorefront.d.ts +2 -2
- package/dist/features/shell/FormShell.js +10 -2
- package/dist/features/shell/QuickFormDrawer.js +5 -5
- package/dist/features/shell/StepForm.js +6 -6
- package/dist/features/site-settings/components/ActionPermissionsManager.js +8 -4
- package/dist/features/site-settings/components/NavPermissionsManager.js +7 -4
- package/dist/features/stores/components/InteractiveStoreCard.js +5 -1
- package/dist/features/stores/components/StoreAboutView.js +4 -1
- package/dist/features/stores/components/StoreAddressSelectorCreate.d.ts +2 -1
- package/dist/features/stores/components/StoreAddressSelectorCreate.js +5 -31
- package/dist/features/stores/components/StoreAuctionsListing.js +6 -3
- package/dist/features/stores/components/StoreGuideHubView.js +5 -2
- package/dist/features/stores/components/StoreHeader.js +8 -1
- package/dist/features/stores/components/StorePreOrdersListing.js +6 -3
- package/dist/features/stores/components/StoreProductsListing.js +6 -3
- package/dist/features/stores/components/StoreReviewsListing.js +8 -2
- package/dist/features/stores/components/StoresIndexListing.js +12 -6
- package/dist/features/stores/hooks/useStoreAddressSelector.d.ts +1 -1
- package/dist/features/stores/hooks/useStores.d.ts +6 -6
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +7 -1
- package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +2 -1
- package/dist/features/wishlist/components/WishlistPage.js +2 -1
- package/dist/features/wishlist/hooks/useUserWishlist.d.ts +15 -15
- package/dist/features/wishlist/hooks/useWishlist.d.ts +1 -1
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +13 -1
- package/dist/next/components/GlobalError.js +2 -2
- package/dist/next/routing/route-map.d.ts +2 -0
- package/dist/next/routing/route-map.js +1 -0
- package/dist/providers/db-firebase/base.repository.d.ts +1 -1
- package/dist/react/ErrorBoundary.js +2 -2
- package/dist/seed/actions/demo-seed-actions.d.ts +1 -1
- package/dist/seed/manifest.js +10 -0
- package/dist/styles.css +2 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/DataTable.js +17 -16
- package/dist/ui/components/DateInput.js +2 -2
- package/dist/ui/components/DetailPageGallery.js +4 -1
- package/dist/ui/components/DetailPageTabs.js +6 -2
- package/dist/ui/components/ImageLightbox.js +5 -3
- package/dist/ui/components/Input.js +6 -3
- package/dist/ui/components/Layout.d.ts +4 -0
- package/dist/ui/components/Layout.js +1 -1
- package/dist/ui/components/Layout.style.css +1 -0
- package/dist/ui/components/ListingFilterDrawer.js +4 -1
- package/dist/ui/components/ListingLayout.js +9 -8
- package/dist/ui/components/ListingToolbar.js +5 -1
- package/dist/ui/components/PaginatedSelect.d.ts +1 -2
- package/dist/ui/components/PaginatedSelect.js +1 -2
- package/dist/ui/components/Radio.js +1 -1
- package/dist/ui/components/Select.js +2 -1
- package/dist/ui/components/Slider.js +1 -1
- package/dist/ui/components/VacationBanner.js +2 -1
- package/dist/ui/components/surface-tokens.d.ts +1 -0
- package/dist/ui/components/surface-tokens.js +1 -0
- package/package.json +22 -4
|
@@ -18,6 +18,10 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|
|
18
18
|
import { Button, Div, Heading, LoginRequiredModal, Modal, Span, Stack, Text, useToast } from "../../../ui";
|
|
19
19
|
import { isAuthError } from "../../../utils/auth-error";
|
|
20
20
|
import { PrizeDrawCollage } from "./PrizeDrawCollage";
|
|
21
|
+
const __P = {
|
|
22
|
+
p4: "p-4",
|
|
23
|
+
};
|
|
24
|
+
const CLS_REFUND_NOTE = "rounded border border-yellow-400/40 bg-yellow-50 px-4 py-3 text-yellow-900 dark:bg-yellow-900/30 dark:text-yellow-100";
|
|
21
25
|
const REVEAL_DURATION_MS = 3200; // total animation length
|
|
22
26
|
const CYCLE_INTERVAL_FAST = 80;
|
|
23
27
|
const CYCLE_INTERVAL_SLOW = 360;
|
|
@@ -143,7 +147,7 @@ export function PrizeRevealModal({ open, onClose, items, orderId, productId, onR
|
|
|
143
147
|
}, REVEAL_DURATION_MS);
|
|
144
148
|
}, [onReveal, orderId, phase, productId, startAnimation]);
|
|
145
149
|
const winnerImg = winner?.images?.[0];
|
|
146
|
-
return (_jsxs(Modal, { isOpen: open, onClose: onClose, title: "Prize Reveal", size: "lg", children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to reveal your prize. Please log in or create an account to continue." }), _jsxs(Stack, { gap: "md", children: [phase === "refunded" ? (_jsxs(Div, { className:
|
|
150
|
+
return (_jsxs(Modal, { isOpen: open, onClose: onClose, title: "Prize Reveal", size: "lg", children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to reveal your prize. Please log in or create an account to continue." }), _jsxs(Stack, { gap: "md", children: [phase === "refunded" ? (_jsxs(Div, { className: CLS_REFUND_NOTE, children: [_jsx(Heading, { level: 3, className: "mb-1", children: "Pool exhausted \u2014 you've been refunded" }), _jsx(Text, { className: "text-sm", children: "Every prize in this draw was already claimed by the time your entry rolled. Your order has been marked refunded automatically." })] })) : null, phase === "error" ? (_jsxs(Div, { className: "rounded border border-error/40 bg-error-surface px-4 py-3 text-error", children: [_jsx(Text, { className: "text-sm font-semibold", children: "Something went wrong" }), _jsx(Text, { className: "text-sm", children: errorMessage })] })) : null, _jsx(PrizeDrawCollage, { items: items, hideWonState: true, highlightItemNumber: highlight }), phase === "idle" ? (_jsx(Button, { type: "button", variant: "primary", size: "lg", onClick: handleRevealClick, children: "\u2728 Reveal my prize" })) : null, phase === "revealing" ? (_jsxs(Div, { className: `rounded bg-[var(--appkit-color-surface-muted)] ${__P.p4} text-center`, children: [_jsx(Text, { className: "text-lg font-semibold", children: "Rolling\u2026" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "The winner was locked by the server before this animation started. Hang tight \u2014 we're just making it look pretty." })] })) : null, phase === "won" && winner ? (_jsxs(Div, { className: `rounded-lg border-2 border-[var(--appkit-color-primary)] bg-[var(--appkit-color-surface)] ${__P.p4} text-center`, children: [_jsx(Text, { className: "text-xs uppercase tracking-wider text-[var(--appkit-color-text-muted)]", children: "You won" }), _jsxs(Heading, { level: 2, className: "my-2", children: ["#", winner.itemNumber, " \u2014 ", winner.title] }), winnerImg ? (
|
|
147
151
|
/* eslint-disable-next-line @next/next/no-img-element */
|
|
148
152
|
_jsx("img", { src: winnerImg, alt: winner.title, className: "mx-auto max-h-64 rounded" })) : null, winner.estimatedValue != null ? (_jsxs(Text, { className: "mt-2 text-sm text-[var(--appkit-color-text-muted)]", children: ["Estimated value: \u20B9", (winner.estimatedValue / 100).toLocaleString("en-IN")] })) : null] })) : null, _jsxs(Div, { className: "rounded border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-muted)] px-3 py-2 text-xs text-[var(--appkit-color-text-muted)]", children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Fairness guarantee:" }), " ", "Winners are picked by ", _jsx("code", { children: "crypto.randomInt" }), " running on LetItRip's server before the animation starts. The animation is theatrical \u2014 neither the store nor LetItRip staff can influence the outcome.", " ", effectiveRngUrl ? (_jsx("a", { href: effectiveRngUrl, target: "_blank", rel: "noreferrer noopener", className: "underline", children: "View RNG source code \u2192" })) : null] })] })] }));
|
|
149
153
|
}
|
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import Link from "next/link";
|
|
3
3
|
import { productRepository, reviewRepository } from "../../../repositories";
|
|
4
|
+
const __P = {
|
|
5
|
+
p3: "p-3",
|
|
6
|
+
p5: "p-5",
|
|
7
|
+
};
|
|
4
8
|
const CLS_BREADCRUMB_LINK = "hover:text-primary-600 transition-colors";
|
|
5
9
|
const ACTION_NOT_WIRED = "Action not wired";
|
|
10
|
+
const CLS_STAR_FULL = "text-yellow-400 text-sm";
|
|
11
|
+
const CLS_STAR_HALF = "text-yellow-300 text-sm";
|
|
12
|
+
const CLS_STAR_EMPTY = "text-zinc-300 dark:text-zinc-600 text-sm";
|
|
13
|
+
const CLS_STOCK_IN = "bg-emerald-50 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400";
|
|
14
|
+
const CLS_STOCK_OUT = "bg-red-50 text-red-700 dark:bg-red-900/30 dark:text-red-400";
|
|
15
|
+
const CLS_BUNDLE_PILL = "inline-flex items-center gap-1 rounded-full border border-teal-300 bg-teal-50 px-2.5 py-1 text-xs font-semibold text-teal-700 transition-colors hover:border-teal-500 hover:bg-teal-100 dark:border-teal-800/60 dark:bg-teal-900/30 dark:text-teal-300 dark:hover:border-teal-600 dark:hover:bg-teal-900/50";
|
|
16
|
+
const CLS_DISCOUNT_BADGE = "rounded-full bg-red-500 px-2 py-0.5 text-white";
|
|
17
|
+
const CLS_FREE_SHIPPING_ICON = "mt-0.5 flex-shrink-0 text-emerald-500";
|
|
18
|
+
const CLS_BUNDLE_BOX = "rounded-xl border border-teal-200 dark:border-teal-800/60 bg-teal-50/60 dark:bg-teal-900/20 p-5";
|
|
19
|
+
const CLS_BUNDLE_ICON = "text-teal-600 dark:text-teal-400";
|
|
20
|
+
const CLS_BUNDLE_TITLE = "text-sm font-semibold text-teal-800 dark:text-teal-200";
|
|
21
|
+
const CLS_BUNDLE_ROW = "flex items-center justify-between gap-4 rounded-lg border border-teal-200 dark:border-teal-800/50 bg-white dark:bg-teal-900/30 px-4 py-3";
|
|
22
|
+
const CLS_BUNDLE_LABEL = "text-xs text-teal-600 dark:text-teal-400 font-medium uppercase tracking-wide mb-0.5";
|
|
23
|
+
const CLS_BUNDLE_CTA = "flex-shrink-0 rounded-lg bg-teal-600 hover:bg-teal-700 px-3 py-1.5 text-xs font-semibold text-white transition-colors";
|
|
6
24
|
import { ROUTES } from "../../../next";
|
|
7
25
|
import { getDefaultCurrency } from "../../../core/baseline-resolver";
|
|
8
|
-
import { Button, Container, Div, Heading, Main, RichText, Row, Section, Span, Stack, Text, } from "../../../ui";
|
|
26
|
+
import { Button, Container, Div, Heading, Main, Nav, RichText, Row, Section, Span, Stack, Text, Ul, Ol, Li, Dl, Dt, Dd, } from "../../../ui";
|
|
9
27
|
import { normalizeRichTextHtml } from "../../../utils/string.formatter";
|
|
10
28
|
import { formatCurrency } from "../../../utils/number.formatter";
|
|
11
29
|
import { safeDisplayName } from "../../../security";
|
|
@@ -80,10 +98,10 @@ function StarRating({ value }) {
|
|
|
80
98
|
const full = Math.floor(value);
|
|
81
99
|
const half = value - full >= 0.5;
|
|
82
100
|
return (_jsx(Row, { align: "center", gap: "xs", children: Array.from({ length: 5 }).map((_, i) => (_jsx(Span, { className: i < full
|
|
83
|
-
?
|
|
101
|
+
? CLS_STAR_FULL
|
|
84
102
|
: i === full && half
|
|
85
|
-
?
|
|
86
|
-
:
|
|
103
|
+
? CLS_STAR_HALF
|
|
104
|
+
: CLS_STAR_EMPTY, children: "\u2605" }, i))) }));
|
|
87
105
|
}
|
|
88
106
|
// ---------------------------------------------------------------------------
|
|
89
107
|
// Component
|
|
@@ -232,7 +250,7 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
|
|
|
232
250
|
price: product.price,
|
|
233
251
|
storeId: product.storeId,
|
|
234
252
|
storeName: product.storeName,
|
|
235
|
-
} }), _jsxs(Container, { size: "xl", className: "px-4 py-6", children: [_jsx(ProductDetailView, { renderBreadcrumb: () => (_jsxs(
|
|
253
|
+
} }), _jsxs(Container, { size: "xl", className: "px-4 py-6", children: [_jsx(ProductDetailView, { renderBreadcrumb: () => (_jsxs(Div, { className: "mb-4 flex items-center justify-between flex-wrap gap-2", children: [_jsxs(Nav, { "aria-label": "Breadcrumb", className: "flex items-center gap-1.5 text-xs text-zinc-500 dark:text-zinc-400 flex-wrap", children: [_jsx(Link, { href: String(ROUTES.HOME), className: CLS_BREADCRUMB_LINK, children: "Home" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.PRODUCTS), className: CLS_BREADCRUMB_LINK, children: "Products" }), category && (_jsxs(_Fragment, { children: [_jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(category)), className: CLS_BREADCRUMB_LINK, children: categoryName || category })] })), subcategory && (_jsxs(_Fragment, { children: [_jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Span, { className: "capitalize", children: subcategory })] }))] }), _jsx(ShareButton, { title: title || undefined })] })), renderGallery: () => (_jsx(ProductGalleryClient, { images: images, productName: title || undefined })), renderInfo: () => (_jsxs(Stack, { gap: "md", children: [_jsxs(Div, { children: [condition && (_jsx(Span, { size: "xs", weight: "medium", className: "mb-2 inline-block rounded-full bg-zinc-100 dark:bg-zinc-800 px-2.5 py-0.5 capitalize text-zinc-600 dark:text-zinc-300", children: condition === "new"
|
|
236
254
|
? "Brand New"
|
|
237
255
|
: condition === "like_new"
|
|
238
256
|
? "Like New"
|
|
@@ -240,15 +258,13 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
|
|
|
240
258
|
? "Refurbished"
|
|
241
259
|
: condition === "used"
|
|
242
260
|
? "Used"
|
|
243
|
-
: condition })), _jsx(Heading, { level: 1, className: "text-xl font-bold leading-snug text-zinc-900 dark:text-zinc-50 sm:text-2xl", children: title || "Untitled Product" })] }), avgRating !== null ? (_jsxs(Row, { align: "center", gap: "sm", children: [_jsx(StarRating, { value: avgRating }), _jsxs(Span, {
|
|
261
|
+
: condition })), _jsx(Heading, { level: 1, className: "text-xl font-bold leading-snug text-zinc-900 dark:text-zinc-50 sm:text-2xl", children: title || "Untitled Product" })] }), avgRating !== null ? (_jsxs(Row, { align: "center", gap: "sm", children: [_jsx(StarRating, { value: avgRating }), _jsxs(Span, { size: "sm", className: "text-zinc-600 dark:text-zinc-400", children: [avgRating.toFixed(1), reviewCount ? ` (${reviewCount} reviews)` : ""] }), _jsxs(Span, { size: "xs", weight: "medium", className: `ml-auto rounded-full px-2.5 py-0.5 ${inStock
|
|
244
262
|
? "bg-success-surface text-success"
|
|
245
263
|
: "bg-error-surface text-error"}`, children: [inStock ? "✓ In Stock" : "✗ Out of Stock", inStock && effectiveStock !== null && effectiveStock <= 10
|
|
246
264
|
? ` — only ${effectiveStock} left`
|
|
247
|
-
: ""] })] })) : (_jsxs(Span, { className: `inline-flex w-fit items-center gap-1.5 rounded-full px-3 py-1 text-xs font-medium ${inStock
|
|
248
|
-
? "bg-emerald-50 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400"
|
|
249
|
-
: "bg-red-50 text-red-700 dark:bg-red-900/30 dark:text-red-400"}`, children: [inStock ? "✓ In Stock" : "✗ Out of Stock", inStock && effectiveStock !== null && effectiveStock <= 10
|
|
265
|
+
: ""] })] })) : (_jsxs(Span, { className: `inline-flex w-fit items-center gap-1.5 rounded-full px-3 py-1 text-xs font-medium ${inStock ? CLS_STOCK_IN : CLS_STOCK_OUT}`, children: [inStock ? "✓ In Stock" : "✗ Out of Stock", inStock && effectiveStock !== null && effectiveStock <= 10
|
|
250
266
|
? ` — only ${effectiveStock} left`
|
|
251
|
-
: ""] })), (categorySlugs.length > 0 || subcategory || brand) && (_jsxs(Row, { gap: "sm", wrap: true, children: [categorySlugs.map((slug, i) => (_jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(slug)), className: "inline-flex items-center rounded-full border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-xs font-medium text-zinc-600 dark:text-zinc-300 transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: categoryNames[i] ?? slug }, slug))), subcategory && (_jsx(Span, { className: "inline-flex items-center rounded-full border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-
|
|
267
|
+
: ""] })), (categorySlugs.length > 0 || subcategory || brand) && (_jsxs(Row, { gap: "sm", wrap: true, children: [categorySlugs.map((slug, i) => (_jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(slug)), className: "inline-flex items-center rounded-full border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-xs font-medium text-zinc-600 dark:text-zinc-300 transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: categoryNames[i] ?? slug }, slug))), subcategory && (_jsx(Span, { size: "xs", weight: "medium", className: "inline-flex items-center rounded-full border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-zinc-500 dark:text-zinc-400 capitalize", children: subcategory })), brand && brandSlug && (_jsx(Link, { href: String(ROUTES.PUBLIC.BRAND_DETAIL(brandSlug)), className: "inline-flex items-center rounded-full border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-xs font-medium text-zinc-600 dark:text-zinc-300 transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: brand })), brand && !brandSlug && (_jsx(Span, { size: "xs", weight: "medium", className: "inline-flex items-center rounded-full border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-800/50 px-2.5 py-1 text-zinc-500 dark:text-zinc-400", children: brand }))] })), bundleMemberships.length > 0 && (_jsx(Row, { gap: "sm", wrap: true, children: bundleMemberships.map((b) => (_jsxs(Link, { href: String(ROUTES.PUBLIC.BUNDLE_DETAIL(b.id)), className: CLS_BUNDLE_PILL, children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83D\uDCE6" }), "In bundle: ", b.title] }, b.id))) })), _jsx(ProductFeatureBadges, { featured: featured, freeShipping: freeShipping, condition: condition ?? undefined, returnable: returnPolicy != null && returnPolicy.length > 0, labels: {
|
|
252
268
|
featured: "Featured",
|
|
253
269
|
fasterDelivery: "Faster Delivery",
|
|
254
270
|
ratedSeller: "Rated Seller",
|
|
@@ -262,9 +278,9 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
|
|
|
262
278
|
codAvailable: "Cash on Delivery",
|
|
263
279
|
wishlistCount: (n) => `${n} wishlisted`,
|
|
264
280
|
categoryProductCount: (n, cat) => `${n} in ${cat}`,
|
|
265
|
-
} }), productFeatures && features.length > 0 && (_jsx(FeatureBadgeList, { productFeatureIds: features, features: productFeatures })), !productFeatures && features.length > 0 && (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 px-4 py-3", children: [_jsx(Text, { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "About this product" }), _jsx(
|
|
281
|
+
} }), productFeatures && features.length > 0 && (_jsx(FeatureBadgeList, { productFeatureIds: features, features: productFeatures })), !productFeatures && features.length > 0 && (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 px-4 py-3", children: [_jsx(Text, { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "About this product" }), _jsx(Ul, { className: "space-y-1.5", children: features.map((f, i) => (_jsxs(Li, { className: "flex items-start gap-2 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-primary-500", children: "\u2022" }), f] }, i))) })] })), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-sm leading-relaxed text-zinc-600 dark:text-zinc-400 line-clamp-4" })), safeSeller && (_jsx(Div, { className: `rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 ${__P.p3}`, children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] uppercase tracking-wide text-zinc-400 dark:text-zinc-400 mb-0.5", children: "Sold by" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-800 dark:text-zinc-200", children: safeSeller }), typeof p.storeRating === "number" && p.storeRating > 0 && (_jsx(Row, { gap: "xs", align: "center", className: "mt-0.5", children: _jsxs(Text, { size: "xs", color: "muted", children: [_jsx("span", { className: "text-warning", "aria-hidden": "true", children: "\u2605" }), " ", p.storeRating.toFixed(1), typeof p.storeReviewCount === "number" &&
|
|
266
282
|
p.storeReviewCount > 0 &&
|
|
267
|
-
` · ${p.storeReviewCount} reviews`] }) }))] }), storeHref && (_jsx(Link, { href: storeHref, className: "shrink-0 rounded-lg bg-primary/10 dark:bg-primary/20 px-3 py-1.5 text-xs font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] }) }))] })), renderActions: () => (_jsxs(Div, { className:
|
|
283
|
+
` · ${p.storeReviewCount} reviews`] }) }))] }), storeHref && (_jsx(Link, { href: storeHref, className: "shrink-0 rounded-lg bg-primary/10 dark:bg-primary/20 px-3 py-1.5 text-xs font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] }) }))] })), renderActions: () => (_jsxs(Div, { className: `rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 ${__P.p5} space-y-4`, children: [formattedPrice && (_jsxs(Div, { children: [_jsxs(Row, { align: "baseline", gap: "sm", wrap: true, children: [_jsx(Text, { className: "text-2xl font-bold text-zinc-900 dark:text-zinc-50", children: formattedPrice }), formattedOriginal && discount && (_jsxs(_Fragment, { children: [_jsx(Span, { size: "sm", className: "text-zinc-400 line-through dark:text-zinc-400", children: formattedOriginal }), _jsxs(Span, { size: "xs", weight: "bold", className: CLS_DISCOUNT_BADGE, children: ["-", discount, "%"] })] }))] }), inStock && effectiveStock !== null && effectiveStock <= 10 && (_jsxs(Text, { className: "mt-1 text-xs text-warning", children: ["Only ", effectiveStock, " left \u2014 order soon!"] }))] })), _jsxs(Stack, { gap: "sm", children: [renderPrimaryActions ? (renderPrimaryActions({
|
|
268
284
|
productId: product.id,
|
|
269
285
|
productSlug: product.slug ?? slug,
|
|
270
286
|
productTitle: product.title,
|
|
@@ -280,20 +296,20 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
|
|
|
280
296
|
price,
|
|
281
297
|
currency,
|
|
282
298
|
minOfferPercent,
|
|
283
|
-
})] }), (shippingInfo || returnPolicy || freeShipping) && (_jsxs(Div, { className: "border-t border-zinc-200 dark:border-zinc-700 pt-4 space-y-2.5", children: [freeShipping && (_jsxs(Row, { align: "start", gap: "sm", children: [_jsx(Span, { className:
|
|
299
|
+
})] }), (shippingInfo || returnPolicy || freeShipping) && (_jsxs(Div, { className: "border-t border-zinc-200 dark:border-zinc-700 pt-4 space-y-2.5", children: [freeShipping && (_jsxs(Row, { align: "start", gap: "sm", children: [_jsx(Span, { className: CLS_FREE_SHIPPING_ICON, children: "\uD83D\uDE9A" }), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs font-medium text-zinc-700 dark:text-zinc-300", children: "Free Delivery" }), shippingInfo && (_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: shippingInfo }))] })] })), !freeShipping && shippingInfo && (_jsxs(Row, { align: "start", gap: "sm", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-zinc-400", children: "\uD83D\uDCE6" }), _jsx(Text, { className: "text-xs text-zinc-600 dark:text-zinc-400", children: shippingInfo })] })), returnPolicy && (_jsxs(Row, { align: "start", gap: "sm", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-zinc-400", children: "\u21BA" }), _jsx(Text, { className: "text-xs text-zinc-600 dark:text-zinc-400", children: returnPolicy })] }))] })), tags.length > 0 && (_jsxs(Div, { className: "border-t border-zinc-200 dark:border-zinc-700 pt-4", children: [_jsx(Text, { className: "mb-2 text-xs font-medium text-zinc-500 dark:text-zinc-400", children: "Tags" }), _jsx(Row, { wrap: true, gap: "xs", children: tags.map((tag) => (_jsx(Span, { className: "rounded-full bg-zinc-100 dark:bg-zinc-800 px-2.5 py-1 text-xs text-zinc-600 dark:text-zinc-300", children: tag }, tag))) })] })), _jsx(Div, { className: "border-t border-zinc-200 dark:border-zinc-700 pt-4", children: _jsx(Row, { wrap: true, gap: "sm", justify: "center", className: "text-center", children: [
|
|
284
300
|
{ icon: "🔒", label: "Secure\nPayment" },
|
|
285
301
|
{ icon: "✓", label: "Verified\nSeller" },
|
|
286
302
|
{ icon: "⭐", label: "Quality\nGuarantee" },
|
|
287
|
-
].map(({ icon, label }) => (_jsxs(Div, { className: "flex flex-col items-center gap-1 text-xs text-zinc-500 dark:text-zinc-400 min-w-[60px]", children: [_jsx(Span, {
|
|
303
|
+
].map(({ icon, label }) => (_jsxs(Div, { className: "flex flex-col items-center gap-1 text-xs text-zinc-500 dark:text-zinc-400 min-w-[60px]", children: [_jsx(Span, { size: "base", children: icon }), _jsx(Span, { className: "whitespace-pre-line leading-tight", children: label })] }, label))) }) })] })), renderSublistingSection: sublistingCategoryId
|
|
288
304
|
? () => (_jsx(SublistingCarouselSection, { sublistingCategoryId: sublistingCategoryId, currentListingId: String(product.id) }))
|
|
289
305
|
: undefined, renderGroupSection: groupId
|
|
290
306
|
? () => (_jsx(ShowGroupSection, { groupId: groupId, currentSlug: String(p.slug ?? product.id), isParent: isGroupParent, groupTitle: groupTitle }))
|
|
291
|
-
: undefined, renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })) : undefined, specsContent: allSpecs.length > 0 ? (_jsx(
|
|
307
|
+
: undefined, renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })) : undefined, specsContent: allSpecs.length > 0 ? (_jsx(Dl, { className: "divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800 overflow-hidden text-sm", children: allSpecs.map((s, i) => (_jsxs(Div, { className: "flex gap-4 px-4 py-3 bg-white dark:bg-zinc-900 even:bg-zinc-50 dark:even:bg-zinc-800/50", children: [_jsx(Dt, { className: "w-36 flex-shrink-0 font-medium text-zinc-700 dark:text-zinc-300", children: s.name }), _jsxs(Dd, { className: "flex-1 text-zinc-600 dark:text-zinc-400", children: [s.value, s.unit ? ` ${s.unit}` : ""] })] }, i))) })) : undefined, ingredientsContent: ingredients.length > 0 ? (_jsx(Ul, { className: "space-y-2", children: ingredients.map((item, i) => (_jsxs(Li, { className: "flex items-start gap-2 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "mt-1 flex-shrink-0 h-1.5 w-1.5 rounded-full bg-primary-400" }), item] }, i))) })) : undefined, howToUseContent: howToUse.length > 0 ? (_jsx(Ol, { className: "space-y-3", children: howToUse.map((step, i) => (_jsxs(Li, { className: "flex items-start gap-3 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { size: "xs", weight: "bold", className: "flex-shrink-0 flex h-6 w-6 items-center justify-center rounded-full bg-primary-100 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300", children: i + 1 }), step] }, i))) })) : undefined, reviewsContent: _jsx(ReviewsList, { reviews: reviews, context: "listing", emptyLabel: "No reviews yet \u2014 be the first to review this product." }), customTabs: customSections.map((s) => ({
|
|
292
308
|
id: s.id,
|
|
293
309
|
label: s.title,
|
|
294
310
|
content: _jsx(CustomSectionTabContent, { section: s }),
|
|
295
311
|
})) })), renderBundleSection: bundleMemberships.length > 0
|
|
296
|
-
? () => (_jsxs(
|
|
312
|
+
? () => (_jsxs(Div, { className: CLS_BUNDLE_BOX, children: [_jsxs(Div, { className: "flex items-center gap-2 mb-3", children: [_jsx(Span, { size: "base", className: CLS_BUNDLE_ICON, "aria-hidden": "true", children: "\uD83D\uDCE6" }), _jsxs(Text, { className: CLS_BUNDLE_TITLE, children: ["Part of ", bundleMemberships.length === 1 ? "a bundle" : `${bundleMemberships.length} bundles`] })] }), _jsx(Div, { className: "flex flex-col gap-3", children: bundleMemberships.map((b) => (_jsxs(Div, { className: CLS_BUNDLE_ROW, children: [_jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: CLS_BUNDLE_LABEL, children: "Included in bundle" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-800 dark:text-zinc-100 truncate", children: b.title })] }), _jsx(Link, { href: String(ROUTES.PUBLIC.BUNDLE_DETAIL(b.id)), className: CLS_BUNDLE_CTA, children: "View Bundle \u2192" })] }, b.id))) })] }))
|
|
297
313
|
: undefined, renderRelated: () => relatedItems.length > 0 ? (_jsx(RelatedProductsCarousel, { items: relatedItems })) : null }), renderPrimaryActions
|
|
298
314
|
? renderPrimaryActions({
|
|
299
315
|
productId: product.id,
|
|
@@ -5,7 +5,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
|
|
|
5
5
|
if (featured) {
|
|
6
6
|
badges.push({
|
|
7
7
|
key: "featured",
|
|
8
|
-
icon: _jsx(Span, {
|
|
8
|
+
icon: _jsx(Span, { size: "xs", children: "\u2605" }),
|
|
9
9
|
label: labels.featured,
|
|
10
10
|
colorClass: "text-amber-700 dark:text-amber-300",
|
|
11
11
|
bgClass: "bg-amber-50 dark:bg-amber-900/30 border-amber-200 dark:border-amber-800",
|
|
@@ -14,7 +14,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
|
|
|
14
14
|
if (fasterDelivery) {
|
|
15
15
|
badges.push({
|
|
16
16
|
key: "fasterDelivery",
|
|
17
|
-
icon: _jsx(Span, {
|
|
17
|
+
icon: _jsx(Span, { size: "xs", children: "\u26A1" }),
|
|
18
18
|
label: labels.fasterDelivery,
|
|
19
19
|
colorClass: "text-orange-700 dark:text-orange-300",
|
|
20
20
|
bgClass: "bg-orange-50 dark:bg-orange-900/30 border-orange-200 dark:border-orange-800",
|
|
@@ -23,7 +23,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
|
|
|
23
23
|
if (ratedSeller) {
|
|
24
24
|
badges.push({
|
|
25
25
|
key: "ratedSeller",
|
|
26
|
-
icon: _jsx(Span, {
|
|
26
|
+
icon: _jsx(Span, { size: "xs", children: "\u2713" }),
|
|
27
27
|
label: labels.ratedSeller,
|
|
28
28
|
colorClass: "text-primary",
|
|
29
29
|
bgClass: "bg-primary/5 dark:bg-primary/10 border-primary/20",
|
|
@@ -41,7 +41,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
|
|
|
41
41
|
: labels.conditionNew;
|
|
42
42
|
badges.push({
|
|
43
43
|
key: "condition",
|
|
44
|
-
icon: _jsx(Span, {
|
|
44
|
+
icon: _jsx(Span, { size: "xs", children: "\u25A3" }),
|
|
45
45
|
label: `${labels.condition}: ${conditionLabel}`,
|
|
46
46
|
colorClass: "text-primary",
|
|
47
47
|
bgClass: "bg-primary/5 dark:bg-primary/10 border-primary/20 dark:border-primary/30",
|
|
@@ -50,7 +50,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
|
|
|
50
50
|
if (returnable && condition === "new") {
|
|
51
51
|
badges.push({
|
|
52
52
|
key: "returnable",
|
|
53
|
-
icon: _jsx(Span, {
|
|
53
|
+
icon: _jsx(Span, { size: "xs", children: "\u21BA" }),
|
|
54
54
|
label: labels.returnable,
|
|
55
55
|
colorClass: "text-teal-700 dark:text-teal-300",
|
|
56
56
|
bgClass: "bg-teal-50 dark:bg-teal-900/30 border-teal-200 dark:border-teal-800",
|
|
@@ -59,7 +59,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
|
|
|
59
59
|
if (freeShipping) {
|
|
60
60
|
badges.push({
|
|
61
61
|
key: "freeShipping",
|
|
62
|
-
icon: _jsx(Span, {
|
|
62
|
+
icon: _jsx(Span, { size: "xs", children: "\uD83D\uDE9A" }),
|
|
63
63
|
label: labels.freeShipping,
|
|
64
64
|
colorClass: "text-emerald-700 dark:text-emerald-300",
|
|
65
65
|
bgClass: "bg-emerald-50 dark:bg-emerald-900/30 border-emerald-200 dark:border-emerald-800",
|
|
@@ -68,7 +68,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
|
|
|
68
68
|
if (codAvailable) {
|
|
69
69
|
badges.push({
|
|
70
70
|
key: "cod",
|
|
71
|
-
icon: _jsx(Span, {
|
|
71
|
+
icon: _jsx(Span, { size: "xs", children: "\u20B9" }),
|
|
72
72
|
label: labels.codAvailable,
|
|
73
73
|
colorClass: "text-purple-700 dark:text-purple-300",
|
|
74
74
|
bgClass: "bg-purple-50 dark:bg-purple-900/30 border-purple-200 dark:border-purple-800",
|
|
@@ -77,7 +77,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
|
|
|
77
77
|
if (wishlistCount && wishlistCount > 0) {
|
|
78
78
|
badges.push({
|
|
79
79
|
key: "wishlist",
|
|
80
|
-
icon: _jsx(Span, {
|
|
80
|
+
icon: _jsx(Span, { size: "xs", children: "\u2665" }),
|
|
81
81
|
label: labels.wishlistCount(wishlistCount),
|
|
82
82
|
colorClass: "text-pink-700 dark:text-pink-300",
|
|
83
83
|
bgClass: "bg-pink-50 dark:bg-pink-900/30 border-pink-200 dark:border-pink-800",
|
|
@@ -89,7 +89,7 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
|
|
|
89
89
|
: String(categoryProductCount);
|
|
90
90
|
badges.push({
|
|
91
91
|
key: "categoryCount",
|
|
92
|
-
icon: _jsx(Span, {
|
|
92
|
+
icon: _jsx(Span, { size: "xs", children: "\u25A6" }),
|
|
93
93
|
label: labels.categoryProductCount(formattedCount, categoryName),
|
|
94
94
|
colorClass: "text-zinc-700 dark:text-zinc-300",
|
|
95
95
|
bgClass: categoryBadgeClassName ??
|
|
@@ -65,6 +65,16 @@ export interface ProductFormProps {
|
|
|
65
65
|
* non-auction product. Returns null/undefined to omit.
|
|
66
66
|
*/
|
|
67
67
|
renderGroupSettings?: (product: ProductFormValue) => React.ReactNode;
|
|
68
|
+
/**
|
|
69
|
+
* Render a "join existing group" picker (create + edit). When omitted, the
|
|
70
|
+
* groupId field is hidden. Receives current groupId and an onChange handler.
|
|
71
|
+
*/
|
|
72
|
+
renderGroupJoinField?: (args: {
|
|
73
|
+
label: string;
|
|
74
|
+
value: string | undefined;
|
|
75
|
+
onChange: (id: string | undefined) => void;
|
|
76
|
+
disabled: boolean;
|
|
77
|
+
}) => React.ReactNode;
|
|
68
78
|
}
|
|
69
|
-
export declare function ProductForm({ product, onChange, isReadonly, renderDescriptionEditor, renderCategorySelector, renderBrandSelector, renderStoreAddressSelector, onMediaAbort, currencyPrefix, renderGroupSettings, }: ProductFormProps): import("react/jsx-runtime").JSX.Element;
|
|
79
|
+
export declare function ProductForm({ product, onChange, isReadonly, renderDescriptionEditor, renderCategorySelector, renderBrandSelector, renderStoreAddressSelector, onMediaAbort, currencyPrefix, renderGroupSettings, renderGroupJoinField, }: ProductFormProps): import("react/jsx-runtime").JSX.Element;
|
|
70
80
|
export {};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useRef } from "react";
|
|
4
4
|
import { useTranslations } from "next-intl";
|
|
5
|
-
import { Alert, Checkbox, Div, FormField, FormGroup, Heading, RichTextEditor, Stack, Text, } from "../../../ui";
|
|
5
|
+
import { Alert, Checkbox, Div, FormField, FormGroup, Heading, Label, RichTextEditor, Stack, Text, } from "../../../ui";
|
|
6
6
|
import { CustomSectionsEditor } from "./CustomSectionsEditor";
|
|
7
7
|
import { SublistingCategorySelect } from "./SublistingCategorySelect";
|
|
8
8
|
import { ProductFeaturesSelector } from "./ProductFeaturesSelector";
|
|
@@ -25,7 +25,7 @@ function readFileAsDataUrl(file) {
|
|
|
25
25
|
reader.readAsDataURL(file);
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
|
-
export function ProductForm({ product, onChange, isReadonly = false, renderDescriptionEditor, renderCategorySelector, renderBrandSelector, renderStoreAddressSelector, onMediaAbort, currencyPrefix = "", renderGroupSettings, }) {
|
|
28
|
+
export function ProductForm({ product, onChange, isReadonly = false, renderDescriptionEditor, renderCategorySelector, renderBrandSelector, renderStoreAddressSelector, onMediaAbort, currencyPrefix = "", renderGroupSettings, renderGroupJoinField, }) {
|
|
29
29
|
const t = useTranslations("adminProducts");
|
|
30
30
|
const { upload } = useMediaUpload();
|
|
31
31
|
const galleryIndexRef = useRef(0);
|
|
@@ -65,7 +65,7 @@ export function ProductForm({ product, onChange, isReadonly = false, renderDescr
|
|
|
65
65
|
value: (product.categorySlugs?.[0] ?? product.category) || "",
|
|
66
66
|
onChange: (value) => update({ categorySlugs: value ? [value] : [] }),
|
|
67
67
|
disabled: isReadonly,
|
|
68
|
-
}) })) : (_jsx(FormField, { name: "category", label: t("formCategory"), type: "text", value: (product.categorySlugs?.[0] ?? product.category) || "", onChange: (value) => update({ categorySlugs: value ? [value] : [] }), disabled: isReadonly })), _jsx(FormField, { name: "subcategory", label: t("formSubcategory"), type: "text", value: product.subcategory || "", onChange: (value) => update({ subcategory: value }), disabled: isReadonly, placeholder: "e.g. Smartphones" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { className: "text-sm font-medium text-zinc-900 dark:text-zinc-100", children: t("formBrand") }), _jsx(
|
|
68
|
+
}) })) : (_jsx(FormField, { name: "category", label: t("formCategory"), type: "text", value: (product.categorySlugs?.[0] ?? product.category) || "", onChange: (value) => update({ categorySlugs: value ? [value] : [] }), disabled: isReadonly })), _jsx(FormField, { name: "subcategory", label: t("formSubcategory"), type: "text", value: product.subcategory || "", onChange: (value) => update({ subcategory: value }), disabled: isReadonly, placeholder: "e.g. Smartphones" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { className: "text-sm font-medium text-zinc-900 dark:text-zinc-100", children: t("formBrand") }), _jsx(Div, { className: "flex gap-3 flex-wrap", children: ["single", "unbranded", "mixed"].map((mode) => (_jsxs(Label, { className: "flex items-center gap-1.5 cursor-pointer select-none text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx("input", { type: "radio", name: "brandMode", value: mode, checked: (product.brandMode ?? "single") === mode, onChange: () => {
|
|
69
69
|
if (mode === "unbranded") {
|
|
70
70
|
update({ brandMode: "unbranded", brand: undefined, brands: [] });
|
|
71
71
|
}
|
|
@@ -83,7 +83,7 @@ export function ProductForm({ product, onChange, isReadonly = false, renderDescr
|
|
|
83
83
|
onValueChange: (value) => update({ brand: value }),
|
|
84
84
|
onValuesChange: (values) => update({ brands: values }),
|
|
85
85
|
disabled: isReadonly,
|
|
86
|
-
})) : product.brandMode === "mixed" ? (_jsx(FormField, { name: "brands", label: "Brands (comma-separated)", type: "text", value: (product.brands || []).join(", "), onChange: (value) => update({ brands: value.split(",").map((b) => b.trim()).filter(Boolean) }), disabled: isReadonly, placeholder: "e.g. Nike, Adidas, Puma" })) : (_jsx(FormField, { name: "brand", label: t("formBrand"), type: "text", value: product.brand || "", onChange: (value) => update({ brand: value }), disabled: isReadonly, placeholder: "e.g. Apple" })) }))] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(
|
|
86
|
+
})) : product.brandMode === "mixed" ? (_jsx(FormField, { name: "brands", label: "Brands (comma-separated)", type: "text", value: (product.brands || []).join(", "), onChange: (value) => update({ brands: value.split(",").map((b) => b.trim()).filter(Boolean) }), disabled: isReadonly, placeholder: "e.g. Nike, Adidas, Puma" })) : (_jsx(FormField, { name: "brand", label: t("formBrand"), type: "text", value: product.brand || "", onChange: (value) => update({ brand: value }), disabled: isReadonly, placeholder: "e.g. Apple" })) }))] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(Div, {}), " ", _jsx(FormField, { name: "status", label: t("formStatus"), type: "select", value: product.status || "draft", onChange: (value) => update({ status: value }), disabled: isReadonly, options: PRODUCT_STATUS_OPTIONS })] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "price", label: t("formPrice"), type: "number", value: String(product.price ?? ""), onChange: (value) => update({ price: Number(value) }), disabled: isReadonly, placeholder: "0" }), _jsx(FormField, { name: "stockQuantity", label: t("formStock"), type: "number", value: String(product.stockQuantity ?? ""), onChange: (value) => update({ stockQuantity: Number(value) }), disabled: isReadonly, placeholder: "0" })] }), !isReadonly && (_jsx(ImageUpload, { currentImage: product.mainImage, onUpload: (file) => upload(file, "products", true, {
|
|
87
87
|
type: "product-image",
|
|
88
88
|
index: 1,
|
|
89
89
|
name: product.title || "product",
|
|
@@ -173,7 +173,12 @@ export function ProductForm({ product, onChange, isReadonly = false, renderDescr
|
|
|
173
173
|
value: product.pickupAddressId || "",
|
|
174
174
|
onChange: (value) => update({ pickupAddressId: value }),
|
|
175
175
|
disabled: isReadonly,
|
|
176
|
-
}) })) : (_jsx(FormField, { name: "pickupAddressId", label: t("formPickupAddress"), type: "text", value: product.pickupAddressId || "", onChange: (value) => update({ pickupAddressId: value }), disabled: isReadonly })), _jsx(SublistingCategorySelect, { value: product.sublistingCategoryId ?? "", onChange: (id) => update({ sublistingCategoryId: id || undefined }), disabled: isReadonly }), !isAuctionListing(product) &&
|
|
176
|
+
}) })) : (_jsx(FormField, { name: "pickupAddressId", label: t("formPickupAddress"), type: "text", value: product.pickupAddressId || "", onChange: (value) => update({ pickupAddressId: value }), disabled: isReadonly })), _jsx(SublistingCategorySelect, { value: product.sublistingCategoryId ?? "", onChange: (id) => update({ sublistingCategoryId: id || undefined }), disabled: isReadonly }), !isAuctionListing(product) && renderGroupJoinField?.({
|
|
177
|
+
label: "Group (optional)",
|
|
178
|
+
value: product.groupId,
|
|
179
|
+
onChange: (id) => update({ groupId: id || undefined }),
|
|
180
|
+
disabled: isReadonly,
|
|
181
|
+
}), !isAuctionListing(product) && renderGroupSettings?.(product), _jsx(ProductFeaturesSelector, { value: product.features ?? [], onChange: (features) => update({ features }), productType: (isAuctionListing(product)
|
|
177
182
|
? "auction"
|
|
178
183
|
: isPreOrderListing(product)
|
|
179
184
|
? "preorder"
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { ImageLightbox } from "../../../ui/components/ImageLightbox";
|
|
5
|
-
import { Text } from "../../../ui";
|
|
5
|
+
import { Div, Text } from "../../../ui";
|
|
6
|
+
const __O = {
|
|
7
|
+
hidden: "overflow-hidden",
|
|
8
|
+
xAuto: "overflow-x-auto",
|
|
9
|
+
};
|
|
6
10
|
const PlaceholderSvg = () => (_jsxs("svg", { width: "64", height: "64", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", "aria-hidden": "true", children: [_jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }), _jsx("circle", { cx: "8.5", cy: "8.5", r: "1.5" }), _jsx("path", { d: "M21 15l-5-5L5 21" })] }));
|
|
7
11
|
export function ProductGalleryClient({ images, productName }) {
|
|
8
12
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
@@ -12,13 +16,13 @@ export function ProductGalleryClient({ images, productName }) {
|
|
|
12
16
|
alt: productName ? `${productName} — image ${i + 1}` : `Product image ${i + 1}`,
|
|
13
17
|
}));
|
|
14
18
|
if (images.length === 0) {
|
|
15
|
-
return (_jsx(
|
|
19
|
+
return (_jsx(Div, { className: `${__O.hidden} rounded-xl border border-zinc-100 bg-zinc-50 dark:border-zinc-800 dark:bg-zinc-900`, children: _jsx(Div, { className: "flex aspect-square items-center justify-center text-zinc-300 dark:text-zinc-700", children: _jsx(PlaceholderSvg, {}) }) }));
|
|
16
20
|
}
|
|
17
21
|
const mainImage = images[activeIndex] ?? images[0];
|
|
18
|
-
return (_jsxs(
|
|
22
|
+
return (_jsxs(Div, { className: "space-y-3", children: [_jsx("div", { className: "overflow-hidden rounded-xl border border-zinc-100 dark:border-zinc-800 cursor-zoom-in", onClick: () => setLightboxIndex(activeIndex), role: "button", tabIndex: 0, onKeyDown: (e) => {
|
|
19
23
|
if (e.key === "Enter" || e.key === " ")
|
|
20
24
|
setLightboxIndex(activeIndex);
|
|
21
|
-
}, "aria-label": `View ${productName ?? "product"} image in full screen`, children: _jsx("img", { src: mainImage, alt: productName ? `${productName} — image ${activeIndex + 1}` : `Product image ${activeIndex + 1}`, className: "aspect-square w-full object-cover transition-transform duration-300 hover:scale-105" }) }), images.length > 1 && (_jsx(
|
|
25
|
+
}, "aria-label": `View ${productName ?? "product"} image in full screen`, children: _jsx("img", { src: mainImage, alt: productName ? `${productName} — image ${activeIndex + 1}` : `Product image ${activeIndex + 1}`, className: "aspect-square w-full object-cover transition-transform duration-300 hover:scale-105" }) }), images.length > 1 && (_jsx(Div, { className: `flex gap-2 ${__O.xAuto} pb-1`, children: images.map((src, i) => (_jsx("button", { type: "button", onClick: () => setActiveIndex(i), className: `flex-shrink-0 h-16 w-16 overflow-hidden rounded-lg border-2 transition-all${i === activeIndex
|
|
22
26
|
? " border-primary-500"
|
|
23
27
|
: " border-transparent opacity-60 hover:opacity-100"}`, "aria-label": `View image ${i + 1}`, "aria-current": i === activeIndex ? "true" : undefined, children: _jsx("img", { src: src, alt: "", className: "h-full w-full object-cover" }) }, i))) })), images.length > 1 && (_jsxs(Text, { className: "text-center text-xs text-zinc-400 dark:text-zinc-400", children: [activeIndex + 1, " / ", images.length] })), _jsx(ImageLightbox, { images: lightboxImages, activeIndex: lightboxIndex, onClose: () => setLightboxIndex(null), onNavigate: (i) => setLightboxIndex(i) })] }));
|
|
24
28
|
}
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { Div, Heading, Stack, Text } from "../../../ui";
|
|
4
4
|
import { Badge } from "../../../ui/components/Badge";
|
|
5
|
+
const __O = {
|
|
6
|
+
hidden: "overflow-hidden",
|
|
7
|
+
};
|
|
5
8
|
const PSA_CERT_URL = (cert) => `https://www.psacard.com/cert/${cert}`;
|
|
6
9
|
const BGS_CERT_URL = (cert) => `https://www.beckett.com/grading/card-lookup/${cert}`;
|
|
7
10
|
function buildCertLookupUrl(service, certNumber) {
|
|
@@ -21,5 +24,5 @@ function buildCertLookupUrl(service, certNumber) {
|
|
|
21
24
|
*/
|
|
22
25
|
export function ProductGradingTab({ grading, slabImageUrl }) {
|
|
23
26
|
const lookupUrl = buildCertLookupUrl(grading.service, grading.certNumber);
|
|
24
|
-
return (_jsxs(Stack, { gap: "lg", children: [_jsxs(Div, { className: "flex items-center gap-4", children: [_jsxs(Div, { className: "flex flex-col items-center justify-center rounded-2xl border-2 border-[var(--appkit-color-primary)] px-6 py-4 min-w-[120px]", children: [_jsx(Text, { className: "text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: grading.service }), _jsx(Text, { className: "text-4xl font-extrabold", children: grading.grade })] }), _jsxs(Stack, { gap: "xs", className: "flex-1", children: [_jsxs(Heading, { level: 3, className: "text-base font-semibold", children: ["Graded by ", grading.service] }), grading.certNumber ? (_jsxs(Text, { className: "text-sm text-zinc-600 dark:text-zinc-400", children: ["Cert #", grading.certNumber, lookupUrl ? (_jsxs(_Fragment, { children: [" — ", _jsx("a", { href: lookupUrl, target: "_blank", rel: "noopener noreferrer", className: "text-[var(--appkit-color-primary)] hover:underline", children: "Verify" })] })) : null] })) : null] })] }), slabImageUrl ? (_jsx(Div, { className:
|
|
27
|
+
return (_jsxs(Stack, { gap: "lg", children: [_jsxs(Div, { className: "flex items-center gap-4", children: [_jsxs(Div, { className: "flex flex-col items-center justify-center rounded-2xl border-2 border-[var(--appkit-color-primary)] px-6 py-4 min-w-[120px]", children: [_jsx(Text, { className: "text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: grading.service }), _jsx(Text, { className: "text-4xl font-extrabold", children: grading.grade })] }), _jsxs(Stack, { gap: "xs", className: "flex-1", children: [_jsxs(Heading, { level: 3, className: "text-base font-semibold", children: ["Graded by ", grading.service] }), grading.certNumber ? (_jsxs(Text, { className: "text-sm text-zinc-600 dark:text-zinc-400", children: ["Cert #", grading.certNumber, lookupUrl ? (_jsxs(_Fragment, { children: [" — ", _jsx("a", { href: lookupUrl, target: "_blank", rel: "noopener noreferrer", className: "text-[var(--appkit-color-primary)] hover:underline", children: "Verify" })] })) : null] })) : null] })] }), slabImageUrl ? (_jsx(Div, { className: `${__O.hidden} rounded-2xl border border-zinc-200 dark:border-zinc-700`, children: _jsx("img", { src: slabImageUrl, alt: "Slab certificate image", className: "w-full h-auto" }) })) : null, grading.attributes && Object.keys(grading.attributes).length > 0 ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 3, className: "text-sm font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "Subgrades & attributes" }), _jsx(Div, { className: "flex flex-wrap gap-2", children: Object.entries(grading.attributes).map(([key, value]) => (_jsxs(Badge, { variant: "default", children: [key, ": ", value] }, key))) })] })) : null] }));
|
|
25
28
|
}
|
|
@@ -13,6 +13,27 @@ import { FeatureBadgeList } from "./FeatureBadge";
|
|
|
13
13
|
import { useProductFeatures } from "./ProductFeaturesContext";
|
|
14
14
|
import { PRODUCT_FEATURE_CARD_MAX_VISIBLE } from "../constants/product-features.constants";
|
|
15
15
|
import { isAuctionListing, isPreOrderListing } from "../utils/listing-type";
|
|
16
|
+
const __P = {
|
|
17
|
+
p3: "p-3",
|
|
18
|
+
};
|
|
19
|
+
const __O = {
|
|
20
|
+
hidden: "overflow-hidden",
|
|
21
|
+
};
|
|
22
|
+
const CLS_BADGE_AUCTION = "bg-amber-500 text-white";
|
|
23
|
+
const CLS_BADGE_PREORDER = "bg-violet-600 text-white";
|
|
24
|
+
const CLS_BADGE_NEW = "rounded-full bg-rose-500 px-2 py-0.5 text-[10px] text-white shadow-sm";
|
|
25
|
+
const CLS_BADGE_SALE = "rounded-full bg-teal-600 px-2 py-0.5 text-[10px] font-bold text-white shadow-sm";
|
|
26
|
+
const CLS_BADGE_TRENDING = "rounded-full bg-indigo-600 px-2 py-0.5 text-[10px] font-bold text-white shadow-sm";
|
|
27
|
+
const CLS_BADGE_LIMITED = "rounded-full bg-sky-600 px-2 py-0.5 text-[10px] font-bold text-white shadow-sm";
|
|
28
|
+
const CLS_HEART_ACTIVE = "bg-rose-500 text-white hover:bg-rose-600";
|
|
29
|
+
const CLS_HEART_IDLE = "bg-white/90 dark:bg-slate-800/90 text-zinc-500 dark:text-zinc-400 hover:text-rose-500 hover:bg-white dark:hover:bg-slate-800";
|
|
30
|
+
const CLS_STAR = "text-[11px] text-amber-400";
|
|
31
|
+
const CLS_DISCOUNT_TEXT = "mt-1 text-[11px] font-semibold text-rose-500";
|
|
32
|
+
const CLS_DISCOUNT_TEXT_BARE = "text-[10px] text-rose-500";
|
|
33
|
+
const CLS_STAR_BARE = "text-amber-400";
|
|
34
|
+
const CLS_BID_TEXT = "text-[11px] text-rose-500";
|
|
35
|
+
const CLS_HEART_ROSE_ACTIVE = "text-rose-500";
|
|
36
|
+
const CLS_HEART_ROSE_IDLE = "text-zinc-300 dark:text-zinc-600 hover:text-rose-400";
|
|
16
37
|
export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlisted, onAddToCart, onBuyNow, className = "", selectionMode = false, isSelected = false, onSelect, }) {
|
|
17
38
|
const discount = product.originalPrice && product.originalPrice > product.price
|
|
18
39
|
? Math.round(((product.originalPrice - product.price) / product.originalPrice) *
|
|
@@ -22,9 +43,9 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
|
|
|
22
43
|
const isAuction = isAuctionListing(product);
|
|
23
44
|
const isPreOrder = isPreOrderListing(product);
|
|
24
45
|
const typeBadge = isAuction
|
|
25
|
-
? { label: "Auction", cls:
|
|
46
|
+
? { label: "Auction", cls: CLS_BADGE_AUCTION }
|
|
26
47
|
: isPreOrder
|
|
27
|
-
? { label: "Pre-Order", cls:
|
|
48
|
+
? { label: "Pre-Order", cls: CLS_BADGE_PREORDER }
|
|
28
49
|
: null;
|
|
29
50
|
const longPress = useLongPress(() => onSelect?.(product.id));
|
|
30
51
|
const featuresList = useProductFeatures();
|
|
@@ -48,9 +69,9 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
|
|
|
48
69
|
className,
|
|
49
70
|
]
|
|
50
71
|
.filter(Boolean)
|
|
51
|
-
.join(" "), children: [_jsxs(Div, { className:
|
|
72
|
+
.join(" "), children: [_jsxs(Div, { className: `relative ${__O.hidden} bg-zinc-100 dark:bg-slate-800 aspect-square`, children: [product.mainImage ? (_jsx(MediaImage, { src: product.mainImage, alt: product.title, size: "card", className: "transition-transform duration-500 group-hover:scale-105" })) : (_jsx(Div, { className: "h-full w-full flex items-center justify-center bg-gradient-to-br from-zinc-100 to-zinc-200 dark:from-slate-800 dark:to-slate-700", children: _jsx(Span, { className: "text-4xl opacity-30", children: "\uD83D\uDECD\uFE0F" }) })), onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (e) => { e.preventDefault(); onSelect(product.id); }, label: isSelected ? "Deselect" : "Select", position: "top-2 left-2", className: selectionMode || isSelected ? "opacity-100" : "opacity-0 group-hover:opacity-100 transition-opacity" })), _jsx(Div, { className: `absolute top-2 flex flex-col gap-1 ${onSelect ? "left-10" : "left-2"}`, children: !selectionMode && !isSelected && (_jsxs(_Fragment, { children: [discount && (_jsxs(Span, { weight: "bold", className: CLS_BADGE_NEW, children: ["-", discount, "%"] })), typeBadge && (_jsx(Span, { weight: "bold", className: `rounded-full px-2 py-0.5 text-[10px] shadow-sm ${typeBadge.cls}`, children: typeBadge.label })), product.partOfBundleIds && product.partOfBundleIds.length > 0 && (_jsx(Span, { className: CLS_BADGE_SALE, title: product.partOfBundleTitles && product.partOfBundleTitles.length > 0
|
|
52
73
|
? `In bundle: ${product.partOfBundleTitles[0]}`
|
|
53
|
-
: "In a bundle", children: "Bundled" })), product.groupId && (_jsx(Span, { className:
|
|
74
|
+
: "In a bundle", children: "Bundled" })), product.groupId && (_jsx(Span, { className: CLS_BADGE_TRENDING, title: product.groupTitle ? `Part of set: ${product.groupTitle}` : "Part of a set", children: product.isGroupParent ? "Set Parent" : "In Set" })), product.sublistingCategoryId && (_jsx(Span, { className: CLS_BADGE_LIMITED, title: "Has variants or sub-listings", children: "Has Variants" }))] })) }), _jsx(BaseListingCard.IconOverlay, { groupIcon: product.groupIcon, sublistingIcon: product.sublistingIcon, position: "bottom-2 right-2" }), onAddToWishlist && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: (e) => {
|
|
54
75
|
e.stopPropagation();
|
|
55
76
|
e.preventDefault();
|
|
56
77
|
onAddToWishlist(product.id);
|
|
@@ -58,9 +79,9 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
|
|
|
58
79
|
"absolute right-2 top-2 flex h-8 w-8 items-center justify-center rounded-full shadow-sm",
|
|
59
80
|
"transition-all duration-150",
|
|
60
81
|
isWishlisted
|
|
61
|
-
?
|
|
62
|
-
:
|
|
63
|
-
].join(" "), children: _jsx("svg", { className: "h-4 w-4", fill: isWishlisted ? "currentColor" : "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" }) }) }))] }), _jsxs(Div, { className:
|
|
82
|
+
? CLS_HEART_ACTIVE
|
|
83
|
+
: CLS_HEART_IDLE,
|
|
84
|
+
].join(" "), children: _jsx("svg", { className: "h-4 w-4", fill: isWishlisted ? "currentColor" : "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" }) }) }))] }), _jsxs(Div, { className: `flex flex-1 flex-col ${__P.p3} pt-2.5`, children: [_jsx(Text, { className: `${THEME_CONSTANTS.utilities.textClamp2} text-sm font-semibold text-zinc-900 dark:text-white leading-snug`, children: product.title }), (() => {
|
|
64
85
|
const categories = Array.isArray(product.categoryNames)
|
|
65
86
|
? product.categoryNames.filter(Boolean)
|
|
66
87
|
: product.categoryName
|
|
@@ -71,16 +92,16 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
|
|
|
71
92
|
const MAX_CHIPS = 3;
|
|
72
93
|
const visible = categories.slice(0, MAX_CHIPS);
|
|
73
94
|
const overflow = Math.max(0, categories.length - MAX_CHIPS);
|
|
74
|
-
return (_jsxs(Row, { className: "mt-1 gap-1 flex-wrap", children: [visible.map((name) => (_jsxs(Span, { className: "inline-flex items-center gap-0.5 rounded-full bg-zinc-100 dark:bg-zinc-800 px-1.5 py-0.5 text-[10px] text-zinc-600 dark:text-zinc-400 truncate max-w-[100px]", children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 7a2 2 0 012-2h14a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V7z" }) }), name] }, name))), overflow > 0 && (_jsxs(Span, { className: "inline-flex items-center rounded-full bg-zinc-100 dark:bg-zinc-800 px-1.5 py-0.5 text-[10px]
|
|
95
|
+
return (_jsxs(Row, { className: "mt-1 gap-1 flex-wrap", children: [visible.map((name) => (_jsxs(Span, { className: "inline-flex items-center gap-0.5 rounded-full bg-zinc-100 dark:bg-zinc-800 px-1.5 py-0.5 text-[10px] text-zinc-600 dark:text-zinc-400 truncate max-w-[100px]", children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 7a2 2 0 012-2h14a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V7z" }) }), name] }, name))), overflow > 0 && (_jsxs(Span, { weight: "medium", className: "inline-flex items-center rounded-full bg-zinc-100 dark:bg-zinc-800 px-1.5 py-0.5 text-[10px] text-zinc-600 dark:text-zinc-400", title: categories.slice(MAX_CHIPS).join(", "), children: ["+", overflow] })), product.brand && (_jsxs(Span, { className: "inline-flex items-center gap-0.5 rounded-full bg-zinc-100 dark:bg-zinc-800 px-1.5 py-0.5 text-[10px] text-zinc-600 dark:text-zinc-400 truncate max-w-[90px]", children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" }) }), product.brand] }))] }));
|
|
75
96
|
})(), (() => {
|
|
76
97
|
const seller = safeDisplayName(product.storeName, "");
|
|
77
98
|
return seller ? (_jsxs(Text, { className: "mt-0.5 text-[11px] text-zinc-400 dark:text-zinc-400 truncate", children: ["by ", seller] })) : null;
|
|
78
|
-
})(), product.rating !== undefined && (_jsxs(Row, { className: "mt-1 gap-1", children: [_jsx(Span, { className:
|
|
99
|
+
})(), product.rating !== undefined && (_jsxs(Row, { className: "mt-1 gap-1", children: [_jsx(Span, { className: CLS_STAR, children: "\u2605" }), _jsxs(Span, { className: "text-[11px] text-zinc-500 dark:text-zinc-400", children: [product.rating.toFixed(1), product.reviewCount ? ` (${product.reviewCount})` : ""] })] })), _jsxs(Div, { className: "mt-auto pt-2", children: [_jsxs(Row, { align: "baseline", className: "gap-2", children: [_jsx(Span, { size: "base", weight: "bold", className: "text-primary dark:text-primary-400", children: formatCurrency(product.price, getDefaultCurrency()) }), product.originalPrice && product.originalPrice > product.price && (_jsx(Span, { size: "xs", className: "text-zinc-400 line-through dark:text-zinc-400", children: formatCurrency(product.originalPrice, getDefaultCurrency()) }))] }), (() => {
|
|
79
100
|
const stock = product.stockCount ?? product.stockQuantity ?? product.availableQuantity;
|
|
80
101
|
if (stock === undefined || isAuction)
|
|
81
102
|
return null;
|
|
82
103
|
if (stock <= 0) {
|
|
83
|
-
return (_jsx(Text, { className:
|
|
104
|
+
return (_jsx(Text, { className: CLS_DISCOUNT_TEXT, children: "Out of stock" }));
|
|
84
105
|
}
|
|
85
106
|
const low = stock <= 5;
|
|
86
107
|
return (_jsx(Text, { className: `mt-1 text-[11px] font-medium ${low
|
|
@@ -117,21 +138,21 @@ function ProductListRow({ product, onClick, onAddToWishlist, isWishlisted, }) {
|
|
|
117
138
|
onClick ? "cursor-pointer" : "",
|
|
118
139
|
]
|
|
119
140
|
.filter(Boolean)
|
|
120
|
-
.join(" "), children: [_jsx(Div, { className:
|
|
141
|
+
.join(" "), children: [_jsx(Div, { className: `flex-shrink-0 w-16 h-16 sm:w-20 sm:h-20 rounded-lg ${__O.hidden} bg-neutral-100 dark:bg-zinc-800`, children: product.mainImage ? (_jsx(MediaImage, { src: product.mainImage, alt: product.title, size: "thumbnail" })) : (_jsx(Div, { className: "w-full h-full bg-neutral-200 dark:bg-zinc-700" })) }), _jsxs(Div, { className: "flex flex-1 flex-col min-w-0 gap-0.5", children: [_jsx(Text, { className: `${THEME_CONSTANTS.utilities.textClamp2} text-sm font-medium text-zinc-900 dark:text-zinc-100`, children: product.title }), (product.categoryName || product.brand) && (_jsx(Span, { className: "text-[11px] text-zinc-400 dark:text-zinc-400 truncate", children: [product.categoryName, product.brand].filter(Boolean).join(" · ") })), _jsxs(Div, { className: "flex items-center gap-2 flex-wrap mt-0.5", children: [_jsx(Span, { size: "sm", weight: "semibold", className: "text-primary", children: formatCurrency(product.price, getDefaultCurrency()) }), discount && (_jsxs(Span, { weight: "bold", className: CLS_DISCOUNT_TEXT_BARE, children: ["-", discount, "%"] })), product.rating !== undefined && (_jsxs(Span, { className: "text-[11px] text-zinc-400 dark:text-zinc-400 flex items-center gap-0.5", children: [_jsx(Span, { className: CLS_STAR_BARE, children: "\u2605" }), product.rating.toFixed(1)] })), (() => {
|
|
121
142
|
const stock = product.stockCount ?? product.stockQuantity ?? product.availableQuantity;
|
|
122
143
|
if (stock === undefined)
|
|
123
144
|
return null;
|
|
124
145
|
if (stock <= 0) {
|
|
125
|
-
return (_jsx(Span, {
|
|
146
|
+
return (_jsx(Span, { weight: "semibold", className: CLS_BID_TEXT, children: "Out of stock" }));
|
|
126
147
|
}
|
|
127
148
|
const low = stock <= 5;
|
|
128
|
-
return (_jsx(Span, { className: `text-[11px]
|
|
149
|
+
return (_jsx(Span, { weight: "medium", className: `text-[11px] ${low
|
|
129
150
|
? "text-warning"
|
|
130
151
|
: "text-zinc-400 dark:text-zinc-400"}`, children: low ? `Only ${stock} left` : `${stock} in stock` }));
|
|
131
152
|
})()] })] }), onAddToWishlist && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: (e) => {
|
|
132
153
|
e.stopPropagation();
|
|
133
154
|
onAddToWishlist(product.id);
|
|
134
|
-
}, "aria-label": isWishlisted ? "Remove from wishlist" : "Add to wishlist", className: `flex-shrink-0 h-8 w-8 flex items-center justify-center rounded-full text-base leading-none ${isWishlisted ?
|
|
155
|
+
}, "aria-label": isWishlisted ? "Remove from wishlist" : "Add to wishlist", className: `flex-shrink-0 h-8 w-8 flex items-center justify-center rounded-full text-base leading-none ${isWishlisted ? CLS_HEART_ROSE_ACTIVE : CLS_HEART_ROSE_IDLE}`, children: isWishlisted ? "♥" : "♡" }))] }));
|
|
135
156
|
}
|
|
136
157
|
function safeHref(href) {
|
|
137
158
|
if (!href)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Div } from "../../../ui/components/Div";
|
|
2
3
|
export function ProductInfo({ isLoading = false, renderTitle, renderPrice, renderBadges, renderDescription, renderVariants, renderSeller, renderRating, className = "", }) {
|
|
3
|
-
return (_jsxs(
|
|
4
|
+
return (_jsxs(Div, { className: `space-y-4 ${className}`, children: [renderTitle?.(isLoading), renderRating?.(), renderPrice?.(isLoading), renderBadges?.(), renderVariants?.(), renderDescription?.(), renderSeller?.()] }));
|
|
4
5
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import React from "react";
|
|
4
|
+
import { Div } from "../../../ui/components/Div";
|
|
4
5
|
const DEFAULT_TABS = [
|
|
5
6
|
{ value: "description", label: "Description" },
|
|
6
7
|
{ value: "specs", label: "Specifications" },
|
|
@@ -17,7 +18,7 @@ export function ProductTabs({ renderDescription, renderSpecs, renderReviews, ext
|
|
|
17
18
|
...extraTabs,
|
|
18
19
|
];
|
|
19
20
|
const tabs = allTabs.length > 0 ? allTabs : DEFAULT_TABS;
|
|
20
|
-
return (_jsxs(
|
|
21
|
+
return (_jsxs(Div, { className: className, children: [renderTabBar ? (renderTabBar(activeTab, setActiveTab, tabs)) : (_jsx(Div, { className: "flex gap-4 border-b mb-4", children: tabs.map((t) => (_jsx("button", { onClick: () => setActiveTab(t.value), className: `pb-2 text-sm font-medium border-b-2 transition-colors ${activeTab === t.value
|
|
21
22
|
? "border-current text-current"
|
|
22
23
|
: "border-transparent text-zinc-500 dark:text-zinc-400"}`, children: t.label }, t.value))) })), activeTab === "description" && renderDescription?.(), activeTab === "specs" && renderSpecs?.(), activeTab === "reviews" && renderReviews?.(), renderExtraTab?.(activeTab)] }));
|
|
23
24
|
}
|