@mohasinac/appkit 4.9.5 → 4.11.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/DashboardLayoutClient.d.ts +6 -1
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +4 -1
- package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +1 -1
- package/dist/_internal/client/features/lottery/LotteryPullForm.js +2 -2
- package/dist/_internal/server/features/admin/daily-digest-actions.d.ts +18 -0
- package/dist/_internal/server/features/admin/daily-digest-actions.js +37 -0
- package/dist/_internal/server/features/auctions/actions.js +3 -2
- package/dist/_internal/server/features/auctions/service.d.ts +4 -3
- package/dist/_internal/server/features/auctions/service.js +6 -6
- package/dist/_internal/server/features/audit-log/actions.d.ts +25 -0
- package/dist/_internal/server/features/audit-log/actions.js +38 -0
- package/dist/_internal/server/features/brands/actions.js +0 -2
- package/dist/_internal/server/features/brands/og.d.ts +4 -1
- package/dist/_internal/server/features/brands/og.js +1 -1
- package/dist/_internal/server/features/bundles/data.d.ts +9 -0
- package/dist/_internal/server/features/bundles/data.js +14 -0
- package/dist/_internal/server/features/bundles/index.d.ts +1 -1
- package/dist/_internal/server/features/bundles/index.js +1 -1
- package/dist/_internal/server/features/catalogue/og.d.ts +20 -0
- package/dist/_internal/server/features/catalogue/og.js +27 -0
- package/dist/_internal/server/features/grouped/data.d.ts +16 -0
- package/dist/_internal/server/features/grouped/data.js +50 -1
- package/dist/_internal/server/features/grouped/index.d.ts +1 -1
- package/dist/_internal/server/features/grouped/index.js +1 -1
- package/dist/_internal/server/features/orders/actions.js +9 -0
- package/dist/_internal/server/features/orders/adapters.js +25 -0
- package/dist/_internal/server/features/products/data.d.ts +23 -0
- package/dist/_internal/server/features/products/data.js +159 -0
- package/dist/_internal/server/features/products/index.d.ts +1 -1
- package/dist/_internal/server/features/products/index.js +1 -1
- package/dist/_internal/server/functions/scheduled.d.ts +3 -1
- package/dist/_internal/server/functions/scheduled.js +17 -1
- package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +40 -0
- package/dist/_internal/server/jobs/core/dailyStatusDigest.js +164 -0
- package/dist/_internal/server/jobs/core/hardBanCascade.js +11 -0
- package/dist/_internal/server/jobs/core/testerSandboxCleanup.d.ts +1 -0
- package/dist/_internal/server/jobs/core/testerSandboxCleanup.js +4 -1
- package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +12 -0
- package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +85 -0
- package/dist/_internal/server/jobs/core/whatsappNotify.js +16 -0
- package/dist/_internal/server/jobs/handlers/dailyStatusDigest.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/dailyStatusDigest.js +4 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/index.js +3 -0
- package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +2 -0
- package/dist/_internal/server/notifications/channel-health.d.ts +27 -0
- package/dist/_internal/server/notifications/channel-health.js +101 -0
- package/dist/_internal/shared/features/auctions/config.d.ts +20 -0
- package/dist/_internal/shared/features/auctions/config.js +31 -1
- package/dist/_internal/shared/features/brands/schema.d.ts +0 -6
- package/dist/_internal/shared/features/brands/schema.js +0 -1
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +7 -0
- package/dist/_internal/shared/features/categories/bundle-schemas.js +3 -0
- package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
- package/dist/_internal/shared/listing-types/art/config.d.ts +1 -1
- package/dist/_internal/shared/listing-types/art/config.js +1 -1
- package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -1
- package/dist/_internal/shared/listing-types/classified/config.js +1 -1
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -1
- package/dist/_internal/shared/listing-types/digital-code/config.js +1 -1
- package/dist/_internal/shared/listing-types/live/config.d.ts +1 -1
- package/dist/_internal/shared/listing-types/live/config.js +1 -1
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -1
- package/dist/_internal/shared/listing-types/prize-draw/config.js +1 -1
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -1
- package/dist/_internal/shared/listing-types/stickers/config.js +1 -1
- package/dist/client.d.ts +21 -12
- package/dist/client.js +14 -7
- package/dist/constants/api-endpoints.d.ts +9 -9
- package/dist/constants/api-endpoints.js +3 -3
- package/dist/contracts/client-auth.d.ts +3 -7
- package/dist/contracts/email.d.ts +1 -0
- package/dist/features/account/components/AddressForm.js +24 -2
- package/dist/features/account/components/BecomeSellerView.d.ts +1 -2
- package/dist/features/account/components/BecomeSellerView.js +1 -1
- package/dist/features/account/components/NotificationBell.js +1 -1
- package/dist/features/account/components/UserBidsView.d.ts +1 -0
- package/dist/features/account/components/UserBidsView.js +47 -0
- package/dist/features/account/components/UserOrdersView.d.ts +4 -11
- package/dist/features/account/components/UserOrdersView.js +54 -4
- package/dist/features/account/components/UserReturnsView.d.ts +4 -9
- package/dist/features/account/components/UserReturnsView.js +37 -3
- package/dist/features/account/components/index.d.ts +3 -2
- package/dist/features/account/components/index.js +1 -0
- package/dist/features/admin/actions/admin-actions.js +22 -0
- package/dist/features/admin/actions/admin-coupon-actions.js +10 -0
- package/dist/features/admin/actions/notification-actions.js +4 -3
- package/dist/features/admin/components/AdminAdsView.d.ts +2 -3
- package/dist/features/admin/components/AdminAdsView.js +86 -89
- package/dist/features/admin/components/AdminAllEventEntriesView.js +18 -3
- package/dist/features/admin/components/AdminAuditLogView.d.ts +11 -0
- package/dist/features/admin/components/AdminAuditLogView.js +95 -0
- package/dist/features/admin/components/AdminBlogEditorView.js +37 -3
- package/dist/features/admin/components/AdminBrandEditorView.js +10 -6
- package/dist/features/admin/components/AdminBundleEditorView.js +18 -2
- package/dist/features/admin/components/AdminCarouselEditorView.js +2 -2
- package/dist/features/admin/components/AdminCarouselGroupEditorView.js +2 -2
- package/dist/features/admin/components/AdminCartsView.js +34 -4
- package/dist/features/admin/components/AdminCategoryEditorView.js +5 -4
- package/dist/features/admin/components/AdminCouponEditorView.js +2 -2
- package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
- package/dist/features/admin/components/AdminHistoryView.js +11 -1
- package/dist/features/admin/components/AdminNotificationsView.js +27 -1
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +10 -1
- package/dist/features/admin/components/AdminOrderEditorView.js +4 -3
- package/dist/features/admin/components/AdminOrdersView.js +92 -24
- package/dist/features/admin/components/AdminPayoutMarkPaidModal.d.ts +7 -0
- package/dist/features/admin/components/AdminPayoutMarkPaidModal.js +47 -0
- package/dist/features/admin/components/AdminPayoutsView.js +15 -31
- package/dist/features/admin/components/AdminProductEditorView.js +26 -3
- package/dist/features/admin/components/AdminSiteSettingsView.js +31 -4
- package/dist/features/admin/components/AdminStoreAddressesView.js +22 -2
- package/dist/features/admin/components/AdminStoresView.js +7 -0
- package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +2 -2
- package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +2 -2
- package/dist/features/admin/components/AdminUserEditorView.d.ts +2 -2
- package/dist/features/admin/components/AdminUserEditorView.js +4 -2
- package/dist/features/admin/components/AdminUsersView.js +1 -1
- package/dist/features/admin/components/AdminWishlistsView.js +14 -1
- package/dist/features/admin/components/DataListingView.d.ts +2 -2
- package/dist/features/admin/components/ViewAuditLogEntryModal.d.ts +19 -0
- package/dist/features/admin/components/ViewAuditLogEntryModal.js +22 -0
- package/dist/features/admin/components/ViewNotificationModal.d.ts +21 -0
- package/dist/features/admin/components/ViewNotificationModal.js +15 -0
- package/dist/features/admin/components/analytics/AdminPageViewsReportView.d.ts +4 -7
- package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +56 -36
- package/dist/features/admin/components/index.d.ts +8 -1
- package/dist/features/admin/components/index.js +4 -0
- package/dist/features/admin/constants/filter-tabs.d.ts +49 -0
- package/dist/features/admin/constants/filter-tabs.js +27 -0
- package/dist/features/admin/hooks/useAdminListing.d.ts +6 -0
- package/dist/features/admin/hooks/useAdminListing.js +3 -1
- package/dist/features/admin/hooks/useAdminListingData.d.ts +9 -1
- package/dist/features/admin/hooks/useAdminListingData.js +9 -2
- package/dist/features/admin/repository/site-settings.repository.d.ts +5 -0
- package/dist/features/admin/schemas/firestore.d.ts +21 -0
- package/dist/features/admin/schemas/firestore.js +6 -0
- package/dist/features/analytics/types.d.ts +1 -1
- package/dist/features/analytics/types.js +8 -0
- package/dist/features/auctions/actions/bid-actions.js +4 -1
- package/dist/features/auctions/components/AuctionBottomActions.d.ts +2 -1
- package/dist/features/auctions/components/AuctionBottomActions.js +14 -1
- package/dist/features/auctions/components/AuctionDetailPageView.js +21 -9
- package/dist/features/auctions/components/LiveMinIncrement.d.ts +18 -0
- package/dist/features/auctions/components/LiveMinIncrement.js +17 -0
- package/dist/features/auctions/components/PlaceBidFormClient.d.ts +5 -2
- package/dist/features/auctions/components/PlaceBidFormClient.js +7 -3
- package/dist/features/auctions/schemas/index.d.ts +5 -0
- package/dist/features/audit-log/repository/audit-log.repository.d.ts +45 -0
- package/dist/features/audit-log/repository/audit-log.repository.js +30 -0
- package/dist/features/audit-log/schemas/firestore.d.ts +59 -0
- package/dist/features/audit-log/schemas/firestore.js +35 -0
- package/dist/features/auth/actions/index.d.ts +0 -1
- package/dist/features/auth/actions/index.js +0 -1
- package/dist/features/auth/hooks/useAuth.d.ts +8 -35
- package/dist/features/auth/hooks/useAuth.js +21 -37
- package/dist/features/auth/permissions/constants.d.ts +1 -1
- package/dist/features/auth/permissions/constants.js +2 -0
- package/dist/features/blog/schemas/index.d.ts +32 -0
- package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +31 -3
- package/dist/features/catalogue/components/CatalogueItemEditorView.js +2 -1
- package/dist/features/catalogue/components/PublicCatalogueItemDetailView.d.ts +11 -0
- package/dist/features/catalogue/components/PublicCatalogueItemDetailView.js +33 -0
- package/dist/features/catalogue/components/PublicCatalogueView.js +2 -1
- package/dist/features/catalogue/index.d.ts +2 -0
- package/dist/features/catalogue/index.js +1 -0
- package/dist/features/categories/components/BrandDetailPageView.js +14 -12
- package/dist/features/categories/components/BundleDetailView.d.ts +3 -1
- package/dist/features/categories/components/BundleDetailView.js +3 -2
- package/dist/features/categories/components/CategoryDetailPageView.js +7 -3
- package/dist/features/categories/components/CategoryHighlightsAndFaqSection.d.ts +14 -0
- package/dist/features/categories/components/CategoryHighlightsAndFaqSection.js +22 -0
- package/dist/features/categories/components/CategoryProductsView.d.ts +1 -5
- package/dist/features/categories/components/CategoryProductsView.js +1 -1
- package/dist/features/categories/components/CategorySelectorCreate.js +16 -2
- package/dist/features/categories/schemas/firestore.d.ts +19 -2
- package/dist/features/categories/schemas/index.d.ts +24 -3
- package/dist/features/categories/schemas/index.js +3 -1
- package/dist/features/categories/types/index.d.ts +7 -0
- package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +17 -3
- package/dist/features/checkout/actions/checkout-value-otp-actions.js +101 -22
- package/dist/features/classified/components/ClassifiedContactSellerPanel.d.ts +12 -0
- package/dist/features/classified/components/ClassifiedContactSellerPanel.js +49 -0
- package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +7 -0
- package/dist/features/classified/components/ClassifiedDetailPageView.js +69 -0
- package/dist/features/contact/components/ContactForm.js +17 -4
- package/dist/features/contact/components/ContactPageView.js +8 -2
- package/dist/features/contact/email.d.ts +1 -0
- package/dist/features/contact/email.js +3 -0
- package/dist/features/digital-codes/components/DigitalCodeDetailPageView.d.ts +19 -0
- package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +79 -0
- package/dist/features/events/components/AdminEventEditorView.js +54 -2
- package/dist/features/events/components/AdminEventEntriesView.d.ts +2 -16
- package/dist/features/events/components/AdminEventEntriesView.js +56 -89
- package/dist/features/events/components/EventFormDrawer.js +5 -1
- package/dist/features/events/components/EventRaffleEntryForm.d.ts +1 -3
- package/dist/features/events/components/EventRaffleEntryForm.js +1 -1
- package/dist/features/events/schemas/index.d.ts +22 -0
- package/dist/features/grouped/components/GroupedListingsCarousel.d.ts +13 -0
- package/dist/features/grouped/components/GroupedListingsCarousel.js +31 -0
- package/dist/features/grouped/repository/grouped-listings.repository.d.ts +12 -0
- package/dist/features/grouped/repository/grouped-listings.repository.js +34 -0
- package/dist/features/homepage/components/CharacterHotspotForm.js +202 -187
- package/dist/features/homepage/components/SectionCarousel.d.ts +1 -7
- package/dist/features/homepage/components/SectionCarousel.js +1 -1
- package/dist/features/layout/BottomActions.js +4 -3
- package/dist/features/layout/BottomActionsContext.d.ts +10 -0
- package/dist/features/layout/BottomActionsContext.js +5 -1
- package/dist/features/layout/TitleBarLayout.d.ts +1 -1
- package/dist/features/layout/TitleBarLayout.js +3 -3
- package/dist/features/layout/hooks/useBottomActions.d.ts +2 -0
- package/dist/features/layout/hooks/useBottomActions.js +4 -1
- package/dist/features/live/components/LiveItemDetailPageView.d.ts +9 -0
- package/dist/features/live/components/LiveItemDetailPageView.js +74 -0
- package/dist/features/media/MediaImage.js +39 -3
- package/dist/features/media/MediaVideo.js +17 -1
- package/dist/features/media/types/index.d.ts +10 -0
- package/dist/features/media/types/index.js +1 -0
- package/dist/features/media/upload/MediaUploadField.d.ts +7 -1
- package/dist/features/media/upload/MediaUploadField.js +11 -7
- package/dist/features/media/upload/video-poster.d.ts +2 -0
- package/dist/features/media/upload/video-poster.js +16 -1
- package/dist/features/media/upload/video-poster.test.js +1 -1
- package/dist/features/orders/components/OrderStatusTimeline.d.ts +12 -0
- package/dist/features/orders/components/OrderStatusTimeline.js +55 -0
- package/dist/features/orders/components/index.d.ts +2 -0
- package/dist/features/orders/components/index.js +1 -0
- package/dist/features/orders/constants/payment-window.d.ts +25 -0
- package/dist/features/orders/constants/payment-window.js +25 -0
- package/dist/features/orders/repository/orders.repository.d.ts +32 -0
- package/dist/features/orders/repository/orders.repository.js +56 -0
- package/dist/features/orders/schemas/index.d.ts +24 -24
- package/dist/features/orders/types/index.d.ts +33 -0
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +9 -1
- package/dist/features/pre-orders/schemas/index.d.ts +5 -0
- package/dist/features/products/components/BidHistory.js +9 -1
- package/dist/features/products/components/GroupSettingsPanel.js +25 -3
- package/dist/features/products/components/PrizeDrawDetailPageView.js +11 -1
- package/dist/features/products/components/PrizeDrawEntryActions.d.ts +1 -4
- package/dist/features/products/components/PrizeDrawEntryActions.js +1 -1
- package/dist/features/products/components/ProductDetailActions.d.ts +1 -2
- package/dist/features/products/components/ProductDetailActions.js +1 -1
- package/dist/features/products/components/ProductDetailPageView.js +11 -116
- package/dist/features/products/components/ProductGrid.js +15 -1
- package/dist/features/products/components/RelatedItemsSection.d.ts +16 -0
- package/dist/features/products/components/RelatedItemsSection.js +17 -0
- package/dist/features/products/constants/action-defs.d.ts +1 -0
- package/dist/features/products/constants/action-defs.js +1 -0
- package/dist/features/products/schemas/index.d.ts +5 -0
- package/dist/features/promotions/components/CouponsIndexListing.d.ts +1 -3
- package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
- package/dist/features/search/components/SearchView.d.ts +1 -3
- package/dist/features/search/components/SearchView.js +1 -1
- package/dist/features/seller/components/QuickProductForm.js +2 -1
- package/dist/features/seller/components/SellerBidsView.js +66 -107
- package/dist/features/seller/components/SellerGoogleReviewsView.js +17 -1
- package/dist/features/seller/components/SellerOrdersView.d.ts +15 -3
- package/dist/features/seller/components/SellerOrdersView.js +134 -163
- package/dist/features/seller/components/SellerPayoutMethodsView.js +60 -48
- package/dist/features/seller/components/SellerPayoutSettingsView.js +69 -4
- package/dist/features/seller/components/SellerPayoutsView.d.ts +12 -0
- package/dist/features/seller/components/SellerPayoutsView.js +25 -5
- package/dist/features/seller/components/SellerProductShell.d.ts +10 -3
- package/dist/features/seller/components/SellerProductShell.js +90 -37
- package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +2 -7
- package/dist/features/seller/components/SellerProductsFilterDrawer.js +4 -4
- package/dist/features/seller/components/SellerProductsView.d.ts +2 -4
- package/dist/features/seller/components/SellerProductsView.js +131 -189
- package/dist/features/seller/components/SellerReviewsView.js +95 -133
- package/dist/features/seller/components/SellerShippingConfigsView.js +47 -67
- package/dist/features/seller/components/SellerShippingView.js +41 -4
- package/dist/features/seller/components/SellerStoreCategoriesView.js +51 -59
- package/dist/features/seller/components/SellerStorefrontView.d.ts +6 -1
- package/dist/features/seller/components/SellerStorefrontView.js +42 -5
- package/dist/features/seller/components/index.d.ts +2 -2
- package/dist/features/seller/components/index.js +2 -2
- package/dist/features/shell/FormShell.d.ts +24 -4
- package/dist/features/shell/FormShell.js +12 -6
- package/dist/features/shell/QuickFormDrawer.js +67 -12
- package/dist/features/shell/StepForm.d.ts +30 -1
- package/dist/features/shell/StepForm.js +47 -4
- package/dist/features/shell/index.d.ts +1 -1
- package/dist/features/shell/index.js +1 -1
- package/dist/features/shipments/components/AdminShipmentEditorView.js +2 -2
- package/dist/features/shipments/schemas/validation.d.ts +14 -4
- package/dist/features/tester/components/AdminTesterFeedbackListView.js +23 -2
- package/dist/features/tester/components/TesterChecklistStepRow.js +1 -1
- package/dist/features/tester/components/TesterHubView.js +3 -2
- package/dist/features/tester/seed-data/orders-tester-seed-data.js +9 -1
- package/dist/features/tester/seed-data/products-tester-seed-data.js +43 -32
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +487 -18
- package/dist/index.d.ts +17 -3
- package/dist/index.js +23 -5
- package/dist/next/routing/route-map.d.ts +13 -0
- package/dist/next/routing/route-map.js +12 -0
- package/dist/providers/email-resend/provider.js +1 -0
- package/dist/providers/firebase-client/auth.d.ts +1 -0
- package/dist/providers/firebase-client/auth.js +7 -1
- package/dist/repositories/index.d.ts +1 -0
- package/dist/repositories/index.js +1 -0
- package/dist/schemas/registry.d.ts +61 -25
- package/dist/security/pii-mask.js +1 -1
- package/dist/seed/bids-seed-data.js +48 -3
- package/dist/seed/categories-seed-data.js +69 -0
- package/dist/seed/grouped-listings-seed-data.js +167 -0
- package/dist/seed/payouts-seed-data.js +4 -4
- package/dist/seed/products-art-seed-data.js +188 -5
- package/dist/seed/products-auctions-seed-data.js +226 -6
- package/dist/seed/products-classifieds-seed-data.js +255 -8
- package/dist/seed/products-digital-codes-seed-data.js +258 -19
- package/dist/seed/products-live-items-seed-data.js +143 -10
- package/dist/seed/products-preorders-seed-data.js +213 -8
- package/dist/seed/products-prize-draws-seed-data.js +198 -0
- package/dist/seed/products-standard-seed-data.js +234 -4
- package/dist/seed/products-stickers-seed-data.js +178 -5
- package/dist/seed/site-settings-seed-data.js +23 -30
- package/dist/seed/store-extensions-seed-data.js +2 -2
- package/dist/server-entry.d.ts +6 -2
- package/dist/server-entry.js +24 -3
- package/dist/server.d.ts +10 -3
- package/dist/server.js +11 -4
- package/dist/styles.css +29 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Form.d.ts +11 -2
- package/dist/ui/components/Form.js +4 -3
- package/dist/ui/components/FormField.d.ts +3 -1
- package/dist/ui/components/FormField.js +22 -4
- package/dist/ui/components/ImageLightbox.js +37 -3
- package/dist/ui/components/ImageLightbox.style.css +28 -0
- package/dist/ui/components/ListingLayout.d.ts +1 -2
- package/dist/ui/components/ListingLayout.js +1 -1
- package/dist/ui/components/RecordDetailModal.d.ts +68 -0
- package/dist/ui/components/RecordDetailModal.js +8 -0
- package/dist/ui/components/SlottedListingView.js +9 -1
- package/dist/ui/forms/FormErrorSummary.d.ts +25 -0
- package/dist/ui/forms/FormErrorSummary.js +37 -0
- package/dist/ui/forms/FormShell.d.ts +37 -2
- package/dist/ui/forms/FormShell.js +37 -7
- package/dist/ui/forms/FormShell.style.css +17 -0
- package/dist/ui/forms/index.d.ts +2 -0
- package/dist/ui/forms/index.js +1 -0
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.js +5 -0
- package/dist/utils/media-url.d.ts +12 -1
- package/dist/utils/media-url.js +59 -1
- package/dist/validation/schemas.d.ts +4 -4
- package/package.json +1 -1
- package/dist/_internal/client/features/classified/ClassifiedDetailView.d.ts +0 -9
- package/dist/_internal/client/features/classified/ClassifiedDetailView.js +0 -55
- package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.d.ts +0 -18
- package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.js +0 -21
- package/dist/_internal/client/features/live/LiveItemDetailView.d.ts +0 -9
- package/dist/_internal/client/features/live/LiveItemDetailView.js +0 -25
- package/dist/_internal/server/jobs/core/prizeRevealClose.d.ts +0 -2
- package/dist/_internal/server/jobs/core/prizeRevealClose.js +0 -28
- package/dist/_internal/server/jobs/core/prizeRevealExpiry.d.ts +0 -2
- package/dist/_internal/server/jobs/core/prizeRevealExpiry.js +0 -61
- package/dist/_internal/server/jobs/core/prizeRevealOpen.d.ts +0 -2
- package/dist/_internal/server/jobs/core/prizeRevealOpen.js +0 -68
- package/dist/_internal/server/jobs/core/prizeRevealReminder.d.ts +0 -2
- package/dist/_internal/server/jobs/core/prizeRevealReminder.js +0 -49
- package/dist/_internal/server/jobs/handlers/prizeRevealClose.d.ts +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealClose.js +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.d.ts +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.js +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealOpen.d.ts +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealOpen.js +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealReminder.d.ts +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealReminder.js +0 -2
- package/dist/features/auth/consent-otp.d.ts +0 -57
- package/dist/features/auth/consent-otp.js +0 -127
- package/dist/features/cart/components/CheckoutOtpModal.d.ts +0 -15
- package/dist/features/cart/components/CheckoutOtpModal.js +0 -12
- package/dist/features/checkout/actions/checkout-actions.d.ts +0 -31
- package/dist/features/checkout/actions/checkout-actions.js +0 -124
- package/dist/features/classified/components/ClassifiedIndexListing.d.ts +0 -5
- package/dist/features/classified/components/ClassifiedIndexListing.js +0 -123
- package/dist/features/classified/components/ClassifiedListView.d.ts +0 -6
- package/dist/features/classified/components/ClassifiedListView.js +0 -44
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +0 -5
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +0 -114
- package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +0 -6
- package/dist/features/digital-codes/components/DigitalCodesListView.js +0 -38
- package/dist/features/live/components/LiveItemsIndexListing.d.ts +0 -5
- package/dist/features/live/components/LiveItemsIndexListing.js +0 -115
- package/dist/features/live/components/LiveItemsListView.d.ts +0 -6
- package/dist/features/live/components/LiveItemsListView.js +0 -44
- package/dist/features/seller/components/SellerTemplatesView.d.ts +0 -12
- package/dist/features/seller/components/SellerTemplatesView.js +0 -276
- package/dist/react/hooks/useVisibleItems.d.ts +0 -37
- package/dist/react/hooks/useVisibleItems.js +0 -59
- package/dist/ui/components/TabStrip.d.ts +0 -34
- package/dist/ui/components/TabStrip.js +0 -56
- package/dist/ui/components/TabStrip.style.css +0 -97
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { normalizeError } from "../../../errors/normalize";
|
|
4
|
-
import { Badge,
|
|
4
|
+
import { Badge, sortBy } from "@mohasinac/appkit/client";
|
|
5
5
|
import { useState, useCallback } from "react";
|
|
6
6
|
import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
|
|
7
|
-
import {
|
|
8
|
-
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
9
|
-
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
10
|
-
import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text, useToast, StickyToolbar, } from "../../../ui";
|
|
11
|
-
import { useBottomActions } from "../../layout";
|
|
7
|
+
import { ConfirmDeleteModal, Div, RowActionMenu, Text, useToast } from "../../../ui";
|
|
12
8
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
13
9
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
14
10
|
import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
|
|
15
11
|
import { ROUTES } from "../../../next";
|
|
16
|
-
import { toRecordArray, toStringValue
|
|
17
|
-
import {
|
|
18
|
-
const PAGE_SIZE = 25;
|
|
12
|
+
import { toRecordArray, toStringValue } from "../hooks/useSellerListingData";
|
|
13
|
+
import { DataListingView } from "../../admin/components/DataListingView";
|
|
19
14
|
const DEFAULT_SORT = "displayOrder";
|
|
20
15
|
const SORT_OPTIONS = [
|
|
21
16
|
{ value: sortBy("displayOrder", "ASC"), label: "Display Order" },
|
|
@@ -42,40 +37,11 @@ const COLUMNS = [
|
|
|
42
37
|
];
|
|
43
38
|
export function SellerStoreCategoriesView({ onCreateClick, onEditClick, onDelete, onBulkDelete, onBulkActivate, onBulkDeactivate, }) {
|
|
44
39
|
const { showToast } = useToast();
|
|
45
|
-
const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
|
|
46
|
-
const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
|
|
47
40
|
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
48
41
|
const { deletingId, handleDelete: performDelete } = useEntityDelete({
|
|
49
42
|
deleteFn: onDelete,
|
|
50
43
|
successMessage: "Category deleted.",
|
|
51
|
-
onSuccess: () => { refetch?.(); },
|
|
52
44
|
});
|
|
53
|
-
const commitSearch = useCallback(() => { table.set(TABLE_KEYS.QUERY, searchInput.trim()); }, [searchInput, table]);
|
|
54
|
-
const resetAll = useCallback(() => {
|
|
55
|
-
table.setMany({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "" });
|
|
56
|
-
setSearchInput("");
|
|
57
|
-
}, [table]);
|
|
58
|
-
const hasActiveState = !!table.get(TABLE_KEYS.QUERY) || table.get(TABLE_KEYS.SORT) !== DEFAULT_SORT;
|
|
59
|
-
const { rows, total, isLoading, errorMessage, refetch } = useSellerListingData({
|
|
60
|
-
queryKey: ["seller", "store-categories"],
|
|
61
|
-
endpoint: SELLER_ENDPOINTS.STORE_CATEGORIES,
|
|
62
|
-
page: table.getNumber(TABLE_KEYS.PAGE, 1),
|
|
63
|
-
pageSize: PAGE_SIZE,
|
|
64
|
-
sorts: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT,
|
|
65
|
-
q: table.get(TABLE_KEYS.QUERY) || undefined,
|
|
66
|
-
mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
|
|
67
|
-
id: toStringValue(item.id, `cat-${index}`),
|
|
68
|
-
raw: item,
|
|
69
|
-
label: String(item.label ?? ""),
|
|
70
|
-
slug: String(item.slug ?? ""),
|
|
71
|
-
productCount: Number(item.productIds?.length ?? 0),
|
|
72
|
-
isActive: Boolean(item.isActive),
|
|
73
|
-
})),
|
|
74
|
-
getTotal: (response, rows) => typeof response.total === "number" ? response.total : rows.length,
|
|
75
|
-
});
|
|
76
|
-
const currentPage = table.getNumber(TABLE_KEYS.PAGE, 1);
|
|
77
|
-
const totalPages = Math.ceil(total / PAGE_SIZE);
|
|
78
|
-
const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
|
|
79
45
|
const handleDelete = useCallback(async (id) => {
|
|
80
46
|
if (!onDelete)
|
|
81
47
|
return;
|
|
@@ -88,11 +54,6 @@ export function SellerStoreCategoriesView({ onCreateClick, onEditClick, onDelete
|
|
|
88
54
|
}
|
|
89
55
|
setDeleteTargetId(null);
|
|
90
56
|
}, [onDelete, performDelete, showToast]);
|
|
91
|
-
const bulkActions = [
|
|
92
|
-
...(onBulkDelete ? [buildBulkAction(ACTIONS.STORE["delete-listing"], async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); refetch?.(); })] : []),
|
|
93
|
-
...(onBulkActivate ? [buildBulkAction(ACTIONS.ADMIN["activate-bundle"], async () => { await onBulkActivate(selection.selectedIds); selection.clearSelection(); refetch?.(); })] : []),
|
|
94
|
-
...(onBulkDeactivate ? [buildBulkAction(ACTIONS.ADMIN["deactivate-bundle"], async () => { await onBulkDeactivate(selection.selectedIds); selection.clearSelection(); refetch?.(); })] : []),
|
|
95
|
-
];
|
|
96
57
|
const handleNavigateNew = () => {
|
|
97
58
|
if (onCreateClick) {
|
|
98
59
|
onCreateClick();
|
|
@@ -100,19 +61,50 @@ export function SellerStoreCategoriesView({ onCreateClick, onEditClick, onDelete
|
|
|
100
61
|
}
|
|
101
62
|
window.location.href = String(ROUTES.STORE.STORE_CATEGORIES_NEW);
|
|
102
63
|
};
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
64
|
+
const config = {
|
|
65
|
+
portal: "seller",
|
|
66
|
+
title: "Store Categories",
|
|
67
|
+
searchPlaceholder: "Search categories by label...",
|
|
68
|
+
emptyLabel: "No categories yet — add your first storefront category",
|
|
69
|
+
filterKeys: [],
|
|
70
|
+
defaultSort: DEFAULT_SORT,
|
|
71
|
+
queryKey: ["seller", "store-categories", "listing"],
|
|
72
|
+
endpoint: SELLER_ENDPOINTS.STORE_CATEGORIES,
|
|
73
|
+
sortOptions: SORT_OPTIONS,
|
|
74
|
+
columns: COLUMNS,
|
|
75
|
+
mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
|
|
76
|
+
id: toStringValue(item.id, `cat-${index}`),
|
|
77
|
+
raw: item,
|
|
78
|
+
label: String(item.label ?? ""),
|
|
79
|
+
slug: String(item.slug ?? ""),
|
|
80
|
+
productCount: Number(item.productIds?.length ?? 0),
|
|
81
|
+
isActive: Boolean(item.isActive),
|
|
82
|
+
})),
|
|
83
|
+
getTotal: (response, rows) => (typeof response.total === "number" ? response.total : rows.length),
|
|
84
|
+
buildFilters: () => undefined,
|
|
85
|
+
primaryAction: { label: "New Category", onClick: handleNavigateNew },
|
|
86
|
+
buildBulkActions: (selection) => {
|
|
87
|
+
const actions = [
|
|
88
|
+
...(onBulkDelete ? [buildBulkAction(ACTIONS.STORE["delete-listing"], async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); })] : []),
|
|
89
|
+
...(onBulkActivate ? [buildBulkAction(ACTIONS.ADMIN["activate-bundle"], async () => { await onBulkActivate(selection.selectedIds); selection.clearSelection(); })] : []),
|
|
90
|
+
...(onBulkDeactivate ? [buildBulkAction(ACTIONS.ADMIN["deactivate-bundle"], async () => { await onBulkDeactivate(selection.selectedIds); selection.clearSelection(); })] : []),
|
|
91
|
+
];
|
|
92
|
+
return actions;
|
|
93
|
+
},
|
|
94
|
+
renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
95
|
+
{
|
|
96
|
+
label: ACTIONS.STORE["edit-listing"].label,
|
|
97
|
+
onClick: () => onEditClick
|
|
98
|
+
? onEditClick(row.id)
|
|
99
|
+
: (window.location.href = String(ROUTES.STORE.STORE_CATEGORIES_EDIT(row.id))),
|
|
100
|
+
},
|
|
101
|
+
...(onDelete ? [{
|
|
102
|
+
label: ACTIONS.STORE["delete-listing"].label,
|
|
103
|
+
destructive: true,
|
|
104
|
+
onClick: () => setDeleteTargetId(row.id),
|
|
105
|
+
disabled: deletingId === row.id,
|
|
106
|
+
}] : []),
|
|
107
|
+
] })),
|
|
108
|
+
};
|
|
109
|
+
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Category", message: "Are you sure you want to delete this category? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
|
|
118
110
|
}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export interface StorefrontSaveResult {
|
|
2
|
+
ok: boolean;
|
|
3
|
+
error?: string;
|
|
4
|
+
issues?: unknown[];
|
|
5
|
+
}
|
|
1
6
|
export interface StorefrontDraft {
|
|
2
7
|
storeName?: string;
|
|
3
8
|
storeDescription?: string;
|
|
@@ -21,7 +26,7 @@ export interface StorefrontDraft {
|
|
|
21
26
|
}
|
|
22
27
|
export interface SellerStorefrontViewProps {
|
|
23
28
|
initialValues?: StorefrontDraft;
|
|
24
|
-
onSave: (data: StorefrontDraft) =>
|
|
29
|
+
onSave: (data: StorefrontDraft) => Promise<StorefrontSaveResult>;
|
|
25
30
|
isLoading?: boolean;
|
|
26
31
|
storeSlug?: string;
|
|
27
32
|
}
|
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useCallback, useState } from "react";
|
|
3
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { z } from "zod";
|
|
4
5
|
import { StackedViewShell } from "../../../ui";
|
|
5
6
|
import { Alert, Div, FormField, FormGroup, Heading, Stack, Text, Toggle, } from "../../../ui";
|
|
7
|
+
import { FormShellContext, useFormShellState, applyZodIssues, FormErrorSummary } from "../../../ui/forms";
|
|
6
8
|
import { ImageUpload, useMediaUpload } from "../../media";
|
|
7
9
|
import { StepForm, useFormShell } from "../../shell";
|
|
10
|
+
// Small local schema for the storefront form-input shape (not the broader
|
|
11
|
+
// `sellerStoreSchema`, which requires id/storeSlug/ownerId/status/createdAt —
|
|
12
|
+
// fields this editable draft never has, so applying it directly would show
|
|
13
|
+
// false "required" errors on every keystroke).
|
|
14
|
+
const storefrontDraftSchema = z.object({
|
|
15
|
+
storeName: z.string().min(2, "Store name is required").max(80),
|
|
16
|
+
storeDescription: z.string().max(10000).optional().or(z.literal("")),
|
|
17
|
+
storeCategory: z.string().max(80).optional().or(z.literal("")),
|
|
18
|
+
bio: z.string().max(300, "Bio must be 300 characters or fewer").optional().or(z.literal("")),
|
|
19
|
+
website: z.string().url("Enter a valid URL").optional().or(z.literal("")),
|
|
20
|
+
vacationMessage: z.string().max(300).optional().or(z.literal("")),
|
|
21
|
+
}).passthrough();
|
|
8
22
|
export function SellerStorefrontView({ initialValues, onSave, isLoading = false, storeSlug = "store", }) {
|
|
9
23
|
const [draft, setDraft] = useState(initialValues ?? {});
|
|
10
24
|
const [saving, setSaving] = useState(false);
|
|
@@ -12,6 +26,11 @@ export function SellerStorefrontView({ initialValues, onSave, isLoading = false,
|
|
|
12
26
|
const [currentStep, setCurrentStep] = useState(0);
|
|
13
27
|
const { markDirty, markClean } = useFormShell();
|
|
14
28
|
const { upload } = useMediaUpload();
|
|
29
|
+
const { shellCtx, setFieldError, clearErrors, validate } = useFormShellState(storefrontDraftSchema);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
validate(draft);
|
|
32
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
33
|
+
}, [draft, validate]);
|
|
15
34
|
const update = useCallback((partial) => {
|
|
16
35
|
setDraft((prev) => ({ ...prev, ...partial }));
|
|
17
36
|
markDirty();
|
|
@@ -21,9 +40,14 @@ export function SellerStorefrontView({ initialValues, onSave, isLoading = false,
|
|
|
21
40
|
setSaving(true);
|
|
22
41
|
setSaved(false);
|
|
23
42
|
try {
|
|
24
|
-
await onSave(draft);
|
|
25
|
-
|
|
26
|
-
|
|
43
|
+
const result = await onSave(draft);
|
|
44
|
+
if (result.ok) {
|
|
45
|
+
markClean();
|
|
46
|
+
clearErrors();
|
|
47
|
+
setSaved(true);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
applyZodIssues(result.issues ?? [], setFieldError);
|
|
27
51
|
}
|
|
28
52
|
finally {
|
|
29
53
|
setSaving(false);
|
|
@@ -33,23 +57,36 @@ export function SellerStorefrontView({ initialValues, onSave, isLoading = false,
|
|
|
33
57
|
const steps = [
|
|
34
58
|
{
|
|
35
59
|
label: "Store Identity",
|
|
60
|
+
fields: ["storeName", "storeDescription", "storeCategory", "bio"],
|
|
36
61
|
validate: (values) => !values.storeName?.trim() ? "Store name is required" : null,
|
|
37
62
|
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Store Identity" }), _jsx(FormField, { name: "storeName", label: "Store Name", type: "text", value: values.storeName ?? "", onChange: (v) => onChange({ storeName: v }), placeholder: "e.g. Pok\u00E9mon Palace", disabled: busy }), _jsx(FormField, { name: "storeCategory", label: "Store Category", type: "text", value: values.storeCategory ?? "", onChange: (v) => onChange({ storeCategory: v }), placeholder: "e.g. Trading Cards, Action Figures", disabled: busy }), _jsx(FormField, { name: "bio", label: "Short Bio (shown in search results)", type: "textarea", value: values.bio ?? "", onChange: (v) => onChange({ bio: v }), placeholder: "One-liner about your store (max 300 chars)", disabled: busy }), _jsx(FormField, { name: "storeDescription", label: "Full Description", type: "textarea", value: values.storeDescription ?? "", onChange: (v) => onChange({ storeDescription: v }), placeholder: "Detailed store description shown on your public store page\u2026", disabled: busy })] })),
|
|
38
63
|
},
|
|
39
64
|
{
|
|
40
65
|
label: "Branding",
|
|
66
|
+
fields: ["storeLogoURL", "storeBannerURL"],
|
|
41
67
|
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Branding" }), _jsxs(FormGroup, { columns: 2, children: [_jsx(ImageUpload, { label: "Store Logo", currentImage: values.storeLogoURL, onUpload: (file) => upload(file, "stores", true, { type: "store-logo", store: storeSlug }), onChange: (url) => onChange({ storeLogoURL: url }), helperText: "Square image, min 200\u00D7200px" }), _jsx(ImageUpload, { label: "Store Banner", currentImage: values.storeBannerURL, onUpload: (file) => upload(file, "stores", true, { type: "store-banner", store: storeSlug }), onChange: (url) => onChange({ storeBannerURL: url }), helperText: "Recommended: 1200\u00D7300px" })] })] })),
|
|
42
68
|
},
|
|
43
69
|
{
|
|
44
70
|
label: "Policies",
|
|
71
|
+
fields: ["returnPolicy", "shippingPolicy"],
|
|
45
72
|
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Policies" }), _jsx(FormField, { name: "returnPolicy", label: "Return Policy", type: "textarea", value: values.returnPolicy ?? "", onChange: (v) => onChange({ returnPolicy: v }), placeholder: "Describe your return policy\u2026", disabled: busy }), _jsx(FormField, { name: "shippingPolicy", label: "Shipping Policy", type: "textarea", value: values.shippingPolicy ?? "", onChange: (v) => onChange({ shippingPolicy: v }), placeholder: "How and when you ship orders\u2026", disabled: busy })] })),
|
|
46
73
|
},
|
|
47
74
|
{
|
|
48
75
|
label: "Contact & Visibility",
|
|
76
|
+
fields: ["website", "location", "socialLinks", "isPublic", "isVacationMode", "vacationMessage"],
|
|
49
77
|
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Contact & Social" }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "website", label: "Website", type: "text", value: values.website ?? "", onChange: (v) => onChange({ website: v }), placeholder: "https://example.com", disabled: busy }), _jsx(FormField, { name: "location", label: "Location", type: "text", value: values.location ?? "", onChange: (v) => onChange({ location: v }), placeholder: "e.g. Mumbai, India", disabled: busy })] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "twitter", label: "Twitter / X URL", type: "text", value: values.socialLinks?.twitter ?? "", onChange: (v) => onChange({ socialLinks: { ...values.socialLinks, twitter: v } }), placeholder: "https://twitter.com/...", disabled: busy }), _jsx(FormField, { name: "instagram", label: "Instagram URL", type: "text", value: values.socialLinks?.instagram ?? "", onChange: (v) => onChange({ socialLinks: { ...values.socialLinks, instagram: v } }), placeholder: "https://instagram.com/...", disabled: busy })] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "facebook", label: "Facebook URL", type: "text", value: values.socialLinks?.facebook ?? "", onChange: (v) => onChange({ socialLinks: { ...values.socialLinks, facebook: v } }), placeholder: "https://facebook.com/...", disabled: busy }), _jsx(FormField, { name: "linkedin", label: "LinkedIn URL", type: "text", value: values.socialLinks?.linkedin ?? "", onChange: (v) => onChange({ socialLinks: { ...values.socialLinks, linkedin: v } }), placeholder: "https://linkedin.com/...", disabled: busy })] }), _jsx(Heading, { level: 4, className: "mt-4 mb-2", children: "Visibility" }), _jsx(Toggle, { checked: values.isPublic !== false, onChange: (checked) => onChange({ isPublic: checked }), label: "Make store public \u2014 visible to all buyers", disabled: busy }), values.isPublic === false && (_jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "Your store is hidden. Existing orders are unaffected." })), _jsx(Heading, { level: 4, className: "mt-4 mb-2", children: "Vacation Mode" }), _jsx(Toggle, { checked: !!values.isVacationMode, onChange: (checked) => onChange({ isVacationMode: checked }), label: "Enable vacation mode \u2014 your store will show a notice to buyers", disabled: busy }), values.isVacationMode && (_jsx(FormField, { name: "vacationMessage", label: "Vacation Message", type: "textarea", value: values.vacationMessage ?? "", onChange: (v) => onChange({ vacationMessage: v }), placeholder: "I'm away until\u2026 Orders placed now will ship when I return.", disabled: busy }))] })),
|
|
50
78
|
},
|
|
51
79
|
];
|
|
80
|
+
const fieldToStepIndex = useMemo(() => {
|
|
81
|
+
const map = {};
|
|
82
|
+
steps.forEach((step, i) => {
|
|
83
|
+
step.fields?.forEach((field) => { map[field] = i; });
|
|
84
|
+
});
|
|
85
|
+
return map;
|
|
86
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
87
|
+
}, [steps.length]);
|
|
88
|
+
const wizardShellCtx = useMemo(() => ({ ...shellCtx, fieldToStepIndex, goToStep: (n) => setCurrentStep(n) }), [shellCtx, fieldToStepIndex, setCurrentStep]);
|
|
52
89
|
return (_jsx(StackedViewShell, { portal: "seller", title: "Storefront Settings", sections: [
|
|
53
|
-
_jsxs(Div, { children: [saved && (_jsx(Alert, { variant: "success", className: "mb-6", children: "Changes saved successfully." })), _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: handleSave, formId: "seller-storefront", currentStep: currentStep, onStepChange: setCurrentStep, completeLabel: "Save Changes", isLoading: busy })] }, "stepform"),
|
|
90
|
+
_jsxs(Div, { children: [saved && (_jsx(Alert, { variant: "success", className: "mb-6", children: "Changes saved successfully." })), _jsxs(FormShellContext.Provider, { value: wizardShellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: handleSave, formId: "seller-storefront", currentStep: currentStep, onStepChange: setCurrentStep, completeLabel: "Save Changes", isLoading: busy })] })] }, "stepform"),
|
|
54
91
|
] }));
|
|
55
92
|
}
|
|
@@ -9,7 +9,7 @@ export type { SellerPreOrdersViewProps } from "./SellerPreOrdersView";
|
|
|
9
9
|
export { SellerPrizeDrawsView } from "./SellerPrizeDrawsView";
|
|
10
10
|
export type { SellerPrizeDrawsViewProps } from "./SellerPrizeDrawsView";
|
|
11
11
|
export { PrintCenterView } from "./PrintCenterView";
|
|
12
|
-
export { SellerOrdersView } from "./SellerOrdersView";
|
|
12
|
+
export { SellerOrdersView, SellerOrderDetailPanel } from "./SellerOrdersView";
|
|
13
13
|
export type { SellerOrdersViewProps } from "./SellerOrdersView";
|
|
14
14
|
export { SellerOffersView } from "./SellerOffersView";
|
|
15
15
|
export type { SellerOffersViewProps } from "./SellerOffersView";
|
|
@@ -23,7 +23,7 @@ export { SellerBidsView } from "./SellerBidsView";
|
|
|
23
23
|
export type { SellerBidsViewProps } from "./SellerBidsView";
|
|
24
24
|
export { SellersListView } from "./SellersListView";
|
|
25
25
|
export type { SellersListViewProps } from "./SellersListView";
|
|
26
|
-
export { SellerPayoutsView } from "./SellerPayoutsView";
|
|
26
|
+
export { SellerPayoutsView, SellerPayoutDetailContent } from "./SellerPayoutsView";
|
|
27
27
|
export type { SellerPayoutsViewProps } from "./SellerPayoutsView";
|
|
28
28
|
export { SellerPayoutStats } from "./SellerPayoutStats";
|
|
29
29
|
export type { SellerPayoutStatsProps } from "./SellerPayoutStats";
|
|
@@ -4,14 +4,14 @@ export { SellerAuctionsView } from "./SellerAuctionsView";
|
|
|
4
4
|
export { SellerPreOrdersView } from "./SellerPreOrdersView";
|
|
5
5
|
export { SellerPrizeDrawsView } from "./SellerPrizeDrawsView";
|
|
6
6
|
export { PrintCenterView } from "./PrintCenterView";
|
|
7
|
-
export { SellerOrdersView } from "./SellerOrdersView";
|
|
7
|
+
export { SellerOrdersView, SellerOrderDetailPanel } from "./SellerOrdersView";
|
|
8
8
|
export { SellerOffersView } from "./SellerOffersView";
|
|
9
9
|
export { SellerOffersPanel } from "./SellerOffersPanel";
|
|
10
10
|
export { SellerCouponsView } from "./SellerCouponsView";
|
|
11
11
|
export { SellerCouponEditorView } from "./SellerCouponEditorView";
|
|
12
12
|
export { SellerBidsView } from "./SellerBidsView";
|
|
13
13
|
export { SellersListView } from "./SellersListView";
|
|
14
|
-
export { SellerPayoutsView } from "./SellerPayoutsView";
|
|
14
|
+
export { SellerPayoutsView, SellerPayoutDetailContent } from "./SellerPayoutsView";
|
|
15
15
|
export { SellerPayoutStats } from "./SellerPayoutStats";
|
|
16
16
|
export { SellerPayoutHistoryTable } from "./SellerPayoutHistoryTable";
|
|
17
17
|
export { SellerPayoutSettingsView } from "./SellerPayoutSettingsView";
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Carries the `schema` prop passed to `<FormShell>` down to any nested
|
|
4
|
+
* `<StepForm>` that doesn't declare its own `schema`/`StepDef.schema` —
|
|
5
|
+
* `FormShell` (chrome) has no form values of its own to validate, so it
|
|
6
|
+
* can't run `.safeParse()` itself; this is what makes the prop load-bearing
|
|
7
|
+
* instead of silently discarded.
|
|
8
|
+
*/
|
|
9
|
+
export declare const FormSchemaContext: import("react").Context<import("zod").ZodTypeAny | undefined>;
|
|
2
10
|
export interface FormShellSection {
|
|
3
11
|
id: string;
|
|
4
12
|
label: string;
|
|
@@ -20,6 +28,15 @@ export interface FormShellProps {
|
|
|
20
28
|
publishLabel?: string;
|
|
21
29
|
/** Override the entire bottom action bar. */
|
|
22
30
|
renderBottomBar?: () => ReactNode;
|
|
31
|
+
/**
|
|
32
|
+
* Rendered above the default Save/Publish buttons in FormShell's own
|
|
33
|
+
* built-in footer (the `onSaveDraft`/`onPublish` branch, not used when
|
|
34
|
+
* `renderBottomBar` is supplied — that override owns its whole footer).
|
|
35
|
+
* Typically `<FormShellContext.Provider value={shellCtx}><FormErrorSummary /></FormShellContext.Provider>`
|
|
36
|
+
* — lets a caller show the shared live error summary beside the built-in
|
|
37
|
+
* buttons without having to reimplement the footer itself.
|
|
38
|
+
*/
|
|
39
|
+
footerTopSlot?: ReactNode;
|
|
23
40
|
/**
|
|
24
41
|
* When provided, a 👁 Preview button appears in the top bar.
|
|
25
42
|
* Clicking it replaces the form body with this read-only render.
|
|
@@ -33,9 +50,12 @@ export interface FormShellProps {
|
|
|
33
50
|
*/
|
|
34
51
|
splitPreview?: boolean;
|
|
35
52
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
53
|
+
* Zod schema covering the form's fields. `FormShell` has no form values of
|
|
54
|
+
* its own, so it can't `.safeParse()` this directly — instead it provides
|
|
55
|
+
* the schema via `FormSchemaContext` to any nested `<StepForm>` that
|
|
56
|
+
* doesn't declare its own `schema`/`StepDef.schema`, so existing
|
|
57
|
+
* `<FormShell schema={x}>` call sites start validating with zero changes.
|
|
58
|
+
* `audit-form-schema` requires every callsite to declare one.
|
|
39
59
|
*/
|
|
40
60
|
schema?: import("zod").ZodTypeAny;
|
|
41
61
|
children: ReactNode;
|
|
@@ -46,4 +66,4 @@ export interface UseFormShellResult {
|
|
|
46
66
|
markClean: () => void;
|
|
47
67
|
}
|
|
48
68
|
export declare function useFormShell(): UseFormShellResult;
|
|
49
|
-
export declare function FormShell({ isOpen, onClose, title, breadcrumb, schema
|
|
69
|
+
export declare function FormShell({ isOpen, onClose, title, breadcrumb, schema, isDirty, isLoading, sections, onSaveDraft, onPublish, saveLabel, publishLabel, renderBottomBar, footerTopSlot, previewSlot, splitPreview: splitPreviewProp, children, }: FormShellProps): import("react").JSX.Element | null;
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { createContext, useCallback, useEffect, useRef, useState } from "react";
|
|
4
4
|
import { X, AlertTriangle, Eye, ArrowLeft } from "lucide-react";
|
|
5
5
|
import { Button } from "../../ui/components/Button";
|
|
6
6
|
import { IconButton } from "../../ui/components/IconButton";
|
|
7
7
|
import { classNames } from "../../ui/style.helper";
|
|
8
8
|
import { FORM_ACTION_META, FORM_ACTION_ID } from "../products/constants/action-defs";
|
|
9
9
|
import { Div, Row, Span, Stack, Text } from "../../ui";
|
|
10
|
+
/**
|
|
11
|
+
* Carries the `schema` prop passed to `<FormShell>` down to any nested
|
|
12
|
+
* `<StepForm>` that doesn't declare its own `schema`/`StepDef.schema` —
|
|
13
|
+
* `FormShell` (chrome) has no form values of its own to validate, so it
|
|
14
|
+
* can't run `.safeParse()` itself; this is what makes the prop load-bearing
|
|
15
|
+
* instead of silently discarded.
|
|
16
|
+
*/
|
|
17
|
+
export const FormSchemaContext = createContext(undefined);
|
|
10
18
|
const __P = {
|
|
11
19
|
p4: "p-[var(--appkit-space-4)]",
|
|
12
20
|
};
|
|
@@ -24,9 +32,7 @@ export function useFormShell() {
|
|
|
24
32
|
};
|
|
25
33
|
}
|
|
26
34
|
const FOCUSABLE = 'a[href],button:not([disabled]),textarea:not([disabled]),input:not([disabled]),select:not([disabled]),[tabindex]:not([tabindex="-1"])';
|
|
27
|
-
export function FormShell({ isOpen, onClose, title, breadcrumb,
|
|
28
|
-
// schema is consumed by callers (audit-form-schema asserts presence at callsites)
|
|
29
|
-
schema: _schema, isDirty = false, isLoading = false, sections, onSaveDraft, onPublish, saveLabel = FORM_ACTION_META[FORM_ACTION_ID.SAVE_DRAFT].label, publishLabel = FORM_ACTION_META[FORM_ACTION_ID.PUBLISH].label, renderBottomBar, previewSlot, splitPreview: splitPreviewProp, children, }) {
|
|
35
|
+
export function FormShell({ isOpen, onClose, title, breadcrumb, schema, isDirty = false, isLoading = false, sections, onSaveDraft, onPublish, saveLabel = FORM_ACTION_META[FORM_ACTION_ID.SAVE_DRAFT].label, publishLabel = FORM_ACTION_META[FORM_ACTION_ID.PUBLISH].label, renderBottomBar, footerTopSlot, previewSlot, splitPreview: splitPreviewProp, children, }) {
|
|
30
36
|
// W1-37: auto-enable splitPreview when a previewSlot is provided. Callers
|
|
31
37
|
// can still pass splitPreview={false} explicitly to opt out.
|
|
32
38
|
const splitPreview = splitPreviewProp ?? Boolean(previewSlot);
|
|
@@ -116,8 +122,8 @@ schema: _schema, isDirty = false, isLoading = false, sections, onSaveDraft, onPu
|
|
|
116
122
|
};
|
|
117
123
|
if (!isOpen)
|
|
118
124
|
return null;
|
|
119
|
-
return (_jsxs(
|
|
125
|
+
return (_jsxs(FormSchemaContext.Provider, { value: schema, children: [_jsx(Div, { surface: "overlay-sm", className: "fixed inset-0 backdrop-blur-[2px]", style: { zIndex: "calc(var(--appkit-z-modal) - 1)" }, "aria-hidden": "true", onClick: attemptClose }), _jsxs(Div, { layout: "flex", ref: panelRef, role: "dialog", "aria-modal": "true", "aria-label": title, className: "fixed top-0 bottom-0 left-0 right-0 lg:left-[10%] lg:right-[10%] [flex-direction:column] bg-[var(--appkit-color-surface)]", shadow: "2xl", style: { zIndex: "var(--appkit-z-modal)" }, children: [_jsxs(Row, { gap: "sm", paddingX: "x-5", className: "flex-shrink-0 sticky top-0 z-10 border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", padding: "y-sm", children: [previewMode ? (_jsxs(Button, { variant: "ghost", type: "button", onClick: () => setPreviewMode(false), "aria-label": "Back to edit", gap: "xs", rounded: "lg", textSize: "sm", textColor: "muted", className: "flex-shrink-0", children: [_jsx(ArrowLeft, { className: "w-4 h-4" }), _jsx(Span, { className: "hidden sm:inline", children: "Back to Edit" })] })) : (_jsx(IconButton, { type: "button", onClick: attemptClose, "aria-label": "Close", variant: "ghost", rounded: "lg", className: "text-[var(--appkit-color-text-muted)] flex-shrink-0", children: _jsx(X, { className: "w-5 h-5" }) })), _jsxs(Div, { className: "flex-1 min-w-0", children: [breadcrumb && (_jsx(Text, { className: "text-[var(--appkit-color-text-muted)] truncate mb-0.5", size: "xs", children: breadcrumb })), _jsx(Text, { className: "text-[var(--appkit-color-text)] truncate", size: "sm", weight: "semibold", children: previewMode ? `Preview — ${title}` : title })] }), _jsx(Row, { gap: "xs", className: "flex-shrink-0", children: previewMode ? null : (_jsxs(_Fragment, { children: [previewSlot && (_jsxs(Button, { variant: "outline", type: "button", onClick: () => setPreviewMode(true), gap: "xs", rounded: "lg", paddingX: "sm", textSize: "sm", textColor: "muted", children: [_jsx(Eye, { className: "w-4 h-4" }), _jsx(Span, { className: "hidden sm:inline", children: "Preview" })] })), onSaveDraft && (_jsx(Button, { variant: "outline", size: "sm", onClick: handleSaveDraft, disabled: isLoading || savingDraft || publishing, isLoading: savingDraft, children: saveLabel })), onPublish && (_jsx(Button, { variant: "primary", size: "sm", onClick: handlePublish, disabled: isLoading || savingDraft || publishing, isLoading: publishing, children: publishLabel }))] })) })] }), _jsxs(Div, { layout: "flex", className: `flex-1 ${__O.hidden}`, children: [sections && sections.length > 0 && !previewMode && (_jsx("nav", { "aria-label": "Form sections", className: "hidden lg:flex flex-col flex-shrink-0 w-48 border-r border-[var(--appkit-color-border)] py-[var(--appkit-space-4)] px-[var(--appkit-space-3)] gap-[var(--appkit-space-1)] overflow-y-auto", children: sections.map((sec) => (_jsx(Button, { variant: "ghost", type: "button", onClick: () => scrollToSection(sec.id), rounded: "lg", paddingX: "sm", paddingY: "xs", textSize: "sm", textColor: "muted", justify: "start", className: "text-left", children: sec.label }, sec.id))) })), sections && sections.length > 0 && !previewMode && (_jsx(Row, { gap: "px", className: `lg:hidden fixed top-[var(--form-shell-topbar-h,57px)] left-0 right-0 z-10 ${__O.xAuto} px-[1.25rem] bg-[var(--appkit-color-surface)] border-b border-[var(--appkit-color-border)]`, padding: "y-xs", children: sections.map((sec) => (_jsx(Button, { variant: "outline", type: "button", onClick: () => scrollToSection(sec.id), rounded: "full", paddingX: "sm", paddingY: "xs", textSize: "xs", textColor: "muted", className: "flex-shrink-0 hover:border-primary hover:text-primary whitespace-nowrap", children: sec.label }, sec.id))) })), _jsx(Div, { ref: bodyRef, className: classNames("flex-1 overflow-y-auto", sections && sections.length > 0 && !previewMode ? "pt-[var(--appkit-space-0)] lg:pt-[var(--appkit-space-0)]" : ""), children: previewMode && previewSlot ? (_jsxs(_Fragment, { children: [_jsxs(Row, { textSize: "sm", gap: "xs", className: "sticky top-0 z-10 bg-[var(--appkit-color-warning-surface)] border-b border-[var(--appkit-color-warning)] text-[var(--appkit-color-warning-text,var(--appkit-color-warning))]", paddingY: "y-xs", paddingX: "x-md", children: [_jsx(Eye, { className: "w-4 h-4 flex-shrink-0" }), _jsx(Span, { children: "Preview \u2014 not visible to buyers until published" })] }), _jsx(Div, { padding: "y-md", children: previewSlot() })] })) : splitPreview && previewSlot ? (
|
|
120
126
|
// S-STORE-3-D — desktop 60/40 split: form left, preview right.
|
|
121
127
|
// Below `lg`, falls back to single-column form (preview-as-modal via existing toggle).
|
|
122
|
-
_jsxs(Div, { className: "lg:grid lg:grid-cols-[3fr_2fr] lg:gap-[1.5rem] lg:px-[1.5rem] lg:py-[1.5rem] lg:max-w-[1400px] lg:mx-auto", children: [_jsx(Div, { className: "max-w-3xl mx-auto px-[1.25rem] sm:px-[1.5rem] lg:max-w-none lg:px-[0] lg:py-[0]", padding: "y-lg", children: children }), _jsxs(Div, { className: `hidden lg:block sticky lg:top-4 lg:self-start lg:max-h-[calc(100vh-6rem)] ${__O.yAuto} border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-raised)] ${__P.p4}`, rounded: "lg", children: [_jsxs(Row, { textWeight: "semibold", textSize: "xs", gap: "xs", className: "mb-3 uppercase tracking-wide text-[var(--appkit-color-text-muted)]", children: [_jsx(Eye, { className: "w-3.5 h-3.5" }), _jsx(Span, { children: "Live preview" })] }), previewSlot()] })] })) : (_jsx(Div, { className: "max-w-3xl mx-auto px-[1.25rem] sm:px-[1.5rem]", padding: "y-lg", children: children })) })] }), !previewMode && renderBottomBar ? (renderBottomBar()) : !previewMode && (onSaveDraft || onPublish) ? (_jsxs(
|
|
128
|
+
_jsxs(Div, { className: "lg:grid lg:grid-cols-[3fr_2fr] lg:gap-[1.5rem] lg:px-[1.5rem] lg:py-[1.5rem] lg:max-w-[1400px] lg:mx-auto", children: [_jsx(Div, { className: "max-w-3xl mx-auto px-[1.25rem] sm:px-[1.5rem] lg:max-w-none lg:px-[0] lg:py-[0]", padding: "y-lg", children: children }), _jsxs(Div, { className: `hidden lg:block sticky lg:top-4 lg:self-start lg:max-h-[calc(100vh-6rem)] ${__O.yAuto} border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-raised)] ${__P.p4}`, rounded: "lg", children: [_jsxs(Row, { textWeight: "semibold", textSize: "xs", gap: "xs", className: "mb-3 uppercase tracking-wide text-[var(--appkit-color-text-muted)]", children: [_jsx(Eye, { className: "w-3.5 h-3.5" }), _jsx(Span, { children: "Live preview" })] }), previewSlot()] })] })) : (_jsx(Div, { className: "max-w-3xl mx-auto px-[1.25rem] sm:px-[1.5rem]", padding: "y-lg", children: children })) })] }), !previewMode && renderBottomBar ? (renderBottomBar()) : !previewMode && (onSaveDraft || onPublish) ? (_jsxs(Stack, { gap: "none", className: "flex-shrink-0 sticky bottom-0 z-10 border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", children: [footerTopSlot && (_jsx(Div, { paddingX: "x-5", padding: "t-sm", children: footerTopSlot })), _jsxs(Row, { justify: "between", paddingX: "x-5", padding: "y-sm", style: { paddingBottom: "calc(var(--appkit-space-3) + var(--keyboard-inset-height, 0px))" }, children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: attemptClose, disabled: isLoading, children: FORM_ACTION_META[FORM_ACTION_ID.DISCARD].label }), _jsxs(Row, { gap: "xs", children: [onSaveDraft && (_jsx(Button, { variant: "outline", size: "sm", onClick: handleSaveDraft, disabled: isLoading || savingDraft || publishing, isLoading: savingDraft, children: saveLabel })), onPublish && (_jsxs(Button, { variant: "primary", size: "sm", onClick: handlePublish, disabled: isLoading || savingDraft || publishing, isLoading: publishing, children: [publishLabel, " \u2192"] }))] })] })] })) : null] }), showUnsaved && (_jsxs(_Fragment, { children: [_jsx(Div, { surface: "overlay-lg", className: "fixed inset-0", style: { zIndex: "var(--appkit-z-confirm)" }, onClick: () => setShowUnsaved(false) }), _jsxs(Div, { className: "fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[90vw] max-w-sm bg-[var(--appkit-color-surface)]", shadow: "2xl", rounded: "xl", padding: "lg", style: { zIndex: "var(--appkit-z-confirm)" }, children: [_jsxs(Row, { gap: "sm", align: "start", className: "mb-4", children: [_jsx(Span, { layout: "flex-center", className: "flex-shrink-0 w-10 h-10 bg-[var(--appkit-color-warning-surface)]", rounded: "full", children: _jsx(AlertTriangle, { className: "w-5 h-5 text-[var(--appkit-color-warning)]" }) }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { className: "text-[var(--appkit-color-text)]", weight: "semibold", children: "Unsaved changes" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "You have unsaved changes. Leave without saving?" })] })] }), _jsxs(Row, { gap: "xs", justify: "end", children: [_jsx(Button, { variant: "outline", size: "sm", onClick: () => setShowUnsaved(false), children: "Stay" }), _jsx(Button, { variant: "danger", size: "sm", onClick: () => { setShowUnsaved(false); onClose(); }, children: "Leave" })] })] })] }))] }));
|
|
123
129
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { X } from "lucide-react";
|
|
5
5
|
import { Button } from "../../ui/components/Button";
|
|
6
6
|
import { IconButton } from "../../ui/components/IconButton";
|
|
7
7
|
import { FormField } from "../../ui/components/FormField";
|
|
8
8
|
import { Toggle } from "../../ui/components/Toggle";
|
|
9
9
|
import { Div, Form, Row, Stack, Text } from "../../ui";
|
|
10
|
+
import { FormShellContext, FormErrorSummary } from "../../ui/forms";
|
|
10
11
|
import { useHandMode } from "../../_internal/client/hand-mode";
|
|
11
12
|
function initValues(fields, defaults = {}) {
|
|
12
13
|
const out = {};
|
|
@@ -67,6 +68,37 @@ export function QuickFormDrawer({ isOpen, onClose, title, fields, defaultValues,
|
|
|
67
68
|
setErrors(errs);
|
|
68
69
|
return Object.keys(errs).length === 0;
|
|
69
70
|
};
|
|
71
|
+
// Live-derived (not state — a pure function of the current values, so it
|
|
72
|
+
// never needs a separate effect) validation for the error summary below.
|
|
73
|
+
// Deliberately kept SEPARATE from the `errors` state above: `errors` only
|
|
74
|
+
// populates on submit and gates each field's inline error display, which
|
|
75
|
+
// must stay submit-gated so an untouched, freshly-opened drawer doesn't
|
|
76
|
+
// show every required field as invalid immediately. The summary is meant
|
|
77
|
+
// to be live per the shared error-summary requirement; the per-field
|
|
78
|
+
// inline errors are not.
|
|
79
|
+
const liveErrors = (() => {
|
|
80
|
+
if (schema) {
|
|
81
|
+
const parsed = schema.safeParse(values);
|
|
82
|
+
if (parsed.success)
|
|
83
|
+
return {};
|
|
84
|
+
const errs = {};
|
|
85
|
+
for (const issue of parsed.error.issues) {
|
|
86
|
+
const path = issue.path[0];
|
|
87
|
+
if (typeof path === "string" && !errs[path])
|
|
88
|
+
errs[path] = issue.message;
|
|
89
|
+
}
|
|
90
|
+
return errs;
|
|
91
|
+
}
|
|
92
|
+
const errs = {};
|
|
93
|
+
for (const f of fields) {
|
|
94
|
+
if (f.required) {
|
|
95
|
+
const v = values[f.name];
|
|
96
|
+
if (v === undefined || v === null || v === "")
|
|
97
|
+
errs[f.name] = `${f.label} is required`;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return errs;
|
|
101
|
+
})();
|
|
70
102
|
const handleSubmit = useCallback(async (e) => {
|
|
71
103
|
e?.preventDefault();
|
|
72
104
|
if (!validate())
|
|
@@ -121,18 +153,41 @@ export function QuickFormDrawer({ isOpen, onClose, title, fields, defaultValues,
|
|
|
121
153
|
document.addEventListener("keydown", handle);
|
|
122
154
|
return () => document.removeEventListener("keydown", handle);
|
|
123
155
|
}, [isOpen, handleClose]);
|
|
156
|
+
// Synthesize a FormShellContextValue from `liveErrors` (not the submit-gated
|
|
157
|
+
// `errors` state) so <FormErrorSummary> — the shared live-error-summary
|
|
158
|
+
// primitive — can be reused here without migrating this drawer's
|
|
159
|
+
// already-working schema/errors mechanism onto useFormShellState. Kept
|
|
160
|
+
// separate from `errors` deliberately: this context only backs the
|
|
161
|
+
// summary, never the per-field inline `error={errors[field.name]}` props
|
|
162
|
+
// above, which must stay submit-gated.
|
|
163
|
+
const shellCtx = useMemo(() => ({
|
|
164
|
+
errors: liveErrors,
|
|
165
|
+
touched: {},
|
|
166
|
+
setFieldError: () => { },
|
|
167
|
+
setFieldTouched: () => { },
|
|
168
|
+
clearFieldError: () => { },
|
|
169
|
+
steps: [],
|
|
170
|
+
currentStep: 0,
|
|
171
|
+
goToStep: () => { },
|
|
172
|
+
nextStep: () => { },
|
|
173
|
+
prevStep: () => { },
|
|
174
|
+
isPublishReady: Object.keys(liveErrors).length === 0,
|
|
175
|
+
isDirty: false,
|
|
176
|
+
isSubmitting: submitting,
|
|
177
|
+
stepErrorCounts: [],
|
|
178
|
+
}), [liveErrors, submitting]);
|
|
124
179
|
if (!isOpen)
|
|
125
180
|
return null;
|
|
126
181
|
const busy = submitting || isLoading;
|
|
127
|
-
return (_jsxs(_Fragment, { children: [_jsx(Div, { surface: "overlay-xs", className: "fixed inset-0 backdrop-blur-[2px] [z-index:calc(var(--appkit-z-modal)+1)]", "aria-hidden": "true", onClick: handleClose }), _jsxs(Div, { ref: drawerRef, role: "dialog", "aria-modal": "true", "aria-label": title, layout: "flex-col", shadow: "2xl", className: `fixed inset-y-0 ${hand === "left" ? "left-0" : "right-0"} bg-[var(--appkit-color-surface)] w-full lg:w-[40%] [z-index:calc(var(--appkit-z-modal)+2)]`, children: [_jsxs(Row, { className: "flex-shrink-0 border-b border-[var(--appkit-color-border)]", padding: "md", align: "center", gap: "3", reverse: hand === "left", children: [_jsx(Text, { className: "flex-1 text-[var(--appkit-color-text)]", size: "base", weight: "semibold", children: title }), _jsx(IconButton, { type: "button", onClick: handleClose, "aria-label": "Close", variant: "ghost", rounded: "lg", className: "text-[var(--appkit-color-text-muted)] hover:bg-[var(--appkit-color-border-subtle)]", children: _jsx(X, { className: "w-5 h-5" }) })] }), _jsxs(Form, { className: "flex-1", overflow: "y-auto", paddingX: "x-md", paddingY: "y-md-lg", spacing: "md", onSubmit: handleSubmit, noValidate: true, children: [fields.map((field) => {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
182
|
+
return (_jsx(FormShellContext.Provider, { value: shellCtx, children: _jsxs(_Fragment, { children: [_jsx(Div, { surface: "overlay-xs", className: "fixed inset-0 backdrop-blur-[2px] [z-index:calc(var(--appkit-z-modal)+1)]", "aria-hidden": "true", onClick: handleClose }), _jsxs(Div, { ref: drawerRef, role: "dialog", "aria-modal": "true", "aria-label": title, layout: "flex-col", shadow: "2xl", className: `fixed inset-y-0 ${hand === "left" ? "left-0" : "right-0"} bg-[var(--appkit-color-surface)] w-full lg:w-[40%] [z-index:calc(var(--appkit-z-modal)+2)]`, children: [_jsxs(Row, { className: "flex-shrink-0 border-b border-[var(--appkit-color-border)]", padding: "md", align: "center", gap: "3", reverse: hand === "left", children: [_jsx(Text, { className: "flex-1 text-[var(--appkit-color-text)]", size: "base", weight: "semibold", children: title }), _jsx(IconButton, { type: "button", onClick: handleClose, "aria-label": "Close", variant: "ghost", rounded: "lg", className: "text-[var(--appkit-color-text-muted)] hover:bg-[var(--appkit-color-border-subtle)]", children: _jsx(X, { className: "w-5 h-5" }) })] }), _jsxs(Form, { className: "flex-1", overflow: "y-auto", paddingX: "x-md", paddingY: "y-md-lg", spacing: "md", onSubmit: handleSubmit, noValidate: true, children: [fields.map((field) => {
|
|
183
|
+
const value = values[field.name];
|
|
184
|
+
if (field.type === "toggle") {
|
|
185
|
+
return (_jsxs(Stack, { gap: "xs", children: [_jsx(Toggle, { checked: !!value, onChange: (checked) => set(field.name, checked), label: field.label }), field.helperText && (_jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: field.helperText }))] }, field.name));
|
|
186
|
+
}
|
|
187
|
+
return (_jsxs(Div, { children: [_jsx(FormField, { name: field.name, label: field.label, type: field.type === "textarea"
|
|
188
|
+
? "textarea"
|
|
189
|
+
: field.type === "select"
|
|
190
|
+
? "select"
|
|
191
|
+
: "text", value: String(value ?? ""), onChange: (v) => set(field.name, field.type === "number" ? Number(v) : v), options: field.options, placeholder: field.placeholder, disabled: busy, error: errors[field.name] }), field.helperText && !errors[field.name] && (_jsx(Text, { className: "mt-1 text-[var(--appkit-color-text-muted)]", size: "xs", children: field.helperText }))] }, field.name));
|
|
192
|
+
}), renderExtra?.(values, set)] }), _jsxs(Div, { className: "flex-shrink-0 border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-bg)]", children: [_jsx(Div, { paddingX: "x-md", padding: "t-sm", children: _jsx(FormErrorSummary, {}) }), _jsxs(Row, { padding: "md", align: "center", justify: "between", gap: "sm", children: [_jsx(Button, { variant: "outline", size: "sm", onClick: handleClose, disabled: busy, children: cancelLabel }), _jsxs(Button, { variant: "primary", size: "sm", onClick: () => void handleSubmit(), disabled: busy, isLoading: busy, children: [submitLabel, " \u2192"] })] })] })] })] }) }));
|
|
138
193
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
2
|
import type { JsonValue } from "@mohasinac/appkit/client";
|
|
3
|
+
import type { ZodTypeAny } from "zod";
|
|
3
4
|
export interface StepDef<T extends object = Record<string, JsonValue>> {
|
|
4
5
|
label: string;
|
|
5
6
|
render: (props: {
|
|
@@ -9,6 +10,19 @@ export interface StepDef<T extends object = Record<string, JsonValue>> {
|
|
|
9
10
|
}) => ReactNode;
|
|
10
11
|
/** Returns an error message string if invalid, or null/undefined if valid. */
|
|
11
12
|
validate?: (values: T) => string | null | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Schema field names this step owns — drives error→step attribution
|
|
15
|
+
* (surfaced to the caller via `onValidationChange`'s `fieldToStepIndex`,
|
|
16
|
+
* consumed by `<FormErrorSummary>`).
|
|
17
|
+
*/
|
|
18
|
+
fields?: string[];
|
|
19
|
+
/**
|
|
20
|
+
* Per-step Zod schema. Runs live (on every value change, not just on
|
|
21
|
+
* Next/Publish) via `onValidationChange`. Falls back to the whole-form
|
|
22
|
+
* `schema` prop, then to a schema inherited from an ancestor `FormShell`
|
|
23
|
+
* via `FormSchemaContext`, when omitted.
|
|
24
|
+
*/
|
|
25
|
+
schema?: ZodTypeAny;
|
|
12
26
|
}
|
|
13
27
|
export interface StepFormProps<T extends object = Record<string, JsonValue>> {
|
|
14
28
|
steps: StepDef<T>[];
|
|
@@ -26,6 +40,21 @@ export interface StepFormProps<T extends object = Record<string, JsonValue>> {
|
|
|
26
40
|
hideActions?: boolean;
|
|
27
41
|
/** Per-step error flags — when true, step button shows a red error badge */
|
|
28
42
|
stepErrors?: boolean[];
|
|
43
|
+
/**
|
|
44
|
+
* Whole-form Zod schema, used by any step that doesn't declare its own
|
|
45
|
+
* `StepDef.schema`. Falls back to an ancestor `FormShell`'s schema (via
|
|
46
|
+
* `FormSchemaContext`) when omitted here too.
|
|
47
|
+
*/
|
|
48
|
+
schema?: ZodTypeAny;
|
|
49
|
+
/**
|
|
50
|
+
* Fired whenever live validation recomputes — the current field-name→
|
|
51
|
+
* message map plus a field-name→step-index map derived from `steps[].fields`.
|
|
52
|
+
* The caller (which owns the single `FormShellContext.Provider` for the
|
|
53
|
+
* surrounding form) composes these into its own context value so
|
|
54
|
+
* `<FormErrorSummary>` and per-field inline errors both work, instead of
|
|
55
|
+
* `StepForm` mounting a second, potentially-shadowing provider itself.
|
|
56
|
+
*/
|
|
57
|
+
onValidationChange?: (fieldErrors: Record<string, string>, fieldToStepIndex: Record<string, number>) => void;
|
|
29
58
|
}
|
|
30
59
|
export interface StepFormActionsProps {
|
|
31
60
|
currentStep: number;
|
|
@@ -48,4 +77,4 @@ export declare function StepIndicator({ steps, currentStep, onStepClick, stepErr
|
|
|
48
77
|
/** True for each step that has a validation error — renders a red dot badge */
|
|
49
78
|
stepErrors?: boolean[];
|
|
50
79
|
}): import("react").JSX.Element;
|
|
51
|
-
export declare function StepForm<T extends object = Record<string, JsonValue>>({ steps, values, onChange, onComplete, completeLabel, isLoading, formId, currentStep, onStepChange, hideActions, stepErrors, }: StepFormProps<T>): import("react").JSX.Element;
|
|
80
|
+
export declare function StepForm<T extends object = Record<string, JsonValue>>({ steps, values, onChange, onComplete, completeLabel, isLoading, formId, currentStep, onStepChange, hideActions, stepErrors, schema, onValidationChange, }: StepFormProps<T>): import("react").JSX.Element;
|