@mohasinac/appkit 4.30.19 → 4.31.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/layout/useSidebarSearch.d.ts +21 -5
- package/dist/_internal/client/features/layout/useSidebarSearch.js +27 -6
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +23 -3
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +106 -87
- package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +16 -5
- package/dist/_internal/client/features/lottery/LotteryPullForm.js +65 -40
- package/dist/_internal/server/features/auth/permissions.d.ts +2 -0
- package/dist/_internal/server/features/auth/permissions.js +3 -2
- package/dist/_internal/server/features/categories/data.js +15 -4
- package/dist/_internal/server/features/classified/index.d.ts +0 -1
- package/dist/_internal/server/features/classified/index.js +0 -1
- package/dist/_internal/server/features/digital-code/index.d.ts +0 -1
- package/dist/_internal/server/features/digital-code/index.js +0 -1
- package/dist/_internal/server/features/live/index.d.ts +0 -1
- package/dist/_internal/server/features/live/index.js +0 -1
- package/dist/_internal/server/features/products/data.js +15 -5
- package/dist/_internal/server/features/products/list-public.d.ts +9 -0
- package/dist/_internal/server/features/products/list-public.js +95 -7
- package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
- package/dist/_internal/server/features/site-settings/adapters.js +8 -5
- package/dist/_internal/server/features/tester/visibility.d.ts +2 -1
- package/dist/_internal/server/features/tester/visibility.js +2 -2
- package/dist/_internal/server/functions/scheduled.d.ts +3 -1
- package/dist/_internal/server/functions/scheduled.js +27 -1
- package/dist/_internal/server/jobs/core/hardBanCascade.js +4 -0
- package/dist/_internal/server/jobs/core/index.d.ts +2 -0
- package/dist/_internal/server/jobs/core/index.js +2 -0
- package/dist/_internal/server/jobs/core/pageViewPrune.d.ts +10 -0
- package/dist/_internal/server/jobs/core/pageViewPrune.js +44 -0
- package/dist/_internal/server/jobs/core/pageViewRollup.d.ts +2 -0
- package/dist/_internal/server/jobs/core/pageViewRollup.js +87 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/index.js +2 -0
- package/dist/_internal/server/jobs/handlers/pageViewPrune.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/pageViewPrune.js +2 -0
- package/dist/_internal/server/jobs/handlers/pageViewRollup.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/pageViewRollup.js +2 -0
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +69 -22
- package/dist/_internal/shared/checkout/rules/classified.rule.d.ts +9 -4
- package/dist/_internal/shared/checkout/rules/classified.rule.js +7 -2
- package/dist/_internal/shared/features/layout/matchesNavQuery.d.ts +14 -0
- package/dist/_internal/shared/features/layout/matchesNavQuery.js +72 -0
- package/dist/_internal/shared/features/layout/types.d.ts +37 -1
- package/dist/_internal/shared/features/layout/types.js +19 -1
- package/dist/_internal/shared/features/notifications/action-url.d.ts +9 -1
- package/dist/_internal/shared/features/notifications/action-url.js +47 -0
- package/dist/_internal/shared/features/offers/config.d.ts +65 -0
- package/dist/_internal/shared/features/offers/config.js +73 -2
- package/dist/_internal/shared/features/orders/schema.d.ts +19 -1
- package/dist/_internal/shared/features/orders/schema.js +22 -2
- package/dist/_internal/shared/features/site-settings/types.d.ts +12 -3
- package/dist/_internal/shared/listing-types/capabilities.d.ts +8 -2
- package/dist/_internal/shared/listing-types/capabilities.js +6 -1
- package/dist/_internal/shared/listing-types/classified/ctas.js +6 -1
- package/dist/_internal/shared/listing-types/feature-flags.d.ts +10 -5
- package/dist/_internal/shared/listing-types/feature-flags.js +11 -6
- package/dist/client.d.ts +37 -20
- package/dist/client.js +36 -14
- package/dist/configs/next.js +10 -2
- package/dist/constants/api-endpoints.d.ts +18 -54
- package/dist/constants/api-endpoints.js +6 -26
- package/dist/constants/field-names.d.ts +6 -24
- package/dist/constants/field-names.js +10 -27
- package/dist/constants/geo/countries.d.ts +50 -0
- package/dist/constants/geo/countries.js +129 -0
- package/dist/constants/geo/subdivisions.d.ts +13 -0
- package/dist/constants/geo/subdivisions.js +104 -0
- package/dist/constants/index.d.ts +2 -2
- package/dist/constants/index.js +2 -2
- package/dist/constants/table-keys.d.ts +24 -0
- package/dist/constants/table-keys.js +28 -0
- package/dist/contracts/extend.d.ts +0 -9
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/realtime-session.js +7 -0
- package/dist/core/browser.d.ts +1 -1
- package/dist/core/browser.js +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/site-config.d.ts +0 -3
- package/dist/core/site-config.js +0 -3
- package/dist/errors/messages.d.ts +0 -8
- package/dist/errors/messages.js +0 -9
- package/dist/features/about/schemas/index.d.ts +8 -8
- package/dist/features/account/components/AddressFilters.js +32 -11
- package/dist/features/account/components/AddressForm.d.ts +26 -25
- package/dist/features/account/components/AddressForm.js +81 -103
- package/dist/features/account/components/AddressesIndexListing.js +8 -4
- package/dist/features/account/components/UserSidebar.d.ts +3 -4
- package/dist/features/account/components/UserSupportView.js +89 -58
- package/dist/features/account/components/index.d.ts +1 -7
- package/dist/features/account/components/index.js +0 -3
- package/dist/features/account/hooks/useAddresses.d.ts +4 -3
- package/dist/features/account/hooks/useAddresses.js +4 -6
- package/dist/features/account/hooks/useCollapsedSections.d.ts +51 -10
- package/dist/features/account/hooks/useCollapsedSections.js +211 -38
- package/dist/features/account/hooks/useProfile.d.ts +8 -0
- package/dist/features/account/index.d.ts +0 -3
- package/dist/features/account/index.js +0 -3
- package/dist/features/account/schemas/index.d.ts +0 -92
- package/dist/features/account/schemas/index.js +42 -20
- package/dist/features/addresses/components/AddressLocationFields.d.ts +13 -0
- package/dist/features/addresses/components/AddressLocationFields.js +41 -0
- package/dist/features/addresses/hooks/usePostalLookup.d.ts +17 -0
- package/dist/features/addresses/hooks/usePostalLookup.js +133 -0
- package/dist/features/addresses/schemas/address-form.d.ts +423 -0
- package/dist/features/addresses/schemas/address-form.js +212 -0
- package/dist/features/addresses/schemas/index.d.ts +1 -0
- package/dist/features/addresses/schemas/index.js +8 -0
- package/dist/features/admin/actions/admin-read-actions.d.ts +1 -1
- package/dist/features/admin/actions/index.d.ts +0 -1
- package/dist/features/admin/actions/index.js +0 -1
- package/dist/features/admin/actions/notification-actions.js +1 -41
- package/dist/features/admin/components/AdminActionIndexView.d.ts +32 -0
- package/dist/features/admin/components/AdminActionIndexView.js +128 -0
- package/dist/features/admin/components/AdminAdEditorView.js +159 -163
- package/dist/features/admin/components/AdminAddressEditorView.js +97 -55
- package/dist/features/admin/components/AdminBrandEditorView.d.ts +15 -0
- package/dist/features/admin/components/AdminBrandEditorView.js +113 -77
- package/dist/features/admin/components/AdminBundleEditorView.d.ts +19 -9
- package/dist/features/admin/components/AdminBundleEditorView.js +136 -168
- package/dist/features/admin/components/AdminCategoryEditorView.js +120 -43
- package/dist/features/admin/components/AdminCouponEditorView.js +145 -109
- package/dist/features/admin/components/AdminEmployeeEditorView.js +125 -56
- package/dist/features/admin/components/AdminFaqEditorView.js +112 -58
- package/dist/features/admin/components/AdminFeatureEditorView.js +108 -68
- package/dist/features/admin/components/AdminNavEditorView.js +69 -44
- package/dist/features/admin/components/AdminOrderEditorView.js +47 -10
- package/dist/features/admin/components/AdminPrizeDrawsView.js +16 -2
- package/dist/features/admin/components/AdminSidebar.d.ts +11 -7
- package/dist/features/admin/components/AdminSiteSettingsView.js +37 -37
- package/dist/features/admin/components/AdminStoreEditorView.js +75 -52
- package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +71 -30
- package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +95 -65
- package/dist/features/admin/components/BrandQuickCreateForm.d.ts +10 -0
- package/dist/features/admin/components/BrandQuickCreateForm.js +49 -26
- package/dist/features/admin/components/CategoryQuickCreateForm.d.ts +11 -0
- package/dist/features/admin/components/CategoryQuickCreateForm.js +48 -26
- package/dist/features/admin/components/index.d.ts +2 -2
- package/dist/features/admin/components/index.js +1 -1
- package/dist/features/admin/constants/site-settings-tabs.d.ts +120 -0
- package/dist/features/admin/constants/site-settings-tabs.js +152 -0
- package/dist/features/admin/index.d.ts +0 -3
- package/dist/features/admin/index.js +0 -2
- package/dist/features/admin/repository/analytics-rollup.repository.d.ts +35 -0
- package/dist/features/admin/repository/analytics-rollup.repository.js +30 -0
- package/dist/features/admin/schemas/admin-editor-forms.d.ts +56 -57
- package/dist/features/admin/schemas/admin-editor-forms.js +97 -54
- package/dist/features/admin/schemas/admin-ops-forms.d.ts +57 -5
- package/dist/features/admin/schemas/admin-ops-forms.js +104 -20
- package/dist/features/admin/schemas/admin-user-form.js +7 -0
- package/dist/features/admin/schemas/firestore.d.ts +48 -95
- package/dist/features/admin/schemas/firestore.js +15 -151
- package/dist/features/admin/schemas/nav-item-form.js +9 -2
- package/dist/features/admin/server.d.ts +0 -4
- package/dist/features/admin/server.js +0 -2
- package/dist/features/admin/types/index.d.ts +0 -7
- package/dist/features/analytics/repository/page-views.repository.d.ts +14 -0
- package/dist/features/analytics/repository/page-views.repository.js +24 -0
- package/dist/features/auth/actions/index.d.ts +0 -1
- package/dist/features/auth/actions/index.js +0 -1
- package/dist/features/auth/actions/realtime-token-actions.js +1 -12
- package/dist/features/auth/auth-helpers.js +5 -7
- package/dist/features/auth/components/Guards.js +2 -1
- package/dist/features/auth/components/LoginForm.d.ts +0 -2
- package/dist/features/auth/components/LoginForm.js +1 -3
- package/dist/features/auth/components/RegisterForm.js +62 -19
- package/dist/features/auth/permissions/constants.d.ts +27 -1
- package/dist/features/auth/role-predicates.d.ts +75 -7
- package/dist/features/auth/role-predicates.js +28 -2
- package/dist/features/auth/schemas/firestore.d.ts +22 -0
- package/dist/features/auth/schemas/index.d.ts +1 -1
- package/dist/features/auth/schemas/index.js +44 -8
- package/dist/features/auth/types/index.d.ts +14 -1
- package/dist/features/blog/api/route.js +10 -2
- package/dist/features/blog/components/BlogIndexListing.js +1 -1
- package/dist/features/blog/hooks/useBlog.js +2 -2
- package/dist/features/blog/schemas/index.d.ts +4 -0
- package/dist/features/blog/schemas/index.js +2 -0
- package/dist/features/blog/types/index.d.ts +1 -1
- package/dist/features/catalogue/components/CatalogueItemEditorView.d.ts +22 -0
- package/dist/features/catalogue/components/CatalogueItemEditorView.js +112 -52
- package/dist/features/catalogue/schemas/validation.d.ts +4 -4
- package/dist/features/catalogue/schemas/validation.js +47 -10
- package/dist/features/categories/schemas/bundle-form.d.ts +142 -0
- package/dist/features/categories/schemas/bundle-form.js +149 -0
- package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +5 -4
- package/dist/features/classified/components/ClassifiedDetailPageView.js +37 -16
- package/dist/features/consultation/components/ConsultationForm.js +1 -1
- package/dist/features/consultation/schemas/index.js +34 -10
- package/dist/features/corporate/schemas/index.js +36 -15
- package/dist/features/filters/FilterPanel.js +3 -3
- package/dist/features/filters/RangeFilter.d.ts +10 -0
- package/dist/features/filters/RangeFilter.js +41 -4
- package/dist/features/homepage/components/MarketplaceHomepageView.js +24 -5
- package/dist/features/homepage/hooks/useBlogArticles.js +1 -1
- package/dist/features/layout/BottomActions.js +84 -11
- package/dist/features/layout/BottomActionsContext.d.ts +1 -6
- package/dist/features/layout/BottomActionsContext.js +1 -1
- package/dist/features/layout/hooks/useBottomActions.js +2 -2
- package/dist/features/layout/hooks/useFormBottomActions.d.ts +12 -1
- package/dist/features/layout/hooks/useFormBottomActions.js +12 -6
- package/dist/features/lottery/schemas/config-write.d.ts +9 -5
- package/dist/features/lottery/schemas/config-write.js +69 -9
- package/dist/features/orders/schemas/buyer-forms.d.ts +6 -3
- package/dist/features/orders/schemas/buyer-forms.js +31 -3
- package/dist/features/orders/schemas/index.d.ts +2 -2
- package/dist/features/products/components/GroupSettingsPanel.js +3 -1
- package/dist/features/products/components/MakeOfferButton.d.ts +13 -2
- package/dist/features/products/components/MakeOfferButton.js +33 -11
- package/dist/features/products/components/ProductDetailActions.js +0 -1
- package/dist/features/products/components/ProductDetailPageView.d.ts +7 -3
- package/dist/features/products/components/ProductDetailPageView.js +8 -5
- package/dist/features/products/constants/action-defs.d.ts +1 -2
- package/dist/features/products/constants/action-defs.js +40 -43
- package/dist/features/products/repository/products.repository.d.ts +5 -1
- package/dist/features/products/repository/products.repository.js +23 -1
- package/dist/features/products/schemas/firestore.d.ts +7 -3
- package/dist/features/products/schemas/product-features.validators.js +3 -0
- package/dist/features/promotions/components/CouponCard.js +8 -7
- package/dist/features/scams/schemas/firestore.d.ts +15 -1
- package/dist/features/scams/schemas/report-form.d.ts +5 -5
- package/dist/features/scams/schemas/report-form.js +18 -3
- package/dist/features/search/action-index/derive.d.ts +49 -0
- package/dist/features/search/action-index/derive.js +121 -0
- package/dist/features/search/action-index/repository.d.ts +42 -0
- package/dist/features/search/action-index/repository.js +100 -0
- package/dist/features/search/action-index/settings-entries.d.ts +41 -0
- package/dist/features/search/action-index/settings-entries.js +268 -0
- package/dist/features/search/action-index/types.d.ts +81 -0
- package/dist/features/search/action-index/types.js +102 -0
- package/dist/features/search/action-index/validate-entry.d.ts +34 -0
- package/dist/features/search/action-index/validate-entry.js +114 -0
- package/dist/features/search/hooks/useNavSuggestions.d.ts +5 -1
- package/dist/features/search/hooks/useNavSuggestions.js +23 -3
- package/dist/features/search/repository/search.repository.js +3 -1
- package/dist/features/seller/actions/offer-actions.js +43 -24
- package/dist/features/seller/actions/seller-actions.js +29 -5
- package/dist/features/seller/components/CategoryChipPicker.d.ts +9 -0
- package/dist/features/seller/components/CategoryChipPicker.js +12 -0
- package/dist/features/seller/components/SellerAddressesView.js +5 -1
- package/dist/features/seller/components/SellerAnalyticsAlertsView.js +83 -43
- package/dist/features/seller/components/SellerArtView.d.ts +14 -7
- package/dist/features/seller/components/SellerArtView.js +4 -119
- package/dist/features/seller/components/SellerClassifiedView.d.ts +14 -7
- package/dist/features/seller/components/SellerClassifiedView.js +4 -124
- package/dist/features/seller/components/SellerCouponEditorView.d.ts +22 -1
- package/dist/features/seller/components/SellerCouponEditorView.js +91 -45
- package/dist/features/seller/components/SellerDigitalCodesView.d.ts +14 -7
- package/dist/features/seller/components/SellerDigitalCodesView.js +4 -126
- package/dist/features/seller/components/SellerListingTypeView.d.ts +66 -0
- package/dist/features/seller/components/SellerListingTypeView.js +277 -0
- package/dist/features/seller/components/SellerLiveView.d.ts +14 -7
- package/dist/features/seller/components/SellerLiveView.js +4 -126
- package/dist/features/seller/components/SellerSidebar.d.ts +3 -6
- package/dist/features/seller/components/SellerStickersView.d.ts +14 -7
- package/dist/features/seller/components/SellerStickersView.js +4 -119
- package/dist/features/seller/components/SellerSupportView.d.ts +31 -0
- package/dist/features/seller/components/SellerSupportView.js +100 -0
- package/dist/features/seller/components/index.d.ts +4 -8
- package/dist/features/seller/components/index.js +2 -4
- package/dist/features/seller/index.d.ts +0 -1
- package/dist/features/seller/index.js +0 -1
- package/dist/features/seller/schemas/coupon-form.d.ts +214 -0
- package/dist/features/seller/schemas/coupon-form.js +155 -23
- package/dist/features/seller/schemas/offer-forms.d.ts +16 -7
- package/dist/features/seller/schemas/offer-forms.js +28 -12
- package/dist/features/shell/FormShell.js +2 -2
- package/dist/features/shell/QuickFormDrawer.js +2 -2
- package/dist/features/shell/SectionForm.d.ts +19 -1
- package/dist/features/shell/SectionForm.js +104 -17
- package/dist/features/shell/build-sections.d.ts +23 -0
- package/dist/features/shell/build-sections.js +106 -8
- package/dist/features/shell/field-ui-meta.d.ts +44 -0
- package/dist/features/shell/field-ui-meta.js +14 -7
- package/dist/features/shell/form-sections.d.ts +46 -0
- package/dist/features/shell/form-sections.js +114 -0
- package/dist/features/shipments/components/AdminShipmentEditorView.js +87 -64
- package/dist/features/shipments/schemas/validation.d.ts +2 -2
- package/dist/features/shipments/schemas/validation.js +44 -13
- package/dist/features/store-extensions/schemas/custom-role-form.js +6 -2
- package/dist/features/store-extensions/schemas/listing-template-form.d.ts +7 -7
- package/dist/features/store-extensions/schemas/payout-method-form.js +14 -0
- package/dist/features/stores/actions/store-query-actions.js +3 -2
- package/dist/features/stores/api/[storeSlug]/auctions/route.js +3 -1
- package/dist/features/stores/api/[storeSlug]/products/route.js +3 -1
- package/dist/features/support/repository/support.repository.d.ts +21 -0
- package/dist/features/support/repository/support.repository.js +63 -0
- package/dist/features/support/schemas/firestore.d.ts +27 -2
- package/dist/features/support/schemas/firestore.js +2 -0
- package/dist/features/support/schemas/ticket-create-form.js +7 -0
- package/dist/features/tester/schemas/checklist-item-form.d.ts +43 -0
- package/dist/features/tester/schemas/checklist-item-form.js +109 -0
- package/dist/features/tester/seed-data/blog-tester-seed-data.js +2 -2
- package/dist/features/tester/seed-data/categories-tester-seed-data.js +2 -2
- package/dist/features/tester/seed-data/events-tester-seed-data.js +5 -5
- package/dist/features/tester/seed-data/orders-tester-seed-data.js +2 -2
- package/dist/features/tester/seed-data/products-tester-seed-data.js +48 -49
- package/dist/features/tester/seed-data/stores-tester-seed-data.js +3 -3
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +275 -29
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +48 -12
- package/dist/http/api-handler.js +2 -1
- package/dist/index.d.ts +24 -103
- package/dist/index.js +33 -141
- package/dist/jobs.d.ts +1 -1
- package/dist/jobs.js +1 -1
- package/dist/monitoring/browser.d.ts +0 -2
- package/dist/monitoring/browser.js +12 -1
- package/dist/monitoring/index.d.ts +0 -2
- package/dist/monitoring/index.js +0 -1
- package/dist/next/api/routeHandler.js +6 -3
- package/dist/next/index.d.ts +1 -2
- package/dist/next/index.js +0 -1
- package/dist/next/middleware/index.d.ts +0 -2
- package/dist/next/middleware/index.js +0 -1
- package/dist/next/routing/route-map.d.ts +8 -7
- package/dist/next/routing/route-map.js +10 -3
- package/dist/providers/db-firebase/admin.js +15 -1
- package/dist/providers/db-firebase/sieve.d.ts +22 -0
- package/dist/react/hooks/useListingTypeFlags.d.ts +1 -1
- package/dist/react/hooks/useListingTypeFlags.js +1 -1
- package/dist/react/hooks/usePendingFilters.js +5 -3
- package/dist/react/hooks/usePendingTable.js +15 -3
- package/dist/repositories/index.d.ts +0 -1
- package/dist/repositories/index.js +0 -1
- package/dist/schemas/registry.d.ts +197 -232
- package/dist/schemas/registry.js +5 -6
- package/dist/schemas/webhooks/razorpay.d.ts +50 -50
- package/dist/security/authorization.d.ts +9 -0
- package/dist/security/authorization.js +16 -2
- package/dist/security/browser.d.ts +1 -3
- package/dist/security/browser.js +5 -2
- package/dist/security/index.d.ts +1 -3
- package/dist/security/index.js +19 -2
- package/dist/security/pii-encrypt.js +16 -0
- package/dist/security/pii-schemas.d.ts +0 -14
- package/dist/security/pii-schemas.js +7 -15
- package/dist/seed/_helpers/category-forest.js +2 -2
- package/dist/seed/_helpers/media.d.ts +19 -0
- package/dist/seed/_helpers/media.js +75 -0
- package/dist/seed/blog-posts-seed-data.js +17 -17
- package/dist/seed/carousel-slides-seed-data.js +7 -7
- package/dist/seed/cart-seed-data.js +13 -13
- package/dist/seed/categories-seed-data.js +10 -10
- package/dist/seed/events-seed-data.js +24 -24
- package/dist/seed/factories/product.factory.js +4 -4
- package/dist/seed/factories/store.factory.js +3 -3
- package/dist/seed/factories/user.factory.js +2 -2
- package/dist/seed/grouped-listings-seed-data.js +11 -11
- package/dist/seed/homepage-sections-seed-data.js +2 -2
- package/dist/seed/index.d.ts +0 -1
- package/dist/seed/index.js +0 -1
- package/dist/seed/manifest.d.ts +1 -1
- package/dist/seed/manifest.js +0 -5
- package/dist/seed/notifications-seed-data.js +20 -1
- package/dist/seed/orders-seed-data.js +2 -2
- package/dist/seed/products-art-seed-data.js +16 -16
- package/dist/seed/products-auctions-seed-data.js +34 -34
- package/dist/seed/products-classifieds-seed-data.js +35 -37
- package/dist/seed/products-digital-codes-seed-data.js +20 -20
- package/dist/seed/products-live-items-seed-data.js +11 -11
- package/dist/seed/products-preorders-seed-data.js +13 -13
- package/dist/seed/products-prize-draws-seed-data.js +43 -43
- package/dist/seed/products-standard-seed-data.js +54 -54
- package/dist/seed/products-stickers-seed-data.js +15 -15
- package/dist/seed/reviews-seed-data.js +4 -4
- package/dist/seed/scammers-seed-data.js +3 -3
- package/dist/seed/site-settings-seed-data.js +11 -24
- package/dist/seed/store-extensions-seed-data.js +10 -10
- package/dist/seed/stores-seed-data.js +11 -11
- package/dist/seed/support-tickets-seed-data.d.ts +14 -0
- package/dist/seed/support-tickets-seed-data.js +20 -1
- package/dist/seed/users-seed-data.js +20 -20
- package/dist/server-entry.d.ts +0 -1
- package/dist/server-entry.js +0 -1
- package/dist/server.d.ts +9 -6
- package/dist/server.js +7 -13
- package/dist/styles.css +248 -68
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +2 -2
- package/dist/tokens/themes/default-light.js +2 -2
- package/dist/tokens/tokens.css +24 -4
- package/dist/ui/components/ActionRow.d.ts +50 -0
- package/dist/ui/components/ActionRow.js +53 -0
- package/dist/ui/components/ActionRow.style.css +145 -0
- package/dist/ui/components/Drawer.d.ts +10 -0
- package/dist/ui/components/Drawer.js +2 -1
- package/dist/ui/components/FilterDrawer.js +4 -1
- package/dist/ui/components/FilterDrawer.style.css +6 -12
- package/dist/ui/components/FormActionBar.js +14 -1
- package/dist/ui/components/FormActionBar.style.css +12 -11
- package/dist/ui/components/ListingLayout.js +8 -1
- package/dist/ui/components/ListingLayout.style.css +6 -13
- package/dist/ui/components/Modal.d.ts +15 -1
- package/dist/ui/components/Modal.js +17 -3
- package/dist/ui/components/QuickCreateModal.js +2 -2
- package/dist/ui/components/QuickCreateModal.style.css +78 -84
- package/dist/ui/components/RecordDetailModal.js +2 -2
- package/dist/ui/components/SideDrawer.d.ts +8 -0
- package/dist/ui/components/SideDrawer.js +2 -1
- package/dist/ui/components/SideDrawer.style.css +6 -3
- package/dist/ui/components/SideModal.d.ts +11 -1
- package/dist/ui/components/SideModal.js +3 -2
- package/dist/ui/components/SideModal.style.css +14 -0
- package/dist/ui/components/Typography.style.css +33 -24
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/forms/FormShell.style.css +260 -311
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1 -0
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +1 -1
- package/dist/validation/schemas.d.ts +0 -19
- package/dist/validation/schemas.js +8 -19
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +3 -6
|
@@ -14,12 +14,10 @@ import { storeRepository } from "../../stores/repository/store.repository";
|
|
|
14
14
|
import { cartRepository } from "../../cart/repository/cart.repository";
|
|
15
15
|
import { maskOfferForSeller } from "../../../security";
|
|
16
16
|
import { ERROR_MESSAGES, AuthorizationError, ValidationError, NotFoundError, OFFER_ERROR_CODES, } from "../../../errors";
|
|
17
|
-
import { siteSettingsRepository } from "../../admin/repository/site-settings.repository";
|
|
18
|
-
import { safeRead } from "../../../errors/safe-read";
|
|
19
17
|
import { canMakeOffer } from "../../../_internal/shared/listing-types/capabilities";
|
|
20
18
|
import { normalizeListingType } from "../../products/utils/listing-type";
|
|
21
19
|
import { OfferStatusValues } from "../schemas";
|
|
22
|
-
import { DEFAULT_MIN_OFFER_PERCENT,
|
|
20
|
+
import { DEFAULT_MIN_OFFER_PERCENT, offerIsOnlyPurchasePath, offersEnabledFor, resolveOfferBounds, } from "../../../_internal/shared/features/offers/config";
|
|
23
21
|
/**
|
|
24
22
|
* How long an accepted offer stays claimable at its locked price. Shared by the
|
|
25
23
|
* seller-accept path, the buyer-accepts-counter path, and the expiry sweep so
|
|
@@ -32,38 +30,59 @@ const ERR_NOT_AUTHORISED = "Not authorized";
|
|
|
32
30
|
export async function makeOffer(userId, userEmail, input) {
|
|
33
31
|
const { productId, offerAmount, buyerNote } = input;
|
|
34
32
|
/**
|
|
35
|
-
*
|
|
36
|
-
* `
|
|
37
|
-
*
|
|
38
|
-
*
|
|
33
|
+
* Two independent gates, checked in widening-to-narrowing order: the listing
|
|
34
|
+
* type's `canMakeOffer` capability, then the seller's own `allowOffers`
|
|
35
|
+
* opt-in.
|
|
36
|
+
*
|
|
37
|
+
* There was a third — the site-wide `featureFlags.offers` kill switch — which
|
|
38
|
+
* cost a Firestore singleton read on every offer attempt. It went with the
|
|
39
|
+
* rest of that group on 2026-08-29. The two that remain are the ones somebody
|
|
40
|
+
* actually sets: a per-type capability and a per-listing choice by the seller
|
|
41
|
+
* who owns the item.
|
|
42
|
+
*
|
|
43
|
+
* Both now go through `offersEnabledFor` / `resolveOfferBounds`, which the
|
|
44
|
+
* buyer's form reads too — the whole point of moving the rule into the shared
|
|
45
|
+
* config. A second copy here is how the form came to advertise a 50% floor
|
|
46
|
+
* this function then rejected (see the config's own header).
|
|
39
47
|
*/
|
|
40
|
-
// Fails OPEN — a settings read that dies must not block offers site-wide. But
|
|
41
|
-
// `null` here is indistinguishable from "the flag is on", so it is recorded.
|
|
42
|
-
const settings = await safeRead(() => siteSettingsRepository.getSingleton(), {
|
|
43
|
-
route: "offers.makeOffer", key: "makeOffer.siteSettings", fallback: null,
|
|
44
|
-
});
|
|
45
|
-
if (settings?.featureFlags?.offers === false) {
|
|
46
|
-
throw new ValidationError(ERROR_MESSAGES.OFFER.DISABLED, {
|
|
47
|
-
code: OFFER_ERROR_CODES.DISABLED,
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
48
|
const product = await productRepository.findById(productId);
|
|
51
49
|
if (!product)
|
|
52
50
|
throw new NotFoundError(ERROR_MESSAGES.PRODUCT.NOT_FOUND);
|
|
51
|
+
const listingType = normalizeListingType(product);
|
|
53
52
|
// Some listing types cannot be negotiated at all — an auction already has
|
|
54
53
|
// bidding, a prize-draw sells fixed-price entries. This was never checked, so
|
|
55
54
|
// an offer could be (and in seed data was) attached to an auction, producing
|
|
56
55
|
// a cart line that claims `listingType: "standard"` in the offer lane.
|
|
57
|
-
if (!canMakeOffer(
|
|
56
|
+
if (!canMakeOffer(listingType)) {
|
|
58
57
|
throw new ValidationError("Offers aren't available for this kind of listing.");
|
|
59
58
|
}
|
|
60
|
-
if (!product.allowOffers)
|
|
59
|
+
if (!offersEnabledFor(listingType, product.allowOffers))
|
|
61
60
|
throw new ValidationError("This product does not accept offers.");
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
const bounds = resolveOfferBounds({
|
|
62
|
+
listingType,
|
|
63
|
+
listedPrice: product.price,
|
|
64
|
+
minOfferPercent: product.minOfferPercent,
|
|
65
|
+
allowOffers: product.allowOffers,
|
|
66
|
+
});
|
|
67
|
+
if (bounds.isBuyRequest) {
|
|
68
|
+
// No cart on this type and the seller has not opted into haggling, so the
|
|
69
|
+
// asking price is the only legal amount. Naming that plainly beats a
|
|
70
|
+
// "minimum offer is ₹X" message where X happens to equal the price.
|
|
71
|
+
if (offerAmount !== bounds.max)
|
|
72
|
+
throw new ValidationError(`This seller is not taking lower offers — send a request to buy at ₹${bounds.max}.`);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
if (offerAmount < bounds.min)
|
|
76
|
+
throw new ValidationError(`Minimum offer is ₹${bounds.min} (${product.minOfferPercent ?? DEFAULT_MIN_OFFER_PERCENT}% of listing price).`);
|
|
77
|
+
if (offerAmount > bounds.max)
|
|
78
|
+
throw new ValidationError(
|
|
79
|
+
// Deliberately NOT "use Add to Cart instead" unconditionally: on a
|
|
80
|
+
// listing whose only purchase path is an offer there is no cart button,
|
|
81
|
+
// so that advice named a control the page does not have.
|
|
82
|
+
offerIsOnlyPurchasePath(listingType)
|
|
83
|
+
? `Your offer cannot exceed the asking price of ₹${product.price}.`
|
|
84
|
+
: "Your offer must be below the listed price. Use Add to Cart instead.");
|
|
85
|
+
}
|
|
67
86
|
const offerCount = await offerRepository.countByBuyerAndProduct(userId, productId, product.updatedAt);
|
|
68
87
|
if (offerCount >= 3)
|
|
69
88
|
throw new ValidationError(ERROR_MESSAGES.OFFER.LIMIT_REACHED);
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* (src/actions/seller.actions.ts) alongside the other seller server actions.
|
|
10
10
|
*/
|
|
11
11
|
import { serverLogger } from "../../../monitoring";
|
|
12
|
-
import { isAdminUser,
|
|
12
|
+
import { isAdminUser, isStrictSellerUser, isTesterUser } from "../../auth/role-predicates";
|
|
13
13
|
import { ApiError, AuthorizationError, NotFoundError, ValidationError, } from "../../../errors";
|
|
14
14
|
import { userRepository } from "../../auth/repository/user.repository";
|
|
15
15
|
import { storeRepository } from "../../stores/repository/store.repository";
|
|
@@ -53,16 +53,40 @@ function maskAccountNumber(accountNumber) {
|
|
|
53
53
|
// --- Become Seller ------------------------------------------------------------
|
|
54
54
|
export async function becomeSeller(userId) {
|
|
55
55
|
const profile = await userRepository.findById(userId);
|
|
56
|
-
|
|
56
|
+
const isTester = isTesterUser(profile);
|
|
57
|
+
/*
|
|
58
|
+
* 🛑 `isStrictSellerUser`, not `isSellerUser`.
|
|
59
|
+
*
|
|
60
|
+
* `isSellerUser` now answers true for the `tester` role — testers own real
|
|
61
|
+
* stores and must clear every seller gate. But that makes it the WRONG test
|
|
62
|
+
* here: a brand-new tester has role `tester` from the moment they are
|
|
63
|
+
* flagged, so an early return keyed on it would send them straight back with
|
|
64
|
+
* `storeStatus: "pending"` and they would never reach the auto-approve below.
|
|
65
|
+
* The tester sandbox depends on that approval.
|
|
66
|
+
*
|
|
67
|
+
* A tester who HAS already onboarded is caught by the `storeStatus` clause,
|
|
68
|
+
* so this stays idempotent for them.
|
|
69
|
+
*/
|
|
70
|
+
const alreadyOnboarded = profile &&
|
|
71
|
+
(isStrictSellerUser(profile) ||
|
|
72
|
+
isAdminUser(profile) ||
|
|
73
|
+
(isTester && Boolean(profile.storeStatus)));
|
|
74
|
+
if (alreadyOnboarded) {
|
|
57
75
|
return {
|
|
58
76
|
alreadySeller: true,
|
|
59
77
|
storeStatus: profile.storeStatus ??
|
|
60
78
|
"pending",
|
|
61
79
|
};
|
|
62
80
|
}
|
|
63
|
-
const storeStatus =
|
|
81
|
+
const storeStatus = isTester ? "approved" : "pending";
|
|
64
82
|
await userRepository.update(userId, {
|
|
65
|
-
|
|
83
|
+
// 🛑 A tester must NOT be demoted to `seller` here. `tester` is a peer of
|
|
84
|
+
// `seller` in the hierarchy and already clears every seller gate
|
|
85
|
+
// (`isSellerUser` returns true for it), so overwriting the role would
|
|
86
|
+
// silently strip their tester identity — and with it the Tester Hub and
|
|
87
|
+
// the test-data visibility their whole programme depends on — the first
|
|
88
|
+
// time they opened a store.
|
|
89
|
+
...(isTester ? {} : { role: "seller" }),
|
|
66
90
|
storeStatus,
|
|
67
91
|
});
|
|
68
92
|
serverLogger.info("becomeSeller: application submitted", { userId, storeStatus });
|
|
@@ -83,7 +107,7 @@ export async function createStore(userId, userName, input) {
|
|
|
83
107
|
storeSlug = `${baseSlug.slice(0, 80 - suffix.length)}${suffix}`;
|
|
84
108
|
}
|
|
85
109
|
const profile = await userRepository.findById(userId);
|
|
86
|
-
const isTester = profile
|
|
110
|
+
const isTester = isTesterUser(profile);
|
|
87
111
|
const store = await storeRepository.create({
|
|
88
112
|
storeSlug,
|
|
89
113
|
ownerId: userId,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface CategoryChipPickerProps {
|
|
3
|
+
selected: string[];
|
|
4
|
+
onSelectedChange: (next: string[]) => void;
|
|
5
|
+
/** Copy under the control. Defaults to the coupon wording. */
|
|
6
|
+
emptyHint?: string;
|
|
7
|
+
allowCreate?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function CategoryChipPicker({ selected, onSelectedChange, emptyHint, allowCreate, }: CategoryChipPickerProps): React.JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { IconButton, Row, Span, Stack, Text } from "../../../ui";
|
|
4
|
+
import { CategoryInlineSelect } from "./CategoryInlineSelect";
|
|
5
|
+
export function CategoryChipPicker({ selected, onSelectedChange, emptyHint = "Leave empty to apply to every category.", allowCreate = false, }) {
|
|
6
|
+
const add = (id) => {
|
|
7
|
+
if (!id || selected.includes(id))
|
|
8
|
+
return;
|
|
9
|
+
onSelectedChange([...selected, id]);
|
|
10
|
+
};
|
|
11
|
+
return (_jsxs(Stack, { gap: "xs", children: [_jsx(CategoryInlineSelect, { value: "", onChange: add, allowCreate: allowCreate, placeholder: "Add a category\u2026" }), selected.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", padding: "t-2xs", children: selected.map((cid) => (_jsxs(Span, { layout: "inline-flex", gap: "xs", border: "strong", padding: "pill-sm", rounded: "full", surface: "muted", color: "primary", size: "xs", children: [cid, _jsx(IconButton, { "aria-label": `Remove ${cid}`, variant: "ghost", size: "sm", onClick: () => onSelectedChange(selected.filter((c) => c !== cid)), icon: "\u00D7" })] }, cid))) })), _jsx(Text, { size: "xs", color: "muted", children: emptyHint })] }));
|
|
12
|
+
}
|
|
@@ -146,5 +146,9 @@ export function SellerAddressesView({ apiBase = SELLER_ENDPOINTS.STORE_ADDRESSES
|
|
|
146
146
|
return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(StickyToolbar, { offset: "header", tone: "default", border: true, padding: "md", children: _jsxs(Row, { justify: "between", children: [_jsxs(Stack, { gap: "none", children: [_jsx(Heading, { level: 2, size: "base", weight: "semibold", color: "primary", children: "Pickup Addresses" }), _jsx(Text, { size: "xs", color: "muted", className: "mt-0.5", children: "Manage your store's pickup and return locations" })] }), _jsxs(Row, { gap: "sm", align: "center", children: [_jsx(TextLink, { href: String(ROUTES.STORE.ADDRESSES_NEW), children: "Open full page \u2192" }), _jsxs(Button, { gap: "sm", size: "sm", onClick: openAdd, children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx(Span, { children: "Add Address" })] })] })] }) }), _jsxs(Div, { paddingX: "x-md-lg", className: "max-w-2xl", padding: "y-lg", children: [errorMessage && (_jsx(Div, { textSize: "sm", className: "mb-4 border border-error/20", color: "error", surface: "danger-surface", padding: "inline", rounded: "xl", children: errorMessage })), isLoading ? (_jsx(Row, { justify: "center", padding: "y-4xl", children: _jsx(Div, { className: "h-6 w-6 animate-spin border-2 border-[var(--appkit-color-primary)] border-t-transparent", rounded: "full" }) })) : addresses.length === 0 ? (_jsxs(Stack, { border: "default", className: "border-2 border-dashed", padding: "y-4xl", align: "center", gap: "3", rounded: "xl", children: [_jsx(MapPin, { className: "h-8 w-8 text-[var(--appkit-color-text-muted)]" }), _jsx(Text, { size: "sm", color: "muted", children: "No pickup addresses yet" }), _jsx(Button, { size: "sm", variant: "outline", onClick: openAdd, children: "Add your first address" })] })) : (_jsxs(_Fragment, { children: [_jsxs(Row, { justify: "end", className: "mb-2", children: [_jsx(Button, { size: "sm", variant: listView === "table" ? "primary" : "ghost", onClick: () => setListView("table"), children: "Table" }), _jsx(Button, { size: "sm", variant: listView === "cards" ? "primary" : "ghost", onClick: () => setListView("cards"), children: "Cards" })] }), listView === "cards" ? (_jsx(Grid, { gap: "sm", 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(Div, { className: `${__O.xAuto}`, rounded: "lg", border: "default", children: _jsxs(Table, { size: "sm", children: [_jsx(Thead, { surface: "muted", children: _jsxs(Tr, { children: [_jsx(Th, { className: "text-left", padding: "sm", weight: "semibold", children: "Label" }), _jsx(Th, { className: "text-left", padding: "sm", weight: "semibold", children: "Name" }), _jsx(Th, { className: "text-left", padding: "sm", weight: "semibold", children: "City" }), _jsx(Th, { className: "text-left", padding: "sm", weight: "semibold", children: "Phone" }), _jsx(Th, { className: "text-right", padding: "sm", weight: "semibold", children: "Actions" })] }) }), _jsx(Tbody, { children: addresses.map((addr) => {
|
|
147
147
|
const isBanned = addr.banStatus === "banned";
|
|
148
148
|
return (_jsxs(Tr, { className: `border-t border-[var(--appkit-color-border)] ${deletingId === addr.id ? "opacity-50" : ""}`, children: [_jsx(Td, { padding: "sm", children: _jsxs(Row, { gap: "xs", align: "center", children: [_jsx(Span, { children: addr.label }), isBanned && _jsx(Badge, { variant: "danger", size: "sm", children: "Banned" })] }) }), _jsx(Td, { padding: "sm", children: addr.fullName }), _jsxs(Td, { padding: "sm", children: [addr.city, ", ", addr.state] }), _jsx(Td, { className: "tabular-nums", padding: "sm", children: addr.phone }), _jsx(Td, { className: "text-right", padding: "sm", children: isBanned ? (_jsx(Span, { size: "xs", color: "muted", title: "Contact support to resolve address ban", children: "Contact support" })) : (_jsxs(Row, { justify: "end", gap: "xs", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: () => openEdit(addr), children: ROW_ACTION_META[ROW_ACTION_ID.EDIT].label }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => handleDelete(addr), children: ROW_ACTION_META[ROW_ACTION_ID.DELETE].label })] })) })] }, addr.id));
|
|
149
|
-
}) })] }) }))] }))] }), _jsx(SideDrawer, { isOpen: drawerOpen, onClose: closeDrawer, title: editingId ? "Edit Address" : "Add Address", footer:
|
|
149
|
+
}) })] }) }))] }))] }), _jsx(SideDrawer, { isOpen: drawerOpen, onClose: closeDrawer, title: editingId ? "Edit Address" : "Add Address", footer:
|
|
150
|
+
/* Bare buttons — the SideDrawer footer slot supplies the ActionRow.
|
|
151
|
+
The `flex-1` these carried would have beaten its sizing under
|
|
152
|
+
`important: true`. */
|
|
153
|
+
_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: closeDrawer, children: "Cancel" }), _jsx(Button, { onClick: handleSave, disabled: saving, children: saving ? "Saving…" : editingId ? "Save Changes" : "Add Address" })] }), children: _jsxs(Stack, { gap: "md", padding: "y-2xs", children: [saveError && (_jsx(Div, { textSize: "sm", className: "border border-error/20", color: "error", surface: "danger-surface", padding: "inlineSm", rounded: "lg", children: saveError })), _jsx(FieldInput, { name: "label", label: "Label *", hint: "e.g. Warehouse, Shop, Home", type: "text", value: draft.label, onChange: setField("label"), placeholder: "Warehouse", maxLength: 60 }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(FieldInput, { name: "fullName", label: "Full Name *", type: "text", value: draft.fullName, onChange: setField("fullName"), placeholder: "Ravi Kumar", maxLength: 100 }), _jsx(FieldInput, { name: "phone", label: "Phone *", type: "tel", value: draft.phone, onChange: setField("phone"), placeholder: "+91 98765 43210", maxLength: 20 })] }), _jsx(FieldInput, { name: "addressLine1", label: "Address Line 1 *", type: "text", value: draft.addressLine1, onChange: setField("addressLine1"), placeholder: "Shop 12, Main Market", maxLength: 200 }), _jsx(FieldInput, { name: "addressLine2", label: "Address Line 2", type: "text", value: draft.addressLine2, onChange: setField("addressLine2"), placeholder: "Building / Floor (optional)", maxLength: 200 }), _jsx(FieldInput, { name: "landmark", label: "Landmark", type: "text", value: draft.landmark, onChange: setField("landmark"), placeholder: "Near metro station (optional)", maxLength: 100 }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(FieldInput, { name: "city", label: "City *", type: "text", value: draft.city, onChange: setField("city"), placeholder: "Mumbai", maxLength: 100 }), _jsx(FieldInput, { name: "state", label: "State *", type: "text", value: draft.state, onChange: setField("state"), placeholder: "Maharashtra", maxLength: 100 })] }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(FieldInput, { name: "postalCode", label: "Postal Code *", type: "text", value: draft.postalCode, onChange: setField("postalCode"), placeholder: "400001", maxLength: 10 }), _jsx(FieldInput, { name: "country", label: "Country *", type: "text", value: draft.country, onChange: setField("country"), placeholder: "India", maxLength: 60 })] }), _jsx(FieldCheckbox, { name: "isDefault", label: "Set as default pickup address", checked: draft.isDefault, onChange: (c) => set("isDefault", c) })] }) }), deleteTargetAddr && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Address", message: `Delete address "${deleteTargetAddr.label}"? This cannot be undone.`, onConfirm: () => { deleteById(deleteTargetAddr.id); setDeleteTargetAddr(null); }, onClose: () => setDeleteTargetAddr(null), isDeleting: deletingId === deleteTargetAddr.id }))] }));
|
|
150
154
|
}
|
|
@@ -1,27 +1,44 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
4
|
-
import { useState, useCallback } from "react";
|
|
4
|
+
import React, { useState, useCallback } from "react";
|
|
5
5
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
6
|
-
import { Alert, Badge, Button, Div,
|
|
6
|
+
import { Alert, Badge, Button, Div, Heading, Row, Section, Stack, Text, Toggle, useToast } from "../../../ui";
|
|
7
7
|
import { apiClient } from "../../../http";
|
|
8
8
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
|
-
import { analyticsAlertCreateSchema } from "../../store-extensions/schemas/analytics-forms";
|
|
9
|
+
import { analyticsAlertCreateSchema, ANALYTICS_ALERT_OPERATORS, } from "../../store-extensions/schemas/analytics-forms";
|
|
10
10
|
import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary";
|
|
11
|
-
import {
|
|
11
|
+
import { FormShellContext, useFormShellState } from "../../../ui/forms/FormShell";
|
|
12
|
+
import { applyZodIssues } from "../../../ui/forms/apply-zod-issues";
|
|
13
|
+
import { buildSectionsFromSchema, visibleValues } from "../../shell/build-sections";
|
|
14
|
+
import { SectionForm, useSectionFormNav } from "../../shell/SectionForm";
|
|
15
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
12
16
|
const __P = {
|
|
13
17
|
p5: "p-[var(--appkit-space-5)]",
|
|
14
18
|
};
|
|
15
19
|
// ---------------------------------------------------------------------------
|
|
16
20
|
// Config
|
|
17
21
|
// ---------------------------------------------------------------------------
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Operators, DERIVED from the schema's own list.
|
|
24
|
+
*
|
|
25
|
+
* The hand-written array had five of the six — `!=` was missing, so "not equal
|
|
26
|
+
* to" could never be chosen although `ALERT_OPERATOR_MAP` declares it and the
|
|
27
|
+
* route accepts it. That map is a `Record<AlertOperator, true>` precisely so
|
|
28
|
+
* the union cannot drift; the drift moved into the UI copy instead.
|
|
29
|
+
*/
|
|
30
|
+
const OPERATOR_LABELS = {
|
|
31
|
+
">": "Greater than (>)",
|
|
32
|
+
"<": "Less than (<)",
|
|
33
|
+
">=": "At least (≥)",
|
|
34
|
+
"<=": "At most (≤)",
|
|
35
|
+
"==": "Equals (==)",
|
|
36
|
+
"!=": "Not equal to (≠)",
|
|
37
|
+
};
|
|
38
|
+
const OPERATOR_OPTIONS = ANALYTICS_ALERT_OPERATORS.map((value) => ({
|
|
39
|
+
value,
|
|
40
|
+
label: OPERATOR_LABELS[value] ?? value,
|
|
41
|
+
}));
|
|
25
42
|
const METRIC_OPTIONS = [
|
|
26
43
|
{ value: "daily_revenue", label: "Daily Revenue (₹)" },
|
|
27
44
|
{ value: "daily_orders", label: "Daily Orders" },
|
|
@@ -57,7 +74,7 @@ function AlertCard({ alert, onToggle, onDelete, }) {
|
|
|
57
74
|
const metricLabel = METRIC_OPTIONS.find((m) => m.value === alert.metric)?.label ?? alert.metric;
|
|
58
75
|
const opLabel = OPERATOR_OPTIONS.find((o) => o.value === alert.operator)?.label ?? alert.operator;
|
|
59
76
|
const windowLabel = WINDOW_OPTIONS.find((w) => w.value === String(alert.windowHours))?.label ?? `${alert.windowHours}h`;
|
|
60
|
-
return (_jsxs(Row, { surface: "card", padding: "sm", align: "start", justify: "between", gap: "md", children: [_jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Row, { className: "mb-1", gap: "sm", wrap: true, children: [_jsx(Text, { size: "sm", weight: "medium", color: "primary", children: alert.label }), _jsx(Badge, { variant: alert.isActive ? "success" : "default", children: alert.isActive ? "Active" : "Paused" })] }), _jsxs(Text, { className: "mb-1", color: "muted", size: "xs", children: [metricLabel, " ", opLabel, " ", alert.threshold, " \u00B7 ", windowLabel] }), _jsx(Row, { gap: "xs", wrap: true, children: alert.notifyChannels.map((ch) => (_jsx(Badge, { variant: OPERATOR_BADGE[alert.operator] ?? "default", children: ch }, ch))) }), alert.lastTriggeredAt && (_jsxs(Text, { className: "mt-1", color: "faint", size: "xs", children: ["Last triggered: ", new Date(alert.lastTriggeredAt).toLocaleString("en-IN")] }))] }), _jsxs(Row, { className: "shrink-0", align: "center", gap: "sm", children: [_jsx(Toggle, { checked: alert.isActive, onChange: (v) => onToggle(alert.id, v), size: "sm" }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => onDelete(alert.id), className: "text-error hover:text-error"
|
|
77
|
+
return (_jsxs(Row, { surface: "card", padding: "sm", align: "start", justify: "between", gap: "md", children: [_jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Row, { className: "mb-1", gap: "sm", wrap: true, children: [_jsx(Text, { size: "sm", weight: "medium", color: "primary", children: alert.label }), _jsx(Badge, { variant: alert.isActive ? "success" : "default", children: alert.isActive ? "Active" : "Paused" })] }), _jsxs(Text, { className: "mb-1", color: "muted", size: "xs", children: [metricLabel, " ", opLabel, " ", alert.threshold, " \u00B7 ", windowLabel] }), _jsx(Row, { gap: "xs", wrap: true, children: alert.notifyChannels.map((ch) => (_jsx(Badge, { variant: OPERATOR_BADGE[alert.operator] ?? "default", children: ch }, ch))) }), alert.lastTriggeredAt && (_jsxs(Text, { className: "mt-1", color: "faint", size: "xs", children: ["Last triggered: ", new Date(alert.lastTriggeredAt).toLocaleString("en-IN")] }))] }), _jsxs(Row, { className: "shrink-0", align: "center", gap: "sm", children: [_jsx(Toggle, { checked: alert.isActive, onChange: (v) => onToggle(alert.id, v), size: "sm" }), _jsx(Button, { variant: "ghost", size: "sm", action: ACTIONS.STORE["delete-analytics-alert"], onClick: () => onDelete(alert.id), className: "text-error hover:text-error" })] })] }));
|
|
61
78
|
}
|
|
62
79
|
const EMPTY_DRAFT = {
|
|
63
80
|
label: "",
|
|
@@ -66,7 +83,17 @@ const EMPTY_DRAFT = {
|
|
|
66
83
|
threshold: "",
|
|
67
84
|
windowHours: "24",
|
|
68
85
|
notifyChannels: ["in-app"],
|
|
86
|
+
isActive: true,
|
|
69
87
|
};
|
|
88
|
+
/**
|
|
89
|
+
* The delivery-channel chips.
|
|
90
|
+
*
|
|
91
|
+
* Module level rather than an inline renderer — an inline one's handler sits
|
|
92
|
+
* six braces deep inside `useMemo`, which is DEEP_NESTING's whole subject.
|
|
93
|
+
*/
|
|
94
|
+
function ChannelChips({ selected, onToggle, }) {
|
|
95
|
+
return (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { color: "muted", size: "xs", weight: "medium", children: "Notify via" }), _jsx(Row, { gap: "sm", wrap: true, children: CHANNEL_OPTIONS.map((ch) => (_jsx(Button, { variant: selected.includes(ch.value) ? "primary" : "outline", type: "button", onClick: () => onToggle(ch.value), rounded: "full", paddingX: "sm", paddingY: "xs", textSize: "xs", children: ch.label }, ch.value))) })] }));
|
|
96
|
+
}
|
|
70
97
|
export function SellerAnalyticsAlertsView({ labels = {}, }) {
|
|
71
98
|
const queryClient = useQueryClient();
|
|
72
99
|
const { showToast } = useToast();
|
|
@@ -82,31 +109,7 @@ export function SellerAnalyticsAlertsView({ labels = {}, }) {
|
|
|
82
109
|
const alerts = data ?? [];
|
|
83
110
|
const createMutation = useApiMutation({
|
|
84
111
|
errorMessage: "Failed to create alert",
|
|
85
|
-
mutationFn: async () =>
|
|
86
|
-
/*
|
|
87
|
-
* Parsed against the SAME schema the route uses, before the request.
|
|
88
|
-
*
|
|
89
|
-
* This form used to hand-build its payload and included `scope: "seller"`
|
|
90
|
-
* — a field the route pins from the session and the schema does not
|
|
91
|
-
* declare. Once that schema became `.strict()`, every "Create Alert"
|
|
92
|
-
* became a 400, and nothing local could have caught it: the client had
|
|
93
|
-
* no schema to check against. Parsing here is the structural fix, not
|
|
94
|
-
* the deletion of one key.
|
|
95
|
-
*/
|
|
96
|
-
const parsed = analyticsAlertCreateSchema.safeParse({
|
|
97
|
-
label: draft.label,
|
|
98
|
-
metric: draft.metric,
|
|
99
|
-
operator: draft.operator,
|
|
100
|
-
threshold: draft.threshold,
|
|
101
|
-
windowHours: draft.windowHours,
|
|
102
|
-
notifyChannels: draft.notifyChannels,
|
|
103
|
-
isActive: true,
|
|
104
|
-
});
|
|
105
|
-
if (!parsed.success) {
|
|
106
|
-
throw new ValidationError(parsed.error.issues[0]?.message ?? "Invalid alert", parsed.error.issues);
|
|
107
|
-
}
|
|
108
|
-
return apiClient.post(SELLER_ENDPOINTS.ANALYTICS_ALERTS, parsed.data);
|
|
109
|
-
},
|
|
112
|
+
mutationFn: async (values) => apiClient.post(SELLER_ENDPOINTS.ANALYTICS_ALERTS, values),
|
|
110
113
|
onSuccess: () => {
|
|
111
114
|
showToast("Alert created", "success");
|
|
112
115
|
void queryClient.invalidateQueries({ queryKey: ["seller", "analytics-alerts"] });
|
|
@@ -137,10 +140,47 @@ export function SellerAnalyticsAlertsView({ labels = {}, }) {
|
|
|
137
140
|
: [...d.notifyChannels, ch],
|
|
138
141
|
}));
|
|
139
142
|
}, []);
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
const sections = React.useMemo(() => buildSectionsFromSchema(analyticsAlertCreateSchema, {
|
|
144
|
+
options: {
|
|
145
|
+
metric: METRIC_OPTIONS,
|
|
146
|
+
operator: OPERATOR_OPTIONS,
|
|
147
|
+
windowHours: WINDOW_OPTIONS,
|
|
148
|
+
},
|
|
149
|
+
renderers: {
|
|
150
|
+
notifyChannels: ({ values }) => (_jsx(ChannelChips, { selected: values.notifyChannels, onToggle: toggleChannel })),
|
|
151
|
+
},
|
|
152
|
+
}), [toggleChannel]);
|
|
153
|
+
const nav = useSectionFormNav(sections, draft, { scope: "store:analytics-alert" });
|
|
154
|
+
const { shellCtx, setFieldError, clearErrors } = useFormShellState(analyticsAlertCreateSchema, {
|
|
155
|
+
sections: nav.sectionMeta,
|
|
156
|
+
onGoToSection: nav.goToSection,
|
|
157
|
+
fieldToSectionIndex: nav.fieldToSectionIndex,
|
|
158
|
+
});
|
|
159
|
+
const submitAlert = () => {
|
|
160
|
+
clearErrors();
|
|
161
|
+
/*
|
|
162
|
+
* Parsed against the SAME schema the route uses, before the request.
|
|
163
|
+
*
|
|
164
|
+
* This form used to hand-build its payload and included `scope: "seller"`
|
|
165
|
+
* — a field the route pins from the session and the schema does not
|
|
166
|
+
* declare. Once that schema became `.strict()`, every "Create Alert"
|
|
167
|
+
* became a 400, and nothing local could have caught it: the client had no
|
|
168
|
+
* schema to check against. The parse is the structural fix; what changed
|
|
169
|
+
* here is only that its issues now reach the fields instead of being
|
|
170
|
+
* flattened into one thrown message.
|
|
171
|
+
*/
|
|
172
|
+
const parsed = analyticsAlertCreateSchema.safeParse(visibleValues(analyticsAlertCreateSchema, draft));
|
|
173
|
+
if (!parsed.success) {
|
|
174
|
+
applyZodIssues(parsed.error.issues, setFieldError);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
createMutation.mutate(parsed.data);
|
|
178
|
+
};
|
|
179
|
+
return (_jsxs(Stack, { gap: "lg", children: [_jsxs(Row, { justify: "between", children: [_jsx(Heading, { level: 2, size: "base", weight: "semibold", color: "primary", children: labels.title ?? "Analytics Alerts" }), _jsx(Button, { size: "sm", onClick: () => setShowForm((v) => !v), children: showForm ? "Cancel" : "+ New Alert" })] }), _jsx(Text, { size: "sm", color: "muted", children: "Get notified when a key metric crosses a threshold. Alerts check the metric over the selected window and fire through your chosen channels." }), showForm && (_jsxs(Section, { className: `${__P.p5} space-y-[1rem]`, rounded: "xl", border: "default", children: [_jsx(Heading, { level: 3, size: "sm", weight: "semibold", color: "primary", children: "Create Alert" }), _jsxs(FormShellContext.Provider, { value: shellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(SectionForm, { sections: sections, values: draft, onChange: (partial) => setDraft((prev) => ({ ...prev, ...partial })), onSubmit: submitAlert, schema: analyticsAlertCreateSchema, openIds: nav.openIds, onOpenChange: nav.setOpenIds, isLoading: createMutation.isPending, submitLabel: "Create alert", onCancel: () => setShowForm(false),
|
|
180
|
+
/*
|
|
181
|
+
* This panel is one card inside a longer analytics page, not the
|
|
182
|
+
* page's own form — a viewport-pinned Save would claim the
|
|
183
|
+
* bottom tier for a control the reader may have scrolled past.
|
|
184
|
+
*/
|
|
185
|
+
bottomBar: false })] })] })), isLoading && (_jsx(Stack, { gap: "sm", children: [1, 2, 3].map((i) => (_jsx(Div, { className: "h-16 animate-pulse", surface: "subtle", rounded: "lg" }, i))) })), !isLoading && alerts.length === 0 && !showForm && (_jsx(Alert, { variant: "info", children: "No alerts configured. Create an alert to get notified when a key metric crosses a threshold." })), !isLoading && alerts.length > 0 && (_jsx(Stack, { gap: "3", children: alerts.map((alert) => (_jsx(AlertCard, { alert: alert, onToggle: (id, isActive) => toggleMutation.mutate({ id, isActive }), onDelete: (id) => deleteMutation.mutate(id) }, alert.id))) }))] }));
|
|
146
186
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SellerArtView — seller browse/manage of art print listings.
|
|
3
|
+
*
|
|
4
|
+
* A named wrapper, kept so the page, the barrel and every existing import path
|
|
5
|
+
* stay unchanged. All behaviour is `SellerListingTypeView`; everything this
|
|
6
|
+
* type does differently is one entry in `SELLER_LISTING_TYPE_SPECS`.
|
|
7
|
+
*
|
|
8
|
+
* This file was 194 lines of a component that four siblings also contained
|
|
9
|
+
* verbatim — see that file's header for why the duplication mattered rather
|
|
10
|
+
* than merely being untidy.
|
|
11
|
+
*/
|
|
1
12
|
import React from "react";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
onDelete?: (id: string) => Promise<void>;
|
|
6
|
-
onBulkDelete?: (ids: string[]) => Promise<void>;
|
|
7
|
-
}
|
|
8
|
-
export declare function SellerArtView({ onCreateClick, onEditClick, onDelete, onBulkDelete, }: SellerArtViewProps): React.JSX.Element;
|
|
13
|
+
import { type SellerListingTypeViewProps } from "./SellerListingTypeView";
|
|
14
|
+
export type SellerArtViewProps = SellerListingTypeViewProps;
|
|
15
|
+
export declare function SellerArtView(props: SellerArtViewProps): React.JSX.Element;
|
|
@@ -1,121 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*/
|
|
7
|
-
import { Badge, sortBy } from "@mohasinac/appkit/client";
|
|
8
|
-
import { useState, useCallback } from "react";
|
|
9
|
-
import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
|
|
10
|
-
import { ConfirmDeleteModal, RowActionMenu, Text } from "../../../ui";
|
|
11
|
-
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
12
|
-
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
13
|
-
import { ROUTES } from "../../../constants/index";
|
|
14
|
-
import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../../admin/hooks/useAdminListingData";
|
|
15
|
-
import { DataListingView } from "../../admin/components/DataListingView";
|
|
16
|
-
import { SELLER_BULK_ACTIONS, ROW_ACTION_META } from "../../products/constants/action-defs";
|
|
17
|
-
import { useAvailabilityScope } from "../../products/hooks/useAvailabilityScope";
|
|
18
|
-
const LISTING_TYPES = ["art"];
|
|
19
|
-
const COLUMNS = [
|
|
20
|
-
{ key: "title", header: "Listing", render: (row) => _jsx(Text, { size: "sm", weight: "medium", children: row.title }) },
|
|
21
|
-
{ key: "price", header: "Price", render: (row) => _jsx(Text, { className: "tabular-nums", size: "sm", children: row.price }) },
|
|
22
|
-
{
|
|
23
|
-
key: "size",
|
|
24
|
-
header: "Size",
|
|
25
|
-
render: (row) => _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: row.size || "—" }),
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
key: "status",
|
|
29
|
-
header: "Status",
|
|
30
|
-
render: (row) => (_jsx(Badge, { variant: row.status === "active" ? "active" : "inactive", size: "xs", className: "capitalize", children: row.status })),
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
key: "createdAt",
|
|
34
|
-
header: "Created",
|
|
35
|
-
render: (row) => _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: row.createdAt }),
|
|
36
|
-
},
|
|
37
|
-
];
|
|
38
|
-
export function SellerArtView({ onCreateClick, onEditClick, onDelete, onBulkDelete, }) {
|
|
39
|
-
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
40
|
-
const { deletingId, handleDelete: performDelete } = useEntityDelete({
|
|
41
|
-
endpoint: SELLER_ENDPOINTS.PRODUCT_BY_ID,
|
|
42
|
-
deleteFn: onDelete,
|
|
43
|
-
successMessage: "Listing deleted.",
|
|
44
|
-
fetchOptions: { credentials: "include" },
|
|
45
|
-
});
|
|
46
|
-
const handleDelete = useCallback(async (id) => {
|
|
47
|
-
await performDelete(id);
|
|
48
|
-
setDeleteTargetId(null);
|
|
49
|
-
}, [performDelete]);
|
|
50
|
-
const handleEdit = useCallback((id) => {
|
|
51
|
-
if (onEditClick)
|
|
52
|
-
onEditClick(id);
|
|
53
|
-
else
|
|
54
|
-
window.location.href = String(ROUTES.STORE.ART_EDIT(id));
|
|
55
|
-
}, [onEditClick]);
|
|
56
|
-
const handleCreate = useCallback(() => {
|
|
57
|
-
if (onCreateClick)
|
|
58
|
-
onCreateClick();
|
|
59
|
-
else
|
|
60
|
-
window.location.href = String(ROUTES.STORE.ART_NEW);
|
|
61
|
-
}, [onCreateClick]);
|
|
62
|
-
const scope = useAvailabilityScope(LISTING_TYPES);
|
|
63
|
-
const config = {
|
|
64
|
-
portal: "seller",
|
|
65
|
-
title: "Art",
|
|
66
|
-
searchPlaceholder: "Search art prints...",
|
|
67
|
-
emptyLabel: "No art listings yet — list your first print",
|
|
68
|
-
filterKeys: [],
|
|
69
|
-
defaultSort: sortBy("createdAt", "DESC"),
|
|
70
|
-
queryKey: ["seller", "art"],
|
|
71
|
-
endpoint: SELLER_ENDPOINTS.PRODUCTS,
|
|
72
|
-
sortOptions: [
|
|
73
|
-
{ value: sortBy("createdAt", "DESC"), label: "Newest" },
|
|
74
|
-
{ value: sortBy("createdAt", "ASC"), label: "Oldest" },
|
|
75
|
-
{ value: "title", label: "Name A–Z" },
|
|
76
|
-
{ value: sortBy("price", "ASC"), label: "Price: Low–High" },
|
|
77
|
-
{ value: sortBy("price", "DESC"), label: "Price: High–Low" },
|
|
78
|
-
],
|
|
79
|
-
columns: COLUMNS,
|
|
80
|
-
mapRows: (response) => toRecordArray(response.products).map((item, index) => {
|
|
81
|
-
const printMeta = (item.printMeta ?? {});
|
|
82
|
-
return {
|
|
83
|
-
id: toStringValue(item.id, `art-${index}`),
|
|
84
|
-
title: toStringValue(item.productTitle ?? item.title, "Untitled"),
|
|
85
|
-
price: toCurrency(item.price),
|
|
86
|
-
size: toStringValue(printMeta.size, ""),
|
|
87
|
-
status: toStringValue(item.status, "draft"),
|
|
88
|
-
createdAt: toRelativeDate(item.createdAt),
|
|
89
|
-
};
|
|
90
|
-
}),
|
|
91
|
-
getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
|
|
92
|
-
buildFilters: () => "listingType==art",
|
|
93
|
-
buildExtraParams: () => scope.extraParams,
|
|
94
|
-
renderAboveContent: scope.renderAboveContent,
|
|
95
|
-
primaryAction: { label: "New Art Print", onClick: () => handleCreate() },
|
|
96
|
-
// Mirrors the "Edit" row action below so table rows and cards both navigate on click.
|
|
97
|
-
onRowClick: (row) => handleEdit(row.id),
|
|
98
|
-
// Rule #7: bulk-action array sourced from the SELLER_BULK_ACTIONS preset.
|
|
99
|
-
buildBulkActions: onBulkDelete
|
|
100
|
-
? (selection) => SELLER_BULK_ACTIONS.art.map((id) => ({
|
|
101
|
-
id,
|
|
102
|
-
label: ROW_ACTION_META[id].label,
|
|
103
|
-
destructive: ROW_ACTION_META[id].destructive,
|
|
104
|
-
onClick: async () => {
|
|
105
|
-
await onBulkDelete(selection.selectedIds);
|
|
106
|
-
selection.clearSelection();
|
|
107
|
-
},
|
|
108
|
-
}))
|
|
109
|
-
: undefined,
|
|
110
|
-
renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
111
|
-
{ label: ACTIONS.STORE["edit-listing"].label, onClick: () => handleEdit(row.id) },
|
|
112
|
-
{
|
|
113
|
-
label: ACTIONS.STORE["delete-listing"].label,
|
|
114
|
-
destructive: true,
|
|
115
|
-
onClick: () => setDeleteTargetId(row.id),
|
|
116
|
-
disabled: deletingId === row.id,
|
|
117
|
-
},
|
|
118
|
-
] })),
|
|
119
|
-
};
|
|
120
|
-
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Art Listing", message: "Are you sure you want to delete this art listing? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { SellerListingTypeView, } from "./SellerListingTypeView";
|
|
4
|
+
export function SellerArtView(props) {
|
|
5
|
+
return _jsx(SellerListingTypeView, { type: "art", ...props });
|
|
121
6
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SellerClassifiedView — seller browse/manage of classified listings.
|
|
3
|
+
*
|
|
4
|
+
* A named wrapper, kept so the page, the barrel and every existing import path
|
|
5
|
+
* stay unchanged. All behaviour is `SellerListingTypeView`; everything this
|
|
6
|
+
* type does differently is one entry in `SELLER_LISTING_TYPE_SPECS`.
|
|
7
|
+
*
|
|
8
|
+
* This file was 208 lines of a component that four siblings also contained
|
|
9
|
+
* verbatim — see that file's header for why the duplication mattered rather
|
|
10
|
+
* than merely being untidy.
|
|
11
|
+
*/
|
|
1
12
|
import React from "react";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
onDelete?: (id: string) => Promise<void>;
|
|
6
|
-
onBulkDelete?: (ids: string[]) => Promise<void>;
|
|
7
|
-
}
|
|
8
|
-
export declare function SellerClassifiedView({ onCreateClick, onEditClick, onDelete, onBulkDelete, }: SellerClassifiedViewProps): React.JSX.Element;
|
|
13
|
+
import { type SellerListingTypeViewProps } from "./SellerListingTypeView";
|
|
14
|
+
export type SellerClassifiedViewProps = SellerListingTypeViewProps;
|
|
15
|
+
export declare function SellerClassifiedView(props: SellerClassifiedViewProps): React.JSX.Element;
|