@mohasinac/appkit 2.7.27 → 2.7.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +1 -1
- package/dist/_internal/server/features/checkout/actions.js +42 -35
- package/dist/_internal/server/features/classified/adapters.d.ts +21 -0
- package/dist/_internal/server/features/classified/adapters.js +24 -0
- package/dist/_internal/server/features/classified/index.d.ts +3 -0
- package/dist/_internal/server/features/classified/index.js +3 -0
- package/dist/_internal/server/features/classified/metadata.d.ts +8 -0
- package/dist/_internal/server/features/classified/metadata.js +43 -0
- package/dist/_internal/server/features/classified/og.d.ts +30 -0
- package/dist/_internal/server/features/classified/og.js +76 -0
- package/dist/_internal/server/features/digital-code/adapters.d.ts +21 -0
- package/dist/_internal/server/features/digital-code/adapters.js +29 -0
- package/dist/_internal/server/features/digital-code/index.d.ts +3 -0
- package/dist/_internal/server/features/digital-code/index.js +3 -0
- package/dist/_internal/server/features/digital-code/metadata.d.ts +8 -0
- package/dist/_internal/server/features/digital-code/metadata.js +36 -0
- package/dist/_internal/server/features/digital-code/og.d.ts +27 -0
- package/dist/_internal/server/features/digital-code/og.js +77 -0
- package/dist/_internal/server/features/live/adapters.d.ts +21 -0
- package/dist/_internal/server/features/live/adapters.js +34 -0
- package/dist/_internal/server/features/live/index.d.ts +3 -0
- package/dist/_internal/server/features/live/index.js +3 -0
- package/dist/_internal/server/features/live/metadata.d.ts +8 -0
- package/dist/_internal/server/features/live/metadata.js +39 -0
- package/dist/_internal/server/features/live/og.d.ts +27 -0
- package/dist/_internal/server/features/live/og.js +72 -0
- package/dist/_internal/server/features/promotions/actions.js +4 -3
- package/dist/_internal/server/jobs/core/onOrderCreate.js +19 -16
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +25 -22
- package/dist/_internal/server/jobs/core/onProductWrite.js +48 -58
- package/dist/_internal/shared/actions/action-registry.js +310 -8
- package/dist/_internal/shared/features/blog/schema.d.ts +4 -4
- package/dist/_internal/shared/features/brands/schema.d.ts +5 -5
- package/dist/_internal/shared/features/cart/schema.d.ts +18 -18
- package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +38 -38
- package/dist/_internal/shared/features/events/schema.d.ts +8 -8
- package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
- package/dist/_internal/shared/features/products/schema.d.ts +42 -42
- package/dist/_internal/shared/features/promotions/schema.d.ts +4 -4
- package/dist/_internal/shared/features/reviews/schema.d.ts +1 -1
- package/dist/_internal/shared/media/limits.js +4 -3
- package/dist/client.d.ts +2 -0
- package/dist/client.js +1 -0
- package/dist/configs/next.js +4 -0
- package/dist/constants/table-keys.d.ts +6 -0
- package/dist/constants/table-keys.js +9 -0
- package/dist/core/hooks/useSyncManager.js +9 -8
- package/dist/features/about/components/FeesView.js +10 -7
- package/dist/features/about/components/HelpPageView.js +10 -1
- package/dist/features/about/components/HowAuctionsWorkView.js +10 -1
- package/dist/features/about/components/HowCheckoutWorksView.js +10 -1
- package/dist/features/about/components/HowOffersWorkView.js +10 -1
- package/dist/features/about/components/HowOrdersWorkView.js +10 -1
- package/dist/features/about/components/HowPayoutsWorkView.js +10 -1
- package/dist/features/about/components/HowPreOrdersWorkView.js +10 -1
- package/dist/features/about/components/HowReviewsWorkView.js +10 -1
- package/dist/features/about/components/PublicProfileView.js +44 -14
- package/dist/features/about/components/SecurityPrivacyView.js +7 -1
- package/dist/features/account/components/AddressesIndexListing.js +2 -2
- package/dist/features/account/components/NotificationBell.js +27 -16
- package/dist/features/account/components/NotificationPreferencesPanel.d.ts +9 -0
- package/dist/features/account/components/NotificationPreferencesPanel.js +91 -0
- package/dist/features/account/components/UserSidebar.js +4 -4
- package/dist/features/account/components/UserSupportView.js +16 -6
- package/dist/features/account/components/index.d.ts +2 -0
- package/dist/features/account/components/index.js +1 -0
- package/dist/features/account/schemas/index.d.ts +4 -4
- package/dist/features/account/types/index.d.ts +34 -0
- package/dist/features/admin/actions/admin-actions.js +4 -3
- package/dist/features/admin/actions/notification-actions.d.ts +24 -22
- package/dist/features/admin/actions/notification-actions.js +122 -22
- package/dist/features/admin/components/AdminAdEditorView.js +29 -15
- package/dist/features/admin/components/AdminAdsView.js +22 -28
- package/dist/features/admin/components/AdminAllEventEntriesView.js +6 -1
- package/dist/features/admin/components/AdminBidsView.js +10 -3
- package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
- package/dist/features/admin/components/AdminBlogView.js +8 -3
- package/dist/features/admin/components/AdminBrandsView.js +7 -2
- package/dist/features/admin/components/AdminBundleEditorView.js +5 -2
- package/dist/features/admin/components/AdminCarouselEditorView.js +6 -3
- package/dist/features/admin/components/AdminCarouselView.js +13 -7
- package/dist/features/admin/components/AdminCategoriesView.js +8 -3
- package/dist/features/admin/components/AdminCategoryEditorView.js +2 -2
- package/dist/features/admin/components/AdminContactView.js +6 -1
- package/dist/features/admin/components/AdminCouponEditorView.js +8 -2
- package/dist/features/admin/components/AdminCouponsView.js +6 -1
- package/dist/features/admin/components/AdminEmployeeEditorView.js +12 -9
- package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
- package/dist/features/admin/components/AdminFaqsView.js +7 -2
- package/dist/features/admin/components/AdminFeaturesView.js +4 -3
- package/dist/features/admin/components/AdminMediaView.js +9 -8
- package/dist/features/admin/components/AdminNavigationView.js +10 -17
- package/dist/features/admin/components/AdminNewsletterView.js +6 -1
- package/dist/features/admin/components/AdminNotificationsView.js +11 -3
- package/dist/features/admin/components/AdminOrdersView.js +6 -1
- package/dist/features/admin/components/AdminPayoutsView.js +10 -3
- package/dist/features/admin/components/AdminPrizeDrawsView.js +10 -3
- package/dist/features/admin/components/AdminProductsView.js +18 -12
- package/dist/features/admin/components/AdminReviewsView.js +33 -24
- package/dist/features/admin/components/AdminScammerEditorView.js +3 -2
- package/dist/features/admin/components/AdminScammersView.js +28 -26
- package/dist/features/admin/components/AdminSectionsView.js +112 -99
- package/dist/features/admin/components/AdminSessionsView.js +10 -3
- package/dist/features/admin/components/AdminSidebar.js +4 -4
- package/dist/features/admin/components/AdminSiteSettingsView.js +45 -4
- package/dist/features/admin/components/AdminStoresView.js +6 -1
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +0 -1
- package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
- package/dist/features/admin/components/AdminSupportTicketsView.js +32 -34
- package/dist/features/admin/components/AdminTeamView.js +6 -1
- package/dist/features/admin/components/AdminUserEditorView.js +8 -15
- package/dist/features/admin/components/AdminUsersView.js +6 -1
- package/dist/features/admin/components/AdminViewCards.js +4 -3
- package/dist/features/admin/components/DashboardStats.js +2 -2
- package/dist/features/admin/components/DataTable.js +2 -2
- package/dist/features/admin/components/sections/adminSectionsTypes.js +4 -3
- package/dist/features/admin/repository/chat.repository.js +8 -8
- package/dist/features/admin/repository/site-settings.repository.d.ts +1 -0
- package/dist/features/admin/repository/site-settings.repository.js +11 -9
- package/dist/features/admin/schemas/firestore.d.ts +38 -0
- package/dist/features/admin/schemas/firestore.js +15 -0
- package/dist/features/auctions/components/AuctionDetailPageView.js +13 -19
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +18 -9
- package/dist/features/auctions/components/MarketplaceAuctionGrid.js +3 -2
- package/dist/features/auctions/components/index.d.ts +0 -1
- package/dist/features/auctions/components/index.js +0 -1
- package/dist/features/auctions/schemas/index.d.ts +14 -14
- package/dist/features/auth/actions/realtime-token-actions.js +19 -4
- package/dist/features/auth/components/RegisterForm.js +8 -4
- package/dist/features/auth/consent-otp.d.ts +2 -0
- package/dist/features/auth/consent-otp.js +8 -0
- package/dist/features/auth/schemas/firestore.d.ts +2 -0
- package/dist/features/auth/schemas/firestore.js +18 -25
- package/dist/features/auth/schemas/index.d.ts +2 -2
- package/dist/features/before-after/api/[id]/route.js +8 -6
- package/dist/features/before-after/schemas/index.d.ts +2 -2
- package/dist/features/blog/actions/blog-actions.d.ts +3 -3
- package/dist/features/blog/components/BlogIndexListing.js +21 -2
- package/dist/features/blog/components/BlogPostForm.js +11 -5
- package/dist/features/blog/components/BlogPostView.js +10 -2
- package/dist/features/blog/schemas/index.d.ts +18 -18
- package/dist/features/cart/components/CartDrawer.js +3 -2
- package/dist/features/cart/repository/cart.repository.js +4 -3
- package/dist/features/cart/utils/pending-ops.d.ts +1 -1
- package/dist/features/categories/api/[id]/route.js +4 -3
- package/dist/features/categories/api/route.js +4 -3
- package/dist/features/categories/components/BrandDetailPageView.js +2 -2
- package/dist/features/categories/components/BrandDetailTabs.js +2 -2
- package/dist/features/categories/components/BundleCollage.d.ts +8 -0
- package/dist/features/categories/components/BundleCollage.js +50 -0
- package/dist/features/categories/components/BundleDetailView.js +2 -10
- package/dist/features/categories/components/BundleItemsPicker.js +20 -13
- package/dist/features/categories/components/CategoriesIndexListing.js +28 -9
- package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
- package/dist/features/categories/components/CategoryDetailTabs.js +2 -2
- package/dist/features/categories/components/CategoryProductsListing.js +52 -13
- package/dist/features/categories/components/index.d.ts +2 -0
- package/dist/features/categories/components/index.js +1 -0
- package/dist/features/categories/schemas/index.d.ts +6 -6
- package/dist/features/checkout/actions/checkout-actions.js +4 -3
- package/dist/features/checkout/hooks/usePaymentCheckout.js +31 -22
- package/dist/features/classified/components/ClassifiedFilters.d.ts +8 -0
- package/dist/features/classified/components/ClassifiedFilters.js +19 -0
- package/dist/features/classified/components/ClassifiedIndexListing.d.ts +4 -0
- package/dist/features/classified/components/ClassifiedIndexListing.js +110 -0
- package/dist/features/classified/components/ClassifiedListView.d.ts +6 -0
- package/dist/features/classified/components/ClassifiedListView.js +43 -0
- package/dist/features/classified/components/index.d.ts +6 -0
- package/dist/features/classified/components/index.js +3 -0
- package/dist/features/collections/api/[slug]/route.js +16 -12
- package/dist/features/collections/schemas/index.d.ts +5 -5
- package/dist/features/consultation/api/[id]/route.js +12 -9
- package/dist/features/consultation/components/ConsultationForm.js +3 -2
- package/dist/features/consultation/schemas/index.d.ts +6 -6
- package/dist/features/contact/email.js +77 -116
- package/dist/features/copilot/components/AdminCopilotView.js +12 -2
- package/dist/features/corporate/api/[id]/route.js +12 -9
- package/dist/features/corporate/components/CorporateInquiryForm.js +2 -1
- package/dist/features/digital-codes/components/DigitalCodeFilters.d.ts +8 -0
- package/dist/features/digital-codes/components/DigitalCodeFilters.js +16 -0
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +4 -0
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +107 -0
- package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +6 -0
- package/dist/features/digital-codes/components/DigitalCodesListView.js +37 -0
- package/dist/features/digital-codes/components/index.d.ts +6 -0
- package/dist/features/digital-codes/components/index.js +3 -0
- package/dist/features/events/actions/event-actions.js +4 -3
- package/dist/features/events/components/AdminEventEditorView.js +3 -2
- package/dist/features/events/components/AdminEventsView.js +4 -2
- package/dist/features/events/components/EventPollWidget.js +5 -5
- package/dist/features/events/components/EventsIndexListing.js +2 -2
- package/dist/features/events/schemas/index.d.ts +20 -20
- package/dist/features/faq/actions/faq-actions.d.ts +8 -8
- package/dist/features/faq/components/ContactCTA.js +3 -1
- package/dist/features/faq/components/FAQAccordion.js +1 -1
- package/dist/features/faq/schemas/index.d.ts +4 -4
- package/dist/features/filters/AsyncFacetSection.d.ts +18 -0
- package/dist/features/filters/AsyncFacetSection.js +65 -0
- package/dist/features/forms/Checkbox.js +2 -2
- package/dist/features/forms/Input.js +2 -2
- package/dist/features/forms/Radio.js +5 -5
- package/dist/features/forms/Select.js +2 -2
- package/dist/features/forms/Slider.js +2 -2
- package/dist/features/forms/Textarea.js +2 -2
- package/dist/features/homepage/api/[id]/route.js +4 -3
- package/dist/features/homepage/api/sections/[id]/route.js +12 -9
- package/dist/features/homepage/components/AdSlot.js +2 -1
- package/dist/features/homepage/components/AdvertisementBanner.js +5 -3
- package/dist/features/homepage/components/BrandsSection.js +2 -2
- package/dist/features/homepage/components/CTABannerSection.js +2 -2
- package/dist/features/homepage/components/CharacterHotspot.d.ts +2 -2
- package/dist/features/homepage/components/CharacterHotspot.js +119 -157
- package/dist/features/homepage/components/CharacterHotspotForm.js +25 -20
- package/dist/features/homepage/components/CustomCardsSection.js +8 -6
- package/dist/features/homepage/components/FeaturedProductsSection.js +2 -2
- package/dist/features/homepage/components/GoogleReviewsSection.js +3 -3
- package/dist/features/homepage/components/HeroBanner.js +5 -4
- package/dist/features/homepage/components/HeroCarousel.js +13 -26
- package/dist/features/homepage/components/HowItWorksSection.js +4 -2
- package/dist/features/homepage/components/SocialFeedSection.js +2 -2
- package/dist/features/homepage/components/SocialPostCard.js +3 -2
- package/dist/features/homepage/lib/social-feed-fetcher.js +6 -3
- package/dist/features/layout/AppLayoutShell.d.ts +8 -2
- package/dist/features/layout/AppLayoutShell.js +54 -78
- package/dist/features/layout/BottomActions.js +43 -48
- package/dist/features/live/components/LiveItemFilters.d.ts +8 -0
- package/dist/features/live/components/LiveItemFilters.js +23 -0
- package/dist/features/live/components/LiveItemsIndexListing.d.ts +4 -0
- package/dist/features/live/components/LiveItemsIndexListing.js +108 -0
- package/dist/features/live/components/LiveItemsListView.d.ts +6 -0
- package/dist/features/live/components/LiveItemsListView.js +43 -0
- package/dist/features/live/components/index.d.ts +6 -0
- package/dist/features/live/components/index.js +3 -0
- package/dist/features/media/MediaLightbox.js +8 -14
- package/dist/features/media/types/index.d.ts +2 -2
- package/dist/features/media/upload/CameraCapture.js +2 -2
- package/dist/features/media/upload/ImageUpload.js +4 -2
- package/dist/features/media/upload/MediaUploadField.js +24 -8
- package/dist/features/media/upload/MediaUploadList.js +1 -1
- package/dist/features/orders/actions/order-actions.js +4 -3
- package/dist/features/orders/components/MarketplaceOrderCard.js +2 -1
- package/dist/features/orders/components/OrderFilters.js +12 -9
- package/dist/features/orders/schemas/index.d.ts +6 -6
- package/dist/features/pre-orders/api/[id]/route.js +12 -9
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +5 -4
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +27 -20
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +17 -52
- package/dist/features/pre-orders/components/PreorderCard.d.ts +0 -9
- package/dist/features/pre-orders/components/PreorderCard.js +2 -13
- package/dist/features/pre-orders/components/index.d.ts +1 -1
- package/dist/features/pre-orders/components/index.js +1 -1
- package/dist/features/pre-orders/schemas/index.d.ts +10 -10
- package/dist/features/products/api/[id]/route.js +9 -7
- package/dist/features/products/api/route.js +1 -1
- package/dist/features/products/columns/productTableColumns.js +2 -2
- package/dist/features/products/components/AuctionsIndexListing.js +15 -51
- package/dist/features/products/components/BidHistory.js +2 -2
- package/dist/features/products/components/CompareOverlay.js +3 -2
- package/dist/features/products/components/MakeOfferButton.js +20 -14
- package/dist/features/products/components/MarketplacePrizeDrawCard.js +2 -1
- package/dist/features/products/components/PrizeDrawCollage.d.ts +1 -15
- package/dist/features/products/components/PrizeDrawCollage.js +54 -14
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
- package/dist/features/products/components/PrizeDrawEntryActions.js +2 -1
- package/dist/features/products/components/PrizeDrawItemsEditor.js +9 -7
- package/dist/features/products/components/PrizeDrawsIndexListing.js +18 -51
- package/dist/features/products/components/PrizeRevealModal.js +24 -14
- package/dist/features/products/components/ProductDetailPageView.js +2 -1
- package/dist/features/products/components/ProductFilters.js +8 -6
- package/dist/features/products/components/ProductForm.js +12 -10
- package/dist/features/products/components/ProductGalleryClient.js +2 -1
- package/dist/features/products/components/ProductGrid.js +11 -14
- package/dist/features/products/components/ProductsIndexListing.js +16 -52
- package/dist/features/products/components/ProductsIndexPageView.js +2 -2
- package/dist/features/products/schemas/index.d.ts +56 -56
- package/dist/features/products/schemas/product-features.validators.d.ts +14 -14
- package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
- package/dist/features/promotions/schemas/index.d.ts +6 -6
- package/dist/features/reviews/actions/review-actions.js +6 -5
- package/dist/features/reviews/api/[id]/route.js +4 -3
- package/dist/features/reviews/components/ReviewDetailPageView.js +2 -2
- package/dist/features/reviews/components/ReviewDetailShell.js +6 -3
- package/dist/features/reviews/components/ReviewsIndexListing.js +2 -2
- package/dist/features/reviews/schemas/index.d.ts +6 -6
- package/dist/features/scams/components/ScamProfileView.js +19 -10
- package/dist/features/scams/components/ScamRegistryView.js +2 -1
- package/dist/features/search/components/Search.d.ts +1 -1
- package/dist/features/search/components/Search.js +56 -49
- package/dist/features/search/schemas/index.d.ts +5 -5
- package/dist/features/seller/actions/offer-actions.js +11 -9
- package/dist/features/seller/components/SellerAddressesView.js +6 -4
- package/dist/features/seller/components/SellerBidsView.js +2 -2
- package/dist/features/seller/components/SellerCouponsView.js +1 -1
- package/dist/features/seller/components/SellerOffersPanel.js +6 -1
- package/dist/features/seller/components/SellerOrdersView.js +1 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +3 -3
- package/dist/features/seller/components/SellerPreOrdersView.js +5 -4
- package/dist/features/seller/components/SellerPrizeDrawsView.js +5 -4
- package/dist/features/seller/components/SellerProductShell.d.ts +19 -1
- package/dist/features/seller/components/SellerProductShell.js +75 -9
- package/dist/features/seller/components/SellerProductsView.js +10 -11
- package/dist/features/seller/components/SellerShippingView.js +3 -3
- package/dist/features/seller/components/SellerSidebar.js +10 -7
- package/dist/features/seller/components/SellerStorefrontView.js +3 -3
- package/dist/features/seller/schemas/index.d.ts +4 -4
- package/dist/features/shell/FormShell.js +2 -1
- package/dist/features/shell/QuickFormDrawer.js +4 -3
- package/dist/features/shell/StepForm.js +4 -3
- package/dist/features/stores/actions/store-query-actions.js +4 -3
- package/dist/features/stores/components/StoreAboutView.js +2 -1
- package/dist/features/stores/components/StoreAuctionsListing.js +43 -64
- package/dist/features/stores/components/StoreDetailLayoutView.js +2 -2
- package/dist/features/stores/components/StorePreOrdersListing.js +33 -57
- package/dist/features/stores/components/StoreProductsListing.js +16 -49
- package/dist/features/stores/components/StoresIndexListing.js +2 -2
- package/dist/features/stores/schemas/index.d.ts +2 -2
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +8 -7
- package/dist/features/wishlist/hooks/useGuestWishlist.d.ts +5 -5
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +6 -6
- package/dist/features/wishlist/utils/guest-wishlist.d.ts +5 -5
- package/dist/index.d.ts +21 -3
- package/dist/index.js +1737 -1725
- package/dist/monitoring/server-logger.js +5 -9
- package/dist/next/api/apiHandler.js +56 -37
- package/dist/next/components/GlobalError.js +2 -1
- package/dist/next/routing/route-map.d.ts +27 -0
- package/dist/next/routing/route-map.js +10 -0
- package/dist/react/ErrorBoundary.js +2 -1
- package/dist/react/contexts/SessionContext.js +38 -28
- package/dist/react/hooks/useCamera.d.ts +1 -1
- package/dist/react/hooks/useCamera.js +8 -7
- package/dist/seed/site-settings-seed-data.js +6 -0
- package/dist/server-entry.d.ts +3 -0
- package/dist/server-entry.js +3 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.js +15 -0
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/DataTable.js +28 -7
- package/dist/ui/components/Button.d.ts +8 -1
- package/dist/ui/components/Button.js +47 -8
- package/dist/ui/components/CollageLightbox.d.ts +18 -0
- package/dist/ui/components/CollageLightbox.js +41 -0
- package/dist/ui/components/Dropdown.js +7 -6
- package/dist/ui/components/ImageLightbox.d.ts +7 -1
- package/dist/ui/components/ImageLightbox.js +15 -5
- package/dist/ui/components/PageLoader.js +4 -3
- package/dist/ui/components/PaginatedMultiSelect.d.ts +28 -0
- package/dist/ui/components/PaginatedMultiSelect.js +141 -0
- package/dist/ui/components/PaginatedMultiSelect.style.css +272 -0
- package/dist/ui/components/Semantic.js +1 -1
- package/dist/ui/components/SideDrawer.js +17 -15
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1 -0
- package/dist/utils/number.formatter.js +5 -13
- package/dist/utils/string.formatter.js +21 -18
- package/dist/validation/schemas.d.ts +2 -2
- package/package.json +1 -1
|
@@ -15,6 +15,8 @@ import { cartRepository } from "../../cart/repository/cart.repository";
|
|
|
15
15
|
import { maskOfferForSeller } from "../../../security";
|
|
16
16
|
import { ERROR_MESSAGES, AuthorizationError, ValidationError, NotFoundError, } from "../../../errors";
|
|
17
17
|
import { OfferStatusValues } from "../schemas";
|
|
18
|
+
const ERR_OFFER_NOT_FOUND = "Offer not found";
|
|
19
|
+
const ERR_NOT_AUTHORISED = "Not authorized";
|
|
18
20
|
// --- Buyer: Make an Offer --------------------------------------------------
|
|
19
21
|
export async function makeOffer(userId, userEmail, input) {
|
|
20
22
|
const { productId, offerAmount, buyerNote } = input;
|
|
@@ -78,7 +80,7 @@ export async function respondToOffer(userId, input) {
|
|
|
78
80
|
const { offerId, action, counterAmount, sellerNote } = input;
|
|
79
81
|
const offer = await offerRepository.findById(offerId);
|
|
80
82
|
if (!offer)
|
|
81
|
-
throw new NotFoundError(
|
|
83
|
+
throw new NotFoundError(ERR_OFFER_NOT_FOUND);
|
|
82
84
|
const offerStore = offer.storeId ? await storeRepository.findById(offer.storeId) : null;
|
|
83
85
|
if (!offerStore || offerStore.ownerId !== userId)
|
|
84
86
|
throw new AuthorizationError("Not authorised to respond to this offer.");
|
|
@@ -131,9 +133,9 @@ export async function respondToOffer(userId, input) {
|
|
|
131
133
|
export async function acceptCounterOffer(userId, offerId) {
|
|
132
134
|
const offer = await offerRepository.findById(offerId);
|
|
133
135
|
if (!offer)
|
|
134
|
-
throw new NotFoundError(
|
|
136
|
+
throw new NotFoundError(ERR_OFFER_NOT_FOUND);
|
|
135
137
|
if (offer.buyerUid !== userId)
|
|
136
|
-
throw new AuthorizationError(
|
|
138
|
+
throw new AuthorizationError(ERR_NOT_AUTHORISED);
|
|
137
139
|
if (offer.status !== OfferStatusValues.COUNTERED)
|
|
138
140
|
throw new ValidationError("No counter to accept.");
|
|
139
141
|
if (new Date() > offer.expiresAt)
|
|
@@ -157,9 +159,9 @@ export async function counterOfferByBuyer(userId, userEmail, input) {
|
|
|
157
159
|
const { offerId, counterAmount, buyerNote } = input;
|
|
158
160
|
const offer = await offerRepository.findById(offerId);
|
|
159
161
|
if (!offer)
|
|
160
|
-
throw new NotFoundError(
|
|
162
|
+
throw new NotFoundError(ERR_OFFER_NOT_FOUND);
|
|
161
163
|
if (offer.buyerUid !== userId)
|
|
162
|
-
throw new AuthorizationError(
|
|
164
|
+
throw new AuthorizationError(ERR_NOT_AUTHORISED);
|
|
163
165
|
if (offer.status !== OfferStatusValues.COUNTERED)
|
|
164
166
|
throw new ValidationError(ERROR_MESSAGES.OFFER.NOT_COUNTERED);
|
|
165
167
|
if (new Date() > offer.expiresAt)
|
|
@@ -219,9 +221,9 @@ export async function counterOfferByBuyer(userId, userEmail, input) {
|
|
|
219
221
|
export async function withdrawOffer(userId, offerId) {
|
|
220
222
|
const offer = await offerRepository.findById(offerId);
|
|
221
223
|
if (!offer)
|
|
222
|
-
throw new NotFoundError(
|
|
224
|
+
throw new NotFoundError(ERR_OFFER_NOT_FOUND);
|
|
223
225
|
if (offer.buyerUid !== userId)
|
|
224
|
-
throw new AuthorizationError(
|
|
226
|
+
throw new AuthorizationError(ERR_NOT_AUTHORISED);
|
|
225
227
|
if (offer.status === OfferStatusValues.EXPIRED)
|
|
226
228
|
throw new ValidationError("This offer has already expired.");
|
|
227
229
|
if (![OfferStatusValues.PENDING, OfferStatusValues.COUNTERED].includes(offer.status))
|
|
@@ -245,9 +247,9 @@ export async function listSellerOffers(userId) {
|
|
|
245
247
|
export async function checkoutOffer(userId, offerId) {
|
|
246
248
|
const offer = await offerRepository.findById(offerId);
|
|
247
249
|
if (!offer)
|
|
248
|
-
throw new NotFoundError(
|
|
250
|
+
throw new NotFoundError(ERR_OFFER_NOT_FOUND);
|
|
249
251
|
if (offer.buyerUid !== userId)
|
|
250
|
-
throw new AuthorizationError(
|
|
252
|
+
throw new AuthorizationError(ERR_NOT_AUTHORISED);
|
|
251
253
|
if (offer.status !== OfferStatusValues.ACCEPTED)
|
|
252
254
|
throw new ValidationError("Only accepted offers can be checked out.");
|
|
253
255
|
if (!offer.lockedPrice)
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useEffect, useState } from "react";
|
|
4
4
|
import { MapPin, Pencil, Plus, Trash2, Star } from "lucide-react";
|
|
5
|
-
import { Button, Div, SideDrawer, Text } from "../../../ui";
|
|
5
|
+
import { Button, Div, Heading, SideDrawer, Text } from "../../../ui";
|
|
6
6
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
7
7
|
const INPUT_CLS = "w-full rounded-lg border border-zinc-300 dark:border-slate-600 bg-white dark:bg-slate-800 px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 placeholder-zinc-400 dark:placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-[var(--appkit-color-primary)]";
|
|
8
|
+
const CLS_GRID_2_COL = "grid grid-cols-2 gap-3";
|
|
8
9
|
function Field({ label, hint, children }) {
|
|
9
|
-
return (_jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "block text-xs font-medium text-zinc-700 dark:text-zinc-300", children: label }), children, hint && _jsx(
|
|
10
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "block text-xs font-medium text-zinc-700 dark:text-zinc-300", children: label }), children, hint && _jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-500", children: hint })] }));
|
|
10
11
|
}
|
|
11
12
|
// ---------------------------------------------------------------------------
|
|
12
13
|
// Helpers
|
|
@@ -141,5 +142,6 @@ export function SellerAddressesView({ apiBase = SELLER_ENDPOINTS.STORE_ADDRESSES
|
|
|
141
142
|
}
|
|
142
143
|
};
|
|
143
144
|
const set = (key, value) => setDraft((p) => ({ ...p, [key]: value }));
|
|
144
|
-
|
|
145
|
+
const handleTextField = (key) => (e) => set(key, e.target.value);
|
|
146
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsxs("div", { className: "sticky z-10 bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-4 py-3 flex items-center justify-between", style: { top: "var(--header-height, 0px)" }, children: [_jsxs(_Fragment, { children: [_jsx(Heading, { level: 2, className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Pickup Addresses" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 mt-0.5", children: "Manage your store's pickup and return locations" })] }), _jsxs(Button, { size: "sm", onClick: openAdd, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "Add Address" })] })] }), _jsxs("div", { className: "py-6 px-4 sm:px-6 max-w-2xl", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-4 py-3 text-sm text-red-700 dark:text-red-200", children: errorMessage })), isLoading ? (_jsx("div", { className: "flex justify-center py-16", children: _jsx("div", { className: "h-6 w-6 animate-spin rounded-full border-2 border-[var(--appkit-color-primary)] border-t-transparent" }) })) : addresses.length === 0 ? (_jsxs(Div, { className: "rounded-xl border-2 border-dashed border-zinc-200 dark:border-slate-700 py-16 flex flex-col items-center gap-3", children: [_jsx(MapPin, { className: "h-8 w-8 text-zinc-300 dark:text-slate-600" }), _jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "No pickup addresses yet" }), _jsx(Button, { size: "sm", variant: "outline", onClick: openAdd, children: "Add your first address" })] })) : (_jsx("div", { className: "grid gap-3", children: addresses.map((addr) => (_jsx("div", { className: deletingId === addr.id ? "opacity-50 pointer-events-none" : "", children: _jsx(AddressCard, { address: addr, onEdit: () => openEdit(addr), onDelete: () => handleDelete(addr) }) }, addr.id))) }))] }), _jsx(SideDrawer, { isOpen: drawerOpen, onClose: closeDrawer, title: editingId ? "Edit Address" : "Add Address", footer: _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: "outline", onClick: closeDrawer, className: "flex-1", children: "Cancel" }), _jsx(Button, { onClick: handleSave, disabled: saving, className: "flex-1", children: saving ? "Saving…" : editingId ? "Save Changes" : "Add Address" })] }), children: _jsxs("div", { className: "space-y-4 py-1", children: [saveError && (_jsx(Div, { className: "rounded-lg border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-3 py-2 text-sm text-red-700 dark:text-red-200", children: saveError })), _jsx(Field, { label: "Label *", hint: "e.g. Warehouse, Shop, Home", children: _jsx("input", { type: "text", value: draft.label, onChange: handleTextField("label"), placeholder: "Warehouse", maxLength: 60, className: INPUT_CLS }) }), _jsxs("div", { className: CLS_GRID_2_COL, children: [_jsx(Field, { label: "Full Name *", children: _jsx("input", { type: "text", value: draft.fullName, onChange: handleTextField("fullName"), placeholder: "Ravi Kumar", maxLength: 100, className: INPUT_CLS }) }), _jsx(Field, { label: "Phone *", children: _jsx("input", { type: "tel", value: draft.phone, onChange: handleTextField("phone"), placeholder: "+91 98765 43210", maxLength: 20, className: INPUT_CLS }) })] }), _jsx(Field, { label: "Address Line 1 *", children: _jsx("input", { type: "text", value: draft.addressLine1, onChange: handleTextField("addressLine1"), placeholder: "Shop 12, Main Market", maxLength: 200, className: INPUT_CLS }) }), _jsx(Field, { label: "Address Line 2", children: _jsx("input", { type: "text", value: draft.addressLine2, onChange: handleTextField("addressLine2"), placeholder: "Building / Floor (optional)", maxLength: 200, className: INPUT_CLS }) }), _jsx(Field, { label: "Landmark", children: _jsx("input", { type: "text", value: draft.landmark, onChange: handleTextField("landmark"), placeholder: "Near metro station (optional)", maxLength: 100, className: INPUT_CLS }) }), _jsxs("div", { className: CLS_GRID_2_COL, children: [_jsx(Field, { label: "City *", children: _jsx("input", { type: "text", value: draft.city, onChange: handleTextField("city"), placeholder: "Mumbai", maxLength: 100, className: INPUT_CLS }) }), _jsx(Field, { label: "State *", children: _jsx("input", { type: "text", value: draft.state, onChange: handleTextField("state"), placeholder: "Maharashtra", maxLength: 100, className: INPUT_CLS }) })] }), _jsxs("div", { className: CLS_GRID_2_COL, children: [_jsx(Field, { label: "Postal Code *", children: _jsx("input", { type: "text", value: draft.postalCode, onChange: handleTextField("postalCode"), placeholder: "400001", maxLength: 10, className: INPUT_CLS }) }), _jsx(Field, { label: "Country *", children: _jsx("input", { type: "text", value: draft.country, onChange: handleTextField("country"), placeholder: "India", maxLength: 60, className: INPUT_CLS }) })] }), _jsxs("label", { className: "flex items-center gap-3 cursor-pointer", children: [_jsx("input", { type: "checkbox", checked: draft.isDefault, onChange: (e) => set("isDefault", e.target.checked), className: "h-4 w-4 rounded border-zinc-300 dark:border-slate-600 text-[var(--appkit-color-primary)] focus:ring-[var(--appkit-color-primary)]" }), _jsx("span", { className: "text-sm text-zinc-700 dark:text-zinc-300", children: "Set as default pickup address" })] })] }) })] }));
|
|
145
147
|
}
|
|
@@ -4,7 +4,7 @@ import { useState, useCallback } from "react";
|
|
|
4
4
|
import { X } from "lucide-react";
|
|
5
5
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
6
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
|
-
import { Badge, Div, FilterChipGroup, ListingToolbar, Pagination } from "../../../ui";
|
|
7
|
+
import { Badge, Div, FilterChipGroup, ListingToolbar, Pagination, Text } from "../../../ui";
|
|
8
8
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
9
|
import { SELLER_BID_STATUS_TABS } from "../../admin/constants/filter-tabs";
|
|
10
10
|
import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
@@ -94,7 +94,7 @@ export function SellerBidsView({ endpoint = SELLER_ENDPOINTS.BIDS }) {
|
|
|
94
94
|
{
|
|
95
95
|
key: "productTitle",
|
|
96
96
|
header: "Auction",
|
|
97
|
-
render: (row) => (_jsxs("div", { className: "space-y-0.5", children: [_jsx(
|
|
97
|
+
render: (row) => (_jsxs("div", { className: "space-y-0.5", children: [_jsx(Text, { className: "font-medium text-sm text-zinc-900 dark:text-zinc-100 line-clamp-1", children: row.productTitle }), _jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-500 font-mono", children: row.productId })] })),
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
100
|
key: "userName",
|
|
@@ -112,7 +112,7 @@ export function SellerCouponsView({ onCreateClick, onEditClick, onToggle, onDele
|
|
|
112
112
|
}
|
|
113
113
|
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by coupon code", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState, extra: onCreateClick
|
|
114
114
|
? (_jsxs(Button, { size: "sm", onClick: onCreateClick, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "Add Coupon" })] }))
|
|
115
|
-
: undefined }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-4 py-3 text-sm text-red-700 dark:text-red-200", children: errorMessage })), isLoading ? (_jsx(Div, { className: "fluid-grid-card gap-3", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Div, { className: "rounded-xl border-2 border-zinc-100 dark:border-slate-700 p-4 animate-pulse space-y-3", children: [_jsx(Div, { className: "h-6 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" }), _jsx(Div, { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx(Div, { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-1/2" })] }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-500", children: "No coupons found \u2014 create your first coupon" }) })) : (_jsx(Div, { className: "fluid-grid-card gap-3", children: rows.map((row) => (_jsx(CouponCard, { coupon: row.raw, onEdit: onEditClick ? handleEdit : undefined, onToggleActive: onToggle ? handleToggle : undefined, onDelete: onDelete ? handleDelete : undefined, className: togglingId === row.id || deletingId === row.id ? "pointer-events-none opacity-60" : undefined }, row.id))) }))] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsxs("div", { className: "space-y-2", children: [_jsx(
|
|
115
|
+
: undefined }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-4 py-3 text-sm text-red-700 dark:text-red-200", children: errorMessage })), isLoading ? (_jsx(Div, { className: "fluid-grid-card gap-3", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Div, { className: "rounded-xl border-2 border-zinc-100 dark:border-slate-700 p-4 animate-pulse space-y-3", children: [_jsx(Div, { className: "h-6 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" }), _jsx(Div, { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx(Div, { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-1/2" })] }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-500", children: "No coupons found \u2014 create your first coupon" }) })) : (_jsx(Div, { className: "fluid-grid-card gap-3", children: rows.map((row) => (_jsx(CouponCard, { coupon: row.raw, onEdit: onEditClick ? handleEdit : undefined, onToggleActive: onToggle ? handleToggle : undefined, onDelete: onDelete ? handleDelete : undefined, className: togglingId === row.id || deletingId === row.id ? "pointer-events-none opacity-60" : undefined }, row.id))) }))] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Active", value: "true" }, { label: "Inactive", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value
|
|
116
116
|
? "bg-[var(--appkit-color-primary)] text-white border-[var(--appkit-color-primary)]"
|
|
117
117
|
: "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-[var(--appkit-color-primary)] py-2.5 text-sm font-semibold text-white transition-colors active:scale-[0.98]", children: ["Apply", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
|
|
118
118
|
}
|
|
@@ -47,12 +47,17 @@ function statusVariant(status) {
|
|
|
47
47
|
default: return "default";
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
+
const PLACEHOLDER_SELLER_NOTE = "Optional note to buyer";
|
|
50
51
|
function OfferCard({ offer, onRespond, onUpdate, onNeedsLogin }) {
|
|
51
52
|
const [uiState, setUiState] = useState("idle");
|
|
52
53
|
const [counterInput, setCounterInput] = useState("");
|
|
53
54
|
const [sellerNote, setSellerNote] = useState("");
|
|
54
55
|
const [error, setError] = useState("");
|
|
55
56
|
const [isPending, startTransition] = useTransition();
|
|
57
|
+
const toAccepting = useCallback(() => setUiState("accepting"), []);
|
|
58
|
+
const toCountering = useCallback(() => setUiState("countering"), []);
|
|
59
|
+
const toDeclining = useCallback(() => setUiState("declining"), []);
|
|
60
|
+
const toIdle = useCallback(() => setUiState("idle"), []);
|
|
56
61
|
const isPendingOffer = offer.status === "pending";
|
|
57
62
|
function submit(action) {
|
|
58
63
|
setError("");
|
|
@@ -100,7 +105,7 @@ function OfferCard({ offer, onRespond, onUpdate, onNeedsLogin }) {
|
|
|
100
105
|
}
|
|
101
106
|
submit({ action: "counter", offerId: offer.id, counterAmount: amount, sellerNote: sellerNote || undefined });
|
|
102
107
|
}
|
|
103
|
-
return (_jsxs(Div, { className: "rounded-xl border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 p-4 space-y-3", children: [_jsxs(Div, { className: "flex items-start justify-between gap-2 flex-wrap", children: [_jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: "font-semibold text-sm text-zinc-900 dark:text-zinc-100 truncate", children: offer.productTitle ?? "Unknown Product" }), _jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 mt-0.5", children: [relativeTime(offer.createdAt), " \u00B7 ", isPendingOffer ? expiresIn(offer.expiresAt) : ""] })] }), _jsx(Badge, { variant: statusVariant(offer.status), className: "shrink-0 capitalize text-xs", children: offer.status })] }), _jsxs(Div, { className: "flex gap-4 flex-wrap", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-500 uppercase tracking-wide", children: "Listed" }), _jsx(Text, { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: formatRupees(offer.listedPrice) })] }), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-500 uppercase tracking-wide", children: "Offered" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100", children: formatRupees(offer.offerAmount) })] }), offer.counterAmount != null && (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-500 uppercase tracking-wide", children: "Your Counter" }), _jsx(Text, { className: "text-sm font-medium text-blue-600 dark:text-blue-400", children: formatRupees(offer.counterAmount) })] }))] }), offer.buyerNote && (_jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 italic", children: ["\"", offer.buyerNote, "\""] })), isPendingOffer && uiState === "idle" && (_jsxs(Div, { className: "flex gap-2 flex-wrap", children: [_jsx(Button, { size: "sm", variant: "primary", onClick:
|
|
108
|
+
return (_jsxs(Div, { className: "rounded-xl border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 p-4 space-y-3", children: [_jsxs(Div, { className: "flex items-start justify-between gap-2 flex-wrap", children: [_jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: "font-semibold text-sm text-zinc-900 dark:text-zinc-100 truncate", children: offer.productTitle ?? "Unknown Product" }), _jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 mt-0.5", children: [relativeTime(offer.createdAt), " \u00B7 ", isPendingOffer ? expiresIn(offer.expiresAt) : ""] })] }), _jsx(Badge, { variant: statusVariant(offer.status), className: "shrink-0 capitalize text-xs", children: offer.status })] }), _jsxs(Div, { className: "flex gap-4 flex-wrap", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-500 uppercase tracking-wide", children: "Listed" }), _jsx(Text, { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: formatRupees(offer.listedPrice) })] }), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-500 uppercase tracking-wide", children: "Offered" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100", children: formatRupees(offer.offerAmount) })] }), offer.counterAmount != null && (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-500 uppercase tracking-wide", children: "Your Counter" }), _jsx(Text, { className: "text-sm font-medium text-blue-600 dark:text-blue-400", children: formatRupees(offer.counterAmount) })] }))] }), offer.buyerNote && (_jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 italic", children: ["\"", offer.buyerNote, "\""] })), isPendingOffer && uiState === "idle" && (_jsxs(Div, { className: "flex gap-2 flex-wrap", children: [_jsx(Button, { size: "sm", variant: "primary", onClick: toAccepting, disabled: isPending, children: "Accept" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toCountering, disabled: isPending, className: "border border-zinc-300 dark:border-zinc-600", children: "Counter" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toDeclining, disabled: isPending, className: "text-red-600 dark:text-red-400 border border-red-200 dark:border-red-800", children: "Decline" })] })), uiState === "accepting" && (_jsxs(Div, { className: "space-y-2", children: [_jsx(Input, { placeholder: PLACEHOLDER_SELLER_NOTE, value: sellerNote, onChange: (e) => setSellerNote(e.target.value), disabled: isPending }), _jsxs(Div, { className: "flex gap-2", children: [_jsx(Button, { size: "sm", variant: "primary", onClick: handleAccept, disabled: isPending, children: isPending ? "Accepting…" : "Confirm Accept" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toIdle, disabled: isPending, children: "Cancel" })] })] })), uiState === "declining" && (_jsxs(Div, { className: "space-y-2", children: [_jsx(Input, { placeholder: PLACEHOLDER_SELLER_NOTE, value: sellerNote, onChange: (e) => setSellerNote(e.target.value), disabled: isPending }), _jsxs(Div, { className: "flex gap-2", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: handleDecline, disabled: isPending, className: "text-red-600 dark:text-red-400 border border-red-200 dark:border-red-800", children: isPending ? "Declining…" : "Confirm Decline" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toIdle, disabled: isPending, children: "Cancel" })] })] })), uiState === "countering" && (_jsxs(Div, { className: "space-y-2", children: [_jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: ["Suggest a price between the buyer's offer (", formatRupees(offer.offerAmount), ") and your listed price (", formatRupees(offer.listedPrice), ")."] }), _jsx(Input, { type: "number", placeholder: "Your counter amount (\u20B9)", value: counterInput, onChange: (e) => setCounterInput(e.target.value), disabled: isPending }), _jsx(Input, { placeholder: PLACEHOLDER_SELLER_NOTE, value: sellerNote, onChange: (e) => setSellerNote(e.target.value), disabled: isPending }), _jsxs(Div, { className: "flex gap-2", children: [_jsx(Button, { size: "sm", variant: "secondary", onClick: handleCounter, disabled: isPending, children: isPending ? "Sending…" : "Send Counter" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toIdle, disabled: isPending, children: "Cancel" })] })] })), error && _jsx(Alert, { variant: "error", children: _jsx(Text, { className: "text-xs", children: error }) })] }));
|
|
104
109
|
}
|
|
105
110
|
export function SellerOffersPanel({ fetchEndpoint = "/api/store/offers", onRespond, className = "", }) {
|
|
106
111
|
const [offers, setOffers] = useState([]);
|
|
@@ -170,7 +170,7 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
|
|
|
170
170
|
{
|
|
171
171
|
key: "primary",
|
|
172
172
|
header: "Order",
|
|
173
|
-
render: (row) => (_jsxs("div", { className: "space-y-0.5 min-w-0", children: [_jsx(
|
|
173
|
+
render: (row) => (_jsxs("div", { className: "space-y-0.5 min-w-0", children: [_jsx(Text, { className: "font-mono text-xs font-semibold text-zinc-900 dark:text-zinc-100 truncate", children: row.primary }), _jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: [row.buyerName, " \u00B7 ", row.itemCount, " item", row.itemCount !== 1 ? "s" : ""] })] })),
|
|
174
174
|
},
|
|
175
175
|
{
|
|
176
176
|
key: "totalAmount",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useEffect, useState } from "react";
|
|
4
|
-
import { Alert, Badge, Button, Div, FormField, FormGroup, Heading, Stack, Text
|
|
4
|
+
import { Alert, Badge, Button, Div, FormField, FormGroup, Heading, Section, Stack, Text } from "../../../ui";
|
|
5
5
|
import { StackedViewShell } from "../../../ui";
|
|
6
6
|
const DEFAULT_DRAFT = {
|
|
7
7
|
method: "upi",
|
|
@@ -83,9 +83,9 @@ export function SellerPayoutSettingsView({ apiBase = "/api/store/payout-settings
|
|
|
83
83
|
return (_jsx(StackedViewShell, { portal: "seller", title: "Payout Settings", sections: [
|
|
84
84
|
_jsxs(Stack, { gap: "lg", children: [current && (_jsx(Div, { className: "flex items-center gap-2", children: _jsx(Badge, { variant: current.isConfigured ? "success" : "warning", children: current.isConfigured ? "Payout configured" : "Not configured" }) })), error && _jsx(Alert, { variant: "error", children: error }), success && _jsx(Alert, { variant: "success", children: "Payout details saved." }), current?.isConfigured && (_jsx(Alert, { variant: "info", children: current.method === "upi"
|
|
85
85
|
? `Current UPI: ${current.upiId}`
|
|
86
|
-
: `Current bank: ${current.bankAccount?.bankName ?? ""} — ••••${current.bankAccount?.accountNumberMasked?.slice(-4) ?? "••••"} (${current.bankAccount?.accountType})` })), _jsxs(
|
|
86
|
+
: `Current bank: ${current.bankAccount?.bankName ?? ""} — ••••${current.bankAccount?.accountNumberMasked?.slice(-4) ?? "••••"} (${current.bankAccount?.accountType})` })), _jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-3", children: "Payout Method" }), _jsx(Stack, { gap: "sm", children: ([
|
|
87
87
|
{ value: "upi", label: "UPI", desc: "Instant payouts via UPI VPA (e.g. name@upi)." },
|
|
88
88
|
{ value: "bank_transfer", label: "Bank Transfer", desc: "NEFT/RTGS to your bank account within 2–3 business days." },
|
|
89
|
-
]).map(({ value, label, desc }) => (_jsxs("label", { className: "flex items-center gap-3 p-3 rounded-lg border border-[var(--appkit-color-border)] cursor-pointer has-[:checked]:border-[var(--appkit-color-primary)] has-[:checked]:bg-[var(--appkit-color-primary)]/5", children: [_jsx("input", { type: "radio", name: "payoutMethod", value: value, checked: draft.method === value, onChange: () => update("method", value), className: "accent-[var(--appkit-color-primary)]", disabled: busy }), _jsxs(Div, { children: [_jsx(Text, { className: "font-medium", children: label }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: desc })] })] }, value))) })] }), isUpi && (_jsxs(
|
|
89
|
+
]).map(({ value, label, desc }) => (_jsxs("label", { className: "flex items-center gap-3 p-3 rounded-lg border border-[var(--appkit-color-border)] cursor-pointer has-[:checked]:border-[var(--appkit-color-primary)] has-[:checked]:bg-[var(--appkit-color-primary)]/5", children: [_jsx("input", { type: "radio", name: "payoutMethod", value: value, checked: draft.method === value, onChange: () => update("method", value), className: "accent-[var(--appkit-color-primary)]", disabled: busy }), _jsxs(Div, { children: [_jsx(Text, { className: "font-medium", children: label }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: desc })] })] }, value))) })] }), isUpi && (_jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-3", children: "UPI Details" }), _jsx(FormField, { name: "upiId", label: "UPI ID (VPA)", type: "text", value: draft.upiId, onChange: (v) => update("upiId", v), placeholder: "yourname@upi", helpText: "Ensure this VPA is registered and active.", disabled: busy })] })), !isUpi && (_jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-3", children: "Bank Account Details" }), _jsxs(Stack, { gap: "md", children: [_jsx(FormField, { name: "accountHolderName", label: "Account Holder Name", type: "text", value: draft.accountHolderName, onChange: (v) => update("accountHolderName", v), placeholder: "Name as on bank account", disabled: busy }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "accountNumber", label: "Account Number", type: "text", value: draft.accountNumber, onChange: (v) => update("accountNumber", v), placeholder: "Enter full account number", helpText: current?.bankAccount ? `Saved: ••••${current.bankAccount.accountNumberMasked?.slice(-4) ?? "••••"}` : "Stored securely, never displayed in full.", disabled: busy }), _jsx(FormField, { name: "ifscCode", label: "IFSC Code", type: "text", value: draft.ifscCode, onChange: (v) => update("ifscCode", v.toUpperCase()), placeholder: "e.g. SBIN0001234", disabled: busy })] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "bankName", label: "Bank Name", type: "text", value: draft.bankName, onChange: (v) => update("bankName", v), placeholder: "e.g. State Bank of India", disabled: busy }), _jsxs(Div, { children: [_jsx(Text, { className: "text-sm font-medium mb-1.5", children: "Account Type" }), _jsx(Stack, { gap: "xs", className: "flex-row", children: ["savings", "current"].map((t) => (_jsxs("label", { className: "flex items-center gap-2 cursor-pointer", children: [_jsx("input", { type: "radio", name: "accountType", value: t, checked: draft.accountType === t, onChange: () => update("accountType", t), className: "accent-[var(--appkit-color-primary)]", disabled: busy }), _jsx(Text, { className: "capitalize text-sm", children: t })] }, t))) })] })] })] })] })), _jsx(Div, { className: "flex justify-end pt-2 border-t border-[var(--appkit-color-border)]", children: _jsx(Button, { variant: "primary", onClick: handleSave, disabled: busy, isLoading: saving, children: "Save Payout Details" }) })] }, "payout"),
|
|
90
90
|
] }));
|
|
91
91
|
}
|
|
@@ -4,10 +4,11 @@ import React, { useState, useCallback } from "react";
|
|
|
4
4
|
import { Pencil, X } from "lucide-react";
|
|
5
5
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
6
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
|
-
import { Alert, Badge, Button, FilterChipGroup, ListingToolbar, Pagination,
|
|
7
|
+
import { Alert, Badge, Button, Div, FilterChipGroup, ListingToolbar, ListingViewShell, Pagination, Row, Text } from "../../../ui";
|
|
8
8
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
9
|
import { SELLER_PRE_ORDER_STATUS_TABS } from "../../admin/constants/filter-tabs";
|
|
10
10
|
import { ROUTES } from "../../../constants";
|
|
11
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
11
12
|
import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
12
13
|
import { DataTable } from "../../admin/components/DataTable";
|
|
13
14
|
import { useActionDispatch } from "../../../react/hooks/use-action-dispatch";
|
|
@@ -33,7 +34,7 @@ const PRE_ORDER_COLUMNS = [
|
|
|
33
34
|
{
|
|
34
35
|
key: "primary",
|
|
35
36
|
header: "Pre-order",
|
|
36
|
-
render: (row) => (_jsxs("div", { className: "space-y-1", children: [_jsx(
|
|
37
|
+
render: (row) => (_jsxs("div", { className: "space-y-1", children: [_jsx(Text, { className: "font-medium text-[var(--appkit-color-text)] line-clamp-1", children: row.primary }), _jsx("span", { className: "text-xs text-[var(--appkit-color-text-muted)]", children: row.secondary })] })),
|
|
37
38
|
},
|
|
38
39
|
{
|
|
39
40
|
key: "price",
|
|
@@ -137,8 +138,8 @@ export function SellerPreOrdersView({ children, ...props }) {
|
|
|
137
138
|
if (hasChildren) {
|
|
138
139
|
return (_jsx(ListingViewShell, { portal: "seller", ...props, children: children }));
|
|
139
140
|
}
|
|
140
|
-
return (_jsxs(
|
|
141
|
+
return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search pre-orders by name\u2026", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky z-10 flex justify-center bg-[var(--appkit-color-surface)]/95 backdrop-blur-sm border-b border-[var(--appkit-color-border)] px-3 py-1.5", style: { top: "calc(var(--header-height, 0px) + 44px)" }, children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Alert, { variant: "error", className: "mb-4", children: errorMessage })), _jsx(DataTable, { columns: PRE_ORDER_COLUMNS, rows: rows, isLoading: isLoading, emptyLabel: "No pre-orders listed yet", getRowHref: (row) => String(ROUTES.STORE.PRE_ORDERS_EDIT(row.id)), renderRowActions: (row) => (_jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => {
|
|
141
142
|
e.stopPropagation();
|
|
142
143
|
void dispatch({ type: "NAVIGATE", href: String(ROUTES.STORE.PRE_ORDERS_EDIT(row.id)) });
|
|
143
|
-
}, "aria-label": "
|
|
144
|
+
}, "aria-label": ACTIONS.STORE["edit-listing"].ariaLabel, children: _jsx(Pencil, { className: "w-4 h-4" }) })) })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx(Div, { role: "presentation", className: "fixed inset-0 z-40 bg-black/40", onClick: () => setFilterOpen(false) }), _jsxs(Div, { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-[var(--appkit-color-surface)] shadow-2xl", children: [_jsxs(Row, { justify: "between", className: "border-b border-[var(--appkit-color-border)] px-4 py-3.5", children: [_jsx(Text, { className: "text-base font-semibold text-[var(--appkit-color-text)]", children: "Filters" }), _jsxs(Row, { className: "gap-2", children: [activeFilterCount > 0 && (_jsx(Button, { variant: "ghost", size: "sm", onClick: clearFilters, className: "text-xs text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-error)]", children: "Clear all" })), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setFilterOpen(false), "aria-label": "Close filters", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx(Div, { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) }), _jsx(Div, { className: "border-t border-[var(--appkit-color-border)] px-4 py-3.5", children: _jsxs(Button, { variant: "primary", onClick: applyFilters, className: "w-full rounded-lg py-2.5 active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
|
|
144
145
|
}
|
|
@@ -4,10 +4,11 @@ import React, { useState, useCallback } from "react";
|
|
|
4
4
|
import { Pencil, X } from "lucide-react";
|
|
5
5
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
6
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
|
-
import { Alert, Badge, Button, FilterChipGroup, ListingToolbar, Pagination,
|
|
7
|
+
import { Alert, Badge, Button, Div, FilterChipGroup, ListingToolbar, ListingViewShell, Pagination, Row, Text } from "../../../ui";
|
|
8
8
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
9
|
import { SELLER_PRIZE_DRAW_STATUS_TABS } from "../../admin/constants/filter-tabs";
|
|
10
10
|
import { ROUTES } from "../../../constants";
|
|
11
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
11
12
|
import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
12
13
|
import { DataTable } from "../../admin/components/DataTable";
|
|
13
14
|
import { useActionDispatch } from "../../../react/hooks/use-action-dispatch";
|
|
@@ -39,7 +40,7 @@ const PRIZE_DRAW_COLUMNS = [
|
|
|
39
40
|
{
|
|
40
41
|
key: "primary",
|
|
41
42
|
header: "Prize Draw",
|
|
42
|
-
render: (row) => (_jsxs("div", { className: "space-y-1", children: [_jsx(
|
|
43
|
+
render: (row) => (_jsxs("div", { className: "space-y-1", children: [_jsx(Text, { className: "font-medium text-[var(--appkit-color-text)] line-clamp-1", children: row.primary }), _jsx("span", { className: "text-xs text-[var(--appkit-color-text-muted)]", children: row.secondary })] })),
|
|
43
44
|
},
|
|
44
45
|
{
|
|
45
46
|
key: "entryFee",
|
|
@@ -134,8 +135,8 @@ export function SellerPrizeDrawsView({ children, ...props }) {
|
|
|
134
135
|
if (hasChildren) {
|
|
135
136
|
return (_jsx(ListingViewShell, { portal: "seller", ...props, children: children }));
|
|
136
137
|
}
|
|
137
|
-
return (_jsxs(
|
|
138
|
+
return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search prize draws by name\u2026", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky z-10 flex justify-center bg-[var(--appkit-color-surface)]/95 backdrop-blur-sm border-b border-[var(--appkit-color-border)] px-3 py-1.5", style: { top: "calc(var(--header-height, 0px) + 44px)" }, children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Alert, { variant: "error", className: "mb-4", children: errorMessage })), _jsx(DataTable, { columns: PRIZE_DRAW_COLUMNS, rows: rows, isLoading: isLoading, emptyLabel: "No prize draws listed yet", getRowHref: (row) => String(ROUTES.STORE.PRIZE_DRAWS_EDIT(row.id)), renderRowActions: (row) => (_jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => {
|
|
138
139
|
e.stopPropagation();
|
|
139
140
|
void dispatch({ type: "NAVIGATE", href: String(ROUTES.STORE.PRIZE_DRAWS_EDIT(row.id)) });
|
|
140
|
-
}, "aria-label": "
|
|
141
|
+
}, "aria-label": ACTIONS.STORE["edit-listing"].ariaLabel, children: _jsx(Pencil, { className: "w-4 h-4" }) })) })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx(Div, { role: "presentation", className: "fixed inset-0 z-40 bg-black/40", onClick: () => setFilterOpen(false) }), _jsxs(Div, { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-[var(--appkit-color-surface)] shadow-2xl", children: [_jsxs(Row, { justify: "between", className: "border-b border-[var(--appkit-color-border)] px-4 py-3.5", children: [_jsx(Text, { className: "text-base font-semibold text-[var(--appkit-color-text)]", children: "Filters" }), _jsxs(Row, { className: "gap-2", children: [activeFilterCount > 0 && (_jsx(Button, { variant: "ghost", size: "sm", onClick: clearFilters, className: "text-xs text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-error)]", children: "Clear all" })), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setFilterOpen(false), "aria-label": "Close filters", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx(Div, { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) }), _jsx(Div, { className: "border-t border-[var(--appkit-color-border)] px-4 py-3.5", children: _jsxs(Button, { variant: "primary", onClick: applyFilters, className: "w-full rounded-lg py-2.5 active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }));
|
|
141
142
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
export type ProductListingMode = "standard" | "auction" | "pre-order" | "prize-draw";
|
|
2
|
+
export type ProductListingMode = "standard" | "auction" | "pre-order" | "prize-draw" | "classified" | "digital-code" | "live";
|
|
3
3
|
export interface SellerProductDraft {
|
|
4
4
|
title?: string;
|
|
5
5
|
slug?: string;
|
|
@@ -38,6 +38,24 @@ export interface SellerProductDraft {
|
|
|
38
38
|
preOrderMaxQuantity?: number;
|
|
39
39
|
preOrderProductionStatus?: "upcoming" | "in_production" | "ready_to_ship";
|
|
40
40
|
preOrderCancellable?: boolean;
|
|
41
|
+
classifiedCity?: string;
|
|
42
|
+
classifiedLocality?: string;
|
|
43
|
+
classifiedPincode?: string;
|
|
44
|
+
classifiedContactMethod?: "chat" | "phone" | "both";
|
|
45
|
+
classifiedAcceptsShipping?: boolean;
|
|
46
|
+
classifiedNegotiable?: boolean;
|
|
47
|
+
digitalCodeDelivery?: "auto-claim" | "manual-email";
|
|
48
|
+
digitalCodePoolSize?: number;
|
|
49
|
+
digitalCodeRedemptionInstructions?: string;
|
|
50
|
+
digitalCodeExpiresAt?: string;
|
|
51
|
+
liveSpecies?: string;
|
|
52
|
+
liveAgeMonths?: number;
|
|
53
|
+
liveSex?: "male" | "female" | "unknown" | "n/a";
|
|
54
|
+
liveCareInfo?: string;
|
|
55
|
+
liveTransportMethod?: "courier" | "in-person" | "specialist";
|
|
56
|
+
liveHandlingFee?: number;
|
|
57
|
+
liveJurisdictions?: string[];
|
|
58
|
+
liveCites?: boolean;
|
|
41
59
|
}
|
|
42
60
|
export interface SellerProductShellProps {
|
|
43
61
|
mode: "create" | "edit";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useRef, useState } from "react";
|
|
4
4
|
import { useRouter } from "next/navigation";
|
|
5
5
|
import { FormShell, StepForm, useFormShell } from "../../shell";
|
|
6
|
-
import { Alert, Button, Div, FormField, FormGroup, Heading, Stack, Text, Toggle
|
|
6
|
+
import { Alert, Button, Div, FormField, FormGroup, Heading, Section, Stack, Text, Toggle } from "../../../ui";
|
|
7
7
|
import { ImageUpload, MediaUploadList, useMediaUpload } from "../../media";
|
|
8
8
|
import { StoreAddressSelectorCreate } from "../../stores/components/StoreAddressSelectorCreate";
|
|
9
9
|
const CONDITION_OPTIONS = [
|
|
@@ -27,7 +27,7 @@ function toPaise(rupeeStr) {
|
|
|
27
27
|
}
|
|
28
28
|
// ── Step 1: Basic ─────────────────────────────────────────────────────────────
|
|
29
29
|
function StepBasic({ values, onChange, renderCategorySelector, renderBrandSelector, renderTemplateSelector, }) {
|
|
30
|
-
return (_jsxs(Stack, { gap: "md", children: [renderTemplateSelector?.({ onApply: onChange }), _jsx(FormField, { name: "title", label: "Title", type: "text", value: values.title ?? "", onChange: (v) => onChange({ title: v }), placeholder: "e.g. Charizard Base Set PSA 9" }), _jsx(FormField, { name: "description", label: "Description", type: "textarea", value: values.description ?? "", onChange: (v) => onChange({ description: v }), placeholder: "Describe your listing in detail\u2026" }), _jsxs(FormGroup, { columns: 2, children: [renderCategorySelector ? (_jsxs(
|
|
30
|
+
return (_jsxs(Stack, { gap: "md", children: [renderTemplateSelector?.({ onApply: onChange }), _jsx(FormField, { name: "title", label: "Title", type: "text", value: values.title ?? "", onChange: (v) => onChange({ title: v }), placeholder: "e.g. Charizard Base Set PSA 9" }), _jsx(FormField, { name: "description", label: "Description", type: "textarea", value: values.description ?? "", onChange: (v) => onChange({ description: v }), placeholder: "Describe your listing in detail\u2026" }), _jsxs(FormGroup, { columns: 2, children: [renderCategorySelector ? (_jsxs(_Fragment, { children: [_jsx(Text, { className: "text-sm font-medium text-[var(--appkit-color-text)] mb-1", children: "Category" }), renderCategorySelector({ value: values.category ?? "", onChange: (v) => onChange({ category: v }) })] })) : (_jsx(FormField, { name: "category", label: "Category", type: "text", value: values.category ?? "", onChange: (v) => onChange({ category: v }), placeholder: "e.g. Trading Cards" })), _jsx(FormField, { name: "condition", label: "Condition", type: "select", value: values.condition ?? "new", onChange: (v) => onChange({ condition: v }), options: CONDITION_OPTIONS })] }), renderBrandSelector ? (_jsxs(_Fragment, { children: [_jsx(Text, { className: "text-sm font-medium text-[var(--appkit-color-text)] mb-1", children: "Brand" }), renderBrandSelector({ value: values.brand ?? "", onChange: (v) => onChange({ brand: v }) })] })) : (_jsx(FormField, { name: "brand", label: "Brand", type: "text", value: values.brand ?? "", onChange: (v) => onChange({ brand: v }), placeholder: "e.g. Pok\u00E9mon Company" })), _jsx(FormField, { name: "tags", label: "Tags (comma-separated)", type: "text", value: (values.tags ?? []).join(", "), onChange: (v) => onChange({ tags: v.split(",").map((t) => t.trim()).filter(Boolean) }), placeholder: "pokemon, psa9, charizard, holo" })] }));
|
|
31
31
|
}
|
|
32
32
|
// ── Step 2: Media ─────────────────────────────────────────────────────────────
|
|
33
33
|
function StepMedia({ values, onChange, storeSlug = "store", }) {
|
|
@@ -65,21 +65,57 @@ function StepAuctionSettings({ values, onChange, }) {
|
|
|
65
65
|
function StepPreOrderSettings({ values, onChange, }) {
|
|
66
66
|
return (_jsxs(Stack, { gap: "md", children: [_jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "preOrderDeliveryDate", label: "Estimated Delivery Date (YYYY-MM-DD)", type: "text", value: values.preOrderDeliveryDate ?? "", onChange: (v) => onChange({ preOrderDeliveryDate: v }), placeholder: "e.g. 2026-12-15", helpText: "When you expect to ship to buyers" }), _jsx(FormField, { name: "preOrderMaxQuantity", label: "Maximum Pre-Order Quantity (optional)", type: "number", value: String(values.preOrderMaxQuantity ?? ""), onChange: (v) => onChange({ preOrderMaxQuantity: v ? Number(v) : undefined }), placeholder: "Unlimited" })] }), _jsx(FormField, { name: "preOrderDepositPercent", label: "Deposit % (0 = full payment now)", type: "number", value: String(values.preOrderDepositPercent ?? 0), onChange: (v) => onChange({ preOrderDepositPercent: Math.min(100, Math.max(0, Number(v))) }), placeholder: "0", helpText: "Buyers pay this percentage upfront; remainder due on shipping" }), _jsx(FormField, { name: "preOrderProductionStatus", label: "Production Status", type: "select", value: values.preOrderProductionStatus ?? "upcoming", onChange: (v) => onChange({ preOrderProductionStatus: v }), options: PRODUCTION_STATUS_OPTIONS }), _jsx(Toggle, { checked: values.preOrderCancellable !== false, onChange: (checked) => onChange({ preOrderCancellable: checked }), label: "Allow buyers to cancel before shipping" })] }));
|
|
67
67
|
}
|
|
68
|
+
// ── Step 3: Classified Settings ───────────────────────────────────────────
|
|
69
|
+
const CLASSIFIED_CONTACT_OPTIONS = [
|
|
70
|
+
{ value: "chat", label: "In-app Chat only" },
|
|
71
|
+
{ value: "phone", label: "Phone / WhatsApp only" },
|
|
72
|
+
{ value: "both", label: "Chat or Phone" },
|
|
73
|
+
];
|
|
74
|
+
function StepClassifiedSettings({ values, onChange, }) {
|
|
75
|
+
return (_jsxs(Stack, { gap: "md", children: [_jsx(Alert, { variant: "info", children: "Classified listings are local meetup / C2C sales. Add your meetup area so buyers know where you are." }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "classifiedCity", label: "City", type: "text", value: values.classifiedCity ?? "", onChange: (v) => onChange({ classifiedCity: v }), placeholder: "e.g. Mumbai" }), _jsx(FormField, { name: "classifiedLocality", label: "Locality / Area (optional)", type: "text", value: values.classifiedLocality ?? "", onChange: (v) => onChange({ classifiedLocality: v }), placeholder: "e.g. Andheri West" })] }), _jsx(FormField, { name: "classifiedPincode", label: "PIN Code (optional)", type: "text", value: values.classifiedPincode ?? "", onChange: (v) => onChange({ classifiedPincode: v }), placeholder: "400053" }), _jsx(FormField, { name: "classifiedContactMethod", label: "Preferred Contact Method", type: "select", value: values.classifiedContactMethod ?? "chat", onChange: (v) => onChange({ classifiedContactMethod: v }), options: CLASSIFIED_CONTACT_OPTIONS }), _jsx(Toggle, { checked: !!values.classifiedAcceptsShipping, onChange: (checked) => onChange({ classifiedAcceptsShipping: checked }), label: "Also open to shipping (in addition to meetup)" }), _jsx(Toggle, { checked: !!values.classifiedNegotiable, onChange: (checked) => onChange({ classifiedNegotiable: checked }), label: "Price is negotiable" })] }));
|
|
76
|
+
}
|
|
77
|
+
// ── Step 3: Digital Code Settings ─────────────────────────────────────────
|
|
78
|
+
const DIGITAL_DELIVERY_OPTIONS = [
|
|
79
|
+
{ value: "auto-claim", label: "Auto-Claim — code revealed instantly after payment" },
|
|
80
|
+
{ value: "manual-email", label: "Manual Email — you send the code within 24 h" },
|
|
81
|
+
];
|
|
82
|
+
function StepDigitalCodeSettings({ values, onChange, }) {
|
|
83
|
+
return (_jsxs(Stack, { gap: "md", children: [_jsx(Alert, { variant: "info", children: "Digital code listings sell game keys, gift cards, or activation codes. Codes are never shown publicly." }), _jsx(FormField, { name: "digitalCodeDelivery", label: "Delivery Method", type: "select", value: values.digitalCodeDelivery ?? "auto-claim", onChange: (v) => onChange({ digitalCodeDelivery: v }), options: DIGITAL_DELIVERY_OPTIONS }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "digitalCodePoolSize", label: "Code Pool Size (optional)", type: "number", value: String(values.digitalCodePoolSize ?? ""), onChange: (v) => onChange({ digitalCodePoolSize: v ? Number(v) : undefined }), placeholder: "e.g. 50", helpText: "Total number of codes you have available" }), _jsx(FormField, { name: "digitalCodeExpiresAt", label: "Code Expiry Date (optional)", type: "text", value: values.digitalCodeExpiresAt ?? "", onChange: (v) => onChange({ digitalCodeExpiresAt: v }), placeholder: "YYYY-MM-DD", helpText: "When the codes expire (if applicable)" })] }), _jsx(FormField, { name: "digitalCodeRedemptionInstructions", label: "Redemption Instructions (optional)", type: "textarea", value: values.digitalCodeRedemptionInstructions ?? "", onChange: (v) => onChange({ digitalCodeRedemptionInstructions: v }), placeholder: "Step-by-step instructions for redeeming the code\u2026", helpText: "Shown to the buyer after purchase" })] }));
|
|
84
|
+
}
|
|
85
|
+
// ── Step 3: Live Item Settings ─────────────────────────────────────────────
|
|
86
|
+
const LIVE_SEX_OPTIONS = [
|
|
87
|
+
{ value: "male", label: "Male" },
|
|
88
|
+
{ value: "female", label: "Female" },
|
|
89
|
+
{ value: "unknown", label: "Unknown" },
|
|
90
|
+
{ value: "n/a", label: "N/A" },
|
|
91
|
+
];
|
|
92
|
+
const LIVE_TRANSPORT_OPTIONS = [
|
|
93
|
+
{ value: "in-person", label: "In-Person handover only" },
|
|
94
|
+
{ value: "courier", label: "Specialist live-animal courier" },
|
|
95
|
+
{ value: "specialist", label: "Third-party specialist transport" },
|
|
96
|
+
];
|
|
97
|
+
function StepLiveItemSettings({ values, onChange, }) {
|
|
98
|
+
return (_jsxs(Stack, { gap: "md", children: [_jsx(Alert, { variant: "warning", children: "Live animal / plant listings must comply with all applicable laws, CITES regulations, and local jurisdiction rules. LetItRip is not responsible for legal compliance \u2014 this is solely the seller's responsibility." }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "liveSpecies", label: "Species / Common Name", type: "text", value: values.liveSpecies ?? "", onChange: (v) => onChange({ liveSpecies: v }), placeholder: "e.g. Axolotl (Ambystoma mexicanum)" }), _jsx(FormField, { name: "liveAgeMonths", label: "Age (months, optional)", type: "number", value: String(values.liveAgeMonths ?? ""), onChange: (v) => onChange({ liveAgeMonths: v ? Number(v) : undefined }), placeholder: "e.g. 6" })] }), _jsx(FormField, { name: "liveSex", label: "Sex", type: "select", value: values.liveSex ?? "unknown", onChange: (v) => onChange({ liveSex: v }), options: LIVE_SEX_OPTIONS }), _jsx(FormField, { name: "liveCareInfo", label: "Care Instructions (optional)", type: "textarea", value: values.liveCareInfo ?? "", onChange: (v) => onChange({ liveCareInfo: v }), placeholder: "Diet, temperature, habitat requirements\u2026" }), _jsx(FormField, { name: "liveTransportMethod", label: "Transport Method", type: "select", value: values.liveTransportMethod ?? "in-person", onChange: (v) => onChange({ liveTransportMethod: v }), options: LIVE_TRANSPORT_OPTIONS }), values.liveTransportMethod !== "in-person" && (_jsx(FormField, { name: "liveHandlingFee", label: "Handling / Transport Fee (\u20B9, optional)", type: "number", value: toRupees(values.liveHandlingFee), onChange: (v) => onChange({ liveHandlingFee: v ? toPaise(v) : undefined }), placeholder: "0" })), _jsx(FormField, { name: "liveJurisdictions", label: "Jurisdictions where sale is permitted (comma-separated)", type: "text", value: (values.liveJurisdictions ?? []).join(", "), onChange: (v) => onChange({ liveJurisdictions: v.split(",").map((s) => s.trim()).filter(Boolean) }), placeholder: "e.g. Maharashtra, Karnataka", helpText: "List all Indian states / UTs where you can legally sell" }), _jsx(Toggle, { checked: !!values.liveCites, onChange: (checked) => onChange({ liveCites: checked }), label: "This species requires CITES documentation" })] }));
|
|
99
|
+
}
|
|
68
100
|
// ── Step: Pricing ─────────────────────────────────────────────────────────
|
|
69
101
|
function StepPricing({ values, onChange, listingType, }) {
|
|
70
102
|
const priceLabel = listingType === "auction"
|
|
71
103
|
? "Suggested Retail Price (₹)"
|
|
72
104
|
: listingType === "pre-order"
|
|
73
105
|
? "Pre-Order Price (₹)"
|
|
74
|
-
:
|
|
75
|
-
|
|
106
|
+
: listingType === "classified"
|
|
107
|
+
? "Asking Price (₹)"
|
|
108
|
+
: listingType === "digital-code"
|
|
109
|
+
? "Price per Code (₹)"
|
|
110
|
+
: "Price (₹)";
|
|
111
|
+
return (_jsxs(Stack, { gap: "md", children: [_jsx(Alert, { variant: "info", children: "All prices in Indian Rupees (\u20B9)." }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "price", label: priceLabel, type: "number", value: toRupees(values.price), onChange: (v) => onChange({ price: toPaise(v) }), placeholder: "999" }), _jsx(FormField, { name: "compareAtPrice", label: "Compare-at Price (\u20B9, optional)", type: "number", value: toRupees(values.compareAtPrice), onChange: (v) => onChange({ compareAtPrice: v ? toPaise(v) : undefined }), placeholder: "1299", helpText: "Original price shown as strikethrough" })] }), (listingType === "standard" || listingType === "classified" || listingType === "live") && (_jsx(FormField, { name: "stockQuantity", label: "Stock Quantity", type: "number", value: String(values.stockQuantity ?? ""), onChange: (v) => onChange({ stockQuantity: Number(v) }), placeholder: "1" })), _jsxs(FormGroup, { columns: 2, children: [_jsx(Toggle, { checked: !!values.featured, onChange: (checked) => onChange({ featured: checked }), label: "Mark as Featured" }), _jsx(Toggle, { checked: !!values.isNew, onChange: (checked) => onChange({ isNew: checked }), label: "Mark as New Arrival" })] })] }));
|
|
76
112
|
}
|
|
77
113
|
// ── Step: Shipping ────────────────────────────────────────────────────────
|
|
78
114
|
function StepShipping({ values, onChange, renderAddressSelector, }) {
|
|
79
115
|
return (_jsxs(Stack, { gap: "md", children: [_jsx(FormField, { name: "shippingPaidBy", label: "Shipping Paid By", type: "select", value: values.shippingPaidBy ?? "buyer", onChange: (v) => onChange({ shippingPaidBy: v }), options: [
|
|
80
116
|
{ value: "buyer", label: "Buyer pays shipping" },
|
|
81
117
|
{ value: "seller", label: "Seller includes free shipping" },
|
|
82
|
-
] }), renderAddressSelector ? (_jsxs(
|
|
118
|
+
] }), renderAddressSelector ? (_jsxs(_Fragment, { children: [_jsx(Text, { className: "text-sm font-medium text-[var(--appkit-color-text)] mb-1", children: "Pickup Address (optional)" }), renderAddressSelector({
|
|
83
119
|
value: values.pickupAddressId ?? "",
|
|
84
120
|
onChange: (v) => onChange({ pickupAddressId: v }),
|
|
85
121
|
})] })) : (_jsx(StoreAddressSelectorCreate, { label: "Pickup Address (optional)", value: values.pickupAddressId ?? "", onChange: (id) => onChange({ pickupAddressId: id }) })), _jsx(Toggle, { checked: !!values.insurance, onChange: (checked) => onChange({ insurance: checked, insuranceCost: checked ? values.insuranceCost ?? 0 : undefined }), label: "Offer shipping insurance" }), values.insurance && (_jsx(FormField, { name: "insuranceCost", label: "Insurance Cost (\u20B9)", type: "number", value: toRupees(values.insuranceCost), onChange: (v) => onChange({ insuranceCost: toPaise(v) }), placeholder: "0" }))] }));
|
|
@@ -123,7 +159,17 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
|
|
|
123
159
|
await onPublish({ ...draft, status: "published" });
|
|
124
160
|
markClean();
|
|
125
161
|
}, [draft, onPublish, markClean]);
|
|
126
|
-
const listingTypeLabel = listingType === "auction"
|
|
162
|
+
const listingTypeLabel = listingType === "auction"
|
|
163
|
+
? "Auction"
|
|
164
|
+
: listingType === "pre-order"
|
|
165
|
+
? "Pre-Order"
|
|
166
|
+
: listingType === "classified"
|
|
167
|
+
? "Classified"
|
|
168
|
+
: listingType === "digital-code"
|
|
169
|
+
? "Digital Code"
|
|
170
|
+
: listingType === "live"
|
|
171
|
+
? "Live Item"
|
|
172
|
+
: "Product";
|
|
127
173
|
const typeSpecificStep = listingType === "auction"
|
|
128
174
|
? {
|
|
129
175
|
label: "Auction Settings",
|
|
@@ -136,7 +182,24 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
|
|
|
136
182
|
render: ({ values, onChange }) => (_jsx(StepPreOrderSettings, { values: values, onChange: onChange })),
|
|
137
183
|
validate: (v) => (!v.preOrderDeliveryDate ? "Estimated delivery date is required" : null),
|
|
138
184
|
}
|
|
139
|
-
:
|
|
185
|
+
: listingType === "classified"
|
|
186
|
+
? {
|
|
187
|
+
label: "Meetup Details",
|
|
188
|
+
render: ({ values, onChange }) => (_jsx(StepClassifiedSettings, { values: values, onChange: onChange })),
|
|
189
|
+
validate: (v) => (!v.classifiedCity?.trim() ? "City is required for classified listings" : null),
|
|
190
|
+
}
|
|
191
|
+
: listingType === "digital-code"
|
|
192
|
+
? {
|
|
193
|
+
label: "Code Details",
|
|
194
|
+
render: ({ values, onChange }) => (_jsx(StepDigitalCodeSettings, { values: values, onChange: onChange })),
|
|
195
|
+
}
|
|
196
|
+
: listingType === "live"
|
|
197
|
+
? {
|
|
198
|
+
label: "Live Item Details",
|
|
199
|
+
render: ({ values, onChange }) => (_jsx(StepLiveItemSettings, { values: values, onChange: onChange })),
|
|
200
|
+
validate: (v) => (!v.liveSpecies?.trim() ? "Species name is required" : null),
|
|
201
|
+
}
|
|
202
|
+
: null;
|
|
140
203
|
const steps = [
|
|
141
204
|
{
|
|
142
205
|
label: "Basic",
|
|
@@ -174,6 +237,9 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
|
|
|
174
237
|
...EDIT_SECTIONS,
|
|
175
238
|
...(listingType === "auction" ? [{ id: "auction", label: "Auction" }] : []),
|
|
176
239
|
...(listingType === "pre-order" ? [{ id: "preorder", label: "Pre-Order" }] : []),
|
|
240
|
+
...(listingType === "classified" ? [{ id: "classified", label: "Meetup Details" }] : []),
|
|
241
|
+
...(listingType === "digital-code" ? [{ id: "digitalcode", label: "Code Details" }] : []),
|
|
242
|
+
...(listingType === "live" ? [{ id: "live", label: "Live Item" }] : []),
|
|
177
243
|
];
|
|
178
|
-
return (_jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, sections: editSections, onSaveDraft: handleSave, onPublish: handlePublish, saveLabel: "Save Changes", publishLabel: "Update", previewSlot: previewSlot, children: _jsxs(Stack, { gap: "lg", children: [_jsxs(
|
|
244
|
+
return (_jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, sections: editSections, onSaveDraft: handleSave, onPublish: handlePublish, saveLabel: "Save Changes", publishLabel: "Update", previewSlot: previewSlot, children: _jsxs(Stack, { gap: "lg", children: [_jsxs(Section, { id: "basic", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Basic Info" }), _jsx(StepBasic, { values: draft, onChange: update, renderCategorySelector: renderCategorySelector, renderBrandSelector: renderBrandSelector, renderTemplateSelector: renderTemplateSelector })] }), _jsxs(Section, { id: "media", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Media" }), _jsx(StepMedia, { values: draft, onChange: update, storeSlug: storeSlug })] }), listingType === "auction" && (_jsxs(Section, { id: "auction", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Auction Settings" }), _jsx(StepAuctionSettings, { values: draft, onChange: update })] })), listingType === "pre-order" && (_jsxs(Section, { id: "preorder", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Pre-Order Settings" }), _jsx(StepPreOrderSettings, { values: draft, onChange: update })] })), listingType === "classified" && (_jsxs(Section, { id: "classified", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Meetup Details" }), _jsx(StepClassifiedSettings, { values: draft, onChange: update })] })), listingType === "digital-code" && (_jsxs(Section, { id: "digitalcode", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Code Details" }), _jsx(StepDigitalCodeSettings, { values: draft, onChange: update })] })), listingType === "live" && (_jsxs(Section, { id: "live", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Live Item Details" }), _jsx(StepLiveItemSettings, { values: draft, onChange: update })] })), _jsxs(Section, { id: "pricing", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Pricing" }), _jsx(StepPricing, { values: draft, onChange: update, listingType: listingType })] }), _jsxs(Section, { id: "shipping", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Shipping" }), _jsx(StepShipping, { values: draft, onChange: update, renderAddressSelector: renderAddressSelector })] }), _jsxs(Section, { id: "publish", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Publish" }), _jsx(StepPublish, { values: draft, onChange: update }), onSaveAsTemplate && (_jsxs(Div, { className: "mt-4 border-t border-[var(--appkit-color-border)] pt-4", children: [_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onSaveAsTemplate(draft), children: "Save as Template" }), _jsx(Text, { className: "mt-1 text-xs text-[var(--appkit-color-secondary-text)]", children: "Save these settings as a reusable template for future listings." })] }))] })] }) }));
|
|
179
245
|
}
|