@mohasinac/appkit 4.10.0 → 4.11.1
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/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/grouped/data.d.ts +4 -0
- package/dist/_internal/server/features/grouped/data.js +24 -0
- 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 +2 -2
- package/dist/_internal/server/features/products/data.js +5 -23
- 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/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/features/products/to-product-item.d.ts +25 -0
- package/dist/_internal/shared/features/products/to-product-item.js +45 -0
- package/dist/client.d.ts +21 -6
- package/dist/client.js +13 -3
- package/dist/constants/api-endpoints.d.ts +6 -9
- package/dist/constants/api-endpoints.js +2 -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 +20 -1
- 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 +12 -0
- package/dist/features/analytics/types.d.ts +1 -1
- package/dist/features/analytics/types.js +8 -0
- 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/categories/components/BrandDetailPageView.js +14 -12
- 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/contact/components/ContactForm.js +17 -4
- package/dist/features/contact/email.d.ts +1 -0
- package/dist/features/contact/email.js +3 -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.js +4 -1
- package/dist/features/grouped/repository/grouped-listings.repository.d.ts +4 -0
- package/dist/features/grouped/repository/grouped-listings.repository.js +18 -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/TitleBarLayout.d.ts +1 -1
- package/dist/features/layout/TitleBarLayout.js +3 -3
- package/dist/features/media/MediaImage.js +39 -3
- 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/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 +1 -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/ProductGrid.js +15 -1
- 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 +89 -36
- 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 +404 -15
- package/dist/index.d.ts +15 -3
- package/dist/index.js +22 -5
- package/dist/next/routing/route-map.d.ts +11 -0
- package/dist/next/routing/route-map.js +5 -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/categories-seed-data.js +69 -0
- package/dist/seed/products-auctions-seed-data.js +11 -0
- package/dist/seed/products-standard-seed-data.js +93 -4
- package/dist/seed/site-settings-seed-data.js +13 -1
- package/dist/seed/store-extensions-seed-data.js +1 -1
- package/dist/server-entry.d.ts +2 -1
- package/dist/server-entry.js +20 -2
- package/dist/server.d.ts +7 -2
- package/dist/server.js +8 -3
- package/dist/styles.css +1 -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/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 +3 -1
- package/dist/utils/media-url.js +20 -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
|
@@ -35,7 +35,12 @@ export interface DashboardLayoutClientProps {
|
|
|
35
35
|
permissions?: string[] | null;
|
|
36
36
|
/** Override active-link highlight. Defaults to usePathname(). */
|
|
37
37
|
activeHref?: string;
|
|
38
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* Responsive controls — accepted for interface parity with the generic
|
|
40
|
+
* `SectionResponsive` shape used elsewhere, but not currently honoured by
|
|
41
|
+
* this component (no caller passes it today). Wire `hideAt`/`showAt`/
|
|
42
|
+
* `compactAt` to real chrome behaviour before relying on this prop.
|
|
43
|
+
*/
|
|
39
44
|
responsive?: SectionResponsive;
|
|
40
45
|
/**
|
|
41
46
|
* Cross-dashboard nav links shown in the sidebar footer. Plain hrefs
|
|
@@ -155,7 +155,10 @@ function DashboardBottomNav({ items, activeHref }) {
|
|
|
155
155
|
const DEFAULT_CONTENT_PADDING_RIGHT = "px-[var(--appkit-space-5)] py-[var(--appkit-space-8)] lg:pl-14 lg:pr-6 xl:pl-16 xl:pr-10";
|
|
156
156
|
const DEFAULT_CONTENT_PADDING_LEFT = "px-[var(--appkit-space-5)] py-[var(--appkit-space-8)] lg:pr-14 lg:pl-6 xl:pr-16 xl:pl-10";
|
|
157
157
|
const DEFAULT_CONTENT_MAX_WIDTH = "max-w-screen-2xl";
|
|
158
|
-
export function DashboardLayoutClient({ variant, groups, permissions, activeHref: explicitActiveHref,
|
|
158
|
+
export function DashboardLayoutClient({ variant, groups, permissions, activeHref: explicitActiveHref,
|
|
159
|
+
// audit-dead-underscore-prop-ok: accepted for interface parity, not yet
|
|
160
|
+
// wired — see the doc comment on `responsive` above; no caller passes it.
|
|
161
|
+
responsive: _responsive, crossNav, className, contentPadding, contentSurface, contentMaxWidth, lightBackground, darkBackground, children, }) {
|
|
159
162
|
const pathname = usePathname();
|
|
160
163
|
const activeHref = explicitActiveHref ?? pathname ?? "";
|
|
161
164
|
const storageKey = `appkit:sidebar-open:${variant}`;
|
|
@@ -16,5 +16,5 @@ interface LotteryPullFormProps {
|
|
|
16
16
|
* Submits TX ID + phone + payment time + item number.
|
|
17
17
|
* On success, shows the user their lottery number and assigned prize slot.
|
|
18
18
|
*/
|
|
19
|
-
export declare function LotteryPullForm({ sourceType, eventId, productId, totalSlots, maxPullsPerUser
|
|
19
|
+
export declare function LotteryPullForm({ sourceType, eventId, productId, totalSlots, maxPullsPerUser, onSuccess, }: LotteryPullFormProps): React.JSX.Element;
|
|
20
20
|
export {};
|
|
@@ -10,7 +10,7 @@ import { apiClient } from "../../../../http";
|
|
|
10
10
|
* Submits TX ID + phone + payment time + item number.
|
|
11
11
|
* On success, shows the user their lottery number and assigned prize slot.
|
|
12
12
|
*/
|
|
13
|
-
export function LotteryPullForm({ sourceType, eventId, productId, totalSlots, maxPullsPerUser
|
|
13
|
+
export function LotteryPullForm({ sourceType, eventId, productId, totalSlots, maxPullsPerUser, onSuccess, }) {
|
|
14
14
|
const [result, setResult] = useState(null);
|
|
15
15
|
const [transactionId, setTransactionId] = useState("");
|
|
16
16
|
const [paymentTime, setPaymentTime] = useState("");
|
|
@@ -39,7 +39,7 @@ export function LotteryPullForm({ sourceType, eventId, productId, totalSlots, ma
|
|
|
39
39
|
if (result) {
|
|
40
40
|
return (_jsxs(Stack, { gap: "sm", padding: "md", rounded: "2xl", surface: "success-surface", className: "border border-success/20", children: [_jsxs(Row, { align: "center", gap: "sm", children: [_jsx(Span, { layout: "inline-flex", color: "inverse", weight: "semibold", className: "bg-success text-[11px] tracking-wide", padding: "pill-sm", rounded: "full", transform: "uppercase", children: "Entry Confirmed" }), _jsxs(Heading, { level: 2, className: "text-success", size: "lg", weight: "bold", children: ["You're #", result.userLotteryNumber, "!"] })] }), _jsxs(Text, { className: "text-success", size: "sm", children: ["You've been assigned", " ", _jsxs(Span, { weight: "bold", children: ["Slot #", result.assignedPrizeSlotNumber] }), result.slotName ? ` — ${result.slotName}` : "", ". Good luck!"] })] }));
|
|
41
41
|
}
|
|
42
|
-
return (_jsx(Form, { onSubmit: (e) => e.preventDefault(), className: "space-y-4", children: ({ setFieldError, clearErrors }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, size: "lg", weight: "semibold", children: "Submit Your Entry" }),
|
|
42
|
+
return (_jsx(Form, { onSubmit: (e) => e.preventDefault(), className: "space-y-4", children: ({ setFieldError, clearErrors }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, size: "lg", weight: "semibold", children: "Submit Your Entry" }), _jsxs(Text, { size: "sm", color: "muted", children: ["Enter your UPI Transaction ID and payment details to claim your slot.", " ", "You may enter up to ", maxPullsPerUser, " time", maxPullsPerUser === 1 ? "" : "s", "."] }), _jsx(FieldInput, { name: "transactionId", label: "Transaction ID (UPI Ref / Payment Ref)", placeholder: "e.g. 123456789012", required: true, value: transactionId, onChange: (v) => { setTransactionId(v); clearErrors(); } }), _jsx(FieldInput, { name: "paymentTime", label: "Payment Date & Time", type: "datetime-local", required: true, value: paymentTime, onChange: (v) => { setPaymentTime(v); clearErrors(); } }), _jsx(FieldInput, { name: "itemNumber", label: `Slot Number (1 – ${totalSlots})`, type: "number", placeholder: `Enter a number between 1 and ${totalSlots}`, required: true, value: itemNumber, onChange: (v) => { setItemNumber(v); clearErrors(); } }), _jsx(FieldInput, { name: "userPhone", label: "Your Phone Number", type: "tel", placeholder: "e.g. 9876543210", required: true, value: userPhone, onChange: (v) => { setUserPhone(v); clearErrors(); } }), _jsx(Button, { type: "submit", variant: "primary", isLoading: mutation.isPending, onClick: () => {
|
|
43
43
|
clearErrors();
|
|
44
44
|
const num = parseInt(itemNumber, 10);
|
|
45
45
|
let valid = true;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manual trigger for the daily status digest.
|
|
3
|
+
*
|
|
4
|
+
* The digest normally runs from the `dailyStatusDigest` scheduled Firebase
|
|
5
|
+
* Function (10:00 IST). Firebase has no "run on first deploy" trigger, so
|
|
6
|
+
* this exists to fire the exact same core function on demand — e.g. right
|
|
7
|
+
* after a fresh deploy, to confirm the whole chain works without waiting
|
|
8
|
+
* for the next morning. Both paths share one implementation; there is no
|
|
9
|
+
* second copy of the digest logic.
|
|
10
|
+
*/
|
|
11
|
+
import { type DailyStatusDigestResult } from "../../jobs/core/dailyStatusDigest";
|
|
12
|
+
export declare function triggerDailyStatusDigest(): Promise<DailyStatusDigestResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Fires the digest once per deployment version, from server startup.
|
|
15
|
+
* Safe to call on every cold start — `runDeploymentDigest` claims the
|
|
16
|
+
* version in a Firestore transaction and no-ops if it's already been sent.
|
|
17
|
+
*/
|
|
18
|
+
export declare function triggerDeploymentDigest(version: string): Promise<DailyStatusDigestResult>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manual trigger for the daily status digest.
|
|
3
|
+
*
|
|
4
|
+
* The digest normally runs from the `dailyStatusDigest` scheduled Firebase
|
|
5
|
+
* Function (10:00 IST). Firebase has no "run on first deploy" trigger, so
|
|
6
|
+
* this exists to fire the exact same core function on demand — e.g. right
|
|
7
|
+
* after a fresh deploy, to confirm the whole chain works without waiting
|
|
8
|
+
* for the next morning. Both paths share one implementation; there is no
|
|
9
|
+
* second copy of the digest logic.
|
|
10
|
+
*/
|
|
11
|
+
import { getAdminDb } from "../../../../providers/db-firebase";
|
|
12
|
+
import { serverLogger } from "../../../../monitoring";
|
|
13
|
+
import { runDailyStatusDigest, runDeploymentDigest, } from "../../jobs/core/dailyStatusDigest";
|
|
14
|
+
function buildManualJobContext(job) {
|
|
15
|
+
return {
|
|
16
|
+
job,
|
|
17
|
+
db: getAdminDb(),
|
|
18
|
+
logger: {
|
|
19
|
+
info: (message, meta) => serverLogger.info(message, meta),
|
|
20
|
+
warn: (message, meta) => serverLogger.warn(message, meta),
|
|
21
|
+
error: (message, err, meta) => serverLogger.error(message, { err, ...(meta ?? {}) }),
|
|
22
|
+
},
|
|
23
|
+
env: (key) => process.env[key],
|
|
24
|
+
now: new Date(),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export async function triggerDailyStatusDigest() {
|
|
28
|
+
return runDailyStatusDigest(buildManualJobContext("dailyStatusDigest:manual"));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Fires the digest once per deployment version, from server startup.
|
|
32
|
+
* Safe to call on every cold start — `runDeploymentDigest` claims the
|
|
33
|
+
* version in a Firestore transaction and no-ops if it's already been sent.
|
|
34
|
+
*/
|
|
35
|
+
export async function triggerDeploymentDigest(version) {
|
|
36
|
+
return runDeploymentDigest(buildManualJobContext("dailyStatusDigest:deploy"), version);
|
|
37
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* recordAdminAction — the single write-site for the admin audit trail.
|
|
3
|
+
*
|
|
4
|
+
* MVP scope: instruments the highest-value already-privileged admin actions
|
|
5
|
+
* (bans, checkout bypass, coupon edits, payout mark-paid, store status
|
|
6
|
+
* changes, role changes) rather than sweeping every write path in the app —
|
|
7
|
+
* see CLAUDE.md's "Admin Audit Log" section for the full instrumented-action
|
|
8
|
+
* list and rationale.
|
|
9
|
+
*
|
|
10
|
+
* Callers should treat this as best-effort/non-blocking — a failure to write
|
|
11
|
+
* an audit entry must never fail the underlying privileged action itself.
|
|
12
|
+
*/
|
|
13
|
+
import type { AdminAuditAction } from "../../../../features/audit-log/schemas/firestore";
|
|
14
|
+
import type { JsonValue } from "../../../../schemas/types";
|
|
15
|
+
export interface RecordAdminActionInput {
|
|
16
|
+
actorUid: string;
|
|
17
|
+
actorName?: string;
|
|
18
|
+
action: AdminAuditAction;
|
|
19
|
+
targetType: string;
|
|
20
|
+
targetId: string;
|
|
21
|
+
targetLabel?: string;
|
|
22
|
+
reason?: string;
|
|
23
|
+
metadata?: Record<string, JsonValue>;
|
|
24
|
+
}
|
|
25
|
+
export declare function recordAdminAction(input: RecordAdminActionInput): Promise<void>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* recordAdminAction — the single write-site for the admin audit trail.
|
|
3
|
+
*
|
|
4
|
+
* MVP scope: instruments the highest-value already-privileged admin actions
|
|
5
|
+
* (bans, checkout bypass, coupon edits, payout mark-paid, store status
|
|
6
|
+
* changes, role changes) rather than sweeping every write path in the app —
|
|
7
|
+
* see CLAUDE.md's "Admin Audit Log" section for the full instrumented-action
|
|
8
|
+
* list and rationale.
|
|
9
|
+
*
|
|
10
|
+
* Callers should treat this as best-effort/non-blocking — a failure to write
|
|
11
|
+
* an audit entry must never fail the underlying privileged action itself.
|
|
12
|
+
*/
|
|
13
|
+
import { adminAuditLogRepository } from "../../../../features/audit-log/repository/audit-log.repository";
|
|
14
|
+
import { normalizeError } from "../../../../errors/normalize";
|
|
15
|
+
import { serverLogger } from "../../../../monitoring";
|
|
16
|
+
export async function recordAdminAction(input) {
|
|
17
|
+
try {
|
|
18
|
+
await adminAuditLogRepository.create({
|
|
19
|
+
actorUid: input.actorUid,
|
|
20
|
+
actorName: input.actorName,
|
|
21
|
+
action: input.action,
|
|
22
|
+
targetType: input.targetType,
|
|
23
|
+
targetId: input.targetId,
|
|
24
|
+
targetLabel: input.targetLabel,
|
|
25
|
+
reason: input.reason,
|
|
26
|
+
metadata: input.metadata,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
const normalized = normalizeError(err);
|
|
31
|
+
serverLogger.warn("recordAdminAction failed (non-critical)", {
|
|
32
|
+
action: input.action,
|
|
33
|
+
targetType: input.targetType,
|
|
34
|
+
targetId: input.targetId,
|
|
35
|
+
error: normalized.message,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -26,8 +26,6 @@ function brandInputToCategoryFields(input) {
|
|
|
26
26
|
out.brandCountry = input.country;
|
|
27
27
|
if (input.founded !== undefined)
|
|
28
28
|
out.brandFounded = input.founded;
|
|
29
|
-
if (input.bannerURL !== undefined)
|
|
30
|
-
out.brandBannerImage = input.bannerURL;
|
|
31
29
|
if (input.logoURL !== undefined) {
|
|
32
30
|
out.display = { coverImage: input.logoURL, showInMenu: false, showInFooter: false };
|
|
33
31
|
}
|
|
@@ -7,7 +7,10 @@ export interface BrandOgData {
|
|
|
7
7
|
interface BrandDocLike {
|
|
8
8
|
name?: string | null;
|
|
9
9
|
description?: string | null;
|
|
10
|
-
logoURL
|
|
10
|
+
/** CategoryDocument has no `logoURL` field — the brand's image lives at `display.coverImage`, the same field the hero banner and generateMetadata's OG meta tag already use. */
|
|
11
|
+
display?: {
|
|
12
|
+
coverImage?: string | null;
|
|
13
|
+
} | null;
|
|
11
14
|
}
|
|
12
15
|
/** High-level OG renderer — accepts the raw brand document from `getBrandForDetail`. */
|
|
13
16
|
export declare function renderBrandOg(doc: BrandDocLike | null | undefined, opts: {
|
|
@@ -7,7 +7,7 @@ export function renderBrandOg(doc, opts) {
|
|
|
7
7
|
name,
|
|
8
8
|
description: doc?.description?.slice(0, 120) ??
|
|
9
9
|
`Shop authentic ${name} collectibles on ${opts.siteName}.`,
|
|
10
|
-
logoUrl: resolveOgImageUrl(doc?.
|
|
10
|
+
logoUrl: resolveOgImageUrl(doc?.display?.coverImage ?? null, opts.baseUrl),
|
|
11
11
|
}, opts.siteName);
|
|
12
12
|
}
|
|
13
13
|
export function renderBrandOgImage(data, siteName) {
|
|
@@ -30,6 +30,10 @@ export declare const getGroupsForProduct: (productId: string) => Promise<Grouped
|
|
|
30
30
|
* to render directly as a public GroupedListingsCarousel section.
|
|
31
31
|
*/
|
|
32
32
|
export declare const getGroupsWithItemsForProduct: (productId: string) => Promise<GroupedListingWithItems[]>;
|
|
33
|
+
/** Groups tagged to a category, hydrated with all member products — for the category detail page's GroupedListingsCarousel. */
|
|
34
|
+
export declare const getGroupsForCategory: (categorySlug: string) => Promise<GroupedListingWithItems[]>;
|
|
35
|
+
/** Groups tagged to a brand, hydrated with all member products — for the brand detail page's GroupedListingsCarousel. */
|
|
36
|
+
export declare const getGroupsForBrand: (brandSlug: string) => Promise<GroupedListingWithItems[]>;
|
|
33
37
|
export interface SitemapGroupedListing {
|
|
34
38
|
slug: string;
|
|
35
39
|
updatedAt: Date;
|
|
@@ -132,6 +132,30 @@ export const getGroupsWithItemsForProduct = cache(async (productId) => {
|
|
|
132
132
|
return { ...group, items: items.filter((p) => p !== null) };
|
|
133
133
|
}));
|
|
134
134
|
});
|
|
135
|
+
/** Groups tagged to a category, hydrated with all member products — for the category detail page's GroupedListingsCarousel. */
|
|
136
|
+
export const getGroupsForCategory = cache(async (categorySlug) => {
|
|
137
|
+
const groups = await groupedListingsRepository.findByCategorySlug(categorySlug).catch((err) => {
|
|
138
|
+
void normalizeError(err);
|
|
139
|
+
serverLogger.warn("grouped-data: getGroupsForCategory failed — returning empty", { categorySlug, error: err instanceof Error ? err.message : String(err) });
|
|
140
|
+
return [];
|
|
141
|
+
});
|
|
142
|
+
return Promise.all(groups.map(async (group) => {
|
|
143
|
+
const items = await Promise.all(group.productIds.map((id) => productRepository.findByIdOrSlug(id).catch(() => null)));
|
|
144
|
+
return { ...group, items: items.filter((p) => p !== null) };
|
|
145
|
+
}));
|
|
146
|
+
});
|
|
147
|
+
/** Groups tagged to a brand, hydrated with all member products — for the brand detail page's GroupedListingsCarousel. */
|
|
148
|
+
export const getGroupsForBrand = cache(async (brandSlug) => {
|
|
149
|
+
const groups = await groupedListingsRepository.findByBrandSlug(brandSlug).catch((err) => {
|
|
150
|
+
void normalizeError(err);
|
|
151
|
+
serverLogger.warn("grouped-data: getGroupsForBrand failed — returning empty", { brandSlug, error: err instanceof Error ? err.message : String(err) });
|
|
152
|
+
return [];
|
|
153
|
+
});
|
|
154
|
+
return Promise.all(groups.map(async (group) => {
|
|
155
|
+
const items = await Promise.all(group.productIds.map((id) => productRepository.findByIdOrSlug(id).catch(() => null)));
|
|
156
|
+
return { ...group, items: items.filter((p) => p !== null) };
|
|
157
|
+
}));
|
|
158
|
+
});
|
|
135
159
|
export async function listSitemapGroupedListings() {
|
|
136
160
|
try {
|
|
137
161
|
const db = getAdminDb();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { getGroupedListingForDetail, getGroupedListingWithItems, listGroupedListings, listFeaturedGroupedListings, listSitemapGroupedListings, getGroupsForProduct, getGroupsWithItemsForProduct, type GroupedListingWithItems, type ListGroupedListingsParams, type SitemapGroupedListing, } from "./data";
|
|
1
|
+
export { getGroupedListingForDetail, getGroupedListingWithItems, listGroupedListings, listFeaturedGroupedListings, listSitemapGroupedListings, getGroupsForProduct, getGroupsWithItemsForProduct, getGroupsForCategory, getGroupsForBrand, type GroupedListingWithItems, type ListGroupedListingsParams, type SitemapGroupedListing, } from "./data";
|
|
2
2
|
export { GROUPED_LISTINGS_PAGE_SIZE, GROUPED_LISTINGS_FEATURED_LIMIT, GROUPED_LISTINGS_SITEMAP_LIMIT, } from "../../../shared/features/grouped/config";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { getGroupedListingForDetail, getGroupedListingWithItems, listGroupedListings, listFeaturedGroupedListings, listSitemapGroupedListings, getGroupsForProduct, getGroupsWithItemsForProduct, } from "./data";
|
|
1
|
+
export { getGroupedListingForDetail, getGroupedListingWithItems, listGroupedListings, listFeaturedGroupedListings, listSitemapGroupedListings, getGroupsForProduct, getGroupsWithItemsForProduct, getGroupsForCategory, getGroupsForBrand, } from "./data";
|
|
2
2
|
export { GROUPED_LISTINGS_PAGE_SIZE, GROUPED_LISTINGS_FEATURED_LIMIT, GROUPED_LISTINGS_SITEMAP_LIMIT, } from "../../../shared/features/grouped/config";
|
|
@@ -161,6 +161,15 @@ export async function attachPaymentProofAction(orderId, proof) {
|
|
|
161
161
|
buyerFraudAgreementAcceptedAt: new Date(),
|
|
162
162
|
buyerReportedUpiId: proof.buyerReportedUpiId,
|
|
163
163
|
paymentUpiMismatch,
|
|
164
|
+
// A re-upload after `adminRequestProofReuploadAction` must clear the
|
|
165
|
+
// stale `reupload_requested` outcome. Both the 2-hour auto-approve
|
|
166
|
+
// sweep (`getUnreviewedProofPastDeadline`) and the admin
|
|
167
|
+
// "Awaiting verification" queue treat *any* set outcome as "already
|
|
168
|
+
// decided" — leaving it set meant a corrected proof was invisible to
|
|
169
|
+
// both: never auto-approved, never surfaced for manual review.
|
|
170
|
+
paymentReviewOutcome: null,
|
|
171
|
+
paymentReviewedBy: null,
|
|
172
|
+
paymentReviewedAt: null,
|
|
164
173
|
});
|
|
165
174
|
notifyAdminsOfPaymentProof({
|
|
166
175
|
id: orderId,
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
function toIsoOrUndefined(value) {
|
|
2
|
+
return value instanceof Date ? value.toISOString() : undefined;
|
|
3
|
+
}
|
|
1
4
|
export function orderDocumentToOrder(doc) {
|
|
2
5
|
const items = doc.items?.length
|
|
3
6
|
? doc.items.map((item) => ({
|
|
@@ -55,10 +58,32 @@ export function orderDocumentToOrder(doc) {
|
|
|
55
58
|
couponCode: doc.couponCode,
|
|
56
59
|
trackingNumber: doc.trackingNumber,
|
|
57
60
|
shippingCarrier: doc.shippingCarrier,
|
|
61
|
+
trackingUrl: doc.trackingUrl,
|
|
58
62
|
notes: doc.notes,
|
|
63
|
+
orderDate: toIsoOrUndefined(doc.orderDate),
|
|
64
|
+
shippingDate: toIsoOrUndefined(doc.shippingDate),
|
|
65
|
+
deliveryDate: toIsoOrUndefined(doc.deliveryDate),
|
|
66
|
+
cancellationDate: toIsoOrUndefined(doc.cancellationDate),
|
|
59
67
|
autoApproved: doc.autoApproved,
|
|
60
68
|
disputeRaised: doc.disputeRaised,
|
|
61
69
|
disputeStatus: doc.disputeStatus,
|
|
70
|
+
// Manual-payment (cash / UPI / EMI) passthrough. These were previously
|
|
71
|
+
// dropped here, which silently disabled the entire buyer proof-upload
|
|
72
|
+
// flow: `/user/orders/[id]/payment` branches on `paymentMethod` and so
|
|
73
|
+
// rendered "this order does not require manual payment upload" for every
|
|
74
|
+
// order, with no UPI ID and no countdown.
|
|
75
|
+
paymentMethod: doc.paymentMethod,
|
|
76
|
+
displayedUpiId: doc.displayedUpiId,
|
|
77
|
+
paymentDeadline: toIsoOrUndefined(doc.paymentDeadline),
|
|
78
|
+
paymentProofUrl: doc.paymentProofUrl,
|
|
79
|
+
paymentProofUploadedAt: toIsoOrUndefined(doc.paymentProofUploadedAt),
|
|
80
|
+
paymentTransactionId: doc.paymentTransactionId,
|
|
81
|
+
buyerReportedUpiId: doc.buyerReportedUpiId,
|
|
82
|
+
buyerMarkedPaid: doc.buyerMarkedPaid,
|
|
83
|
+
paymentUpiMismatch: doc.paymentUpiMismatch,
|
|
84
|
+
paymentReviewOutcome: doc.paymentReviewOutcome,
|
|
85
|
+
paymentReviewNote: doc.paymentReviewNote,
|
|
86
|
+
cancellationReason: doc.cancellationReason,
|
|
62
87
|
createdAt: doc.createdAt instanceof Date
|
|
63
88
|
? doc.createdAt.toISOString()
|
|
64
89
|
: String(doc.createdAt),
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { toProductItem } from "../../../shared/features/products/to-product-item";
|
|
2
|
+
export { toProductItem };
|
|
1
3
|
import type { ProductDocument } from "../../../../features/products/schemas/firestore";
|
|
2
4
|
import type { ListingType } from "../../../../features/products/types";
|
|
3
5
|
import type { ProductItem } from "../../../../features/products/types";
|
|
@@ -26,8 +28,6 @@ export interface RelatedItemsResult {
|
|
|
26
28
|
relatedByTags: ProductItem[];
|
|
27
29
|
relatedByStore: ProductItem[];
|
|
28
30
|
}
|
|
29
|
-
/** Firestore doc → card-grid shape. Shared by every related/similar-items carousel. */
|
|
30
|
-
export declare function toProductItem(doc: FirestoreDocument): ProductItem;
|
|
31
31
|
/**
|
|
32
32
|
* Same 4-signal related-items computation used across every listing-type
|
|
33
33
|
* detail page (category / brand / tag-overlap / same-store), each excluding
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { cache } from "react";
|
|
2
|
+
// Imported (not just re-exported) because this module calls it internally.
|
|
3
|
+
// It lives in _internal/shared so `"use client"` components can import it
|
|
4
|
+
// without dragging this file's firebase-admin chain into the client bundle.
|
|
5
|
+
import { toProductItem } from "../../../shared/features/products/to-product-item";
|
|
6
|
+
export { toProductItem };
|
|
2
7
|
import { productRepository } from "../../../../repositories";
|
|
3
8
|
import { reviewRepository } from "../../../../repositories";
|
|
4
9
|
import { getAdminDb } from "../../../../providers/db-firebase";
|
|
@@ -94,29 +99,6 @@ export async function listSitemapProducts() {
|
|
|
94
99
|
const RELATED_QUERY_PAGE_SIZE = 9;
|
|
95
100
|
const RELATED_DISPLAY_LIMIT = 8;
|
|
96
101
|
/** Firestore doc → card-grid shape. Shared by every related/similar-items carousel. */
|
|
97
|
-
export function toProductItem(doc) {
|
|
98
|
-
return {
|
|
99
|
-
id: String(doc.id ?? ""),
|
|
100
|
-
title: String(doc.title ?? doc.name ?? ""),
|
|
101
|
-
price: typeof doc.price === "number" ? doc.price : 0,
|
|
102
|
-
originalPrice: typeof doc.originalPrice === "number" ? doc.originalPrice : undefined,
|
|
103
|
-
mainImage: Array.isArray(doc.images)
|
|
104
|
-
? doc.images[0]
|
|
105
|
-
: typeof doc.mainImage === "string"
|
|
106
|
-
? doc.mainImage
|
|
107
|
-
: undefined,
|
|
108
|
-
status: doc.status ?? "published",
|
|
109
|
-
slug: typeof doc.slug === "string" ? doc.slug : undefined,
|
|
110
|
-
storeName: typeof doc.storeName === "string" ? doc.storeName : undefined,
|
|
111
|
-
rating: typeof doc.rating === "number" ? doc.rating : undefined,
|
|
112
|
-
reviewCount: typeof doc.reviewCount === "number" ? doc.reviewCount : undefined,
|
|
113
|
-
// Without this, every related-item card silently linked to the standard
|
|
114
|
-
// PDP regardless of its real type (pluginFor() defaults to "standard"
|
|
115
|
-
// when listingType is missing) — same bug class as the Phase 1 routing
|
|
116
|
-
// fix, one hop further downstream in the related-items card link path.
|
|
117
|
-
listingType: doc.listingType ?? undefined,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
102
|
/**
|
|
121
103
|
* Excludes the current product plus any listing-type-specific "invalid to
|
|
122
104
|
* surface as related" state: sold/archived/out-of-stock/draft, ended
|
|
@@ -7,6 +7,7 @@ export declare const couponExpiry: import("./types").ScheduledFunctionDefinition
|
|
|
7
7
|
export declare const offerExpiry: import("./types").ScheduledFunctionDefinition;
|
|
8
8
|
export declare const productStatsSync: import("./types").ScheduledFunctionDefinition;
|
|
9
9
|
export declare const revenueRollup: import("./types").ScheduledFunctionDefinition;
|
|
10
|
+
export declare const dailyStatusDigest: import("./types").ScheduledFunctionDefinition;
|
|
10
11
|
export declare const dailyDataCleanup: import("./types").ScheduledFunctionDefinition;
|
|
11
12
|
export declare const countersReconcile: import("./types").ScheduledFunctionDefinition;
|
|
12
13
|
export declare const positionsReconcile: import("./types").ScheduledFunctionDefinition;
|
|
@@ -19,8 +20,9 @@ export declare const cleanupRtdbEvents: import("./types").ScheduledFunctionDefin
|
|
|
19
20
|
export declare const mediaTmpCleanup: import("./types").ScheduledFunctionDefinition;
|
|
20
21
|
export declare const draftPrune: import("./types").ScheduledFunctionDefinition;
|
|
21
22
|
export declare const testerSandboxCleanup: import("./types").ScheduledFunctionDefinition;
|
|
23
|
+
export declare const testerSandboxRefresh: import("./types").ScheduledFunctionDefinition;
|
|
22
24
|
export declare const prizeDrawExpiryReveal: import("./types").ScheduledFunctionDefinition;
|
|
23
25
|
export declare const bundleStockSync: import("./types").ScheduledFunctionDefinition;
|
|
24
26
|
export declare const emiInstallmentReminder: import("./types").ScheduledFunctionDefinition;
|
|
25
27
|
export declare const catalogueImageStalenessReminder: import("./types").ScheduledFunctionDefinition;
|
|
26
|
-
export declare const SCHEDULED_FUNCTIONS: readonly [import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition];
|
|
28
|
+
export declare const SCHEDULED_FUNCTIONS: readonly [import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Scheduled function definitions (Cloud Scheduler triggers).
|
|
2
2
|
// Cron syntax accepts both Firebase shorthand and standard cron expressions.
|
|
3
|
-
import { auctionSettlementHandler, autoPayoutEligibilityHandler, bundleStockSyncHandler, cartPruneHandler, cleanupRtdbEventsHandler, countersReconcileHandler, couponExpiryHandler, dailyDataCleanupHandler, draftPruneHandler, emiInstallmentReminderHandler, catalogueImageStalenessReminderHandler, mediaTmpCleanupHandler, notificationPruneHandler, offerExpiryHandler, payoutBatchHandler, paymentWindowTimeoutHandler, hardBanReinstatementHandler, paymentReviewAutoApproveHandler, pendingOrderTimeoutHandler, positionsReconcileHandler, prizeDrawExpiryRevealHandler, productStatsSyncHandler, revenueRollupHandler, weeklyPayoutEligibilityHandler, testerSandboxCleanupHandler, } from "../jobs/handlers";
|
|
3
|
+
import { auctionSettlementHandler, autoPayoutEligibilityHandler, bundleStockSyncHandler, cartPruneHandler, cleanupRtdbEventsHandler, countersReconcileHandler, couponExpiryHandler, dailyDataCleanupHandler, draftPruneHandler, emiInstallmentReminderHandler, catalogueImageStalenessReminderHandler, mediaTmpCleanupHandler, notificationPruneHandler, offerExpiryHandler, payoutBatchHandler, paymentWindowTimeoutHandler, hardBanReinstatementHandler, paymentReviewAutoApproveHandler, pendingOrderTimeoutHandler, positionsReconcileHandler, prizeDrawExpiryRevealHandler, productStatsSyncHandler, revenueRollupHandler, dailyStatusDigestHandler, weeklyPayoutEligibilityHandler, testerSandboxCleanupHandler, testerSandboxRefreshHandler, } from "../jobs/handlers";
|
|
4
4
|
import { defineFunction } from "./define";
|
|
5
5
|
const REGION = "asia-south1";
|
|
6
6
|
const EVERY_5_MIN = "every 5 minutes";
|
|
@@ -67,6 +67,13 @@ export const revenueRollup = defineFunction({
|
|
|
67
67
|
handler: revenueRollupHandler,
|
|
68
68
|
options: { region: REGION, timeoutSeconds: 300, memory: "256MiB", maxInstances: 1 },
|
|
69
69
|
});
|
|
70
|
+
export const dailyStatusDigest = defineFunction({
|
|
71
|
+
name: "dailyStatusDigest",
|
|
72
|
+
description: "Email the previous 24h order summary + platform status to the team every morning at 10:00 IST.",
|
|
73
|
+
trigger: { kind: "schedule", cron: "0 10 * * *", timeZone: "Asia/Kolkata" },
|
|
74
|
+
handler: dailyStatusDigestHandler,
|
|
75
|
+
options: { region: REGION, timeoutSeconds: 120, memory: "256MiB", maxInstances: 1 },
|
|
76
|
+
});
|
|
70
77
|
export const dailyDataCleanup = defineFunction({
|
|
71
78
|
name: "dailyDataCleanup",
|
|
72
79
|
description: "Daily data cleanup (drafts, transient records) at 02:00 UTC.",
|
|
@@ -151,6 +158,13 @@ export const testerSandboxCleanup = defineFunction({
|
|
|
151
158
|
handler: testerSandboxCleanupHandler,
|
|
152
159
|
options: { region: REGION, timeoutSeconds: 300, memory: "256MiB", maxInstances: 1 },
|
|
153
160
|
});
|
|
161
|
+
export const testerSandboxRefresh = defineFunction({
|
|
162
|
+
name: "testerSandboxRefresh",
|
|
163
|
+
description: "Revert live tester QA sandbox fixtures to their canonical seed shape and prune tester-created extras (every 4 hours).",
|
|
164
|
+
trigger: { kind: "schedule", cron: "0 */4 * * *", timeZone: "UTC" },
|
|
165
|
+
handler: testerSandboxRefreshHandler,
|
|
166
|
+
options: { region: REGION, timeoutSeconds: 300, memory: "256MiB", maxInstances: 1 },
|
|
167
|
+
});
|
|
154
168
|
export const prizeDrawExpiryReveal = defineFunction({
|
|
155
169
|
name: "prizeDrawExpiryReveal",
|
|
156
170
|
description: "Assign winners for outstanding paid orders on scheduled-mode prize draws past their expiry, then close them (every 5 minutes).",
|
|
@@ -189,6 +203,7 @@ export const SCHEDULED_FUNCTIONS = [
|
|
|
189
203
|
offerExpiry,
|
|
190
204
|
productStatsSync,
|
|
191
205
|
revenueRollup,
|
|
206
|
+
dailyStatusDigest,
|
|
192
207
|
dailyDataCleanup,
|
|
193
208
|
countersReconcile,
|
|
194
209
|
positionsReconcile,
|
|
@@ -201,6 +216,7 @@ export const SCHEDULED_FUNCTIONS = [
|
|
|
201
216
|
mediaTmpCleanup,
|
|
202
217
|
draftPrune,
|
|
203
218
|
testerSandboxCleanup,
|
|
219
|
+
testerSandboxRefresh,
|
|
204
220
|
prizeDrawExpiryReveal,
|
|
205
221
|
bundleStockSync,
|
|
206
222
|
emiInstallmentReminder,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core: daily status digest email.
|
|
3
|
+
*
|
|
4
|
+
* Emails the previous 24h of order activity to the team every morning. The
|
|
5
|
+
* digest's arrival is itself the platform health signal — if it stops
|
|
6
|
+
* landing, something in the Firestore → Functions → Resend chain needs a
|
|
7
|
+
* look. Deliberately no separate error/exception tracking: there is no
|
|
8
|
+
* structured error-log collection to query, and building one just to fill
|
|
9
|
+
* this email would be scope no one asked for.
|
|
10
|
+
*
|
|
11
|
+
* Runs from a scheduled Firebase Function (not a Vercel route), so the
|
|
12
|
+
* unbounded-ish order scan below is safe against CLAUDE.md Rule #6's 10s
|
|
13
|
+
* sync ceiling — it has the Function's much larger budget.
|
|
14
|
+
*/
|
|
15
|
+
import type { JobContext } from "../runtime/types";
|
|
16
|
+
export interface DailyStatusDigestSummary {
|
|
17
|
+
orderCount: number;
|
|
18
|
+
revenue: number;
|
|
19
|
+
statusBreakdown: Record<string, number>;
|
|
20
|
+
stuckPendingCount: number;
|
|
21
|
+
activeListingCount: number;
|
|
22
|
+
}
|
|
23
|
+
/** Gathers the last-24h numbers. Exported so the admin manual-trigger route can reuse it. */
|
|
24
|
+
export declare function collectDailyStatusSummary(): Promise<DailyStatusDigestSummary>;
|
|
25
|
+
export interface DailyStatusDigestResult {
|
|
26
|
+
sent: boolean;
|
|
27
|
+
reason?: string;
|
|
28
|
+
summary?: DailyStatusDigestSummary;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Sends the digest once per deployment version.
|
|
32
|
+
*
|
|
33
|
+
* Called from server startup. On Vercel that means EVERY lambda cold start,
|
|
34
|
+
* not once per deploy — so the version marker below is what makes this a
|
|
35
|
+
* per-deployment event rather than a per-cold-start email storm. The claim
|
|
36
|
+
* runs in a transaction because several cold starts can race on the first
|
|
37
|
+
* request after a deploy; exactly one wins and sends.
|
|
38
|
+
*/
|
|
39
|
+
export declare function runDeploymentDigest(ctx: JobContext, version: string): Promise<DailyStatusDigestResult>;
|
|
40
|
+
export declare function runDailyStatusDigest(ctx: JobContext, version?: string): Promise<DailyStatusDigestResult>;
|