@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
|
@@ -570,15 +570,6 @@ export declare const orderFirestoreSchema: z.ZodObject<{
|
|
|
570
570
|
bin: string;
|
|
571
571
|
} | undefined;
|
|
572
572
|
payoutStatus?: "paid" | "eligible" | "requested" | undefined;
|
|
573
|
-
items?: {
|
|
574
|
-
productId: string;
|
|
575
|
-
productTitle: string;
|
|
576
|
-
quantity: number;
|
|
577
|
-
unitPrice: number;
|
|
578
|
-
totalPrice: number;
|
|
579
|
-
listingType?: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live" | undefined;
|
|
580
|
-
prizeRevealStatus?: "closed" | "open" | "pending" | "revealed" | undefined;
|
|
581
|
-
}[] | undefined;
|
|
582
573
|
paymentId?: string | undefined;
|
|
583
574
|
shippingAddress?: string | undefined;
|
|
584
575
|
trackingNumber?: string | undefined;
|
|
@@ -601,6 +592,15 @@ export declare const orderFirestoreSchema: z.ZodObject<{
|
|
|
601
592
|
shippingMethod?: "custom" | undefined;
|
|
602
593
|
shippingCarrier?: string | undefined;
|
|
603
594
|
trackingUrl?: string | undefined;
|
|
595
|
+
items?: {
|
|
596
|
+
productId: string;
|
|
597
|
+
productTitle: string;
|
|
598
|
+
quantity: number;
|
|
599
|
+
unitPrice: number;
|
|
600
|
+
totalPrice: number;
|
|
601
|
+
listingType?: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live" | undefined;
|
|
602
|
+
prizeRevealStatus?: "closed" | "open" | "pending" | "revealed" | undefined;
|
|
603
|
+
}[] | undefined;
|
|
604
604
|
bundleId?: string | undefined;
|
|
605
605
|
prizeWon?: {
|
|
606
606
|
title: string;
|
|
@@ -612,6 +612,8 @@ export declare const orderFirestoreSchema: z.ZodObject<{
|
|
|
612
612
|
} | undefined;
|
|
613
613
|
prizeDrawProductId?: string | undefined;
|
|
614
614
|
couponCode?: string | undefined;
|
|
615
|
+
emiEnabled?: boolean | undefined;
|
|
616
|
+
emiTenureMonths?: number | undefined;
|
|
615
617
|
orderType?: string | undefined;
|
|
616
618
|
imageUrls?: string[] | undefined;
|
|
617
619
|
refundFeeDeducted?: number | undefined;
|
|
@@ -627,8 +629,6 @@ export declare const orderFirestoreSchema: z.ZodObject<{
|
|
|
627
629
|
couponId?: string | undefined;
|
|
628
630
|
}[] | undefined;
|
|
629
631
|
codHandlingFee?: number | undefined;
|
|
630
|
-
emiEnabled?: boolean | undefined;
|
|
631
|
-
emiTenureMonths?: number | undefined;
|
|
632
632
|
emiTokenAmount?: number | undefined;
|
|
633
633
|
emiSurchargeAmount?: number | undefined;
|
|
634
634
|
emiInstallments?: {
|
|
@@ -718,15 +718,6 @@ export declare const orderFirestoreSchema: z.ZodObject<{
|
|
|
718
718
|
bin: string;
|
|
719
719
|
} | undefined;
|
|
720
720
|
payoutStatus?: "paid" | "eligible" | "requested" | undefined;
|
|
721
|
-
items?: {
|
|
722
|
-
productId: string;
|
|
723
|
-
productTitle: string;
|
|
724
|
-
quantity: number;
|
|
725
|
-
unitPrice: number;
|
|
726
|
-
totalPrice: number;
|
|
727
|
-
listingType?: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live" | undefined;
|
|
728
|
-
prizeRevealStatus?: "closed" | "open" | "pending" | "revealed" | undefined;
|
|
729
|
-
}[] | undefined;
|
|
730
721
|
paymentId?: string | undefined;
|
|
731
722
|
shippingAddress?: string | undefined;
|
|
732
723
|
trackingNumber?: string | undefined;
|
|
@@ -749,6 +740,15 @@ export declare const orderFirestoreSchema: z.ZodObject<{
|
|
|
749
740
|
shippingMethod?: "custom" | undefined;
|
|
750
741
|
shippingCarrier?: string | undefined;
|
|
751
742
|
trackingUrl?: string | undefined;
|
|
743
|
+
items?: {
|
|
744
|
+
productId: string;
|
|
745
|
+
productTitle: string;
|
|
746
|
+
quantity: number;
|
|
747
|
+
unitPrice: number;
|
|
748
|
+
totalPrice: number;
|
|
749
|
+
listingType?: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live" | undefined;
|
|
750
|
+
prizeRevealStatus?: "closed" | "open" | "pending" | "revealed" | undefined;
|
|
751
|
+
}[] | undefined;
|
|
752
752
|
bundleId?: string | undefined;
|
|
753
753
|
prizeWon?: {
|
|
754
754
|
title: string;
|
|
@@ -760,6 +760,8 @@ export declare const orderFirestoreSchema: z.ZodObject<{
|
|
|
760
760
|
} | undefined;
|
|
761
761
|
prizeDrawProductId?: string | undefined;
|
|
762
762
|
couponCode?: string | undefined;
|
|
763
|
+
emiEnabled?: boolean | undefined;
|
|
764
|
+
emiTenureMonths?: number | undefined;
|
|
763
765
|
orderType?: string | undefined;
|
|
764
766
|
imageUrls?: string[] | undefined;
|
|
765
767
|
refundFeeDeducted?: number | undefined;
|
|
@@ -775,8 +777,6 @@ export declare const orderFirestoreSchema: z.ZodObject<{
|
|
|
775
777
|
couponId?: string | undefined;
|
|
776
778
|
}[] | undefined;
|
|
777
779
|
codHandlingFee?: number | undefined;
|
|
778
|
-
emiEnabled?: boolean | undefined;
|
|
779
|
-
emiTenureMonths?: number | undefined;
|
|
780
780
|
emiTokenAmount?: number | undefined;
|
|
781
781
|
emiSurchargeAmount?: number | undefined;
|
|
782
782
|
emiInstallments?: {
|
|
@@ -962,6 +962,7 @@ export declare const orderSchema: z.ZodObject<{
|
|
|
962
962
|
[k: string]: unknown;
|
|
963
963
|
};
|
|
964
964
|
userId: string;
|
|
965
|
+
paymentStatus: string;
|
|
965
966
|
items: {
|
|
966
967
|
title: string;
|
|
967
968
|
price: number;
|
|
@@ -972,7 +973,6 @@ export declare const orderSchema: z.ZodObject<{
|
|
|
972
973
|
storeId?: string | undefined;
|
|
973
974
|
attributes?: Record<string, string> | undefined;
|
|
974
975
|
}[];
|
|
975
|
-
paymentStatus: string;
|
|
976
976
|
total: number;
|
|
977
977
|
subtotal: number;
|
|
978
978
|
orderStatus: "pending" | "cancelled" | "processing" | "refunded" | "delivered" | "confirmed" | "shipped" | "return_requested" | "returned";
|
|
@@ -999,6 +999,7 @@ export declare const orderSchema: z.ZodObject<{
|
|
|
999
999
|
[k: string]: unknown;
|
|
1000
1000
|
};
|
|
1001
1001
|
userId: string;
|
|
1002
|
+
paymentStatus: string;
|
|
1002
1003
|
items: {
|
|
1003
1004
|
title: string;
|
|
1004
1005
|
price: number;
|
|
@@ -1009,7 +1010,6 @@ export declare const orderSchema: z.ZodObject<{
|
|
|
1009
1010
|
storeId?: string | undefined;
|
|
1010
1011
|
attributes?: Record<string, string> | undefined;
|
|
1011
1012
|
}[];
|
|
1012
|
-
paymentStatus: string;
|
|
1013
1013
|
total: number;
|
|
1014
1014
|
subtotal: number;
|
|
1015
1015
|
orderStatus: "pending" | "cancelled" | "processing" | "refunded" | "delivered" | "confirmed" | "shipped" | "return_requested" | "returned";
|
|
@@ -67,6 +67,8 @@ export interface Order {
|
|
|
67
67
|
couponCode?: string;
|
|
68
68
|
trackingNumber?: string;
|
|
69
69
|
shippingCarrier?: string;
|
|
70
|
+
/** Carrier tracking page URL — rendered as an external link that opens in a new tab. No live-tracking API integration; this is just the passthrough URL a seller/admin entered. */
|
|
71
|
+
trackingUrl?: string;
|
|
70
72
|
notes?: string;
|
|
71
73
|
timeline?: OrderTimeline[];
|
|
72
74
|
physicalLocation?: {
|
|
@@ -76,10 +78,41 @@ export interface Order {
|
|
|
76
78
|
};
|
|
77
79
|
createdAt?: string;
|
|
78
80
|
updatedAt?: string;
|
|
81
|
+
/** Real per-status timestamps written by the order-status-update path — used to render a genuine status timeline (not fabricated/estimated). */
|
|
82
|
+
orderDate?: string;
|
|
83
|
+
shippingDate?: string;
|
|
84
|
+
deliveryDate?: string;
|
|
85
|
+
cancellationDate?: string;
|
|
79
86
|
/** Tier PP — true when the 2-hour auto-approve sweep confirmed this order's payment instead of a manual admin review. Drives the "Raise a dispute" CTA. */
|
|
80
87
|
autoApproved?: boolean;
|
|
81
88
|
disputeRaised?: boolean;
|
|
82
89
|
disputeStatus?: "open" | "resolved";
|
|
90
|
+
/**
|
|
91
|
+
* Manual-payment (cash / UPI / EMI) fields. Every one of these already
|
|
92
|
+
* existed on `OrderDocument` but was dropped by `orderDocumentToOrder`,
|
|
93
|
+
* so the buyer-facing surfaces that need them read `undefined`:
|
|
94
|
+
* `/user/orders/[id]/payment` gated its whole render on `paymentMethod`
|
|
95
|
+
* and therefore told every buyer "this order does not require manual
|
|
96
|
+
* payment upload", and the 15-minute countdown + UPI ID never rendered.
|
|
97
|
+
* (CLAUDE.md Root Cause Pattern #38 — adapter/serializer field drift.)
|
|
98
|
+
*/
|
|
99
|
+
paymentMethod?: string;
|
|
100
|
+
/** UPI ID the buyer was told to pay to — shown on the payment page and diffed against `buyerReportedUpiId` during admin review. */
|
|
101
|
+
displayedUpiId?: string;
|
|
102
|
+
/** ISO end of the 15-minute payment window; drives the buyer countdown. */
|
|
103
|
+
paymentDeadline?: string;
|
|
104
|
+
paymentProofUrl?: string;
|
|
105
|
+
paymentProofUploadedAt?: string;
|
|
106
|
+
paymentTransactionId?: string;
|
|
107
|
+
buyerReportedUpiId?: string;
|
|
108
|
+
buyerMarkedPaid?: boolean;
|
|
109
|
+
paymentUpiMismatch?: boolean;
|
|
110
|
+
/** Admin decision on the submitted proof; unset means "not reviewed yet". */
|
|
111
|
+
paymentReviewOutcome?: "approved" | "reupload_requested" | "rejected_fraud";
|
|
112
|
+
/** Admin's note — the reason shown to the buyer on a re-upload request or fraud rejection. */
|
|
113
|
+
paymentReviewNote?: string;
|
|
114
|
+
/** Why the order was cancelled — distinguishes a payment-window expiry / fraud rejection from an ordinary cancellation. */
|
|
115
|
+
cancellationReason?: string;
|
|
83
116
|
/**
|
|
84
117
|
* Reveal-mode prize-draw fields (SB4-H/SB8-C). Set once the winner has
|
|
85
118
|
* been automatically assigned to this order (on payment confirmation,
|
|
@@ -21,6 +21,7 @@ export declare const preorderItemSchema: z.ZodObject<{
|
|
|
21
21
|
thumbnailUrl: z.ZodOptional<z.ZodString>;
|
|
22
22
|
source: z.ZodOptional<z.ZodEnum<["upload", "youtube", "external"]>>;
|
|
23
23
|
youtubeId: z.ZodOptional<z.ZodString>;
|
|
24
|
+
duration: z.ZodOptional<z.ZodNumber>;
|
|
24
25
|
}, "strip", z.ZodTypeAny, {
|
|
25
26
|
type: "video" | "image" | "file";
|
|
26
27
|
url: string;
|
|
@@ -28,6 +29,7 @@ export declare const preorderItemSchema: z.ZodObject<{
|
|
|
28
29
|
alt?: string | undefined;
|
|
29
30
|
thumbnailUrl?: string | undefined;
|
|
30
31
|
youtubeId?: string | undefined;
|
|
32
|
+
duration?: number | undefined;
|
|
31
33
|
}, {
|
|
32
34
|
type: "video" | "image" | "file";
|
|
33
35
|
url: string;
|
|
@@ -35,6 +37,7 @@ export declare const preorderItemSchema: z.ZodObject<{
|
|
|
35
37
|
alt?: string | undefined;
|
|
36
38
|
thumbnailUrl?: string | undefined;
|
|
37
39
|
youtubeId?: string | undefined;
|
|
40
|
+
duration?: number | undefined;
|
|
38
41
|
}>, "many">>;
|
|
39
42
|
salePrice: z.ZodNumber;
|
|
40
43
|
regularPrice: z.ZodNumber;
|
|
@@ -62,6 +65,7 @@ export declare const preorderItemSchema: z.ZodObject<{
|
|
|
62
65
|
alt?: string | undefined;
|
|
63
66
|
thumbnailUrl?: string | undefined;
|
|
64
67
|
youtubeId?: string | undefined;
|
|
68
|
+
duration?: number | undefined;
|
|
65
69
|
}[] | undefined;
|
|
66
70
|
franchise?: string | undefined;
|
|
67
71
|
preorderShipDate?: string | undefined;
|
|
@@ -82,6 +86,7 @@ export declare const preorderItemSchema: z.ZodObject<{
|
|
|
82
86
|
alt?: string | undefined;
|
|
83
87
|
thumbnailUrl?: string | undefined;
|
|
84
88
|
youtubeId?: string | undefined;
|
|
89
|
+
duration?: number | undefined;
|
|
85
90
|
}[] | undefined;
|
|
86
91
|
isFeatured?: boolean | undefined;
|
|
87
92
|
franchise?: string | undefined;
|
|
@@ -19,6 +19,14 @@ function formatBidDate(raw) {
|
|
|
19
19
|
return raw;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
+
/** Bidder identity is already masked server-side (`maskPublicBid`) when a
|
|
23
|
+
* display name is present; this is only a fallback for bare bidder ids. */
|
|
24
|
+
function maskBidderId(id) {
|
|
25
|
+
if (!id)
|
|
26
|
+
return "Anonymous";
|
|
27
|
+
const tail = id.slice(-4);
|
|
28
|
+
return `Bidder ***${tail}`;
|
|
29
|
+
}
|
|
22
30
|
export function BidHistory({ isLoading = false, isEmpty = false, renderList, renderBid, bids = [], renderEmpty, renderSkeleton, currency, labels = {}, className = "", }) {
|
|
23
31
|
if (isLoading) {
|
|
24
32
|
if (renderSkeleton)
|
|
@@ -32,5 +40,5 @@ export function BidHistory({ isLoading = false, isEmpty = false, renderList, ren
|
|
|
32
40
|
}
|
|
33
41
|
if (renderList)
|
|
34
42
|
return _jsx(Div, { className: className, children: renderList() });
|
|
35
|
-
return (_jsxs(Div, { className: className, children: [labels.title && (_jsx(Heading, { level: 3, className: "mb-3 tracking-wide", color: "muted", size: "sm", weight: "semibold", transform: "uppercase", children: labels.title })), _jsx(Stack, { gap: "sm", children: bids.map((bid, i) => renderBid ? (_jsx(React.Fragment, { children: renderBid(bid, i) }, bid.id)) : (_jsxs(Div, { layout: "flex", align: "center", justify: "between", rounded: "lg", padding: "sm", textSize: "sm", className: "border border-[var(--appkit-color-border-subtle)] bg-[var(--appkit-color-surface)]", "data-section": "bidhistory-div-422", children: [_jsx(Span, { weight: "bold", className: "text-primary-600 dark:text-primary-400", children: currency ? formatCurrency(bid.amount, currency) : bid.amount.toLocaleString() }), _jsx(Span, { size: "xs", color: "muted", children: formatBidDate(bid.placedAt) })] }, bid.id))) })] }));
|
|
43
|
+
return (_jsxs(Div, { className: className, children: [labels.title && (_jsx(Heading, { level: 3, className: "mb-3 tracking-wide", color: "muted", size: "sm", weight: "semibold", transform: "uppercase", children: labels.title })), _jsx(Stack, { gap: "sm", children: bids.map((bid, i) => renderBid ? (_jsx(React.Fragment, { children: renderBid(bid, i) }, bid.id)) : (_jsxs(Div, { layout: "flex", align: "center", justify: "between", rounded: "lg", padding: "sm", textSize: "sm", className: "border border-[var(--appkit-color-border-subtle)] bg-[var(--appkit-color-surface)]", "data-section": "bidhistory-div-422", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Span, { weight: "bold", className: "text-primary-600 dark:text-primary-400", children: currency ? formatCurrency(bid.amount, currency) : bid.amount.toLocaleString() }), _jsx(Span, { size: "xs", color: "muted", children: bid.bidderName || maskBidderId(bid.bidderId) })] }), _jsx(Span, { size: "xs", color: "muted", children: formatBidDate(bid.placedAt) })] }, bid.id))) })] }));
|
|
36
44
|
}
|
|
@@ -1,12 +1,22 @@
|
|
|
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 { useState } from "react";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import { z } from "zod";
|
|
5
6
|
import { Button, Code, ConfirmDeleteModal, Div, FormField, Heading, Modal, Row, Select, SideDrawer, Span, Stack, Tabs, TabsContent, TabsList, TabsTrigger, Text, useToast } from "../../../ui";
|
|
7
|
+
import { FormShellContext, useFormShellState, FormErrorSummary } from "../../../ui/forms";
|
|
6
8
|
import { MediaImage } from "../../media/MediaImage";
|
|
7
9
|
import { apiClient } from "../../../http";
|
|
8
10
|
import { PRODUCT_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
11
|
import { ProductInlineSelect } from "../../seller/components/ProductInlineSelect";
|
|
12
|
+
const groupTitleSchema = z.object({
|
|
13
|
+
groupTitle: z.string().min(1, "Group title is required"),
|
|
14
|
+
});
|
|
15
|
+
const createChildSchema = z.object({
|
|
16
|
+
title: z.string().min(1, "Title is required"),
|
|
17
|
+
price: z.string().refine((v) => v.trim() !== "" && !Number.isNaN(parseFloat(v)) && parseFloat(v) > 0, "Enter a valid price"),
|
|
18
|
+
condition: z.string(),
|
|
19
|
+
});
|
|
10
20
|
const __P = {
|
|
11
21
|
p4: "p-[var(--appkit-space-4)]",
|
|
12
22
|
};
|
|
@@ -33,6 +43,11 @@ export function GroupSettingsPanel({ productId, productSlug, groupId, isGroupPar
|
|
|
33
43
|
const [linkTargets, setLinkTargets] = useState([]);
|
|
34
44
|
const [children, setChildren] = useState(null);
|
|
35
45
|
const [confirmAction, setConfirmAction] = useState(null);
|
|
46
|
+
const { shellCtx: titleShellCtx, validate: validateTitle } = useFormShellState(groupTitleSchema);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
validateTitle({ groupTitle: editTitle });
|
|
49
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
50
|
+
}, [editTitle, validateTitle]);
|
|
36
51
|
if (isAuction)
|
|
37
52
|
return null;
|
|
38
53
|
const groupEndpoint = `${storeProductsEndpoint}/${productId}/group`;
|
|
@@ -69,6 +84,8 @@ export function GroupSettingsPanel({ productId, productSlug, groupId, isGroupPar
|
|
|
69
84
|
}
|
|
70
85
|
}
|
|
71
86
|
async function saveTitle() {
|
|
87
|
+
if (Object.keys(titleShellCtx.errors).length > 0)
|
|
88
|
+
return;
|
|
72
89
|
setLoading(true);
|
|
73
90
|
try {
|
|
74
91
|
await apiClient.patch(groupEndpoint, { groupTitle: editTitle });
|
|
@@ -218,8 +235,13 @@ export function GroupSettingsPanel({ productId, productSlug, groupId, isGroupPar
|
|
|
218
235
|
setOpen(next);
|
|
219
236
|
if (next && isGroupParent && children === null)
|
|
220
237
|
loadChildren();
|
|
221
|
-
}, paddingX: "none", paddingY: "xs", justify: "between", className: "w-full text-left group", "aria-expanded": open, children: [_jsx(Heading, { level: 3, size: "sm", weight: "semibold", color: "muted", children: "Group Settings" }), _jsx(Span, { size: "xs", className: "group-hover:text-[var(--appkit-color-text-muted)] dark:group-hover:text-[var(--appkit-color-text-faint)] transition-colors", color: "faint", children: open ? "▲" : "▼" })] }), open && (_jsxs(Stack, { gap: "sm", className: `mt-3 ${__P.p4}`, surface: "muted", rounded: "lg", border: "default", children: [!groupId && !groupParentSlug && (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Group related listings together \u2014 e.g. a set, bundle, or multi-part item. Parts can be sold individually but shown together." }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: startGroup, isLoading: loading, children: "Start a group" })] })), isGroupParent && groupId && (_jsxs(Stack, { gap: "md", children: [_jsxs(Row, { align: "start", gap: "sm", wrap: true, children: [_jsx(Div, { className: "flex-1 min-w-[200px]", children: _jsx(FormField, { name: "groupTitle", label: "Group title", type: "text", value: editTitle, onChange: setEditTitle, placeholder: "e.g. Human Toy Complete Set" }) }), _jsx(Div, { padding: "t-lg", children: _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: saveTitle, isLoading: loading, children: "Save title" }) })] }), _jsxs(Div, { children: [_jsxs(Text, { className: "mb-2", color: "muted", size: "xs", weight: "semibold", children: ["Members (", childSlugsCount + 1, " \u2014 including this listing)"] }), loading && !children ? (_jsx(Text, { size: "xs", color: "faint", children: "Loading\u2026" })) : (_jsxs(Div, { className: "divide-y divide-zinc-100 divide-[var(--appkit-color-border-subtle)]", children: [_jsxs(Row, { align: "center", gap: "sm", padding: "y-xs", children: [_jsx(Span, { padding: "pill-2xs", weight: "semibold", className: "bg-[var(--appkit-color-primary)]/10 text-[var(--appkit-color-primary)] text-[10px]", rounded: "default", children: "Parent" }), _jsx(Text, { className: "flex-1", color: "primary", size: "sm", children: productSlug })] }), (children ?? []).filter((c) => c.id !== productId).map((child) => (_jsxs(Row, { align: "center", gap: "sm", padding: "y-xs", children: [child.images?.[0] ? (_jsx(Div, { className: "relative w-8 h-8 flex-shrink-0 border border-[var(--appkit-color-border)]", rounded: "full", overflow: "hidden", children: _jsx(MediaImage, { src: child.images[0], alt: child.title, size: "thumbnail" }) })) : (_jsx(Div, { className: "w-8 h-8", surface: "subtle", rounded: "full" })), _jsx(Text, { className: "flex-1 truncate", color: "primary", size: "sm", children: child.title }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => requestUnlinkChild(child.id), isLoading: loading, className: `${CLS_DELETE_LINK} text-[length:var(--appkit-text-xs)]`, children: "Unlink" })] }, child.id)))] }))] }), _jsxs(Row, { gap: "sm", wrap: true, children: [_jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => setShowAddModal(true), children: "Add child listing" }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: requestDissolveGroup, isLoading: loading, className: CLS_DELETE_LINK, children: "Dissolve group" })] })] })), !isGroupParent && groupParentSlug && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Text, { size: "sm", color: "muted", children: ["Part of:", " ", _jsx(Span, { weight: "medium", color: "primary", children: groupTitle ?? groupParentSlug })] }), _jsxs(Text, { size: "xs", color: "muted", children: ["Parent listing: ", _jsx(Code, { className: "font-mono", children: groupParentSlug })] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: requestLeaveGroup, isLoading: loading, className: `${CLS_DELETE_LINK} w-fit`, children: "Leave group" })] }))] })), (groupChildSlugs?.length ?? 0) >= 4 ? (_jsx(SideDrawer, { isOpen: showAddModal, onClose: () => setShowAddModal(false), title: "Add child listing", children: _jsx(AddChildContent, { addTab: addTab, setAddTab: setAddTab, createForm: createForm, setCreateForm: setCreateForm, productSlug: productSlug, storeProductsEndpoint: storeProductsEndpoint, linkTargets: linkTargets, setLinkTargets: setLinkTargets, onAddCreate: addCreateChild, onAddLink: addLinkChild, loading: loading }) })) : (_jsx(Modal, { open: showAddModal, onClose: () => setShowAddModal(false), title: "Add child listing", size: "lg", children: _jsx(AddChildContent, { addTab: addTab, setAddTab: setAddTab, createForm: createForm, setCreateForm: setCreateForm, productSlug: productSlug, storeProductsEndpoint: storeProductsEndpoint, linkTargets: linkTargets, setLinkTargets: setLinkTargets, onAddCreate: addCreateChild, onAddLink: addLinkChild, loading: loading }) })), confirmAction && (_jsx(ConfirmDeleteModal, { isOpen: true, title: confirmAction.title, message: confirmAction.message, onConfirm: confirmAction.onConfirm, onClose: () => setConfirmAction(null), isDeleting: loading }))] }));
|
|
238
|
+
}, paddingX: "none", paddingY: "xs", justify: "between", className: "w-full text-left group", "aria-expanded": open, children: [_jsx(Heading, { level: 3, size: "sm", weight: "semibold", color: "muted", children: "Group Settings" }), _jsx(Span, { size: "xs", className: "group-hover:text-[var(--appkit-color-text-muted)] dark:group-hover:text-[var(--appkit-color-text-faint)] transition-colors", color: "faint", children: open ? "▲" : "▼" })] }), open && (_jsxs(Stack, { gap: "sm", className: `mt-3 ${__P.p4}`, surface: "muted", rounded: "lg", border: "default", children: [!groupId && !groupParentSlug && (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Group related listings together \u2014 e.g. a set, bundle, or multi-part item. Parts can be sold individually but shown together." }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: startGroup, isLoading: loading, children: "Start a group" })] })), isGroupParent && groupId && (_jsxs(Stack, { gap: "md", children: [_jsxs(FormShellContext.Provider, { value: titleShellCtx, children: [_jsxs(Row, { align: "start", gap: "sm", wrap: true, children: [_jsx(Div, { className: "flex-1 min-w-[200px]", children: _jsx(FormField, { name: "groupTitle", label: "Group title", type: "text", value: editTitle, onChange: setEditTitle, placeholder: "e.g. Human Toy Complete Set" }) }), _jsx(Div, { padding: "t-lg", children: _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: saveTitle, isLoading: loading, children: "Save title" }) })] }), _jsx(FormErrorSummary, {})] }), _jsxs(Div, { children: [_jsxs(Text, { className: "mb-2", color: "muted", size: "xs", weight: "semibold", children: ["Members (", childSlugsCount + 1, " \u2014 including this listing)"] }), loading && !children ? (_jsx(Text, { size: "xs", color: "faint", children: "Loading\u2026" })) : (_jsxs(Div, { className: "divide-y divide-zinc-100 divide-[var(--appkit-color-border-subtle)]", children: [_jsxs(Row, { align: "center", gap: "sm", padding: "y-xs", children: [_jsx(Span, { padding: "pill-2xs", weight: "semibold", className: "bg-[var(--appkit-color-primary)]/10 text-[var(--appkit-color-primary)] text-[10px]", rounded: "default", children: "Parent" }), _jsx(Text, { className: "flex-1", color: "primary", size: "sm", children: productSlug })] }), (children ?? []).filter((c) => c.id !== productId).map((child) => (_jsxs(Row, { align: "center", gap: "sm", padding: "y-xs", children: [child.images?.[0] ? (_jsx(Div, { className: "relative w-8 h-8 flex-shrink-0 border border-[var(--appkit-color-border)]", rounded: "full", overflow: "hidden", children: _jsx(MediaImage, { src: child.images[0], alt: child.title, size: "thumbnail" }) })) : (_jsx(Div, { className: "w-8 h-8", surface: "subtle", rounded: "full" })), _jsx(Text, { className: "flex-1 truncate", color: "primary", size: "sm", children: child.title }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => requestUnlinkChild(child.id), isLoading: loading, className: `${CLS_DELETE_LINK} text-[length:var(--appkit-text-xs)]`, children: "Unlink" })] }, child.id)))] }))] }), _jsxs(Row, { gap: "sm", wrap: true, children: [_jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => setShowAddModal(true), children: "Add child listing" }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: requestDissolveGroup, isLoading: loading, className: CLS_DELETE_LINK, children: "Dissolve group" })] })] })), !isGroupParent && groupParentSlug && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Text, { size: "sm", color: "muted", children: ["Part of:", " ", _jsx(Span, { weight: "medium", color: "primary", children: groupTitle ?? groupParentSlug })] }), _jsxs(Text, { size: "xs", color: "muted", children: ["Parent listing: ", _jsx(Code, { className: "font-mono", children: groupParentSlug })] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: requestLeaveGroup, isLoading: loading, className: `${CLS_DELETE_LINK} w-fit`, children: "Leave group" })] }))] })), (groupChildSlugs?.length ?? 0) >= 4 ? (_jsx(SideDrawer, { isOpen: showAddModal, onClose: () => setShowAddModal(false), title: "Add child listing", children: _jsx(AddChildContent, { addTab: addTab, setAddTab: setAddTab, createForm: createForm, setCreateForm: setCreateForm, productSlug: productSlug, storeProductsEndpoint: storeProductsEndpoint, linkTargets: linkTargets, setLinkTargets: setLinkTargets, onAddCreate: addCreateChild, onAddLink: addLinkChild, loading: loading }) })) : (_jsx(Modal, { open: showAddModal, onClose: () => setShowAddModal(false), title: "Add child listing", size: "lg", children: _jsx(AddChildContent, { addTab: addTab, setAddTab: setAddTab, createForm: createForm, setCreateForm: setCreateForm, productSlug: productSlug, storeProductsEndpoint: storeProductsEndpoint, linkTargets: linkTargets, setLinkTargets: setLinkTargets, onAddCreate: addCreateChild, onAddLink: addLinkChild, loading: loading }) })), confirmAction && (_jsx(ConfirmDeleteModal, { isOpen: true, title: confirmAction.title, message: confirmAction.message, onConfirm: confirmAction.onConfirm, onClose: () => setConfirmAction(null), isDeleting: loading }))] }));
|
|
222
239
|
}
|
|
223
240
|
function AddChildContent({ addTab, setAddTab, createForm, setCreateForm, productSlug, storeProductsEndpoint, linkTargets, setLinkTargets, onAddCreate, onAddLink, loading, }) {
|
|
224
|
-
|
|
241
|
+
const { shellCtx, validate } = useFormShellState(createChildSchema);
|
|
242
|
+
useEffect(() => {
|
|
243
|
+
validate(createForm);
|
|
244
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
245
|
+
}, [createForm, validate]);
|
|
246
|
+
return (_jsx(Stack, { gap: "md", children: _jsxs(Tabs, { value: addTab, onChange: (v) => setAddTab(v), children: [_jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "create", children: "Create new child" }), _jsx(TabsTrigger, { value: "link", children: "Link existing" })] }), _jsx(TabsContent, { value: "create", children: _jsx(FormShellContext.Provider, { value: shellCtx, children: _jsxs(Stack, { gap: "sm", className: "mt-4", children: [_jsx(FormField, { name: "title", label: "Title *", type: "text", value: createForm.title, onChange: (v) => setCreateForm({ ...createForm, title: v }), placeholder: `${productSlug}-part` }), _jsx(FormField, { name: "price", label: "Price (\u20B9) *", type: "number", value: createForm.price, onChange: (v) => setCreateForm({ ...createForm, price: v }), placeholder: "0" }), _jsx(Select, { label: "Condition", value: createForm.condition, onValueChange: (v) => setCreateForm({ ...createForm, condition: v }), options: CONDITION_OPTIONS }), _jsx(Text, { className: "dark:text-[var(--appkit-color-text-faint)]/80", color: "faint", size: "xs", children: "Other fields (category, brand, shipping, return policy) are inherited from this parent listing. Need more control? Edit the full listing after saving." }), _jsx(FormErrorSummary, {}), _jsx(Button, { type: "button", onClick: onAddCreate, isLoading: loading, disabled: !createForm.title || !createForm.price, children: "Create and link child" })] }) }) }), _jsx(TabsContent, { value: "link", children: _jsxs(Stack, { gap: "sm", className: "mt-4", children: [_jsx(Text, { size: "xs", color: "muted", children: "Search your existing products or pre-orders. Auctions cannot be linked. Select multiple to bulk-link." }), _jsx(ProductInlineSelect, { scope: "store", endpoint: storeProductsEndpoint, filters: "listingType==standard", multiple: true, value: linkTargets, onChange: setLinkTargets, placeholder: "Search listings\u2026" }), _jsx(Button, { type: "button", onClick: onAddLink, isLoading: loading, disabled: linkTargets.length === 0, children: linkTargets.length > 1 ? `Link ${linkTargets.length} to group` : "Link to group" })] }) })] }) }));
|
|
225
247
|
}
|
|
@@ -128,5 +128,5 @@ export async function PrizeDrawDetailPageView({ id, initialPrizeDraw, currentUse
|
|
|
128
128
|
price: pricePerEntry,
|
|
129
129
|
storeId: typeof p.storeId === "string" ? p.storeId : undefined,
|
|
130
130
|
storeName: storeName ?? undefined,
|
|
131
|
-
} }), _jsxs(Container, { size: "xl", padding: "y-lg", children: [_jsxs(Row, { className: "mb-4", align: "center", justify: "between", gap: "sm", wrap: true, children: [_jsxs("nav", { "aria-label": "Breadcrumb", className: "flex items-center gap-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-xs)] text-[var(--appkit-color-text-muted)] flex-wrap", children: [_jsx(Link, { href: String(ROUTES.HOME), className: "hover:text-primary-600 transition-colors", children: "Home" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.PRIZE_DRAWS), className: "hover:text-primary-600 transition-colors", children: "Prize Draws" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Span, { className: "truncate max-w-[200px]", color: "muted", children: title })] }), _jsx(ShareButton, { title: title })] }), _jsx(PreOrderDetailView, { renderGallery: () => (_jsx(PrizeDrawCollage, { items: items, hideWonState: true })), renderInfo: () => (_jsxs(Stack, { gap: "md", children: [_jsxs(Div, { children: [_jsxs(Row, { gap: "xs", wrap: true, className: "mb-2", children: [_jsx(Span, { size: "xs", weight: "semibold", className: CLS_PRIZE_BADGE, children: "Prize Draw" }), _jsx(Span, { size: "xs", weight: "semibold", className: `inline-block ${statusClass(revealStatus)}`, padding: "pill-sm", rounded: "full", children: statusLabel(revealStatus) }), maxPerUser !== null && (_jsxs(Span, { size: "xs", weight: "medium", className: "inline-block", padding: "pill-sm", rounded: "full", surface: "subtle", color: "muted", children: ["Limit: ", maxPerUser, " entries per customer"] })), maxPerUser !== null && userEntriesUsed !== null && (_jsxs(Span, { size: "xs", weight: "semibold", className: CLS_PRIZE_BADGE, children: ["You have used ", userEntriesUsed, "/", maxPerUser] }))] }), _jsx(Heading, { level: 1, className: "leading-snug", smSize: "2xl", color: "primary", size: "xl", weight: "bold", children: title })] }), _jsx(Div, { className: `${__P.p4}`, border: "subtle", rounded: "xl", surface: "muted", children: _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "Entries" }), _jsxs(Text, { size: "sm", weight: "semibold", children: [current, " / ", max, " (", remaining, " left)"] })] }), revealStart && (_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "Reveal window opens" }), _jsx(Text, { size: "sm", weight: "medium", children: revealStart.toLocaleString() })] })), revealEnd && (_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "Reveal window closes" }), _jsx(Text, { size: "sm", weight: "medium", children: revealEnd.toLocaleString() })] }))] }) }), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-[length:var(--appkit-text-sm)] leading-relaxed text-[var(--appkit-color-text-muted)] line-clamp-4" })), safeSeller && (_jsx(Div, { className: `${__P.p3}`, border: "subtle", rounded: "xl", surface: "muted", children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] tracking-wide mb-0.5", color: "faint", transform: "uppercase", children: "Sold by" }), _jsx(Text, { size: "sm", weight: "semibold", color: "primary", children: safeSeller })] }), storeHref && (_jsx(Link, { href: storeHref, className: "shrink-0 rounded-lg bg-primary/10 dark:bg-primary/20 px-[var(--appkit-space-3)] py-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-xs)] font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] }) }))] })), renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-[var(--appkit-color-text-muted)]" })) : undefined })), renderBuyBar: () => (_jsx(Div, { padding: "5", id: "prize-draw-buy-bar", border: "subtle", surface: "muted", rounded: "xl", children: _jsx(PrizeDrawEntryActions, { productId: String(product.id), productSlug: slug, title: title,
|
|
131
|
+
} }), _jsxs(Container, { size: "xl", padding: "y-lg", children: [_jsxs(Row, { className: "mb-4", align: "center", justify: "between", gap: "sm", wrap: true, children: [_jsxs("nav", { "aria-label": "Breadcrumb", className: "flex items-center gap-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-xs)] text-[var(--appkit-color-text-muted)] flex-wrap", children: [_jsx(Link, { href: String(ROUTES.HOME), className: "hover:text-primary-600 transition-colors", children: "Home" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.PRIZE_DRAWS), className: "hover:text-primary-600 transition-colors", children: "Prize Draws" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Span, { className: "truncate max-w-[200px]", color: "muted", children: title })] }), _jsx(ShareButton, { title: title })] }), _jsx(PreOrderDetailView, { renderGallery: () => (_jsx(PrizeDrawCollage, { items: items, hideWonState: true })), renderInfo: () => (_jsxs(Stack, { gap: "md", children: [_jsxs(Div, { children: [_jsxs(Row, { gap: "xs", wrap: true, className: "mb-2", children: [_jsx(Span, { size: "xs", weight: "semibold", className: CLS_PRIZE_BADGE, children: "Prize Draw" }), _jsx(Span, { size: "xs", weight: "semibold", className: `inline-block ${statusClass(revealStatus)}`, padding: "pill-sm", rounded: "full", children: statusLabel(revealStatus) }), maxPerUser !== null && (_jsxs(Span, { size: "xs", weight: "medium", className: "inline-block", padding: "pill-sm", rounded: "full", surface: "subtle", color: "muted", children: ["Limit: ", maxPerUser, " entries per customer"] })), maxPerUser !== null && userEntriesUsed !== null && (_jsxs(Span, { size: "xs", weight: "semibold", className: CLS_PRIZE_BADGE, children: ["You have used ", userEntriesUsed, "/", maxPerUser] }))] }), _jsx(Heading, { level: 1, className: "leading-snug", smSize: "2xl", color: "primary", size: "xl", weight: "bold", children: title })] }), _jsx(Div, { className: `${__P.p4}`, border: "subtle", rounded: "xl", surface: "muted", children: _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "Entries" }), _jsxs(Text, { size: "sm", weight: "semibold", children: [current, " / ", max, " (", remaining, " left)"] })] }), revealStart && (_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "Reveal window opens" }), _jsx(Text, { size: "sm", weight: "medium", children: revealStart.toLocaleString() })] })), revealEnd && (_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "Reveal window closes" }), _jsx(Text, { size: "sm", weight: "medium", children: revealEnd.toLocaleString() })] }))] }) }), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-[length:var(--appkit-text-sm)] leading-relaxed text-[var(--appkit-color-text-muted)] line-clamp-4" })), safeSeller && (_jsx(Div, { className: `${__P.p3}`, border: "subtle", rounded: "xl", surface: "muted", children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] tracking-wide mb-0.5", color: "faint", transform: "uppercase", children: "Sold by" }), _jsx(Text, { size: "sm", weight: "semibold", color: "primary", children: safeSeller })] }), storeHref && (_jsx(Link, { href: storeHref, className: "shrink-0 rounded-lg bg-primary/10 dark:bg-primary/20 px-[var(--appkit-space-3)] py-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-xs)] font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] }) }))] })), renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-[var(--appkit-color-text-muted)]" })) : undefined })), renderBuyBar: () => (_jsx(Div, { padding: "5", id: "prize-draw-buy-bar", border: "subtle", surface: "muted", rounded: "xl", children: _jsx(PrizeDrawEntryActions, { productId: String(product.id), productSlug: slug, title: title, pricePerEntry: pricePerEntry, currency: currency, remainingEntries: remaining, revealStatus: revealStatus, prizeGithubFileUrl: githubUrl }) })), renderRelated: () => (_jsxs(Stack, { gap: "xl", children: [_jsx(GroupedListingsCarousel, { groups: groups }), _jsx(RelatedItemsSection, { relatedItems: relatedItems, relatedByBrand: relatedByBrand, relatedByTags: relatedByTags, relatedByStore: relatedByStore, categoryLabel: categoryName, brandLabel: brand, storeLabel: storeName ?? undefined })] })) }), _jsx(PrizeDrawBottomActions, { pricePerEntry: pricePerEntry, currency: currency, closed: revealStatus === "closed" || remaining === 0 })] })] }));
|
|
132
132
|
}
|
|
@@ -2,14 +2,11 @@ export interface PrizeDrawEntryActionsProps {
|
|
|
2
2
|
productId: string;
|
|
3
3
|
productSlug?: string;
|
|
4
4
|
title: string;
|
|
5
|
-
thumb?: string;
|
|
6
5
|
pricePerEntry: number;
|
|
7
6
|
currency: string;
|
|
8
7
|
remainingEntries: number;
|
|
9
8
|
revealStatus: "pending" | "open" | "closed" | undefined;
|
|
10
9
|
prizeGithubFileUrl?: string;
|
|
11
|
-
storeId?: string;
|
|
12
|
-
storeName?: string;
|
|
13
10
|
}
|
|
14
11
|
/**
|
|
15
12
|
* Client buy panel for a prize-draw detail page (SB4-G).
|
|
@@ -18,4 +15,4 @@ export interface PrizeDrawEntryActionsProps {
|
|
|
18
15
|
* - On confirm → add 1 entry to guest cart and route to /user/cart
|
|
19
16
|
* - "View RNG source" link → prizeGithubFileUrl
|
|
20
17
|
*/
|
|
21
|
-
export declare function PrizeDrawEntryActions({ productId, productSlug, title,
|
|
18
|
+
export declare function PrizeDrawEntryActions({ productId, productSlug, title, pricePerEntry, currency, remainingEntries, revealStatus, prizeGithubFileUrl, }: PrizeDrawEntryActionsProps): import("react").JSX.Element;
|
|
@@ -16,7 +16,7 @@ import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
|
16
16
|
* - On confirm → add 1 entry to guest cart and route to /user/cart
|
|
17
17
|
* - "View RNG source" link → prizeGithubFileUrl
|
|
18
18
|
*/
|
|
19
|
-
export function PrizeDrawEntryActions({ productId, productSlug, title,
|
|
19
|
+
export function PrizeDrawEntryActions({ productId, productSlug, title, pricePerEntry, currency, remainingEntries, revealStatus, prizeGithubFileUrl, }) {
|
|
20
20
|
const router = useRouter();
|
|
21
21
|
const { requireAuth, modalOpen, modalMessage, closeModal } = useAuthGate();
|
|
22
22
|
const [consentOpen, setConsentOpen] = useState(false);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export interface ProductDetailActionsProps {
|
|
2
2
|
productId: string;
|
|
3
|
-
productSlug: string;
|
|
4
3
|
productTitle: string;
|
|
5
4
|
productImage?: string;
|
|
6
5
|
price?: number;
|
|
@@ -22,4 +21,4 @@ export interface ProductDetailActionsProps {
|
|
|
22
21
|
* to the server APIs with guest-fallback. Replaces the previously-unwired
|
|
23
22
|
* placeholder buttons inside ProductDetailPageView.
|
|
24
23
|
*/
|
|
25
|
-
export declare function ProductDetailActions({ productId,
|
|
24
|
+
export declare function ProductDetailActions({ productId, productTitle, productImage, price, currency, storeId, storeName, inStock, variant, }: ProductDetailActionsProps): import("react").JSX.Element;
|
|
@@ -19,7 +19,7 @@ import { normalizeError } from "../../../errors/normalize";
|
|
|
19
19
|
* to the server APIs with guest-fallback. Replaces the previously-unwired
|
|
20
20
|
* placeholder buttons inside ProductDetailPageView.
|
|
21
21
|
*/
|
|
22
|
-
export function ProductDetailActions({ productId,
|
|
22
|
+
export function ProductDetailActions({ productId, productTitle, productImage, price, currency, storeId, storeName, inStock, variant = "desktop", }) {
|
|
23
23
|
const router = useRouter();
|
|
24
24
|
const { showToast } = useToast();
|
|
25
25
|
const { requireAuth, modalOpen, modalMessage, closeModal } = useAuthGate();
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import Link from "next/link";
|
|
5
|
+
import { useRouter } from "next/navigation";
|
|
6
|
+
import { ROUTES } from "../../../next";
|
|
5
7
|
import { BaseListingCard, Button, Div, Grid, PriceDisplay, Row, Span, Stack, Text } from "../../../ui";
|
|
6
8
|
import { MediaImage } from "../../media/MediaImage";
|
|
7
9
|
import { formatCurrency } from "../../../utils/number.formatter";
|
|
@@ -37,6 +39,7 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
|
|
|
37
39
|
? Math.round(((product.originalPrice - product.price) / product.originalPrice) *
|
|
38
40
|
100)
|
|
39
41
|
: null;
|
|
42
|
+
const router = useRouter();
|
|
40
43
|
const listingPlugin = pluginFor(normalizeListingType(product));
|
|
41
44
|
const typeBadge = listingPlugin.badge
|
|
42
45
|
? { label: listingPlugin.badge.label, cls: listingPlugin.badge.className }
|
|
@@ -86,7 +89,18 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
|
|
|
86
89
|
const MAX_CHIPS = 3;
|
|
87
90
|
const visible = categories.slice(0, MAX_CHIPS);
|
|
88
91
|
const overflow = Math.max(0, categories.length - MAX_CHIPS);
|
|
89
|
-
return (_jsxs(Row, { className: "mt-1", gap: "xs", wrap: true, children: [visible.map((name) => (_jsxs(Span, { padding: "pill-2xs", layout: "inline-flex", className: "gap-[0.125rem] text-[10px]", rounded: "full", surface: "subtle", color: "muted", children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 7a2 2 0 012-2h14a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V7z" }) }), name] }, name))), overflow > 0 && (_jsxs(Span, { padding: "pill-2xs", layout: "inline-flex", weight: "medium", className: "text-[10px]", rounded: "full", surface: "subtle", color: "muted", title: categories.slice(MAX_CHIPS).join(", "), children: ["+", overflow] })), product.brand && (_jsxs(Span, { padding: "pill-2xs", layout: "inline-flex", gap: "2xs", className:
|
|
92
|
+
return (_jsxs(Row, { className: "mt-1", gap: "xs", wrap: true, children: [visible.map((name) => (_jsxs(Span, { padding: "pill-2xs", layout: "inline-flex", className: "gap-[0.125rem] text-[10px]", rounded: "full", surface: "subtle", color: "muted", children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 7a2 2 0 012-2h14a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V7z" }) }), name] }, name))), overflow > 0 && (_jsxs(Span, { padding: "pill-2xs", layout: "inline-flex", weight: "medium", className: "text-[10px]", rounded: "full", surface: "subtle", color: "muted", title: categories.slice(MAX_CHIPS).join(", "), children: ["+", overflow] })), product.brand && (_jsxs(Span, { padding: "pill-2xs", layout: "inline-flex", gap: "2xs", className: `text-[10px] ${product.brandSlug ? "cursor-pointer hover:underline" : ""}`, rounded: "full", surface: "subtle", color: "muted", ...(product.brandSlug
|
|
93
|
+
? {
|
|
94
|
+
onClick: (e) => {
|
|
95
|
+
// The whole card is already wrapped in a <Link> — a nested
|
|
96
|
+
// <a> here would be invalid HTML, so this navigates via
|
|
97
|
+
// stopPropagation + router.push instead of a real Link.
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
e.stopPropagation();
|
|
100
|
+
router.push(String(ROUTES.PUBLIC.BRAND_DETAIL(product.brandSlug)));
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
: {}), children: [_jsx("svg", { className: "h-2.5 w-2.5 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" }) }), product.brand] }))] }));
|
|
90
104
|
})(), (() => {
|
|
91
105
|
const seller = safeDisplayName(product.storeName, "");
|
|
92
106
|
return seller ? (_jsxs(Text, { className: "mt-0.5 text-[11px]", color: "faint", children: ["by ", seller] })) : null;
|
|
@@ -400,4 +400,5 @@ export declare const SELLER_BULK_ACTIONS: {
|
|
|
400
400
|
readonly storeCategories: readonly ["row-activate", "row-deactivate", "row-delete"];
|
|
401
401
|
readonly groupedListings: readonly ["row-delete"];
|
|
402
402
|
readonly offers: readonly ["row-approve", "row-reject"];
|
|
403
|
+
readonly reviews: readonly ["row-reply"];
|
|
403
404
|
};
|
|
@@ -566,4 +566,5 @@ export const SELLER_BULK_ACTIONS = {
|
|
|
566
566
|
storeCategories: [ROW_ACTION_ID.ACTIVATE, ROW_ACTION_ID.DEACTIVATE, ROW_ACTION_ID.DELETE],
|
|
567
567
|
groupedListings: [ROW_ACTION_ID.DELETE],
|
|
568
568
|
offers: [ROW_ACTION_ID.APPROVE, ROW_ACTION_ID.REJECT],
|
|
569
|
+
reviews: [ROW_ACTION_ID.REPLY],
|
|
569
570
|
};
|
|
@@ -76,6 +76,7 @@ export declare const productItemSchema: z.ZodObject<{
|
|
|
76
76
|
thumbnailUrl: z.ZodOptional<z.ZodString>;
|
|
77
77
|
source: z.ZodOptional<z.ZodEnum<["upload", "youtube", "external"]>>;
|
|
78
78
|
youtubeId: z.ZodOptional<z.ZodString>;
|
|
79
|
+
duration: z.ZodOptional<z.ZodNumber>;
|
|
79
80
|
}, "strip", z.ZodTypeAny, {
|
|
80
81
|
type: "video" | "image" | "file";
|
|
81
82
|
url: string;
|
|
@@ -83,6 +84,7 @@ export declare const productItemSchema: z.ZodObject<{
|
|
|
83
84
|
alt?: string | undefined;
|
|
84
85
|
thumbnailUrl?: string | undefined;
|
|
85
86
|
youtubeId?: string | undefined;
|
|
87
|
+
duration?: number | undefined;
|
|
86
88
|
}, {
|
|
87
89
|
type: "video" | "image" | "file";
|
|
88
90
|
url: string;
|
|
@@ -90,6 +92,7 @@ export declare const productItemSchema: z.ZodObject<{
|
|
|
90
92
|
alt?: string | undefined;
|
|
91
93
|
thumbnailUrl?: string | undefined;
|
|
92
94
|
youtubeId?: string | undefined;
|
|
95
|
+
duration?: number | undefined;
|
|
93
96
|
}>, "many">>;
|
|
94
97
|
video: z.ZodOptional<z.ZodObject<{
|
|
95
98
|
url: z.ZodString;
|
|
@@ -445,6 +448,7 @@ export declare const productItemSchema: z.ZodObject<{
|
|
|
445
448
|
alt?: string | undefined;
|
|
446
449
|
thumbnailUrl?: string | undefined;
|
|
447
450
|
youtubeId?: string | undefined;
|
|
451
|
+
duration?: number | undefined;
|
|
448
452
|
}[] | undefined;
|
|
449
453
|
inStock?: boolean | undefined;
|
|
450
454
|
rating?: number | undefined;
|
|
@@ -583,6 +587,7 @@ export declare const productItemSchema: z.ZodObject<{
|
|
|
583
587
|
alt?: string | undefined;
|
|
584
588
|
thumbnailUrl?: string | undefined;
|
|
585
589
|
youtubeId?: string | undefined;
|
|
590
|
+
duration?: number | undefined;
|
|
586
591
|
}[] | undefined;
|
|
587
592
|
inStock?: boolean | undefined;
|
|
588
593
|
rating?: number | undefined;
|
|
@@ -2,9 +2,7 @@ import React from "react";
|
|
|
2
2
|
export interface CouponsIndexListingProps {
|
|
3
3
|
/** Pre-fetched coupons to show on first render */
|
|
4
4
|
initialCoupons?: any[];
|
|
5
|
-
/** If set, only show coupons from this store (slug, for display) */
|
|
6
|
-
storeSlug?: string;
|
|
7
5
|
/** If set, only show coupons from this store (id, for filtering) */
|
|
8
6
|
storeId?: string;
|
|
9
7
|
}
|
|
10
|
-
export declare function CouponsIndexListing({ initialCoupons,
|
|
8
|
+
export declare function CouponsIndexListing({ initialCoupons, storeId, }: CouponsIndexListingProps): React.JSX.Element;
|
|
@@ -28,7 +28,7 @@ const COUPON_TYPES = [
|
|
|
28
28
|
{ value: COUPON_FIELDS.TYPE_VALUES.BUY_X_GET_Y, label: "Buy X Get Y" },
|
|
29
29
|
];
|
|
30
30
|
const FILTER_KEYS = [TABLE_KEYS.TYPE, TABLE_KEYS.DATE_FROM, TABLE_KEYS.DATE_TO];
|
|
31
|
-
export function CouponsIndexListing({ initialCoupons,
|
|
31
|
+
export function CouponsIndexListing({ initialCoupons, storeId, }) {
|
|
32
32
|
const table = useUrlTable({ defaults: { pageSize: "12", sort: DEFAULT_SORT } });
|
|
33
33
|
const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
|
|
34
34
|
const [filterOpen, setFilterOpen] = useState(false);
|
|
@@ -4,8 +4,6 @@ export interface SearchViewProps {
|
|
|
4
4
|
query?: string;
|
|
5
5
|
/** Total result count */
|
|
6
6
|
total: number;
|
|
7
|
-
/** Whether data is loading */
|
|
8
|
-
isLoading: boolean;
|
|
9
7
|
labels?: {
|
|
10
8
|
searchTitle?: string;
|
|
11
9
|
resultsCount?: (count: number, query: string) => string;
|
|
@@ -26,4 +24,4 @@ export interface SearchViewProps {
|
|
|
26
24
|
renderPagination?: () => React.ReactNode;
|
|
27
25
|
className?: string;
|
|
28
26
|
}
|
|
29
|
-
export declare function SearchView({ query, total,
|
|
27
|
+
export declare function SearchView({ query, total, labels, renderSearchInput, renderFilters, renderActiveFilters, renderToolbar, renderResults, renderPagination, className, }: SearchViewProps): React.JSX.Element;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Div, Heading, Main, Row, Span, Stack, Text } from "../../../ui";
|
|
3
|
-
export function SearchView({ query, total,
|
|
3
|
+
export function SearchView({ query, total, labels = {}, renderSearchInput, renderFilters, renderActiveFilters, renderToolbar, renderResults, renderPagination, className = "", }) {
|
|
4
4
|
const hasQuery = !!query?.trim();
|
|
5
5
|
return (_jsx(Main, { className: `min-h-screen ${className}`, children: _jsxs(Stack, { padding: "y-lg", gap: "md", children: [_jsx(Div, { children: renderSearchInput() }), hasQuery && (_jsx(Div, { children: _jsx(Heading, { level: 1, size: "xl", weight: "semibold", children: labels.resultsCount
|
|
6
6
|
? labels.resultsCount(total, query)
|
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { Row } from "@mohasinac/appkit/ui";
|
|
4
4
|
import { useState } from "react";
|
|
5
5
|
import { Alert, Button, Div, FormField, Stack, Text } from "../../../ui";
|
|
6
|
+
import { FormErrorSummary } from "../../../ui/forms";
|
|
6
7
|
const __P = {
|
|
7
8
|
p5: "p-[var(--appkit-space-5)]",
|
|
8
9
|
};
|
|
@@ -50,5 +51,5 @@ export function QuickProductForm({ values, onChange, onPublish, onSave, onSwitch
|
|
|
50
51
|
return (_jsxs(Stack, { gap: "lg", className: `${__P.p5}`, children: [_jsx(Div, { children: _jsx(Text, { size: "sm", color: "muted", children: "Quick add \u2014 fill the essentials and publish. You can add more details later." }) }), touched && Object.keys(errors).length > 0 && (_jsx(Alert, { variant: "error", children: "Please fix the highlighted fields before publishing." })), _jsx(FormField, { name: "title", label: "Product Name", type: "text", value: values.title ?? "", onChange: (v) => onChange({ title: v }), placeholder: "e.g. Charizard Base Set PSA 9", required: true, error: touched ? errors.title : undefined }), renderCategorySelector ? (_jsxs(Div, { children: [_jsx(Text, { className: "mb-1", color: "muted", size: "sm", weight: "medium", children: "Category" }), renderCategorySelector({
|
|
51
52
|
value: values.category ?? "",
|
|
52
53
|
onChange: (v) => onChange({ category: v }),
|
|
53
|
-
}), touched && errors.category && (_jsx(Text, { className: "text-[var(--appkit-color-error)] mt-1", size: "xs", children: errors.category }))] })) : (_jsx(FormField, { name: "category", label: "Category", type: "text", value: values.category ?? "", onChange: (v) => onChange({ category: v }), placeholder: "e.g. Trading Cards", error: touched ? errors.category : undefined })), _jsx(FormField, { name: "price", label: "Price (\u20B9)", type: "number", value: toRupeesString(values.price), onChange: (v) => onChange({ price: fromRupeesString(v) }), placeholder: "e.g. 499", required: true, error: touched ? errors.price : undefined }), _jsx(FormField, { name: "mainImage", label: "Product Image", type: "image", value: values.mainImage ?? "", onChange: (v) => onChange({ mainImage: v }), onUpload: onUploadImage, required: true, error: touched ? errors.mainImage : undefined }), _jsx(FormField, { name: "description", label: "Description", type: "textarea", value: values.description ?? "", onChange: (v) => onChange({ description: v }), placeholder: "Brief description (optional)", rows: 3 }), _jsx(FormField, { name: "stockQuantity", label: "Stock Quantity", type: "number", value: String(values.stockQuantity ?? 1), onChange: (v) => onChange({ stockQuantity: Math.max(0, parseInt(v, 10) || 0) }), placeholder: "1", hint: "How many units are available" }), _jsxs(Stack, { gap: "3", padding: "t-xs", children: [_jsxs(Row, { gap: "3", children: [_jsx(Button, { variant: "primary", onClick: handlePublish, disabled: isLoading, className: "flex-1", children: isLoading ? "Publishing..." : "Publish" }), _jsx(Button, { variant: "secondary", onClick: handleSave, disabled: isLoading, children: "Save Draft" })] }), _jsx(Button, { variant: "ghost", size: "sm", textSize: "xs", onClick: onSwitchToFull, className: "self-center", children: "Show all fields (advanced)" })] })] }));
|
|
54
|
+
}), touched && errors.category && (_jsx(Text, { className: "text-[var(--appkit-color-error)] mt-1", size: "xs", children: errors.category }))] })) : (_jsx(FormField, { name: "category", label: "Category", type: "text", value: values.category ?? "", onChange: (v) => onChange({ category: v }), placeholder: "e.g. Trading Cards", error: touched ? errors.category : undefined })), _jsx(FormField, { name: "price", label: "Price (\u20B9)", type: "number", value: toRupeesString(values.price), onChange: (v) => onChange({ price: fromRupeesString(v) }), placeholder: "e.g. 499", required: true, error: touched ? errors.price : undefined }), _jsx(FormField, { name: "mainImage", label: "Product Image", type: "image", value: values.mainImage ?? "", onChange: (v) => onChange({ mainImage: v }), onUpload: onUploadImage, required: true, error: touched ? errors.mainImage : undefined }), _jsx(FormField, { name: "description", label: "Description", type: "textarea", value: values.description ?? "", onChange: (v) => onChange({ description: v }), placeholder: "Brief description (optional)", rows: 3 }), _jsx(FormField, { name: "stockQuantity", label: "Stock Quantity", type: "number", value: String(values.stockQuantity ?? 1), onChange: (v) => onChange({ stockQuantity: Math.max(0, parseInt(v, 10) || 0) }), placeholder: "1", hint: "How many units are available" }), _jsxs(Stack, { gap: "3", padding: "t-xs", children: [_jsx(FormErrorSummary, {}), _jsxs(Row, { gap: "3", children: [_jsx(Button, { variant: "primary", onClick: handlePublish, disabled: isLoading, className: "flex-1", children: isLoading ? "Publishing..." : "Publish" }), _jsx(Button, { variant: "secondary", onClick: handleSave, disabled: isLoading, children: "Save Draft" })] }), _jsx(Button, { variant: "ghost", size: "sm", textSize: "xs", onClick: onSwitchToFull, className: "self-center", children: "Show all fields (advanced)" })] })] }));
|
|
54
55
|
}
|