@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
|
@@ -8,6 +8,7 @@ export { UserAccountHubView } from "./UserAccountHubView";
|
|
|
8
8
|
export { ProfileView } from "./ProfileView";
|
|
9
9
|
export { UserSettingsView } from "./UserSettingsView";
|
|
10
10
|
export { UserOrdersView } from "./UserOrdersView";
|
|
11
|
+
export { UserBidsView } from "./UserBidsView";
|
|
11
12
|
export { OrderDetailView } from "./OrderDetailView";
|
|
12
13
|
export { UserAddressesView } from "./UserAddressesView";
|
|
13
14
|
export { UserNotificationsView } from "./UserNotificationsView";
|
|
@@ -17,6 +17,8 @@ import { getProviders } from "../../../contracts";
|
|
|
17
17
|
import { getAdminAuth } from "../../../providers/db-firebase";
|
|
18
18
|
import { isAdminUser } from "../../auth/role-predicates";
|
|
19
19
|
import { assertPrizeDrawNotLocked, assertPrizeDrawWonItemsImmutable, } from "../../../_internal/server/features/products/service";
|
|
20
|
+
import { recordAdminAction } from "../../../_internal/server/features/audit-log/actions";
|
|
21
|
+
import { AdminAuditActionValues } from "../../audit-log/schemas/firestore";
|
|
20
22
|
const ERR_UID_REQUIRED = "uid is required";
|
|
21
23
|
export async function revokeSession(adminId, sessionId) {
|
|
22
24
|
if (!sessionId?.trim()) {
|
|
@@ -85,6 +87,16 @@ export async function adminUpdatePayout(adminId, id, input) {
|
|
|
85
87
|
adminId,
|
|
86
88
|
payoutId: id,
|
|
87
89
|
});
|
|
90
|
+
if (updateData.status === "paid") {
|
|
91
|
+
void recordAdminAction({
|
|
92
|
+
actorUid: adminId,
|
|
93
|
+
action: AdminAuditActionValues.PAYOUT_MARK_PAID,
|
|
94
|
+
targetType: "payout",
|
|
95
|
+
targetId: id,
|
|
96
|
+
targetLabel: existing.sellerName ?? id,
|
|
97
|
+
metadata: { amount: existing.netAmount ?? existing.amount },
|
|
98
|
+
});
|
|
99
|
+
}
|
|
88
100
|
return updated;
|
|
89
101
|
}
|
|
90
102
|
export async function adminUpdateUser(adminId, uid, input) {
|
|
@@ -112,6 +124,16 @@ export async function adminUpdateUser(adminId, uid, input) {
|
|
|
112
124
|
targetUid: uid,
|
|
113
125
|
changes: Object.keys(input),
|
|
114
126
|
});
|
|
127
|
+
if (input.role !== undefined && input.role !== existing.role) {
|
|
128
|
+
void recordAdminAction({
|
|
129
|
+
actorUid: adminId,
|
|
130
|
+
action: AdminAuditActionValues.USER_ROLE_CHANGE,
|
|
131
|
+
targetType: "user",
|
|
132
|
+
targetId: uid,
|
|
133
|
+
targetLabel: existing.displayName ?? uid,
|
|
134
|
+
metadata: { fromRole: existing.role, toRole: input.role },
|
|
135
|
+
});
|
|
136
|
+
}
|
|
115
137
|
return updated;
|
|
116
138
|
}
|
|
117
139
|
/**
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
import { couponsRepository } from "../../promotions/repository/coupons.repository";
|
|
8
8
|
import { NotFoundError, ValidationError } from "../../../errors";
|
|
9
9
|
import { serverLogger } from "../../../monitoring";
|
|
10
|
+
import { recordAdminAction } from "../../../_internal/server/features/audit-log/actions";
|
|
11
|
+
import { AdminAuditActionValues } from "../../audit-log/schemas/firestore";
|
|
10
12
|
export async function adminCreateCoupon(adminId, input) {
|
|
11
13
|
const coupon = await couponsRepository.create({
|
|
12
14
|
...input,
|
|
@@ -60,6 +62,14 @@ export async function adminUpdateCoupon(adminId, id, input) {
|
|
|
60
62
|
adminId,
|
|
61
63
|
couponId: id,
|
|
62
64
|
});
|
|
65
|
+
void recordAdminAction({
|
|
66
|
+
actorUid: adminId,
|
|
67
|
+
action: AdminAuditActionValues.COUPON_UPDATE,
|
|
68
|
+
targetType: "coupon",
|
|
69
|
+
targetId: id,
|
|
70
|
+
targetLabel: existing.code,
|
|
71
|
+
metadata: { changedFields: Object.keys(input) },
|
|
72
|
+
});
|
|
63
73
|
return updated;
|
|
64
74
|
}
|
|
65
75
|
export async function adminDeleteCoupon(adminId, id) {
|
|
@@ -3,6 +3,7 @@ import { notificationRepository } from "../repository/notification.repository";
|
|
|
3
3
|
import { siteSettingsRepository } from "../repository/site-settings.repository";
|
|
4
4
|
import { userRepository } from "../../auth/repository/user.repository";
|
|
5
5
|
import { createResendProvider } from "../../../providers/email-resend/provider";
|
|
6
|
+
import { isChannelHealthy, withChannelRetry } from "../../../_internal/server/notifications/channel-health";
|
|
6
7
|
import { enqueueJob } from "../../jobs/actions/enqueue-job";
|
|
7
8
|
import { serverLogger } from "../../../monitoring";
|
|
8
9
|
import { decryptPii } from "../../../security/index";
|
|
@@ -131,15 +132,15 @@ export async function sendNotification(input) {
|
|
|
131
132
|
const apiKey = creds.resendApiKey?.trim() ?? "";
|
|
132
133
|
const fromEmail = settings.emailSettings?.fromEmail ?? "noreply@letitrip.in";
|
|
133
134
|
const fromName = settings.emailSettings?.fromName ?? "LetItRip";
|
|
134
|
-
if (apiKey && !apiKey.includes("PLACEHOLDER")) {
|
|
135
|
+
if (apiKey && !apiKey.includes("PLACEHOLDER") && (await isChannelHealthy("email"))) {
|
|
135
136
|
try {
|
|
136
137
|
const emailProvider = createResendProvider({ apiKey, fromEmail, fromName });
|
|
137
|
-
await emailProvider.send({
|
|
138
|
+
await withChannelRetry("email", () => emailProvider.send({
|
|
138
139
|
to: resolvedEmail,
|
|
139
140
|
subject: title,
|
|
140
141
|
html: emailHtml ?? `<p>${message}</p>`,
|
|
141
142
|
text: message,
|
|
142
|
-
});
|
|
143
|
+
}));
|
|
143
144
|
emailStatus = "sent";
|
|
144
145
|
}
|
|
145
146
|
catch (err) {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import type { StackedViewShellProps } from "../../../ui";
|
|
3
2
|
export type AdminAdStatus = "draft" | "active" | "scheduled" | "paused";
|
|
4
3
|
export type AdminAdProvider = "manual" | "adsense" | "thirdParty";
|
|
5
4
|
export interface AdminAdItem {
|
|
@@ -14,7 +13,7 @@ export interface AdminAdItem {
|
|
|
14
13
|
endAt?: string;
|
|
15
14
|
updatedAt?: string;
|
|
16
15
|
}
|
|
17
|
-
export interface AdminAdsViewProps
|
|
16
|
+
export interface AdminAdsViewProps {
|
|
18
17
|
endpoint?: string;
|
|
19
18
|
labels?: {
|
|
20
19
|
title?: string;
|
|
@@ -22,4 +21,4 @@ export interface AdminAdsViewProps extends Omit<StackedViewShellProps, "sections
|
|
|
22
21
|
createHref?: string;
|
|
23
22
|
renderEditLink?: (item: AdminAdItem) => React.ReactNode;
|
|
24
23
|
}
|
|
25
|
-
export declare function AdminAdsView({ endpoint, labels, createHref, renderEditLink,
|
|
24
|
+
export declare function AdminAdsView({ endpoint, labels, createHref, renderEditLink, }: AdminAdsViewProps): React.JSX.Element;
|
|
@@ -1,65 +1,30 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { normalizeError } from "../../../errors/normalize";
|
|
4
|
-
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
4
|
+
import { useApiMutation, sieveFilter, SIEVE_OP, sortBy } from "@mohasinac/appkit/client";
|
|
5
5
|
import React from "react";
|
|
6
6
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
7
|
-
import { Alert, Button, Checkbox, Div, Input, Label, Row, Select, Stack,
|
|
7
|
+
import { Alert, Button, Checkbox, Div, Input, Label, PaginatedSelect, Row, Select, Stack, Text, TextLink } from "../../../ui";
|
|
8
8
|
import { apiClient } from "../../../http";
|
|
9
9
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
10
|
-
import {
|
|
10
|
+
import { DataListingView } from "./DataListingView";
|
|
11
11
|
const __P = {
|
|
12
12
|
p3: "p-[var(--appkit-space-3)]",
|
|
13
13
|
};
|
|
14
14
|
function AdsSettingsPanel({ adsenseClientId, setAdsenseClientId, thirdPartyScriptUrl, setThirdPartyScriptUrl, consentRequired, setConsentRequired, serverCredentialIssues, localCredentialIssues, credentialStatus, providerCredentialsMasked, settingsMutation, hasPendingCredentialInput, currentConsentRequired, settingsMessage, onSave, }) {
|
|
15
15
|
return (_jsxs(Stack, { border: "default", className: __P.p3, gap: "3", rounded: "lg", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Provider and publish settings" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: "Save provider credentials here before publishing AdSense or third-party inventory." }), serverCredentialIssues.length > 0 ? (_jsx(Alert, { variant: "warning", title: "Provider credentials need attention", children: serverCredentialIssues.join("; ") })) : null, _jsxs(Div, { layout: "grid", gap: "3", className: "grid-cols-1 md:grid-cols-2", children: [_jsx(Input, { label: "AdSense client id", value: adsenseClientId, onChange: (event) => setAdsenseClientId(event.target.value), placeholder: providerCredentialsMasked?.adsenseClientId || "ca-pub-XXXXXXXXXX" }), _jsx(Input, { label: "Third-party script URL", value: thirdPartyScriptUrl, onChange: (event) => setThirdPartyScriptUrl(event.target.value), placeholder: providerCredentialsMasked?.thirdPartyScriptUrl || "https://..." })] }), _jsxs(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: ["Stored credentials: AdSense ", credentialStatus?.hasAdsenseClientId ? "configured" : "missing", " \u00B7 Third-party ", credentialStatus?.hasThirdPartyScriptUrl ? "configured" : "missing"] }), _jsxs(Row, { align: "center", justify: "between", gap: "3", children: [_jsxs(Label, { layout: "flex", gap: "md", size: "sm", children: [_jsx(Checkbox, { bare: true, checked: consentRequired, onChange: (event) => setConsentRequired(event.target.checked) }), "Require consent globally for ad rendering"] }), _jsx(Button, { size: "sm", variant: "outline", disabled: settingsMutation.isPending || localCredentialIssues.length > 0 || (!hasPendingCredentialInput && consentRequired === Boolean(currentConsentRequired)), onClick: onSave, children: settingsMutation.isPending ? "Saving..." : "Save settings" })] }), localCredentialIssues.length > 0 ? (_jsx(Alert, { variant: "error", title: "Fix settings before saving", children: localCredentialIssues.join("; ") })) : null, settingsMessage ? (_jsx(Alert, { variant: settingsMessage.toLowerCase().includes("failed") ? "error" : "success", title: "Settings", children: settingsMessage })) : null] }));
|
|
16
16
|
}
|
|
17
|
-
function
|
|
18
|
-
return (_jsxs(Div, { layout: "grid", gap: "3", className: "grid-cols-1 md:grid-cols-4", children: [_jsx(Input, { label: "Search", value: q, onChange: (event) => { onPageReset(); setQ(event.target.value); }, placeholder: "Search ads" }), _jsx(Select, { label: "Status", value: status, options: [
|
|
19
|
-
{ label: "All", value: "all" },
|
|
20
|
-
{ label: "Draft", value: "draft" },
|
|
21
|
-
{ label: "Active", value: "active" },
|
|
22
|
-
{ label: "Scheduled", value: "scheduled" },
|
|
23
|
-
{ label: "Paused", value: "paused" },
|
|
24
|
-
], onChange: (event) => { onPageReset(); setStatus(event.target.value); } }), _jsx(Select, { label: "Provider", value: provider, options: [
|
|
25
|
-
{ label: "All", value: "all" },
|
|
26
|
-
{ label: "Manual", value: "manual" },
|
|
27
|
-
{ label: "AdSense", value: "adsense" },
|
|
28
|
-
{ label: "Third Party", value: "thirdParty" },
|
|
29
|
-
], onChange: (event) => { onPageReset(); setProvider(event.target.value); } }), _jsx(Select, { label: "Placement", value: placement, options: [
|
|
30
|
-
{ label: "All", value: "all" },
|
|
31
|
-
...placements.map((item) => ({ label: item.label, value: item.id })),
|
|
32
|
-
], onChange: (event) => { onPageReset(); setPlacement(event.target.value); } })] }));
|
|
33
|
-
}
|
|
34
|
-
export function AdminAdsView({ endpoint = ADMIN_ENDPOINTS.ADS, labels = {}, createHref = "/admin/ads/new", renderEditLink, ...rest }) {
|
|
17
|
+
export function AdminAdsView({ endpoint = ADMIN_ENDPOINTS.ADS, labels = {}, createHref = "/admin/ads/new", renderEditLink, }) {
|
|
35
18
|
const queryClient = useQueryClient();
|
|
36
|
-
const [page, setPage] = React.useState(1);
|
|
37
|
-
const [pageSize] = React.useState(20);
|
|
38
|
-
const [q, setQ] = React.useState("");
|
|
39
|
-
const [status, setStatus] = React.useState("all");
|
|
40
|
-
const [provider, setProvider] = React.useState("all");
|
|
41
|
-
const [placement, setPlacement] = React.useState("all");
|
|
42
19
|
const [consentRequired, setConsentRequired] = React.useState(false);
|
|
43
20
|
const [adsenseClientId, setAdsenseClientId] = React.useState("");
|
|
44
21
|
const [thirdPartyScriptUrl, setThirdPartyScriptUrl] = React.useState("");
|
|
45
22
|
const [settingsMessage, setSettingsMessage] = React.useState(null);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
sp.set("page", String(page));
|
|
52
|
-
sp.set("pageSize", String(pageSize));
|
|
53
|
-
if (q.trim())
|
|
54
|
-
sp.set("q", q.trim());
|
|
55
|
-
if (status !== "all")
|
|
56
|
-
sp.set("status", status);
|
|
57
|
-
if (provider !== "all")
|
|
58
|
-
sp.set("provider", provider);
|
|
59
|
-
if (placement !== "all")
|
|
60
|
-
sp.set("placement", placement);
|
|
61
|
-
return apiClient.get(`${endpoint}?${sp.toString()}`);
|
|
62
|
-
},
|
|
23
|
+
// Lightweight metadata-only fetch (placements, consent, credential status) —
|
|
24
|
+
// decoupled from the paginated listing query DataListingView owns internally.
|
|
25
|
+
const metaQuery = useQuery({
|
|
26
|
+
queryKey: ["admin-ads-meta", endpoint],
|
|
27
|
+
queryFn: () => apiClient.get(`${endpoint}?page=1&pageSize=1`),
|
|
63
28
|
staleTime: 10000,
|
|
64
29
|
});
|
|
65
30
|
const statusMutation = useApiMutation({
|
|
@@ -68,13 +33,14 @@ export function AdminAdsView({ endpoint = ADMIN_ENDPOINTS.ADS, labels = {}, crea
|
|
|
68
33
|
},
|
|
69
34
|
onSuccess: async () => {
|
|
70
35
|
await queryClient.invalidateQueries({ queryKey: ["admin-ads"] });
|
|
36
|
+
await queryClient.invalidateQueries({ queryKey: ["admin-ads-meta"] });
|
|
71
37
|
},
|
|
72
38
|
});
|
|
73
39
|
React.useEffect(() => {
|
|
74
|
-
if (!
|
|
40
|
+
if (!metaQuery.data)
|
|
75
41
|
return;
|
|
76
|
-
setConsentRequired(Boolean(
|
|
77
|
-
}, [
|
|
42
|
+
setConsentRequired(Boolean(metaQuery.data.consentRequired));
|
|
43
|
+
}, [metaQuery.data]);
|
|
78
44
|
const settingsMutation = useApiMutation({
|
|
79
45
|
mutationFn: async (payload) => {
|
|
80
46
|
await apiClient.patch(endpoint, payload);
|
|
@@ -83,46 +49,14 @@ export function AdminAdsView({ endpoint = ADMIN_ENDPOINTS.ADS, labels = {}, crea
|
|
|
83
49
|
setSettingsMessage("Ad settings saved.");
|
|
84
50
|
setAdsenseClientId("");
|
|
85
51
|
setThirdPartyScriptUrl("");
|
|
86
|
-
await queryClient.invalidateQueries({ queryKey: ["admin-ads"] });
|
|
52
|
+
await queryClient.invalidateQueries({ queryKey: ["admin-ads-meta"] });
|
|
87
53
|
},
|
|
88
54
|
onError: (error) => {
|
|
89
55
|
setSettingsMessage(error instanceof Error ? error.message : "Failed to save ad settings");
|
|
90
56
|
},
|
|
91
57
|
});
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
{
|
|
95
|
-
key: "name",
|
|
96
|
-
header: "Ad",
|
|
97
|
-
render: (row) => (_jsxs(Div, { children: [_jsx(Text, { weight: "medium", children: row.name }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: row.id })] })),
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
key: "provider",
|
|
101
|
-
header: "Provider",
|
|
102
|
-
render: (row) => _jsx(Text, { className: "tracking-wide", size: "xs", transform: "uppercase", children: row.provider }),
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
key: "status",
|
|
106
|
-
header: "Status",
|
|
107
|
-
render: (row) => (_jsxs(Div, { children: [_jsx(Text, { className: "tracking-wide", size: "xs", transform: "uppercase", children: row.status }), row.publishReady === false ? (_jsx(Text, { className: "text-[11px] text-error", children: "Publish blocked" })) : null] })),
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
key: "placementIds",
|
|
111
|
-
header: "Placements",
|
|
112
|
-
render: (row) => (_jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: row.placementIds.join(", ") })),
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
key: "actions",
|
|
116
|
-
header: "Actions",
|
|
117
|
-
render: (row) => {
|
|
118
|
-
const nextStatus = row.status === "active" ? "paused" : "active";
|
|
119
|
-
const cannotPublish = nextStatus === "active" && row.publishReady === false;
|
|
120
|
-
return (_jsxs(Row, { align: "center", gap: "sm", children: [renderEditLink ? renderEditLink(row) : (_jsx(TextLink, { variant: "bare", href: `/admin/ads/${row.id}/edit`, rounded: "md", paddingX: "sm", size: "xs", layout: "inline-flex", align: "center", className: "h-8 border border-neutral-200 border-[var(--appkit-color-border)]", children: "Edit" })), _jsx(Button, { size: "sm", variant: "outline", disabled: statusMutation.isPending || cannotPublish, onClick: () => statusMutation.mutate({ id: row.id, nextStatus }), children: row.status === "active" ? "Pause" : "Publish" })] }));
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
], [renderEditLink, statusMutation]);
|
|
124
|
-
const placements = adsQuery.data?.placements ?? [];
|
|
125
|
-
const credentialStatus = adsQuery.data?.providerCredentialStatus;
|
|
58
|
+
const placements = metaQuery.data?.placements ?? [];
|
|
59
|
+
const credentialStatus = metaQuery.data?.providerCredentialStatus;
|
|
126
60
|
const serverCredentialIssues = credentialStatus?.issues ?? [];
|
|
127
61
|
const localCredentialIssues = React.useMemo(() => {
|
|
128
62
|
const issues = [];
|
|
@@ -155,11 +89,74 @@ export function AdminAdsView({ endpoint = ADMIN_ENDPOINTS.ADS, labels = {}, crea
|
|
|
155
89
|
};
|
|
156
90
|
settingsMutation.mutate(payload);
|
|
157
91
|
};
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
92
|
+
const columns = [
|
|
93
|
+
{
|
|
94
|
+
key: "name",
|
|
95
|
+
header: "Ad",
|
|
96
|
+
render: (row) => (_jsxs(Div, { children: [_jsx(Text, { weight: "medium", children: row.name }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: row.id })] })),
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
key: "provider",
|
|
100
|
+
header: "Provider",
|
|
101
|
+
render: (row) => _jsx(Text, { className: "tracking-wide", size: "xs", transform: "uppercase", children: row.provider }),
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
key: "status",
|
|
105
|
+
header: "Status",
|
|
106
|
+
render: (row) => (_jsxs(Div, { children: [_jsx(Text, { className: "tracking-wide", size: "xs", transform: "uppercase", children: row.status }), row.publishReady === false ? (_jsx(Text, { className: "text-[11px] text-error", children: "Publish blocked" })) : null] })),
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
key: "placementIds",
|
|
110
|
+
header: "Placements",
|
|
111
|
+
render: (row) => (_jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: row.placementIds.join(", ") })),
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
key: "actions",
|
|
115
|
+
header: "Actions",
|
|
116
|
+
render: (row) => {
|
|
117
|
+
const nextStatus = row.status === "active" ? "paused" : "active";
|
|
118
|
+
const cannotPublish = nextStatus === "active" && row.publishReady === false;
|
|
119
|
+
return (_jsxs(Row, { align: "center", gap: "sm", children: [renderEditLink ? renderEditLink(row) : (_jsx(TextLink, { variant: "bare", href: `/admin/ads/${row.id}/edit`, rounded: "md", paddingX: "sm", size: "xs", layout: "inline-flex", align: "center", className: "h-8 border border-neutral-200 border-[var(--appkit-color-border)]", children: "Edit" })), _jsx(Button, { size: "sm", variant: "outline", disabled: statusMutation.isPending || cannotPublish, onClick: () => statusMutation.mutate({ id: row.id, nextStatus }), children: row.status === "active" ? "Pause" : "Publish" })] }));
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
];
|
|
123
|
+
const config = {
|
|
124
|
+
portal: "admin",
|
|
125
|
+
title: labels.title ?? "Ad Inventory",
|
|
126
|
+
searchPlaceholder: "Search ads",
|
|
127
|
+
emptyLabel: "No ads found",
|
|
128
|
+
filterKeys: ["status", "provider", "placement"],
|
|
129
|
+
defaultSort: sortBy("updatedAt", "DESC"),
|
|
130
|
+
queryKey: ["admin-ads", endpoint],
|
|
131
|
+
endpoint,
|
|
132
|
+
sortOptions: [{ value: sortBy("updatedAt", "DESC"), label: "Recently updated" }],
|
|
133
|
+
columns,
|
|
134
|
+
mapRows: (response) => response.items,
|
|
135
|
+
getTotal: (response) => response.total,
|
|
136
|
+
buildFilters: (state) => {
|
|
137
|
+
const clauses = [];
|
|
138
|
+
if (state.status)
|
|
139
|
+
clauses.push(sieveFilter("status", SIEVE_OP.EQ, state.status));
|
|
140
|
+
if (state.provider)
|
|
141
|
+
clauses.push(sieveFilter("provider", SIEVE_OP.EQ, state.provider));
|
|
142
|
+
if (state.placement)
|
|
143
|
+
clauses.push(sieveFilter("placement", SIEVE_OP.EQ, state.placement));
|
|
144
|
+
return clauses.length ? clauses.join(",") : undefined;
|
|
145
|
+
},
|
|
146
|
+
toolbarExtra: (_jsx(TextLink, { variant: "bare", href: createHref, rounded: "md", paddingX: "sm", size: "sm", weight: "medium", layout: "inline-flex", align: "center", className: "h-9 bg-[var(--appkit-color-surface)] text-[var(--appkit-color-text)]", children: "New ad" })),
|
|
147
|
+
renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Select, { label: "Status", value: pendingFilters.status || "all", options: [
|
|
148
|
+
{ label: "All", value: "all" },
|
|
149
|
+
{ label: "Draft", value: "draft" },
|
|
150
|
+
{ label: "Active", value: "active" },
|
|
151
|
+
{ label: "Scheduled", value: "scheduled" },
|
|
152
|
+
{ label: "Paused", value: "paused" },
|
|
153
|
+
], onChange: (e) => setPendingFilters((p) => ({ ...p, status: e.target.value === "all" ? "" : e.target.value })) }), _jsx(Select, { label: "Provider", value: pendingFilters.provider || "all", options: [
|
|
154
|
+
{ label: "All", value: "all" },
|
|
155
|
+
{ label: "Manual", value: "manual" },
|
|
156
|
+
{ label: "AdSense", value: "adsense" },
|
|
157
|
+
{ label: "Third Party", value: "thirdParty" },
|
|
158
|
+
], onChange: (e) => setPendingFilters((p) => ({ ...p, provider: e.target.value === "all" ? "" : e.target.value })) }), _jsx(Label, { size: "sm", color: "muted", children: "Placement" }), _jsx(PaginatedSelect, { value: pendingFilters.placement || undefined, onChange: (v) => setPendingFilters((p) => ({ ...p, placement: v ?? "" })), options: placements.map((item) => ({ value: item.id, label: item.label })) })] })),
|
|
159
|
+
renderAboveContent: () => (_jsxs(Stack, { gap: "md", className: __P.p3, children: [metaQuery.error ? (_jsx(Alert, { variant: "error", title: "Could not load ads", children: metaQuery.error instanceof Error ? metaQuery.error.message : "Unknown error" })) : null, _jsx(AdsSettingsPanel, { adsenseClientId: adsenseClientId, setAdsenseClientId: setAdsenseClientId, thirdPartyScriptUrl: thirdPartyScriptUrl, setThirdPartyScriptUrl: setThirdPartyScriptUrl, consentRequired: consentRequired, setConsentRequired: setConsentRequired, serverCredentialIssues: serverCredentialIssues, localCredentialIssues: localCredentialIssues, credentialStatus: credentialStatus, providerCredentialsMasked: metaQuery.data?.providerCredentialsMasked, settingsMutation: settingsMutation, hasPendingCredentialInput: hasPendingCredentialInput, currentConsentRequired: Boolean(metaQuery.data?.consentRequired), settingsMessage: settingsMessage, onSave: saveSettings })] })),
|
|
160
|
+
};
|
|
161
|
+
return _jsx(DataListingView, { config: config });
|
|
165
162
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
4
4
|
import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit/client";
|
|
5
5
|
import { sortBy } from "@mohasinac/appkit/client";
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { useQueryClient } from "@tanstack/react-query";
|
|
8
|
-
import { FilterChipGroup, ListingLayout, RowActionMenu, useToast } from "../../../ui";
|
|
8
|
+
import { FilterChipGroup, ListingLayout, RecordDetailModal, RowActionMenu, useToast } from "../../../ui";
|
|
9
9
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
10
10
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
11
11
|
import { ADMIN_EVENT_ENTRY_STATUS_TABS } from "../constants/filter-tabs";
|
|
@@ -15,6 +15,7 @@ import { apiClient } from "../../../http";
|
|
|
15
15
|
export function AdminAllEventEntriesView({ children, ...props }) {
|
|
16
16
|
const queryClient = useQueryClient();
|
|
17
17
|
const { showToast } = useToast();
|
|
18
|
+
const [selected, setSelected] = React.useState(null);
|
|
18
19
|
const updateMutation = useApiMutation({
|
|
19
20
|
mutationFn: async ({ id, status }) => {
|
|
20
21
|
await apiClient.patch(ADMIN_ENDPOINTS.ADMIN_EVENT_ENTRY_BY_ID(id), { status });
|
|
@@ -52,10 +53,18 @@ export function AdminAllEventEntriesView({ children, ...props }) {
|
|
|
52
53
|
status: toStringValue(item.status ?? item.reviewStatus, "PENDING"),
|
|
53
54
|
updatedAt: toRelativeDate(item.submittedAt ?? item.createdAt),
|
|
54
55
|
eventId: toStringValue(item.eventId, ""),
|
|
56
|
+
_raw: item,
|
|
55
57
|
})),
|
|
56
58
|
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
57
59
|
buildFilters: (state) => state.status && state.status !== "All" ? sieveFilter("status", SIEVE_OP.EQ, state.status) : undefined,
|
|
60
|
+
// Confirm/waitlist/cancel used to be the only affordances — an admin
|
|
61
|
+
// decided an entry's fate without ever seeing the entrant's answers.
|
|
62
|
+
onRowClick: (row) => setSelected(row),
|
|
58
63
|
renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
64
|
+
{
|
|
65
|
+
label: "View details",
|
|
66
|
+
onClick: () => setSelected(row),
|
|
67
|
+
},
|
|
59
68
|
{
|
|
60
69
|
label: ACTIONS.ADMIN["confirm-entry"].label,
|
|
61
70
|
onClick: () => updateMutation.mutate({ id: row.id, status: "CONFIRMED" }),
|
|
@@ -72,5 +81,11 @@ export function AdminAllEventEntriesView({ children, ...props }) {
|
|
|
72
81
|
] })),
|
|
73
82
|
renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Status", tabs: ADMIN_EVENT_ENTRY_STATUS_TABS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) })),
|
|
74
83
|
};
|
|
75
|
-
|
|
84
|
+
const raw = selected?._raw ?? {};
|
|
85
|
+
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(RecordDetailModal, { isOpen: Boolean(selected), onClose: () => setSelected(null), title: selected?.primary ?? "Event Entry", badges: [{ label: selected?.status ?? "PENDING", variant: "default" }], fields: [
|
|
86
|
+
{ label: "Event", value: toStringValue(raw.eventId, "—") },
|
|
87
|
+
{ label: "Email", value: toStringValue(raw.userEmail, "—") },
|
|
88
|
+
{ label: "Points", value: String(raw.points ?? "—") },
|
|
89
|
+
{ label: "Submitted", value: selected?.updatedAt ?? "—" },
|
|
90
|
+
], metadata: raw.responses ?? undefined })] }));
|
|
76
91
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AdminAuditLogView — read-only list of admin action audit entries.
|
|
3
|
+
* Entries are written exclusively via `recordAdminAction()` from the
|
|
4
|
+
* instrumented privileged-action call sites (bans, checkout bypass, coupon
|
|
5
|
+
* edits, payout mark-paid, store status changes, role changes) — this view
|
|
6
|
+
* has no create/edit/delete affordance, only "view details".
|
|
7
|
+
*/
|
|
8
|
+
import React from "react";
|
|
9
|
+
import type { ListingLayoutProps } from "../../../ui";
|
|
10
|
+
export type AdminAuditLogViewProps = ListingLayoutProps;
|
|
11
|
+
export declare function AdminAuditLogView({ children, ...props }: AdminAuditLogViewProps): React.JSX.Element;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* AdminAuditLogView — read-only list of admin action audit entries.
|
|
5
|
+
* Entries are written exclusively via `recordAdminAction()` from the
|
|
6
|
+
* instrumented privileged-action call sites (bans, checkout bypass, coupon
|
|
7
|
+
* edits, payout mark-paid, store status changes, role changes) — this view
|
|
8
|
+
* has no create/edit/delete affordance, only "view details".
|
|
9
|
+
*/
|
|
10
|
+
import React, { useState } from "react";
|
|
11
|
+
import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit/client";
|
|
12
|
+
import { sortBy } from "@mohasinac/appkit/client";
|
|
13
|
+
import { FilterChipGroup, Input, ListingLayout, RowActionMenu, Stack } from "../../../ui";
|
|
14
|
+
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
15
|
+
import { ADMIN_AUDIT_LOG_ACTION_TABS } from "../constants/filter-tabs";
|
|
16
|
+
import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData";
|
|
17
|
+
import { DataListingView } from "./DataListingView";
|
|
18
|
+
import { ViewAuditLogEntryModal } from "./ViewAuditLogEntryModal";
|
|
19
|
+
const ACTION_LABELS = {
|
|
20
|
+
user_hard_ban: "User hard-banned",
|
|
21
|
+
user_soft_ban: "User soft-banned",
|
|
22
|
+
user_unban: "User unbanned",
|
|
23
|
+
checkout_bypass: "Admin checkout bypass",
|
|
24
|
+
coupon_update: "Coupon updated",
|
|
25
|
+
payout_mark_paid: "Payout marked paid",
|
|
26
|
+
store_status_change: "Store status changed",
|
|
27
|
+
user_role_change: "User role changed",
|
|
28
|
+
};
|
|
29
|
+
export function AdminAuditLogView({ children, ...props }) {
|
|
30
|
+
const [viewEntry, setViewEntry] = useState(null);
|
|
31
|
+
if (React.Children.count(children) > 0) {
|
|
32
|
+
return (_jsx(ListingLayout, { portal: "admin", ...props, children: children }));
|
|
33
|
+
}
|
|
34
|
+
const openEntry = (row) => {
|
|
35
|
+
const raw = row._raw;
|
|
36
|
+
setViewEntry({
|
|
37
|
+
id: row.id,
|
|
38
|
+
actorUid: toStringValue(raw.actorUid, ""),
|
|
39
|
+
actorName: toStringValue(raw.actorName, "") || undefined,
|
|
40
|
+
action: toStringValue(raw.action, ""),
|
|
41
|
+
targetType: toStringValue(raw.targetType, ""),
|
|
42
|
+
targetId: toStringValue(raw.targetId, ""),
|
|
43
|
+
targetLabel: toStringValue(raw.targetLabel, "") || undefined,
|
|
44
|
+
reason: toStringValue(raw.reason, "") || undefined,
|
|
45
|
+
metadata: raw.metadata ?? undefined,
|
|
46
|
+
createdAt: toStringValue(raw.createdAt, "") || undefined,
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
const config = {
|
|
50
|
+
portal: "admin",
|
|
51
|
+
title: "Audit Log",
|
|
52
|
+
searchPlaceholder: "Search by actor uid",
|
|
53
|
+
emptyLabel: "No audit log entries found",
|
|
54
|
+
filterKeys: ["action", "actorUid"],
|
|
55
|
+
defaultSort: sortBy("createdAt", "DESC"),
|
|
56
|
+
queryKey: ["admin", "audit-log", "listing"],
|
|
57
|
+
endpoint: ADMIN_ENDPOINTS.AUDIT_LOG,
|
|
58
|
+
sortOptions: [
|
|
59
|
+
{ value: sortBy("createdAt", "DESC"), label: "Newest" },
|
|
60
|
+
{ value: sortBy("createdAt", "ASC"), label: "Oldest" },
|
|
61
|
+
],
|
|
62
|
+
mapRows: (response) => toRecordArray(response.entries).map((item, index) => {
|
|
63
|
+
const action = toStringValue(item.action, "unknown");
|
|
64
|
+
return {
|
|
65
|
+
id: toStringValue(item.id, `audit-${index}`),
|
|
66
|
+
primary: ACTION_LABELS[action] ?? action,
|
|
67
|
+
secondary: [
|
|
68
|
+
toStringValue(item.actorName ?? item.actorUid, "Unknown actor"),
|
|
69
|
+
`${toStringValue(item.targetType, "")}: ${toStringValue(item.targetLabel ?? item.targetId, "")}`,
|
|
70
|
+
].join(" · "),
|
|
71
|
+
status: action,
|
|
72
|
+
updatedAt: toRelativeDate(item.createdAt),
|
|
73
|
+
_raw: item,
|
|
74
|
+
};
|
|
75
|
+
}),
|
|
76
|
+
getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
|
|
77
|
+
onRowClick: (row) => openEntry(row),
|
|
78
|
+
buildFilters: (state) => {
|
|
79
|
+
const parts = [];
|
|
80
|
+
if (state.action && state.action !== "All")
|
|
81
|
+
parts.push(sieveFilter("action", SIEVE_OP.EQ, state.action));
|
|
82
|
+
if (state.actorUid)
|
|
83
|
+
parts.push(sieveFilter("actorUid", SIEVE_OP.EQ, state.actorUid));
|
|
84
|
+
return parts.length > 0 ? parts.join(",") : undefined;
|
|
85
|
+
},
|
|
86
|
+
renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
87
|
+
{
|
|
88
|
+
label: "View details",
|
|
89
|
+
onClick: () => openEntry(row),
|
|
90
|
+
},
|
|
91
|
+
] })),
|
|
92
|
+
renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(Stack, { gap: "md", children: [_jsx(FilterChipGroup, { label: "Action", tabs: ADMIN_AUDIT_LOG_ACTION_TABS, value: pendingFilters.action ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, action: id })) }), _jsx(Input, { label: "Actor UID", value: pendingFilters.actorUid ?? "", onChange: (e) => setPendingFilters((p) => ({ ...p, actorUid: e.target.value })), placeholder: "Filter by actor uid" })] })),
|
|
93
|
+
};
|
|
94
|
+
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(ViewAuditLogEntryModal, { entry: viewEntry, isOpen: Boolean(viewEntry), onClose: () => setViewEntry(null) })] }));
|
|
95
|
+
}
|
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { normalizeError } from "../../../errors/normalize";
|
|
4
4
|
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
5
|
-
import React from "react";
|
|
5
|
+
import React, { useEffect, useMemo } from "react";
|
|
6
|
+
import { z } from "zod";
|
|
6
7
|
import { useQuery } from "@tanstack/react-query";
|
|
7
8
|
import { Button, ConfirmDeleteModal, Div, Heading, Input, RichTextEditor, RichTextRenderer, Row, Select, Span, Stack, StackedViewShell, TagInput, Text, Toggle, useToast } from "../../../ui";
|
|
9
|
+
import { FormShellContext, useFormShellState, applyZodIssues, FormErrorSummary } from "../../../ui/forms";
|
|
8
10
|
import { ImageUpload, MediaImage, useMediaUpload } from "../../media";
|
|
9
11
|
import { apiClient } from "../../../http";
|
|
10
12
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
13
|
+
import { blogPostCategorySchema } from "../../blog/schemas";
|
|
11
14
|
import { StepForm } from "../../shell";
|
|
15
|
+
// Form-input subset — `blogPostSchema` (blog schemas) requires `id` and uses
|
|
16
|
+
// a `MediaField` shape for `coverImage`, neither of which this draft has
|
|
17
|
+
// (coverImage here is a plain uploaded-URL string; id doesn't exist pre-save).
|
|
18
|
+
const blogDraftSchema = z.object({
|
|
19
|
+
title: z.string().min(1, "Title is required"),
|
|
20
|
+
slug: z.string().min(1, "Slug is required").regex(/^blog-/, "Slug must start with 'blog-'"),
|
|
21
|
+
category: blogPostCategorySchema,
|
|
22
|
+
metaDescription: z.string().max(160).optional().or(z.literal("")),
|
|
23
|
+
}).passthrough();
|
|
12
24
|
const __P = {
|
|
13
25
|
p4: "p-[var(--appkit-space-4)]",
|
|
14
26
|
};
|
|
@@ -72,6 +84,11 @@ export function AdminBlogEditorView({ postId, onSaved, onDeleted, embedded, ...r
|
|
|
72
84
|
const [showDeleteConfirm, setShowDeleteConfirm] = React.useState(false);
|
|
73
85
|
const { showToast } = useToast();
|
|
74
86
|
const { upload } = useMediaUpload();
|
|
87
|
+
const { shellCtx, setFieldError, validate } = useFormShellState(blogDraftSchema);
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
validate(draft);
|
|
90
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
91
|
+
}, [draft, validate]);
|
|
75
92
|
const update = React.useCallback((partial) => {
|
|
76
93
|
setDraft((prev) => ({ ...prev, ...partial }));
|
|
77
94
|
}, []);
|
|
@@ -146,6 +163,10 @@ export function AdminBlogEditorView({ postId, onSaved, onDeleted, embedded, ...r
|
|
|
146
163
|
onSaved(id);
|
|
147
164
|
},
|
|
148
165
|
onError: (err) => {
|
|
166
|
+
const issues = err?.issues;
|
|
167
|
+
if (issues && issues.length > 0) {
|
|
168
|
+
applyZodIssues(issues, setFieldError);
|
|
169
|
+
}
|
|
149
170
|
showToast(err?.message ?? "Failed to save post.", "error");
|
|
150
171
|
},
|
|
151
172
|
});
|
|
@@ -163,6 +184,7 @@ export function AdminBlogEditorView({ postId, onSaved, onDeleted, embedded, ...r
|
|
|
163
184
|
const steps = [
|
|
164
185
|
{
|
|
165
186
|
label: "Content",
|
|
187
|
+
fields: ["title", "slug", "excerpt", "content"],
|
|
166
188
|
validate: (values) => !values.title.trim() ? "Title is required" : null,
|
|
167
189
|
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "5", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Content" }), _jsx(Input, { label: "Title", value: values.title, onChange: (e) => {
|
|
168
190
|
const v = e.target.value;
|
|
@@ -174,6 +196,7 @@ export function AdminBlogEditorView({ postId, onSaved, onDeleted, embedded, ...r
|
|
|
174
196
|
},
|
|
175
197
|
{
|
|
176
198
|
label: "Media",
|
|
199
|
+
fields: ["coverImage", "youtubeId"],
|
|
177
200
|
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "5", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Media" }), _jsx(ImageUpload, { label: "Cover Image", currentImage: values.coverImage, onUpload: (file) => upload(file, "blog", true, {
|
|
178
201
|
type: "blog-cover",
|
|
179
202
|
title: values.title || values.slug,
|
|
@@ -182,6 +205,7 @@ export function AdminBlogEditorView({ postId, onSaved, onDeleted, embedded, ...r
|
|
|
182
205
|
},
|
|
183
206
|
{
|
|
184
207
|
label: "SEO & Tags",
|
|
208
|
+
fields: ["category", "tags", "metaTitle", "metaDescription"],
|
|
185
209
|
render: ({ values, onChange }) => {
|
|
186
210
|
const readTime = Math.max(1, Math.round(values.content.replace(/<[^>]*>/g, "").split(/\s+/).filter(Boolean).length / 200));
|
|
187
211
|
return (_jsxs(Stack, { gap: "5", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "SEO & Tags" }), _jsxs(Div, { layout: "grid", gap: "4", className: "grid-cols-2", children: [_jsx(Select, { label: "Category", options: CATEGORY_OPTIONS, value: values.category, onValueChange: (v) => onChange({ category: v }) }), _jsxs(Div, { children: [_jsx(Text, { className: "mb-1.5", size: "sm", weight: "medium", children: "Estimated Read Time" }), _jsxs(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: ["~", readTime, " min (auto-calculated from content)"] })] })] }), _jsx(TagInput, { label: "Tags", value: values.tags, onChange: (t) => onChange({ tags: t }), placeholder: "e.g. pokemon, grading, tcg" }), _jsx(Input, { label: "Meta Title (optional)", value: values.metaTitle, onChange: (e) => onChange({ metaTitle: e.target.value }), placeholder: "Defaults to post title" }), _jsx(Input, { label: "Meta Description (optional)", value: values.metaDescription, onChange: (e) => onChange({ metaDescription: e.target.value }), placeholder: "SEO description \u2014 max 160 chars", maxLength: 160 })] }));
|
|
@@ -189,6 +213,7 @@ export function AdminBlogEditorView({ postId, onSaved, onDeleted, embedded, ...r
|
|
|
189
213
|
},
|
|
190
214
|
{
|
|
191
215
|
label: "Publish",
|
|
216
|
+
fields: ["status", "publishedAt", "authorName", "isFeatured"],
|
|
192
217
|
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "5", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Publish Settings" }), _jsxs(Div, { layout: "grid", gap: "4", className: "grid-cols-2", children: [_jsx(Select, { label: "Status", options: STATUS_OPTIONS, value: values.status, onValueChange: (v) => onChange({ status: v }) }), _jsx(Input, { label: "Publish date (optional)", value: values.publishedAt, onChange: (e) => onChange({ publishedAt: e.target.value }), type: "date", helperText: "Auto-set to now when publishing." })] }), _jsx(Input, { label: "Author Name", value: values.authorName, onChange: (e) => onChange({ authorName: e.target.value }), placeholder: "Author display name" }), _jsx(Toggle, { label: "Featured post", checked: values.isFeatured, onChange: (checked) => onChange({ isFeatured: checked }) }), isEdit && (_jsx(Div, { className: "border-t border-[var(--appkit-color-border)]", padding: "t-md", children: _jsx(Button, { type: "button", variant: "danger", size: "sm", onClick: () => setShowDeleteConfirm(true), isLoading: deleteMutation.isPending, children: "Delete post" }) }))] })),
|
|
193
218
|
},
|
|
194
219
|
];
|
|
@@ -196,7 +221,16 @@ export function AdminBlogEditorView({ postId, onSaved, onDeleted, embedded, ...r
|
|
|
196
221
|
setShowDeleteConfirm(false);
|
|
197
222
|
deleteMutation.mutate();
|
|
198
223
|
}, onClose: () => setShowDeleteConfirm(false), title: "Delete post", message: "This will permanently delete the blog post. This cannot be undone." }));
|
|
199
|
-
const
|
|
224
|
+
const fieldToStepIndex = useMemo(() => {
|
|
225
|
+
const map = {};
|
|
226
|
+
steps.forEach((step, i) => {
|
|
227
|
+
step.fields?.forEach((field) => { map[field] = i; });
|
|
228
|
+
});
|
|
229
|
+
return map;
|
|
230
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
231
|
+
}, [steps.length]);
|
|
232
|
+
const wizardShellCtx = useMemo(() => ({ ...shellCtx, fieldToStepIndex, goToStep: (n) => setCurrentStep(n) }), [shellCtx, fieldToStepIndex, setCurrentStep]);
|
|
233
|
+
const formContent = (_jsxs(FormShellContext.Provider, { value: wizardShellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: () => { saveMutation.mutate(); }, formId: "admin-blog", currentStep: currentStep, onStepChange: setCurrentStep, completeLabel: isEdit ? "Save Changes" : "Create Post", isLoading: isLoading }), deleteModal] }));
|
|
200
234
|
if (embedded) {
|
|
201
235
|
return _jsx(Div, { className: `${__O.yAuto} ${__P.p4}`, children: formContent });
|
|
202
236
|
}
|