@mohasinac/appkit 3.4.7 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/client/features/classified/ClassifiedDetailView.js +1 -1
- package/dist/_internal/client/features/digital-code/CodeRevealPanel.js +1 -1
- package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.js +1 -1
- package/dist/_internal/client/features/filters/filter-load-options.js +10 -9
- package/dist/_internal/client/features/layout/DashboardLayoutClient.d.ts +6 -1
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +11 -4
- package/dist/_internal/client/features/live/LiveItemDetailView.js +2 -2
- package/dist/_internal/client/features/maintenance/views/AnalysisRunnerView.js +10 -3
- package/dist/_internal/client/features/maintenance/views/ServerErrorsListView.js +2 -2
- package/dist/_internal/client/scaffolds/DashboardScaffold.js +3 -1
- package/dist/_internal/server/features/checkout/actions.d.ts +16 -0
- package/dist/_internal/server/features/checkout/actions.js +149 -35
- package/dist/_internal/server/features/checkout/bundle-expansion.d.ts +31 -0
- package/dist/_internal/server/features/checkout/bundle-expansion.js +41 -0
- package/dist/_internal/server/features/lottery/actions.js +14 -4
- package/dist/_internal/server/features/maintenance/analyze.js +4 -2
- package/dist/_internal/server/features/orders/actions.js +9 -0
- package/dist/_internal/server/features/orders/adapters.js +19 -0
- package/dist/_internal/server/features/seo/robots.js +1 -1
- package/dist/_internal/server/functions/firestore.d.ts +47 -1
- package/dist/_internal/server/functions/firestore.js +56 -1
- package/dist/_internal/server/functions/scheduled.d.ts +2 -1
- package/dist/_internal/server/functions/scheduled.js +9 -1
- package/dist/_internal/server/jobs/core/catalogueImageStalenessReminder.d.ts +10 -0
- package/dist/_internal/server/jobs/core/catalogueImageStalenessReminder.js +49 -0
- package/dist/_internal/server/jobs/core/cleanupRtdbEvents.js +32 -0
- package/dist/_internal/server/jobs/core/hardBanCascade.d.ts +26 -0
- package/dist/_internal/server/jobs/core/hardBanCascade.js +179 -0
- package/dist/_internal/server/jobs/core/index.d.ts +4 -1
- package/dist/_internal/server/jobs/core/index.js +4 -1
- package/dist/_internal/server/jobs/core/jobRunners.d.ts +28 -0
- package/dist/_internal/server/jobs/core/jobRunners.js +37 -0
- package/dist/_internal/server/jobs/core/onCatalogueSubmittedForApproval.d.ts +15 -0
- package/dist/_internal/server/jobs/core/onCatalogueSubmittedForApproval.js +38 -0
- package/dist/_internal/server/jobs/core/onJobCreated.d.ts +22 -0
- package/dist/_internal/server/jobs/core/onJobCreated.js +59 -0
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.d.ts +6 -1
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +5 -2
- package/dist/_internal/server/jobs/handlers/catalogueImageStalenessReminder.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/catalogueImageStalenessReminder.js +2 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +6 -0
- package/dist/_internal/server/jobs/handlers/index.js +8 -0
- package/dist/_internal/server/jobs/handlers/onCatalogueSubmittedForApproval.d.ts +12 -0
- package/dist/_internal/server/jobs/handlers/onCatalogueSubmittedForApproval.js +20 -0
- package/dist/_internal/server/jobs/handlers/onJobCreated.d.ts +3 -0
- package/dist/_internal/server/jobs/handlers/onJobCreated.js +9 -0
- package/dist/_internal/server/jobs/handlers/onShipmentAllocationSync.d.ts +25 -0
- package/dist/_internal/server/jobs/handlers/onShipmentAllocationSync.js +71 -0
- package/dist/_internal/server/jobs/handlers/onShipmentDeleted.d.ts +14 -0
- package/dist/_internal/server/jobs/handlers/onShipmentDeleted.js +23 -0
- package/dist/_internal/server/jobs/handlers/onShipmentItemWrite.d.ts +17 -0
- package/dist/_internal/server/jobs/handlers/onShipmentItemWrite.js +26 -0
- package/dist/_internal/server/jobs/handlers/weeklyPayoutEligibility.js +3 -1
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +136 -0
- package/dist/_internal/shared/features/blog/schema.d.ts +8 -8
- package/dist/_internal/shared/features/brands/schema.d.ts +4 -4
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +8 -8
- package/dist/_internal/shared/features/events/schema.d.ts +4 -4
- package/dist/_internal/shared/features/products/schema.d.ts +8 -8
- package/dist/_internal/shared/features/promotions/schema.d.ts +4 -4
- package/dist/_internal/shared/features/reviews/schema.d.ts +4 -4
- package/dist/client/api/useFeatureFlags.d.ts +22 -0
- package/dist/client/api/useFeatureFlags.js +27 -0
- package/dist/client/observability/reportClientError.js +3 -2
- package/dist/client.d.ts +4 -2
- package/dist/client.js +2 -1
- package/dist/configs/next.js +1 -0
- package/dist/constants/api-endpoints.d.ts +279 -3
- package/dist/constants/api-endpoints.js +130 -2
- package/dist/core/hooks/useSyncManager.js +5 -4
- package/dist/errors/conflict-error.d.ts +4 -0
- package/dist/errors/conflict-error.js +6 -0
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.js +1 -0
- package/dist/features/about/components/FeesView.js +2 -2
- package/dist/features/about/components/HelpPageView.js +2 -2
- package/dist/features/about/components/HowAuctionsWorkView.js +2 -2
- package/dist/features/about/components/HowCheckoutWorksView.js +2 -2
- package/dist/features/about/components/HowEmiWorksView.js +2 -2
- package/dist/features/about/components/HowOffersWorkView.js +3 -3
- package/dist/features/about/components/HowOrdersWorkView.js +3 -3
- package/dist/features/about/components/HowPayoutsWorkView.js +2 -2
- package/dist/features/about/components/HowPreOrdersWorkView.js +2 -2
- package/dist/features/about/components/HowReviewsWorkView.js +2 -2
- package/dist/features/about/components/PublicProfileView.d.ts +8 -1
- package/dist/features/about/components/PublicProfileView.js +11 -9
- package/dist/features/about/components/SecurityPrivacyView.js +2 -2
- package/dist/features/about/components/UnauthorizedView.js +2 -2
- package/dist/features/account/components/AddressBook.js +1 -1
- package/dist/features/account/components/AddressesIndexListing.js +1 -1
- package/dist/features/account/components/NotificationBell.js +5 -5
- package/dist/features/account/components/NotificationPreferencesPanel.js +5 -2
- package/dist/features/account/components/UserOffersPanel.js +5 -4
- package/dist/features/account/components/UserSidebar.js +2 -2
- package/dist/features/account/components/UserSupportView.js +3 -3
- package/dist/features/account/schemas/index.d.ts +12 -12
- package/dist/features/addresses/schemas/index.d.ts +6 -6
- package/dist/features/admin/components/AdminAdEditorView.js +3 -3
- package/dist/features/admin/components/AdminAddressEditorView.js +3 -3
- package/dist/features/admin/components/AdminAdsView.js +3 -3
- package/dist/features/admin/components/AdminBlogEditorView.js +1 -1
- package/dist/features/admin/components/AdminBlogView.js +12 -15
- package/dist/features/admin/components/AdminBrandEditorView.js +1 -1
- package/dist/features/admin/components/AdminBrandsView.js +12 -13
- package/dist/features/admin/components/AdminBundleEditorView.js +5 -4
- package/dist/features/admin/components/AdminBundlesView.js +32 -23
- package/dist/features/admin/components/AdminCarouselEditorView.js +5 -5
- package/dist/features/admin/components/AdminCarouselView.js +2 -2
- package/dist/features/admin/components/AdminCatalogGuideView.js +1 -1
- package/dist/features/admin/components/AdminCategoriesView.js +12 -13
- package/dist/features/admin/components/AdminCategoryEditorView.js +2 -2
- package/dist/features/admin/components/AdminContactEditorView.js +2 -2
- package/dist/features/admin/components/AdminCouponEditorView.d.ts +10 -1
- package/dist/features/admin/components/AdminCouponEditorView.js +7 -2
- package/dist/features/admin/components/AdminCouponsView.js +32 -27
- package/dist/features/admin/components/AdminEmployeeEditorView.js +3 -3
- package/dist/features/admin/components/AdminFaqEditorView.js +1 -1
- package/dist/features/admin/components/AdminFaqsView.js +20 -20
- package/dist/features/admin/components/AdminFeatureEditorView.js +5 -5
- package/dist/features/admin/components/AdminFeaturesView.js +9 -10
- package/dist/features/admin/components/AdminFilterBar.js +1 -1
- package/dist/features/admin/components/AdminFulfillmentView.js +4 -4
- package/dist/features/admin/components/AdminGuideHubView.js +2 -2
- package/dist/features/admin/components/AdminMediaView.js +3 -2
- package/dist/features/admin/components/AdminNavigationView.js +1 -1
- package/dist/features/admin/components/AdminOrderEditorView.js +3 -3
- package/dist/features/admin/components/AdminOrdersView.js +21 -30
- package/dist/features/admin/components/AdminPageHeader.js +3 -3
- package/dist/features/admin/components/AdminPayoutsView.js +8 -8
- package/dist/features/admin/components/AdminPrizeDrawsView.js +8 -9
- package/dist/features/admin/components/AdminProductEditorView.d.ts +9 -1
- package/dist/features/admin/components/AdminProductEditorView.js +7 -4
- package/dist/features/admin/components/AdminProductsView.js +30 -41
- package/dist/features/admin/components/AdminReviewsView.js +14 -17
- package/dist/features/admin/components/AdminScammerEditorView.js +5 -5
- package/dist/features/admin/components/AdminSectionsView.js +3 -3
- package/dist/features/admin/components/AdminSessionsView.js +8 -10
- package/dist/features/admin/components/AdminSidebar.js +2 -2
- package/dist/features/admin/components/AdminSiteSettingsView.js +10 -3
- package/dist/features/admin/components/AdminStoreEditorView.js +4 -5
- package/dist/features/admin/components/AdminStoresView.js +18 -13
- package/dist/features/admin/components/AdminSupportTicketDetailView.js +7 -7
- package/dist/features/admin/components/AdminTeamView.js +9 -5
- package/dist/features/admin/components/AdminUsersView.js +19 -15
- package/dist/features/admin/components/AdminViewCards.js +5 -5
- package/dist/features/admin/components/DashboardStats.js +1 -1
- package/dist/features/admin/components/DataListingView.js +2 -2
- package/dist/features/admin/components/DataTable.js +2 -2
- package/dist/features/admin/components/DrawerFormFooter.js +1 -1
- package/dist/features/admin/components/analytics/AdminAnalyticsCharts.js +2 -2
- package/dist/features/admin/components/analytics/AdminStatCard.js +1 -1
- package/dist/features/admin/hooks/useAdminListing.d.ts +3 -2
- package/dist/features/admin/hooks/useAdminListing.js +8 -2
- package/dist/features/admin/permission-map.js +2 -0
- package/dist/features/admin/schemas/firestore.d.ts +7 -0
- package/dist/features/admin/schemas/firestore.js +4 -0
- package/dist/features/auctions/components/AuctionBidsTable.js +1 -1
- package/dist/features/auctions/components/AuctionDetailPageView.js +7 -7
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +3 -3
- package/dist/features/auctions/components/MarketplaceAuctionGrid.js +4 -4
- package/dist/features/auctions/components/PlaceBidFormClient.js +1 -1
- package/dist/features/auctions/schemas/index.d.ts +16 -16
- package/dist/features/auth/permissions/constants.d.ts +1 -1
- package/dist/features/auth/permissions/constants.js +2 -0
- package/dist/features/auth/schemas/index.d.ts +6 -6
- package/dist/features/before-after/schemas/index.d.ts +3 -3
- package/dist/features/blog/actions/blog-actions.d.ts +32 -32
- package/dist/features/blog/components/BlogFeaturedCard.js +2 -2
- package/dist/features/blog/components/BlogIndexListing.js +2 -2
- package/dist/features/blog/components/BlogListView.js +4 -4
- package/dist/features/blog/components/BlogPostView.js +4 -4
- package/dist/features/blog/schemas/index.d.ts +77 -77
- package/dist/features/cart/components/CartDrawer.js +2 -2
- package/dist/features/catalogue/actions/approve-catalogue-listing.d.ts +12 -0
- package/dist/features/catalogue/actions/approve-catalogue-listing.js +50 -0
- package/dist/features/catalogue/actions/list-from-catalogue.d.ts +17 -0
- package/dist/features/catalogue/actions/list-from-catalogue.js +50 -0
- package/dist/features/catalogue/actions/submit-for-approval.d.ts +8 -0
- package/dist/features/catalogue/actions/submit-for-approval.js +30 -0
- package/dist/features/catalogue/components/AdminCatalogueApprovalsView.d.ts +2 -0
- package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +53 -0
- package/dist/features/catalogue/components/CatalogueItemEditorView.d.ts +7 -0
- package/dist/features/catalogue/components/CatalogueItemEditorView.js +79 -0
- package/dist/features/catalogue/components/PublicCatalogueView.d.ts +5 -0
- package/dist/features/catalogue/components/PublicCatalogueView.js +22 -0
- package/dist/features/catalogue/components/UserCatalogueView.d.ts +12 -0
- package/dist/features/catalogue/components/UserCatalogueView.js +51 -0
- package/dist/features/catalogue/index.d.ts +12 -0
- package/dist/features/catalogue/index.js +9 -0
- package/dist/features/catalogue/repository/catalogue.repository.d.ts +39 -0
- package/dist/features/catalogue/repository/catalogue.repository.js +68 -0
- package/dist/features/catalogue/schemas/firestore.d.ts +47 -0
- package/dist/features/catalogue/schemas/firestore.js +22 -0
- package/dist/features/catalogue/schemas/index.d.ts +2 -0
- package/dist/features/catalogue/schemas/index.js +2 -0
- package/dist/features/catalogue/schemas/validation.d.ts +71 -0
- package/dist/features/catalogue/schemas/validation.js +25 -0
- package/dist/features/catalogue/utils/freshness.d.ts +10 -0
- package/dist/features/catalogue/utils/freshness.js +15 -0
- package/dist/features/catalogue/utils/product-from-item.d.ts +15 -0
- package/dist/features/catalogue/utils/product-from-item.js +34 -0
- package/dist/features/categories/components/BrandDetailPageView.js +1 -1
- package/dist/features/categories/components/BrandDetailTabs.js +2 -2
- package/dist/features/categories/components/BundleCollage.js +2 -2
- package/dist/features/categories/components/BundleItemsPicker.js +3 -2
- package/dist/features/categories/components/CategoriesIndexListing.js +8 -6
- package/dist/features/categories/components/CategoryBundlesListing.js +10 -4
- package/dist/features/categories/components/CategoryDetailPageView.js +1 -1
- package/dist/features/categories/components/CategoryDetailTabs.js +2 -2
- package/dist/features/categories/components/CategoryGrid.js +3 -3
- package/dist/features/categories/components/CategoryProductsListing.js +1 -1
- package/dist/features/categories/components/CategorySortSelect.js +1 -1
- package/dist/features/categories/components/CategoryStoresListing.js +1 -1
- package/dist/features/categories/components/CategoryTableColumns.js +1 -1
- package/dist/features/categories/components/CategoryTree.js +2 -2
- package/dist/features/categories/components/ConcernCard.js +1 -1
- package/dist/features/categories/hooks/useCategories.js +1 -1
- package/dist/features/categories/schemas/index.d.ts +32 -32
- package/dist/features/classified/components/ClassifiedFilters.js +2 -2
- package/dist/features/classified/components/ClassifiedIndexListing.js +9 -3
- package/dist/features/collections/schemas/index.d.ts +2 -2
- package/dist/features/consultation/components/ConsultationForm.js +1 -1
- package/dist/features/consultation/schemas/index.d.ts +10 -10
- package/dist/features/contact/components/ContactForm.js +4 -4
- package/dist/features/contact/components/ContactInfoSidebar.js +1 -1
- package/dist/features/contact/components/ContactPageView.js +2 -1
- package/dist/features/copilot/components/AdminCopilotView.js +5 -4
- package/dist/features/corporate/schemas/index.d.ts +2 -2
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +3 -3
- package/dist/features/events/components/AdminEventEditorView.js +4 -4
- package/dist/features/events/components/AdminEventEntriesView.js +2 -2
- package/dist/features/events/components/AdminEventsView.js +8 -8
- package/dist/features/events/components/EventBanner.js +1 -1
- package/dist/features/events/components/EventCard.js +3 -3
- package/dist/features/events/components/EventLeaderboard.js +1 -1
- package/dist/features/events/components/EventOfferCard.js +1 -1
- package/dist/features/events/components/EventPollWidget.js +6 -5
- package/dist/features/events/components/EventRaffleEntryForm.js +1 -1
- package/dist/features/events/components/EventRaffleWinnerView.js +5 -5
- package/dist/features/events/components/EventRafflesSection.js +1 -1
- package/dist/features/events/components/EventSaleBanner.js +1 -1
- package/dist/features/events/components/EventsIndexListing.js +4 -2
- package/dist/features/events/components/EventsListView.js +2 -2
- package/dist/features/events/components/SpinWheelView.js +11 -5
- package/dist/features/events/schemas/index.d.ts +100 -100
- package/dist/features/faq/actions/faq-actions.d.ts +6 -6
- package/dist/features/faq/components/ContactCTA.js +3 -3
- package/dist/features/faq/components/FAQCategorySidebar.js +2 -2
- package/dist/features/faq/components/FAQHelpfulButtons.js +3 -3
- package/dist/features/faq/schemas/index.d.ts +12 -12
- package/dist/features/filters/AsyncFacetSection.js +4 -4
- package/dist/features/filters/FilterFacetSection.js +8 -8
- package/dist/features/filters/RangeFilter.js +2 -2
- package/dist/features/filters/SwitchFilter.js +1 -1
- package/dist/features/forms/Checkbox.js +2 -8
- package/dist/features/forms/Input.js +2 -1
- package/dist/features/forms/Radio.js +3 -3
- package/dist/features/forms/Select.d.ts +1 -1
- package/dist/features/forms/Select.js +3 -2
- package/dist/features/forms/Slider.js +5 -11
- package/dist/features/forms/Textarea.js +2 -1
- package/dist/features/grouped/schemas/index.d.ts +6 -6
- package/dist/features/homepage/actions/homepage-section-actions.d.ts +4 -4
- package/dist/features/homepage/components/AdvertisementBanner.js +4 -4
- package/dist/features/homepage/components/AnnouncementBar.js +3 -3
- package/dist/features/homepage/components/BeforeAfterCard.js +1 -1
- package/dist/features/homepage/components/BrandsSection.js +9 -9
- package/dist/features/homepage/components/CTABannerSection.js +1 -1
- package/dist/features/homepage/components/CharacterHotspot.js +4 -4
- package/dist/features/homepage/components/CharacterHotspotForm.js +15 -13
- package/dist/features/homepage/components/CollectionCardsSection.js +1 -1
- package/dist/features/homepage/components/CustomCardsSection.js +6 -6
- package/dist/features/homepage/components/CustomerReviewsSection.js +2 -2
- package/dist/features/homepage/components/FAQSection.js +2 -2
- package/dist/features/homepage/components/FeaturedBundlesSection.js +3 -3
- package/dist/features/homepage/components/FeaturedResultsSection.js +2 -2
- package/dist/features/homepage/components/GoogleReviewsSection.js +6 -6
- package/dist/features/homepage/components/HeroBanner.js +1 -1
- package/dist/features/homepage/components/HeroCarousel.js +5 -4
- package/dist/features/homepage/components/HeroSection.js +1 -7
- package/dist/features/homepage/components/HomepageSkeleton.js +1 -1
- package/dist/features/homepage/components/HowItWorksInfoView.js +1 -1
- package/dist/features/homepage/components/HowItWorksSection.js +2 -2
- package/dist/features/homepage/components/NewsletterBanner.js +2 -2
- package/dist/features/homepage/components/NewsletterSection.js +1 -1
- package/dist/features/homepage/components/PromoGrid.js +1 -1
- package/dist/features/homepage/components/SectionCarousel.js +6 -6
- package/dist/features/homepage/components/SecurityHighlightsSection.js +2 -2
- package/dist/features/homepage/components/ShopByCategorySection.js +10 -10
- package/dist/features/homepage/components/SiteFeaturesSection.js +2 -2
- package/dist/features/homepage/components/SocialFeedSection.js +5 -5
- package/dist/features/homepage/components/SocialPostCard.js +1 -1
- package/dist/features/homepage/components/StatsCounterSection.js +1 -1
- package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
- package/dist/features/homepage/components/TrustBadges.js +1 -1
- package/dist/features/homepage/components/TrustFeaturesSection.js +2 -2
- package/dist/features/homepage/components/TrustIndicatorsSection.js +2 -2
- package/dist/features/homepage/components/WelcomeSection.js +2 -2
- package/dist/features/homepage/components/WhatsAppCommunitySection.js +1 -1
- package/dist/features/homepage/hooks/useActiveAd.js +2 -1
- package/dist/features/homepage/schemas/firestore.d.ts +10 -0
- package/dist/features/homepage/schemas/index.d.ts +116 -116
- package/dist/features/jobs/actions/enqueue-job.d.ts +24 -0
- package/dist/features/jobs/actions/enqueue-job.js +44 -0
- package/dist/features/jobs/repository/jobs.repository.d.ts +21 -0
- package/dist/features/jobs/repository/jobs.repository.js +48 -0
- package/dist/features/jobs/schemas/firestore.d.ts +54 -0
- package/dist/features/jobs/schemas/firestore.js +24 -0
- package/dist/features/layout/AppLayoutShell.js +17 -11
- package/dist/features/layout/AutoBreadcrumbs.js +1 -1
- package/dist/features/layout/BackToTop.js +2 -2
- package/dist/features/layout/BottomActions.js +7 -7
- package/dist/features/layout/BottomNavItem.js +2 -2
- package/dist/features/layout/BottomNavLayout.js +13 -4
- package/dist/features/layout/BottomNavbar.d.ts +9 -1
- package/dist/features/layout/BottomNavbar.js +12 -5
- package/dist/features/layout/BottomSheet.js +1 -1
- package/dist/features/layout/Breadcrumbs.js +1 -1
- package/dist/features/layout/FooterLayout.js +2 -2
- package/dist/features/layout/NavItem.js +3 -3
- package/dist/features/layout/NavbarLayout.js +6 -6
- package/dist/features/layout/SidebarLayout.d.ts +3 -0
- package/dist/features/layout/SidebarLayout.js +3 -3
- package/dist/features/layout/TitleBarLayout.js +4 -4
- package/dist/features/live/components/LiveItemFilters.js +2 -2
- package/dist/features/live/components/LiveItemsIndexListing.js +3 -3
- package/dist/features/lottery/types/index.d.ts +3 -1
- package/dist/features/lottery/types/index.js +16 -3
- package/dist/features/loyalty/components/CoinsDisplay.js +2 -2
- package/dist/features/media/MediaImage.d.ts +6 -1
- package/dist/features/media/MediaImage.js +10 -4
- package/dist/features/media/MediaLightbox.js +1 -1
- package/dist/features/media/MediaPickerModal.js +4 -3
- package/dist/features/media/MediaVideo.js +1 -1
- package/dist/features/media/modals/ImageCropModal.js +1 -1
- package/dist/features/media/modals/ImageEditor.js +1 -1
- package/dist/features/media/repository/media-assets.repository.d.ts +9 -0
- package/dist/features/media/types/index.d.ts +4 -4
- package/dist/features/media/upload/MediaUploadField.js +3 -3
- package/dist/features/media/upload/MediaUploadList.js +1 -1
- package/dist/features/messages/hooks/useConversation.js +4 -3
- package/dist/features/messages/hooks/useConversations.js +2 -1
- package/dist/features/messages/schemas/index.d.ts +6 -6
- package/dist/features/orders/components/MarketplaceOrderCard.js +1 -1
- package/dist/features/orders/components/OrderPaymentSummary.d.ts +16 -0
- package/dist/features/orders/components/OrderPaymentSummary.js +32 -0
- package/dist/features/orders/components/OrderSiblingPayments.js +1 -1
- package/dist/features/orders/components/OrdersList.d.ts +7 -2
- package/dist/features/orders/components/OrdersList.js +5 -5
- package/dist/features/orders/components/RefundHistoryTable.js +1 -1
- package/dist/features/orders/components/RefundRequestView.js +1 -1
- package/dist/features/orders/components/index.d.ts +2 -0
- package/dist/features/orders/components/index.js +1 -0
- package/dist/features/orders/repository/orders.repository.d.ts +8 -0
- package/dist/features/orders/repository/orders.repository.js +24 -0
- package/dist/features/orders/schemas/firestore.d.ts +59 -0
- package/dist/features/orders/schemas/firestore.js +5 -0
- package/dist/features/orders/schemas/index.d.ts +91 -40
- package/dist/features/orders/schemas/index.js +10 -0
- package/dist/features/orders/types/index.d.ts +15 -0
- package/dist/features/payments/schemas/index.d.ts +12 -12
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +5 -5
- package/dist/features/pre-orders/components/PreOrderActionsClient.js +1 -1
- package/dist/features/pre-orders/components/PreOrderBadge.js +1 -1
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +7 -7
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +3 -3
- package/dist/features/pre-orders/schemas/index.d.ts +12 -12
- package/dist/features/products/columns/productTableColumns.js +2 -2
- package/dist/features/products/components/AuctionsIndexListing.js +3 -3
- package/dist/features/products/components/CompareOverlay.js +15 -10
- package/dist/features/products/components/CustomFieldsEditor.js +2 -2
- package/dist/features/products/components/CustomSectionsEditor.js +3 -3
- package/dist/features/products/components/FeatureBadge.js +2 -2
- package/dist/features/products/components/GroupSettingsPanel.js +5 -4
- package/dist/features/products/components/MakeOfferButton.js +4 -4
- package/dist/features/products/components/MarketplaceBundleCard.js +3 -2
- package/dist/features/products/components/MarketplacePrizeDrawCard.js +1 -1
- package/dist/features/products/components/PrizeDrawCollage.js +6 -6
- package/dist/features/products/components/PrizeDrawDetailPageView.js +5 -5
- package/dist/features/products/components/PrizeDrawEntryActions.js +1 -1
- package/dist/features/products/components/PrizeDrawItemsEditor.js +4 -4
- package/dist/features/products/components/PrizeDrawsIndexListing.js +11 -4
- package/dist/features/products/components/PrizeDrawsSection.js +1 -1
- package/dist/features/products/components/PrizeRevealModal.js +9 -4
- package/dist/features/products/components/ProductDetailActions.js +2 -1
- package/dist/features/products/components/ProductDetailPageView.js +16 -16
- package/dist/features/products/components/ProductFeaturesSelector.js +5 -5
- package/dist/features/products/components/ProductForm.js +1 -1
- package/dist/features/products/components/ProductGalleryClient.js +5 -3
- package/dist/features/products/components/ProductGrid.js +11 -11
- package/dist/features/products/components/ProductTabs.js +2 -2
- package/dist/features/products/components/ProductTabsShell.js +2 -1
- package/dist/features/products/components/ProductsIndexListing.js +6 -1
- package/dist/features/products/components/ShareButton.js +2 -1
- package/dist/features/products/components/ShowGroupSection.js +9 -5
- package/dist/features/products/components/SublistingCarouselSection.js +8 -4
- package/dist/features/products/constants/action-defs.d.ts +10 -2
- package/dist/features/products/constants/action-defs.js +20 -2
- package/dist/features/products/schemas/firestore.d.ts +5 -0
- package/dist/features/products/schemas/index.d.ts +40 -40
- package/dist/features/products/schemas/product-features.validators.d.ts +14 -14
- package/dist/features/promotions/components/CouponCard.js +13 -7
- package/dist/features/promotions/components/CouponsIndexListing.js +4 -6
- package/dist/features/promotions/components/PromotionsView.js +2 -2
- package/dist/features/promotions/schemas/index.d.ts +26 -26
- package/dist/features/reviews/components/ReviewDetailPageView.js +1 -1
- package/dist/features/reviews/components/ReviewDetailShell.js +11 -11
- package/dist/features/reviews/components/ReviewModal.js +1 -1
- package/dist/features/reviews/components/ReviewsIndexListing.js +2 -2
- package/dist/features/reviews/components/ReviewsList.js +2 -2
- package/dist/features/reviews/schemas/index.d.ts +22 -22
- package/dist/features/scams/components/ScamAwarenessModal.js +2 -2
- package/dist/features/scams/components/ScamProfileView.js +3 -3
- package/dist/features/scams/components/ScamRegistryView.js +2 -2
- package/dist/features/scams/schemas/index.d.ts +20 -20
- package/dist/features/search/components/Search.js +9 -9
- package/dist/features/search/components/SearchFiltersRow.js +1 -1
- package/dist/features/search/components/SearchResultsSection.js +3 -3
- package/dist/features/search/components/SearchView.js +1 -1
- package/dist/features/search/hooks/useNavSuggestions.js +2 -1
- package/dist/features/search/hooks/useSearch.js +2 -2
- package/dist/features/search/schemas/index.d.ts +3 -3
- package/dist/features/seller/components/BrandInlineSelect.js +2 -2
- package/dist/features/seller/components/CategoryInlineSelect.js +2 -2
- package/dist/features/seller/components/QuickProductForm.js +1 -1
- package/dist/features/seller/components/SellerAddressesView.js +4 -4
- package/dist/features/seller/components/SellerAnalyticsAlertsView.js +3 -3
- package/dist/features/seller/components/SellerAnalyticsView.js +2 -2
- package/dist/features/seller/components/SellerArtView.js +11 -11
- package/dist/features/seller/components/SellerAuctionsView.js +11 -11
- package/dist/features/seller/components/SellerBidsView.js +3 -3
- package/dist/features/seller/components/SellerBundlesView.js +12 -12
- package/dist/features/seller/components/SellerClassifiedView.js +11 -11
- package/dist/features/seller/components/SellerCouponEditorView.js +2 -2
- package/dist/features/seller/components/SellerDigitalCodesView.js +11 -11
- package/dist/features/seller/components/SellerFeaturesView.js +4 -4
- package/dist/features/seller/components/SellerLiveView.js +11 -11
- package/dist/features/seller/components/SellerOffersPanel.js +3 -2
- package/dist/features/seller/components/SellerOrdersView.js +2 -2
- package/dist/features/seller/components/SellerPayoutMethodsView.js +1 -1
- package/dist/features/seller/components/SellerPayoutRequestView.js +6 -5
- package/dist/features/seller/components/SellerPayoutSettingsView.js +5 -4
- package/dist/features/seller/components/SellerPreOrdersView.js +1 -1
- package/dist/features/seller/components/SellerPrizeDrawsView.js +1 -1
- package/dist/features/seller/components/SellerProductShell.js +20 -6
- package/dist/features/seller/components/SellerProductsCards.js +3 -3
- package/dist/features/seller/components/SellerProductsView.js +4 -4
- package/dist/features/seller/components/SellerReviewsView.js +7 -6
- package/dist/features/seller/components/SellerShippingView.js +2 -1
- package/dist/features/seller/components/SellerSidebar.js +5 -5
- package/dist/features/seller/components/SellerStickersView.js +11 -11
- package/dist/features/seller/components/SellerTemplatesView.js +1 -1
- package/dist/features/seller/schemas/index.d.ts +20 -20
- package/dist/features/server-errors/schemas/index.d.ts +6 -6
- package/dist/features/shell/CommandPalette.d.ts +27 -0
- package/dist/features/shell/CommandPalette.js +92 -0
- package/dist/features/shell/FormShell.js +4 -3
- package/dist/features/shell/QuickFormDrawer.js +3 -2
- package/dist/features/shell/StepForm.js +2 -2
- package/dist/features/shell/index.d.ts +2 -0
- package/dist/features/shell/index.js +1 -0
- package/dist/features/shipments/components/AdminShipmentEditorView.d.ts +7 -0
- package/dist/features/shipments/components/AdminShipmentEditorView.js +123 -0
- package/dist/features/shipments/components/AdminShipmentLotItemsView.d.ts +6 -0
- package/dist/features/shipments/components/AdminShipmentLotItemsView.js +96 -0
- package/dist/features/shipments/components/AdminShipmentProjectionsView.d.ts +9 -0
- package/dist/features/shipments/components/AdminShipmentProjectionsView.js +44 -0
- package/dist/features/shipments/components/AdminShipmentsView.d.ts +8 -0
- package/dist/features/shipments/components/AdminShipmentsView.js +82 -0
- package/dist/features/shipments/components/ShipmentItemLinkModal.d.ts +15 -0
- package/dist/features/shipments/components/ShipmentItemLinkModal.js +37 -0
- package/dist/features/shipments/hooks/useShipments.d.ts +69 -0
- package/dist/features/shipments/hooks/useShipments.js +96 -0
- package/dist/features/shipments/index.d.ts +10 -0
- package/dist/features/shipments/index.js +7 -0
- package/dist/features/shipments/manifest.d.ts +2 -0
- package/dist/features/shipments/manifest.js +26 -0
- package/dist/features/shipments/repository/shipment-items.repository.d.ts +56 -0
- package/dist/features/shipments/repository/shipment-items.repository.js +78 -0
- package/dist/features/shipments/repository/shipment-lots.repository.d.ts +48 -0
- package/dist/features/shipments/repository/shipment-lots.repository.js +55 -0
- package/dist/features/shipments/repository/shipments.repository.d.ts +50 -0
- package/dist/features/shipments/repository/shipments.repository.js +77 -0
- package/dist/features/shipments/schemas/firestore.d.ts +150 -0
- package/dist/features/shipments/schemas/firestore.js +76 -0
- package/dist/features/shipments/schemas/index.d.ts +2 -0
- package/dist/features/shipments/schemas/index.js +2 -0
- package/dist/features/shipments/schemas/validation.d.ts +350 -0
- package/dist/features/shipments/schemas/validation.js +96 -0
- package/dist/features/shipments/utils/cost-allocation.d.ts +25 -0
- package/dist/features/shipments/utils/cost-allocation.js +83 -0
- package/dist/features/site-settings/components/ActionPermissionsManager.js +2 -2
- package/dist/features/stores/components/InteractiveStoreCard.js +2 -2
- package/dist/features/stores/components/StoreAboutView.js +1 -1
- package/dist/features/stores/components/StoreAuctionsListing.js +3 -3
- package/dist/features/stores/components/StoreAuctionsView.js +1 -1
- package/dist/features/stores/components/StoreCapabilitiesGuideView.js +1 -1
- package/dist/features/stores/components/StoreClassifiedsListing.js +2 -2
- package/dist/features/stores/components/StoreDetailLayoutView.js +1 -1
- package/dist/features/stores/components/StoreDigitalCodesListing.js +2 -2
- package/dist/features/stores/components/StoreFinanceGuideView.js +2 -2
- package/dist/features/stores/components/StoreGuideHubView.js +2 -2
- package/dist/features/stores/components/StoreHeader.js +4 -4
- package/dist/features/stores/components/StoreLiveItemsListing.js +2 -2
- package/dist/features/stores/components/StoreNavTabs.js +2 -2
- package/dist/features/stores/components/StoreOrdersGuideView.js +1 -1
- package/dist/features/stores/components/StorePreOrdersListing.js +3 -3
- package/dist/features/stores/components/StoreProductsListing.js +1 -1
- package/dist/features/stores/components/StoreReviewsListing.js +2 -2
- package/dist/features/stores/components/StoreReviewsView.js +1 -1
- package/dist/features/stores/components/StoreSettingsGuideView.js +1 -1
- package/dist/features/stores/components/StoresIndexListing.js +9 -3
- package/dist/features/stores/schemas/index.d.ts +10 -10
- package/dist/features/support/schemas/index.d.ts +22 -22
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +3 -3
- package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +1 -1
- package/dist/features/wishlist/hooks/useWishlistCount.js +1 -2
- package/dist/index.d.ts +44 -1
- package/dist/index.js +37 -1
- package/dist/next/routing/route-map.d.ts +18 -0
- package/dist/next/routing/route-map.js +9 -0
- package/dist/react/hooks/useVisualViewportInset.d.ts +1 -0
- package/dist/react/hooks/useVisualViewportInset.js +59 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.js +1 -0
- package/dist/repositories/index.d.ts +5 -0
- package/dist/repositories/index.js +5 -0
- package/dist/schemas/registry.d.ts +398 -364
- package/dist/schemas/sieve.d.ts +2 -2
- package/dist/schemas/webhooks/google-oauth.d.ts +2 -2
- package/dist/schemas/webhooks/razorpay.d.ts +100 -100
- package/dist/seed/_helpers/media.js +1 -0
- package/dist/seed/actions/demo-seed-actions.d.ts +1 -1
- package/dist/seed/catalogue-seed-data.d.ts +2 -0
- package/dist/seed/catalogue-seed-data.js +112 -0
- package/dist/seed/grouped-listings-seed-data.d.ts +5 -0
- package/dist/seed/homepage-sections-seed-data.js +0 -1
- package/dist/seed/index.d.ts +2 -0
- package/dist/seed/index.js +2 -0
- package/dist/seed/manifest.js +6 -0
- package/dist/seed/products-preorders-seed-data.d.ts +5 -0
- package/dist/seed/shipments-seed-data.d.ts +5 -0
- package/dist/seed/shipments-seed-data.js +185 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +5 -0
- package/dist/styles.css +75 -19
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/index.d.ts +0 -2
- package/dist/tokens/index.js +0 -2
- package/dist/tokens/tokens.css +12 -2
- package/dist/ui/DataTable.js +4 -3
- package/dist/ui/components/Button.d.ts +4 -1
- package/dist/ui/components/Button.js +11 -5
- package/dist/ui/components/Checkbox.d.ts +9 -1
- package/dist/ui/components/Checkbox.js +5 -2
- package/dist/ui/components/ClaimCouponButton.js +2 -1
- package/dist/ui/components/ConfirmDeleteModal.style.css +1 -1
- package/dist/ui/components/Drawer.style.css +13 -1
- package/dist/ui/components/Dropdown.style.css +2 -2
- package/dist/ui/components/FilterDrawer.d.ts +4 -1
- package/dist/ui/components/FilterDrawer.js +8 -2
- package/dist/ui/components/Form.d.ts +1 -1
- package/dist/ui/components/Form.js +2 -2
- package/dist/ui/components/FormActionBar.style.css +6 -1
- package/dist/ui/components/IconButton.d.ts +6 -1
- package/dist/ui/components/IconButton.js +5 -2
- package/dist/ui/components/IconButton.style.css +11 -0
- package/dist/ui/components/ImageGallery.style.css +2 -0
- package/dist/ui/components/ImageLightbox.style.css +1 -0
- package/dist/ui/components/ListingFilterDrawer.d.ts +4 -1
- package/dist/ui/components/ListingFilterDrawer.js +4 -3
- package/dist/ui/components/ListingLayout.style.css +2 -2
- package/dist/ui/components/Modal.style.css +1 -1
- package/dist/ui/components/Pagination.d.ts +5 -1
- package/dist/ui/components/Pagination.js +4 -2
- package/dist/ui/components/RowActionMenu.js +1 -1
- package/dist/ui/components/RowActionMenu.style.css +1 -1
- package/dist/ui/components/Select.d.ts +6 -1
- package/dist/ui/components/Select.js +18 -13
- package/dist/ui/components/Select.style.css +1 -1
- package/dist/ui/components/Semantic.d.ts +13 -0
- package/dist/ui/components/Semantic.js +16 -3
- package/dist/ui/components/SideDrawer.style.css +16 -4
- package/dist/ui/components/SideModal.style.css +1 -1
- package/dist/ui/components/StickyToolbar.d.ts +3 -2
- package/dist/ui/components/StickyToolbar.js +1 -1
- package/dist/ui/components/Textarea.d.ts +5 -0
- package/dist/ui/components/Textarea.js +8 -4
- package/dist/ui/components/Toast.style.css +3 -0
- package/dist/ui/components/Typography.js +69 -8
- package/dist/ui/components/UnsavedChangesModal.style.css +1 -1
- package/dist/ui/components/surface-tokens.d.ts +121 -113
- package/dist/ui/components/surface-tokens.js +110 -104
- package/dist/ui/forms/FormShell.d.ts +8 -27
- package/dist/ui/forms/FormShell.js +1 -194
- package/dist/ui/forms/index.d.ts +2 -2
- package/dist/ui/forms/index.js +1 -1
- package/dist/ui/index.d.ts +8 -4
- package/dist/ui/index.js +4 -2
- package/dist/utils/id-generators.d.ts +27 -0
- package/dist/utils/id-generators.js +45 -0
- package/dist/utils/number.formatter.d.ts +7 -0
- package/dist/utils/number.formatter.js +9 -0
- package/dist/validation/schemas.d.ts +5 -5
- package/package.json +1 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { sortBy } from "@mohasinac/appkit";
|
|
5
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
6
|
+
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
7
|
+
import { Button, Modal, Row, Stack, Text, Textarea } from "../../../ui";
|
|
8
|
+
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
|
+
import { apiClient } from "../../../http";
|
|
10
|
+
import { toRecordArray, toRelativeDate, toStringValue, } from "../../admin/hooks/useAdminListingData";
|
|
11
|
+
import { DataListingView } from "../../admin/components/DataListingView";
|
|
12
|
+
export function AdminCatalogueApprovalsView() {
|
|
13
|
+
const queryClient = useQueryClient();
|
|
14
|
+
const [rejectTarget, setRejectTarget] = React.useState(null);
|
|
15
|
+
const [rejectReason, setRejectReason] = React.useState("");
|
|
16
|
+
const invalidate = () => queryClient.invalidateQueries({ queryKey: ["admin", "catalogue-approvals"] });
|
|
17
|
+
const approveMutation = useApiMutation({
|
|
18
|
+
successMessage: "Approved and listed",
|
|
19
|
+
mutationFn: (id) => apiClient.post(ADMIN_ENDPOINTS.CATALOGUE_APPROVE(id)),
|
|
20
|
+
onSuccess: invalidate,
|
|
21
|
+
});
|
|
22
|
+
const rejectMutation = useApiMutation({
|
|
23
|
+
successMessage: "Rejected",
|
|
24
|
+
mutationFn: () => apiClient.post(ADMIN_ENDPOINTS.CATALOGUE_REJECT(rejectTarget), { reason: rejectReason }),
|
|
25
|
+
onSuccess: () => {
|
|
26
|
+
setRejectTarget(null);
|
|
27
|
+
setRejectReason("");
|
|
28
|
+
invalidate();
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
const config = {
|
|
32
|
+
portal: "admin",
|
|
33
|
+
title: "Catalogue Approvals",
|
|
34
|
+
searchPlaceholder: "Search by title",
|
|
35
|
+
emptyLabel: "No pending catalogue requests",
|
|
36
|
+
filterKeys: [],
|
|
37
|
+
defaultSort: sortBy("createdAt", "DESC"),
|
|
38
|
+
queryKey: ["admin", "catalogue-approvals", "listing"],
|
|
39
|
+
endpoint: ADMIN_ENDPOINTS.CATALOGUE_APPROVALS,
|
|
40
|
+
sortOptions: [{ value: sortBy("createdAt", "DESC"), label: "Newest" }],
|
|
41
|
+
mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
|
|
42
|
+
id: toStringValue(item.id, `catalogue-${index}`),
|
|
43
|
+
primary: toStringValue(item.title, "Untitled item"),
|
|
44
|
+
secondary: toStringValue(item.ownerId, ""),
|
|
45
|
+
status: toStringValue(item.listingStatus, "pending_admin_approval"),
|
|
46
|
+
updatedAt: toRelativeDate(item.submittedForApprovalAt ?? item.createdAt),
|
|
47
|
+
})),
|
|
48
|
+
getTotal: (response, mappedRows) => (typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length),
|
|
49
|
+
buildFilters: () => undefined,
|
|
50
|
+
renderRowActions: (row) => (_jsxs(Row, { gap: "sm", children: [_jsx(Button, { size: "sm", isLoading: approveMutation.isPending, onClick: () => approveMutation.mutate(row.id), children: "Approve" }), _jsx(Button, { size: "sm", variant: "danger", onClick: () => setRejectTarget(row.id), children: "Reject" })] })),
|
|
51
|
+
};
|
|
52
|
+
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(Modal, { isOpen: !!rejectTarget, onClose: () => setRejectTarget(null), title: "Reject this catalogue listing?", size: "sm", children: _jsxs(Stack, { gap: "md", children: [_jsx(Text, { variant: "secondary", children: "The owner will see this reason." }), _jsx(Textarea, { value: rejectReason, onChange: (e) => setRejectReason(e.target.value), rows: 3, placeholder: "Reason for rejection" }), _jsx(Button, { isLoading: rejectMutation.isPending, disabled: !rejectReason.trim(), variant: "danger", onClick: () => rejectMutation.mutate(), children: "Reject" })] }) })] }));
|
|
53
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { CatalogueItemDocument } from "../schemas/firestore";
|
|
3
|
+
export interface CatalogueItemEditorViewProps {
|
|
4
|
+
item?: CatalogueItemDocument;
|
|
5
|
+
onSaved?: (id: string) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function CatalogueItemEditorView({ item, onSaved }: CatalogueItemEditorViewProps): React.JSX.Element;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
5
|
+
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
6
|
+
import { Alert, Button, FieldInput, FieldSelect, FieldTextarea, Form, Grid, Row, Span, Stack, Toggle } from "../../../ui";
|
|
7
|
+
import { MediaUploadList } from "../../media/upload/MediaUploadList";
|
|
8
|
+
import { useMediaUpload } from "../../media";
|
|
9
|
+
import { apiClient } from "../../../http";
|
|
10
|
+
import { ACCOUNT_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
11
|
+
import { createCatalogueItemSchema } from "../schemas/validation";
|
|
12
|
+
const CONDITION_OPTIONS = [
|
|
13
|
+
{ label: "New", value: "new" },
|
|
14
|
+
{ label: "Like new", value: "like_new" },
|
|
15
|
+
{ label: "Good", value: "good" },
|
|
16
|
+
{ label: "Fair", value: "fair" },
|
|
17
|
+
{ label: "Poor", value: "poor" },
|
|
18
|
+
{ label: "Used", value: "used" },
|
|
19
|
+
{ label: "Refurbished", value: "refurbished" },
|
|
20
|
+
];
|
|
21
|
+
export function CatalogueItemEditorView({ item, onSaved }) {
|
|
22
|
+
const isCreate = !item;
|
|
23
|
+
const queryClient = useQueryClient();
|
|
24
|
+
const { upload } = useMediaUpload();
|
|
25
|
+
const uploadIndexRef = React.useRef(0);
|
|
26
|
+
const [title, setTitle] = React.useState(item?.title ?? "");
|
|
27
|
+
const [description, setDescription] = React.useState(item?.description ?? "");
|
|
28
|
+
const [condition, setCondition] = React.useState(item?.condition ?? "");
|
|
29
|
+
const [price, setPrice] = React.useState(item?.price ? String(item.price / 100) : "0");
|
|
30
|
+
const [quantity, setQuantity] = React.useState(String(item?.quantity ?? 1));
|
|
31
|
+
const [visibility, setVisibility] = React.useState(item?.visibility ?? "public");
|
|
32
|
+
const [images, setImages] = React.useState(item?.images ?? []);
|
|
33
|
+
const galleryFields = images.map((url) => ({ url, type: "image" }));
|
|
34
|
+
const handleUpload = async (file) => {
|
|
35
|
+
uploadIndexRef.current += 1;
|
|
36
|
+
return upload(file, "catalogue", true, {
|
|
37
|
+
type: "catalogue-image",
|
|
38
|
+
item: title || "item",
|
|
39
|
+
index: uploadIndexRef.current,
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
const saveMutation = useApiMutation({
|
|
43
|
+
successMessage: isCreate ? "Added to your catalogue" : "Catalogue item updated",
|
|
44
|
+
mutationFn: async () => {
|
|
45
|
+
const payload = {
|
|
46
|
+
title,
|
|
47
|
+
description: description || undefined,
|
|
48
|
+
condition: condition || undefined,
|
|
49
|
+
price: Math.round(Number(price) * 100),
|
|
50
|
+
quantity: Number(quantity),
|
|
51
|
+
visibility,
|
|
52
|
+
images,
|
|
53
|
+
mainImage: images[0],
|
|
54
|
+
};
|
|
55
|
+
if (isCreate)
|
|
56
|
+
return apiClient.post(ACCOUNT_ENDPOINTS.CATALOGUE, payload);
|
|
57
|
+
return apiClient.patch(ACCOUNT_ENDPOINTS.CATALOGUE_BY_ID(item.id), payload);
|
|
58
|
+
},
|
|
59
|
+
onSuccess: (saved) => {
|
|
60
|
+
queryClient.invalidateQueries({ queryKey: ["user", "catalogue"] });
|
|
61
|
+
onSaved?.(saved.id);
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
return (_jsx(Form, { schema: createCatalogueItemSchema, spacing: "md", children: ({ setFieldError }) => (_jsxs(Stack, { gap: "md", children: [item?.listingStatus && item.listingStatus !== "not_listed" && (_jsxs(Alert, { variant: "info", children: ["This item is ", item.listingStatus.replace(/_/g, " "), item.listingStatus === "rejected" && item.rejectionReason ? `: ${item.rejectionReason}` : "."] })), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(FieldInput, { name: "title", label: "Title", required: true, value: title, onChange: setTitle }), _jsx(FieldSelect, { name: "condition", label: "Condition", value: condition, onChange: setCondition, options: CONDITION_OPTIONS }), _jsx(FieldInput, { name: "price", label: "Estimated resale price (\u20B9)", type: "number", min: "0", value: price, onChange: setPrice }), _jsx(FieldInput, { name: "quantity", label: "Quantity", type: "number", min: "1", value: quantity, onChange: setQuantity })] }), _jsx(FieldTextarea, { name: "description", label: "Description", value: description, onChange: setDescription, rows: 3 }), _jsx(MediaUploadList, { label: "Photos", value: galleryFields, onChange: (fields) => setImages(fields.map((f) => f.url)), onUpload: handleUpload, accept: "image/*", maxItems: 8, helperText: "Photos older than 30 days must be refreshed before this item can be listed." }), _jsxs(Row, { gap: "sm", align: "center", children: [_jsx(Toggle, { checked: visibility === "public", onChange: (checked) => setVisibility(checked ? "public" : "private"), size: "sm" }), _jsx(Span, { children: visibility === "public" ? "Public — visible on your profile" : "Private — only you can see it" })] }), _jsx(Button, { type: "button", isLoading: saveMutation.isPending, onClick: () => {
|
|
65
|
+
const parsed = createCatalogueItemSchema.safeParse({
|
|
66
|
+
title,
|
|
67
|
+
images,
|
|
68
|
+
price: Math.round(Number(price) * 100),
|
|
69
|
+
quantity: Number(quantity),
|
|
70
|
+
visibility,
|
|
71
|
+
});
|
|
72
|
+
if (!parsed.success) {
|
|
73
|
+
for (const issue of parsed.error.issues)
|
|
74
|
+
setFieldError(String(issue.path[0]), issue.message);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
saveMutation.mutate();
|
|
78
|
+
}, children: isCreate ? "Add to Catalogue" : "Save Changes" })] })) }));
|
|
79
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useQuery } from "@tanstack/react-query";
|
|
4
|
+
import { Div, Grid, Heading, Skeleton, Text } from "../../../ui";
|
|
5
|
+
import { MediaImage } from "../../media/MediaImage";
|
|
6
|
+
import { apiClient } from "../../../http";
|
|
7
|
+
import { ACCOUNT_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
8
|
+
import { formatPaise } from "../../../utils/number.formatter";
|
|
9
|
+
export function PublicCatalogueView({ ownerSlug }) {
|
|
10
|
+
const { data, isLoading } = useQuery({
|
|
11
|
+
queryKey: ["catalogue", "public", ownerSlug],
|
|
12
|
+
queryFn: () => apiClient.get(ACCOUNT_ENDPOINTS.PUBLIC_CATALOGUE(ownerSlug)),
|
|
13
|
+
});
|
|
14
|
+
if (isLoading) {
|
|
15
|
+
return (_jsx(Grid, { cols: 4, gap: "md", children: [1, 2, 3, 4].map((n) => (_jsx(Skeleton, { variant: "rectangular", height: 200 }, n))) }));
|
|
16
|
+
}
|
|
17
|
+
const items = data?.items ?? [];
|
|
18
|
+
if (items.length === 0) {
|
|
19
|
+
return _jsx(Text, { variant: "secondary", children: "Nothing public here yet." });
|
|
20
|
+
}
|
|
21
|
+
return (_jsx(Grid, { cols: 4, gap: "md", children: items.map((item) => (_jsxs(Div, { rounded: "xl", border: "default", padding: "md", surface: "card", children: [_jsx(MediaImage, { src: item.mainImage || item.images[0] || "", alt: item.title, size: "card" }), _jsx(Div, { padding: "t-sm", children: _jsx(Heading, { level: 4, size: "sm", children: item.title }) }), typeof item.price === "number" && item.price > 0 && (_jsx(Text, { size: "sm", color: "muted", children: formatPaise(item.price) }))] }, item.id))) }));
|
|
22
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface UserCatalogueViewProps {
|
|
3
|
+
/**
|
|
4
|
+
* True for sellers AND admins — both can list a catalogue item directly
|
|
5
|
+
* (no approval queue). Sellers list under their own store; admins list
|
|
6
|
+
* under the platform's consignment store, since admins have no personal
|
|
7
|
+
* seller store and approving their own "Request to sell" would be a
|
|
8
|
+
* pointless round trip. Ordinary buyers get "Request to sell" instead.
|
|
9
|
+
*/
|
|
10
|
+
canListDirectly: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function UserCatalogueView({ canListDirectly }: UserCatalogueViewProps): React.JSX.Element;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
5
|
+
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
6
|
+
import { Badge, Button, Div, Grid, Heading, Row, SideDrawer, Skeleton, Stack, Text } from "../../../ui";
|
|
7
|
+
import { MediaImage } from "../../media/MediaImage";
|
|
8
|
+
import { apiClient } from "../../../http";
|
|
9
|
+
import { ACCOUNT_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
10
|
+
import { CatalogueItemEditorView } from "./CatalogueItemEditorView";
|
|
11
|
+
const STATUS_VARIANT = {
|
|
12
|
+
not_listed: "secondary",
|
|
13
|
+
pending_admin_approval: "warning",
|
|
14
|
+
listed: "success",
|
|
15
|
+
rejected: "default",
|
|
16
|
+
};
|
|
17
|
+
export function UserCatalogueView({ canListDirectly }) {
|
|
18
|
+
const queryClient = useQueryClient();
|
|
19
|
+
const { data, isLoading } = useQuery({
|
|
20
|
+
queryKey: ["user", "catalogue"],
|
|
21
|
+
queryFn: () => apiClient.get(ACCOUNT_ENDPOINTS.CATALOGUE),
|
|
22
|
+
});
|
|
23
|
+
const items = data?.items ?? [];
|
|
24
|
+
const [editingId, setEditingId] = React.useState(null);
|
|
25
|
+
const [creating, setCreating] = React.useState(false);
|
|
26
|
+
const invalidate = () => queryClient.invalidateQueries({ queryKey: ["user", "catalogue"] });
|
|
27
|
+
const toggleVisibilityMutation = useApiMutation({
|
|
28
|
+
successMessage: "Visibility updated",
|
|
29
|
+
mutationFn: (item) => apiClient.patch(ACCOUNT_ENDPOINTS.CATALOGUE_BY_ID(item.id), {
|
|
30
|
+
visibility: item.visibility === "public" ? "private" : "public",
|
|
31
|
+
}),
|
|
32
|
+
onSuccess: invalidate,
|
|
33
|
+
});
|
|
34
|
+
const deleteMutation = useApiMutation({
|
|
35
|
+
successMessage: "Removed from catalogue",
|
|
36
|
+
mutationFn: (id) => apiClient.delete(ACCOUNT_ENDPOINTS.CATALOGUE_BY_ID(id)),
|
|
37
|
+
onSuccess: invalidate,
|
|
38
|
+
});
|
|
39
|
+
const listMutation = useApiMutation({
|
|
40
|
+
successMessage: "Listed",
|
|
41
|
+
mutationFn: (id) => apiClient.post(ACCOUNT_ENDPOINTS.CATALOGUE_LIST(id)),
|
|
42
|
+
onSuccess: invalidate,
|
|
43
|
+
});
|
|
44
|
+
const submitMutation = useApiMutation({
|
|
45
|
+
successMessage: "Requested — an admin will review it",
|
|
46
|
+
mutationFn: (id) => apiClient.post(ACCOUNT_ENDPOINTS.CATALOGUE_SUBMIT(id)),
|
|
47
|
+
onSuccess: invalidate,
|
|
48
|
+
});
|
|
49
|
+
const editingItem = items.find((i) => i.id === editingId);
|
|
50
|
+
return (_jsxs(Stack, { gap: "md", children: [_jsxs(Row, { align: "center", justify: "between", children: [_jsx(Heading, { level: 2, children: "My Catalogue" }), _jsx(Button, { onClick: () => setCreating(true), children: "+ Add Item" })] }), isLoading ? (_jsx(Grid, { cols: 3, gap: "md", children: [1, 2, 3].map((n) => (_jsx(Skeleton, { variant: "rectangular", height: 220 }, n))) })) : items.length === 0 ? (_jsx(Text, { variant: "secondary", children: "Nothing in your catalogue yet." })) : (_jsx(Grid, { cols: 3, gap: "md", children: items.map((item) => (_jsxs(Div, { rounded: "xl", border: "default", padding: "md", surface: "card", children: [_jsx(MediaImage, { src: item.mainImage || item.images[0] || "", alt: item.title, size: "card" }), _jsxs(Stack, { gap: "xs", padding: "t-sm", children: [_jsx(Text, { weight: "medium", children: item.title }), _jsxs(Row, { gap: "sm", align: "center", children: [_jsx(Badge, { variant: STATUS_VARIANT[item.listingStatus], children: item.listingStatus.replace(/_/g, " ") }), _jsx(Badge, { variant: "secondary", children: item.visibility })] }), _jsxs(Row, { gap: "sm", wrap: true, children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: () => setEditingId(item.id), children: "Edit" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => toggleVisibilityMutation.mutate(item), children: item.visibility === "public" ? "Make private" : "Make public" }), item.listingStatus === "not_listed" && (canListDirectly ? (_jsx(Button, { size: "sm", isLoading: listMutation.isPending, onClick: () => listMutation.mutate(item.id), children: "List" })) : (_jsx(Button, { size: "sm", isLoading: submitMutation.isPending, onClick: () => submitMutation.mutate(item.id), children: "Request to sell" }))), item.listingStatus === "not_listed" && (_jsx(Button, { size: "sm", variant: "ghost", isLoading: deleteMutation.isPending, onClick: () => deleteMutation.mutate(item.id), children: "Delete" }))] })] })] }, item.id))) })), _jsx(SideDrawer, { isOpen: creating, onClose: () => setCreating(false), title: "Add to Catalogue", children: _jsx(CatalogueItemEditorView, { onSaved: () => { setCreating(false); invalidate(); } }) }), _jsx(SideDrawer, { isOpen: !!editingItem, onClose: () => setEditingId(null), title: "Edit Catalogue Item", children: editingItem && (_jsx(CatalogueItemEditorView, { item: editingItem, onSaved: () => { setEditingId(null); invalidate(); } })) })] }));
|
|
51
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./schemas";
|
|
2
|
+
export * from "./utils/freshness";
|
|
3
|
+
export { listFromCatalogueAction } from "./actions/list-from-catalogue";
|
|
4
|
+
export { submitCatalogueItemForApprovalAction } from "./actions/submit-for-approval";
|
|
5
|
+
export { approveCatalogueListingAction, rejectCatalogueListingAction, } from "./actions/approve-catalogue-listing";
|
|
6
|
+
export { UserCatalogueView } from "./components/UserCatalogueView";
|
|
7
|
+
export type { UserCatalogueViewProps } from "./components/UserCatalogueView";
|
|
8
|
+
export { CatalogueItemEditorView } from "./components/CatalogueItemEditorView";
|
|
9
|
+
export type { CatalogueItemEditorViewProps } from "./components/CatalogueItemEditorView";
|
|
10
|
+
export { PublicCatalogueView } from "./components/PublicCatalogueView";
|
|
11
|
+
export type { PublicCatalogueViewProps } from "./components/PublicCatalogueView";
|
|
12
|
+
export { AdminCatalogueApprovalsView } from "./components/AdminCatalogueApprovalsView";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./schemas";
|
|
2
|
+
export * from "./utils/freshness";
|
|
3
|
+
export { listFromCatalogueAction } from "./actions/list-from-catalogue";
|
|
4
|
+
export { submitCatalogueItemForApprovalAction } from "./actions/submit-for-approval";
|
|
5
|
+
export { approveCatalogueListingAction, rejectCatalogueListingAction, } from "./actions/approve-catalogue-listing";
|
|
6
|
+
export { UserCatalogueView } from "./components/UserCatalogueView";
|
|
7
|
+
export { CatalogueItemEditorView } from "./components/CatalogueItemEditorView";
|
|
8
|
+
export { PublicCatalogueView } from "./components/PublicCatalogueView";
|
|
9
|
+
export { AdminCatalogueApprovalsView } from "./components/AdminCatalogueApprovalsView";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Personal Catalogue Repository (Feature B).
|
|
3
|
+
*/
|
|
4
|
+
import { BaseRepository, type SieveModel, type FirebaseSieveResult } from "../../../providers/db-firebase";
|
|
5
|
+
import { type CatalogueItemDocument, type CatalogueItemCreateInput, type CatalogueItemUpdateInput } from "../schemas/firestore";
|
|
6
|
+
export declare class CatalogueRepository extends BaseRepository<CatalogueItemDocument> {
|
|
7
|
+
constructor();
|
|
8
|
+
create(input: CatalogueItemCreateInput): Promise<CatalogueItemDocument>;
|
|
9
|
+
/** Stamps lastImageUpdateAt whenever `images` changes — the single field the freshness gate checks. */
|
|
10
|
+
update(itemId: string, input: CatalogueItemUpdateInput): Promise<CatalogueItemDocument>;
|
|
11
|
+
listPublicByOwner(ownerId: string): Promise<CatalogueItemDocument[]>;
|
|
12
|
+
listByOwner(ownerId: string): Promise<CatalogueItemDocument[]>;
|
|
13
|
+
listPendingApproval(model: SieveModel): Promise<FirebaseSieveResult<CatalogueItemDocument>>;
|
|
14
|
+
static readonly SIEVE_FIELDS: {
|
|
15
|
+
id: {
|
|
16
|
+
canFilter: boolean;
|
|
17
|
+
canSort: boolean;
|
|
18
|
+
};
|
|
19
|
+
ownerId: {
|
|
20
|
+
canFilter: boolean;
|
|
21
|
+
canSort: boolean;
|
|
22
|
+
};
|
|
23
|
+
visibility: {
|
|
24
|
+
canFilter: boolean;
|
|
25
|
+
canSort: boolean;
|
|
26
|
+
};
|
|
27
|
+
listingStatus: {
|
|
28
|
+
canFilter: boolean;
|
|
29
|
+
canSort: boolean;
|
|
30
|
+
};
|
|
31
|
+
createdAt: {
|
|
32
|
+
canFilter: boolean;
|
|
33
|
+
canSort: boolean;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/** Bounded scan for the staleness-reminder Function — images older than N days, not yet reminded for this update. */
|
|
37
|
+
listStale(olderThanDate: Date, limit?: number): Promise<CatalogueItemDocument[]>;
|
|
38
|
+
}
|
|
39
|
+
export declare const catalogueRepository: CatalogueRepository;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Personal Catalogue Repository (Feature B).
|
|
3
|
+
*/
|
|
4
|
+
import { BaseRepository, prepareForFirestore, } from "../../../providers/db-firebase";
|
|
5
|
+
import { CATALOGUE_COLLECTION, CATALOGUE_FIELDS, createCatalogueItemId, } from "../schemas/firestore";
|
|
6
|
+
export class CatalogueRepository extends BaseRepository {
|
|
7
|
+
constructor() {
|
|
8
|
+
super(CATALOGUE_COLLECTION);
|
|
9
|
+
}
|
|
10
|
+
async create(input) {
|
|
11
|
+
const id = createCatalogueItemId({ ownerSlug: input.ownerId, title: input.title });
|
|
12
|
+
const now = new Date();
|
|
13
|
+
const data = {
|
|
14
|
+
...input,
|
|
15
|
+
listingStatus: "not_listed",
|
|
16
|
+
lastImageUpdateAt: now,
|
|
17
|
+
createdAt: now,
|
|
18
|
+
updatedAt: now,
|
|
19
|
+
};
|
|
20
|
+
await this.getCollection().doc(id).set(prepareForFirestore(data));
|
|
21
|
+
return { id, ...data };
|
|
22
|
+
}
|
|
23
|
+
/** Stamps lastImageUpdateAt whenever `images` changes — the single field the freshness gate checks. */
|
|
24
|
+
async update(itemId, input) {
|
|
25
|
+
const patch = { ...input };
|
|
26
|
+
if (input.images !== undefined) {
|
|
27
|
+
patch.lastImageUpdateAt = new Date();
|
|
28
|
+
}
|
|
29
|
+
return super.update(itemId, patch);
|
|
30
|
+
}
|
|
31
|
+
async listPublicByOwner(ownerId) {
|
|
32
|
+
const snap = await this.getCollection()
|
|
33
|
+
.where(CATALOGUE_FIELDS.OWNER_ID, "==", ownerId)
|
|
34
|
+
.where(CATALOGUE_FIELDS.VISIBILITY, "==", "public")
|
|
35
|
+
.orderBy(CATALOGUE_FIELDS.CREATED_AT, "desc")
|
|
36
|
+
.get();
|
|
37
|
+
return snap.docs.map((doc) => this.mapDoc(doc));
|
|
38
|
+
}
|
|
39
|
+
async listByOwner(ownerId) {
|
|
40
|
+
const snap = await this.getCollection()
|
|
41
|
+
.where(CATALOGUE_FIELDS.OWNER_ID, "==", ownerId)
|
|
42
|
+
.orderBy(CATALOGUE_FIELDS.CREATED_AT, "desc")
|
|
43
|
+
.get();
|
|
44
|
+
return snap.docs.map((doc) => this.mapDoc(doc));
|
|
45
|
+
}
|
|
46
|
+
async listPendingApproval(model) {
|
|
47
|
+
return this.sieveQuery(model, CatalogueRepository.SIEVE_FIELDS, {
|
|
48
|
+
defaultPageSize: 25,
|
|
49
|
+
maxPageSize: 100,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/** Bounded scan for the staleness-reminder Function — images older than N days, not yet reminded for this update. */
|
|
53
|
+
async listStale(olderThanDate, limit = 200) {
|
|
54
|
+
const snap = await this.getCollection()
|
|
55
|
+
.where(CATALOGUE_FIELDS.LAST_IMAGE_UPDATE_AT, "<", olderThanDate)
|
|
56
|
+
.limit(limit)
|
|
57
|
+
.get();
|
|
58
|
+
return snap.docs.map((doc) => this.mapDoc(doc));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
CatalogueRepository.SIEVE_FIELDS = {
|
|
62
|
+
id: { canFilter: true, canSort: false },
|
|
63
|
+
ownerId: { canFilter: true, canSort: false },
|
|
64
|
+
visibility: { canFilter: true, canSort: false },
|
|
65
|
+
listingStatus: { canFilter: true, canSort: false },
|
|
66
|
+
createdAt: { canFilter: true, canSort: true },
|
|
67
|
+
};
|
|
68
|
+
export const catalogueRepository = new CatalogueRepository();
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Personal Catalogue (Feature B) Firestore Document Types & Constants.
|
|
3
|
+
*
|
|
4
|
+
* Naming note: this is unrelated to `CatalogProductDocument` (SB-UNI-L, the
|
|
5
|
+
* shared master-catalog sellers create offers against) — "Catalogue" here is
|
|
6
|
+
* a user's personal photo inventory of items they own, slug-prefixed
|
|
7
|
+
* `mycatalog-` to stay visually distinct from `catalog-`.
|
|
8
|
+
*/
|
|
9
|
+
import { type GenerateCatalogueItemIdInput } from "../../../utils/id-generators";
|
|
10
|
+
import type { BaseDocument } from "../../../_internal/shared/types/base-document";
|
|
11
|
+
import type { ProductDraftFields } from "../../shipments/schemas/firestore";
|
|
12
|
+
export declare const CATALOGUE_COLLECTION: "catalogueItems";
|
|
13
|
+
export type CatalogueVisibility = "public" | "private";
|
|
14
|
+
export type CatalogueOwnerRole = "user" | "seller" | "admin";
|
|
15
|
+
export type CatalogueListingStatus = "not_listed" | "pending_admin_approval" | "listed" | "rejected";
|
|
16
|
+
export interface CatalogueItemDocument extends BaseDocument, Partial<Omit<ProductDraftFields, "title" | "images" | "mainImage">> {
|
|
17
|
+
ownerId: string;
|
|
18
|
+
ownerRole: CatalogueOwnerRole;
|
|
19
|
+
title: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
images: string[];
|
|
22
|
+
mainImage?: string;
|
|
23
|
+
quantity: number;
|
|
24
|
+
visibility: CatalogueVisibility;
|
|
25
|
+
watermarkOverride?: {
|
|
26
|
+
text?: string;
|
|
27
|
+
};
|
|
28
|
+
lastImageUpdateAt: Date;
|
|
29
|
+
staleReminderSentAt?: Date;
|
|
30
|
+
listingStatus: CatalogueListingStatus;
|
|
31
|
+
submittedForApprovalAt?: Date;
|
|
32
|
+
rejectionReason?: string;
|
|
33
|
+
linkedProductId?: string;
|
|
34
|
+
linkedProductSlug?: string;
|
|
35
|
+
}
|
|
36
|
+
export declare const CATALOGUE_IMAGE_FRESHNESS_DAYS: 30;
|
|
37
|
+
export declare const CATALOGUE_FIELDS: {
|
|
38
|
+
readonly ID: "id";
|
|
39
|
+
readonly OWNER_ID: "ownerId";
|
|
40
|
+
readonly VISIBILITY: "visibility";
|
|
41
|
+
readonly LISTING_STATUS: "listingStatus";
|
|
42
|
+
readonly LAST_IMAGE_UPDATE_AT: "lastImageUpdateAt";
|
|
43
|
+
readonly CREATED_AT: "createdAt";
|
|
44
|
+
};
|
|
45
|
+
export type CatalogueItemCreateInput = Omit<CatalogueItemDocument, "id" | "createdAt" | "updatedAt" | "lastImageUpdateAt" | "listingStatus">;
|
|
46
|
+
export type CatalogueItemUpdateInput = Partial<Omit<CatalogueItemDocument, "id" | "createdAt" | "ownerId">>;
|
|
47
|
+
export declare function createCatalogueItemId(input: GenerateCatalogueItemIdInput): string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Personal Catalogue (Feature B) Firestore Document Types & Constants.
|
|
3
|
+
*
|
|
4
|
+
* Naming note: this is unrelated to `CatalogProductDocument` (SB-UNI-L, the
|
|
5
|
+
* shared master-catalog sellers create offers against) — "Catalogue" here is
|
|
6
|
+
* a user's personal photo inventory of items they own, slug-prefixed
|
|
7
|
+
* `mycatalog-` to stay visually distinct from `catalog-`.
|
|
8
|
+
*/
|
|
9
|
+
import { generateCatalogueItemId, } from "../../../utils/id-generators";
|
|
10
|
+
export const CATALOGUE_COLLECTION = "catalogueItems";
|
|
11
|
+
export const CATALOGUE_IMAGE_FRESHNESS_DAYS = 30;
|
|
12
|
+
export const CATALOGUE_FIELDS = {
|
|
13
|
+
ID: "id",
|
|
14
|
+
OWNER_ID: "ownerId",
|
|
15
|
+
VISIBILITY: "visibility",
|
|
16
|
+
LISTING_STATUS: "listingStatus",
|
|
17
|
+
LAST_IMAGE_UPDATE_AT: "lastImageUpdateAt",
|
|
18
|
+
CREATED_AT: "createdAt",
|
|
19
|
+
};
|
|
20
|
+
export function createCatalogueItemId(input) {
|
|
21
|
+
return generateCatalogueItemId(input);
|
|
22
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const createCatalogueItemSchema: z.ZodObject<{
|
|
3
|
+
title: z.ZodString;
|
|
4
|
+
description: z.ZodOptional<z.ZodString>;
|
|
5
|
+
images: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
6
|
+
mainImage: z.ZodOptional<z.ZodString>;
|
|
7
|
+
condition: z.ZodOptional<z.ZodEnum<["new", "like_new", "good", "fair", "poor", "used", "refurbished", "broken", "graded"]>>;
|
|
8
|
+
categorySlugs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
9
|
+
brandSlug: z.ZodOptional<z.ZodString>;
|
|
10
|
+
price: z.ZodOptional<z.ZodNumber>;
|
|
11
|
+
quantity: z.ZodDefault<z.ZodNumber>;
|
|
12
|
+
visibility: z.ZodDefault<z.ZodEnum<["public", "private"]>>;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
title: string;
|
|
15
|
+
images: string[];
|
|
16
|
+
visibility: "public" | "private";
|
|
17
|
+
quantity: number;
|
|
18
|
+
description?: string | undefined;
|
|
19
|
+
categorySlugs?: string[] | undefined;
|
|
20
|
+
brandSlug?: string | undefined;
|
|
21
|
+
price?: number | undefined;
|
|
22
|
+
mainImage?: string | undefined;
|
|
23
|
+
condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | "graded" | undefined;
|
|
24
|
+
}, {
|
|
25
|
+
title: string;
|
|
26
|
+
description?: string | undefined;
|
|
27
|
+
categorySlugs?: string[] | undefined;
|
|
28
|
+
brandSlug?: string | undefined;
|
|
29
|
+
price?: number | undefined;
|
|
30
|
+
mainImage?: string | undefined;
|
|
31
|
+
images?: string[] | undefined;
|
|
32
|
+
condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | "graded" | undefined;
|
|
33
|
+
visibility?: "public" | "private" | undefined;
|
|
34
|
+
quantity?: number | undefined;
|
|
35
|
+
}>;
|
|
36
|
+
export declare const updateCatalogueItemSchema: z.ZodObject<{
|
|
37
|
+
title: z.ZodOptional<z.ZodString>;
|
|
38
|
+
description: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
39
|
+
images: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString, "many">>>;
|
|
40
|
+
mainImage: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
41
|
+
condition: z.ZodOptional<z.ZodOptional<z.ZodEnum<["new", "like_new", "good", "fair", "poor", "used", "refurbished", "broken", "graded"]>>>;
|
|
42
|
+
categorySlugs: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
|
|
43
|
+
brandSlug: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
44
|
+
price: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
|
|
45
|
+
quantity: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
46
|
+
visibility: z.ZodOptional<z.ZodDefault<z.ZodEnum<["public", "private"]>>>;
|
|
47
|
+
}, "strip", z.ZodTypeAny, {
|
|
48
|
+
title?: string | undefined;
|
|
49
|
+
description?: string | undefined;
|
|
50
|
+
categorySlugs?: string[] | undefined;
|
|
51
|
+
brandSlug?: string | undefined;
|
|
52
|
+
price?: number | undefined;
|
|
53
|
+
mainImage?: string | undefined;
|
|
54
|
+
images?: string[] | undefined;
|
|
55
|
+
condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | "graded" | undefined;
|
|
56
|
+
visibility?: "public" | "private" | undefined;
|
|
57
|
+
quantity?: number | undefined;
|
|
58
|
+
}, {
|
|
59
|
+
title?: string | undefined;
|
|
60
|
+
description?: string | undefined;
|
|
61
|
+
categorySlugs?: string[] | undefined;
|
|
62
|
+
brandSlug?: string | undefined;
|
|
63
|
+
price?: number | undefined;
|
|
64
|
+
mainImage?: string | undefined;
|
|
65
|
+
images?: string[] | undefined;
|
|
66
|
+
condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | "graded" | undefined;
|
|
67
|
+
visibility?: "public" | "private" | undefined;
|
|
68
|
+
quantity?: number | undefined;
|
|
69
|
+
}>;
|
|
70
|
+
export type CreateCatalogueItemInput = z.infer<typeof createCatalogueItemSchema>;
|
|
71
|
+
export type UpdateCatalogueItemInput = z.infer<typeof updateCatalogueItemSchema>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const productConditionSchema = z.enum([
|
|
3
|
+
"new",
|
|
4
|
+
"like_new",
|
|
5
|
+
"good",
|
|
6
|
+
"fair",
|
|
7
|
+
"poor",
|
|
8
|
+
"used",
|
|
9
|
+
"refurbished",
|
|
10
|
+
"broken",
|
|
11
|
+
"graded",
|
|
12
|
+
]);
|
|
13
|
+
export const createCatalogueItemSchema = z.object({
|
|
14
|
+
title: z.string().min(1, "Title is required"),
|
|
15
|
+
description: z.string().optional(),
|
|
16
|
+
images: z.array(z.string()).default([]),
|
|
17
|
+
mainImage: z.string().optional(),
|
|
18
|
+
condition: productConditionSchema.optional(),
|
|
19
|
+
categorySlugs: z.array(z.string()).optional(),
|
|
20
|
+
brandSlug: z.string().optional(),
|
|
21
|
+
price: z.number().int().min(0).optional(),
|
|
22
|
+
quantity: z.number().int().min(1).default(1),
|
|
23
|
+
visibility: z.enum(["public", "private"]).default("public"),
|
|
24
|
+
});
|
|
25
|
+
export const updateCatalogueItemSchema = createCatalogueItemSchema.partial();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared gate for both the seller "List" action and the buyer "Request to
|
|
3
|
+
* sell" action — photos older than CATALOGUE_IMAGE_FRESHNESS_DAYS (30) must
|
|
4
|
+
* be refreshed before a catalogue item can become a real listing. Checked
|
|
5
|
+
* once at write time against the repository-stamped `lastImageUpdateAt`, not
|
|
6
|
+
* re-derived per image at read time.
|
|
7
|
+
*/
|
|
8
|
+
export declare function assertCatalogueImagesFresh(item: {
|
|
9
|
+
lastImageUpdateAt: Date;
|
|
10
|
+
}): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CATALOGUE_IMAGE_FRESHNESS_DAYS } from "../schemas/firestore";
|
|
2
|
+
import { ValidationError } from "../../../errors";
|
|
3
|
+
/**
|
|
4
|
+
* Shared gate for both the seller "List" action and the buyer "Request to
|
|
5
|
+
* sell" action — photos older than CATALOGUE_IMAGE_FRESHNESS_DAYS (30) must
|
|
6
|
+
* be refreshed before a catalogue item can become a real listing. Checked
|
|
7
|
+
* once at write time against the repository-stamped `lastImageUpdateAt`, not
|
|
8
|
+
* re-derived per image at read time.
|
|
9
|
+
*/
|
|
10
|
+
export function assertCatalogueImagesFresh(item) {
|
|
11
|
+
const ageDays = (Date.now() - new Date(item.lastImageUpdateAt).getTime()) / 86400000;
|
|
12
|
+
if (ageDays > CATALOGUE_IMAGE_FRESHNESS_DAYS) {
|
|
13
|
+
throw new ValidationError(`Photos for this item are ${Math.floor(ageDays)} days old — upload fresh photos (within ${CATALOGUE_IMAGE_FRESHNESS_DAYS} days) before listing it.`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CatalogueItemDocument } from "../schemas/firestore";
|
|
2
|
+
import type { ProductDocument } from "../../products/schemas/firestore";
|
|
3
|
+
/** The platform's own consignment store — used whenever a catalogue item is
|
|
4
|
+
* listed by someone with no personal seller store of their own (buyer
|
|
5
|
+
* approval path, admin direct-list path). */
|
|
6
|
+
export declare const CONSIGNMENT_STORE_ID = "store-letitrip-official";
|
|
7
|
+
/**
|
|
8
|
+
* Shared field mapping from a catalogue item to a new product — used by
|
|
9
|
+
* both the direct-listing path (seller/admin) and the admin-approval path
|
|
10
|
+
* (buyer). Reuses `ProductDraftFields`-shaped fields already on the
|
|
11
|
+
* catalogue item (title/images/price/condition/categorySlugs/brandSlug) as
|
|
12
|
+
* a near-literal copy; only `storeId` and the `sourceCatalogueItemId`/
|
|
13
|
+
* `sourceCatalogueOwnerId` back-reference differ per caller.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createProductFromCatalogueItem(item: CatalogueItemDocument, storeId: string): Promise<ProductDocument>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { productRepository } from "../../../repositories";
|
|
2
|
+
/** The platform's own consignment store — used whenever a catalogue item is
|
|
3
|
+
* listed by someone with no personal seller store of their own (buyer
|
|
4
|
+
* approval path, admin direct-list path). */
|
|
5
|
+
export const CONSIGNMENT_STORE_ID = "store-letitrip-official";
|
|
6
|
+
/**
|
|
7
|
+
* Shared field mapping from a catalogue item to a new product — used by
|
|
8
|
+
* both the direct-listing path (seller/admin) and the admin-approval path
|
|
9
|
+
* (buyer). Reuses `ProductDraftFields`-shaped fields already on the
|
|
10
|
+
* catalogue item (title/images/price/condition/categorySlugs/brandSlug) as
|
|
11
|
+
* a near-literal copy; only `storeId` and the `sourceCatalogueItemId`/
|
|
12
|
+
* `sourceCatalogueOwnerId` back-reference differ per caller.
|
|
13
|
+
*/
|
|
14
|
+
export async function createProductFromCatalogueItem(item, storeId) {
|
|
15
|
+
return productRepository.create({
|
|
16
|
+
title: item.title,
|
|
17
|
+
description: item.description || "Listed via LetItRip's personal catalogue.",
|
|
18
|
+
categorySlugs: item.categorySlugs ?? [],
|
|
19
|
+
brandSlug: item.brandSlug,
|
|
20
|
+
price: item.price ?? 0,
|
|
21
|
+
currency: "INR",
|
|
22
|
+
stockQuantity: item.quantity,
|
|
23
|
+
mainImage: item.mainImage ?? item.images[0] ?? "",
|
|
24
|
+
images: item.images,
|
|
25
|
+
status: "published",
|
|
26
|
+
storeId,
|
|
27
|
+
featured: false,
|
|
28
|
+
tags: [],
|
|
29
|
+
condition: item.condition,
|
|
30
|
+
listingType: "standard",
|
|
31
|
+
sourceCatalogueItemId: item.id,
|
|
32
|
+
sourceCatalogueOwnerId: item.ownerId,
|
|
33
|
+
});
|
|
34
|
+
}
|