@mohasinac/appkit 4.59.0 โ 4.60.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/.build-stamp.json +3 -3
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +62 -5
- package/dist/_internal/client/features/maintenance/views/MaintenanceDashboardView.js +2 -2
- package/dist/_internal/server/features/brands/actions.js +78 -4
- package/dist/_internal/server/features/checkout/actions.d.ts +36 -13
- package/dist/_internal/server/features/checkout/actions.js +668 -183
- package/dist/_internal/server/features/checkout/supplier-identity.js +18 -1
- package/dist/_internal/server/features/gateway-events/index.d.ts +10 -0
- package/dist/_internal/server/features/gateway-events/index.js +10 -0
- package/dist/_internal/server/features/gateway-events/ingest.d.ts +127 -0
- package/dist/_internal/server/features/gateway-events/ingest.js +188 -0
- package/dist/_internal/server/features/gateway-events/redact.d.ts +66 -0
- package/dist/_internal/server/features/gateway-events/redact.js +151 -0
- package/dist/_internal/server/features/grievance/actions.d.ts +63 -0
- package/dist/_internal/server/features/grievance/actions.js +173 -0
- package/dist/_internal/server/features/grievance/index.d.ts +8 -0
- package/dist/_internal/server/features/grievance/index.js +8 -0
- package/dist/_internal/server/features/grouped/data.js +28 -3
- package/dist/_internal/server/features/lottery/actions.js +99 -4
- package/dist/_internal/server/features/order-completion/actions.d.ts +92 -0
- package/dist/_internal/server/features/order-completion/actions.js +336 -0
- package/dist/_internal/server/features/order-completion/index.d.ts +7 -0
- package/dist/_internal/server/features/order-completion/index.js +7 -0
- package/dist/_internal/server/features/orders/actions.d.ts +13 -0
- package/dist/_internal/server/features/orders/actions.js +56 -2
- package/dist/_internal/server/features/orders/adapters.d.ts +20 -2
- package/dist/_internal/server/features/orders/adapters.js +44 -0
- package/dist/_internal/server/features/orders/cancellation-refund.d.ts +116 -0
- package/dist/_internal/server/features/orders/cancellation-refund.js +466 -0
- package/dist/_internal/server/features/orders/index.d.ts +2 -1
- package/dist/_internal/server/features/orders/index.js +1 -1
- package/dist/_internal/server/features/orders/service.d.ts +60 -0
- package/dist/_internal/server/features/orders/service.js +74 -0
- package/dist/_internal/server/features/payment-cases/disputes.d.ts +76 -0
- package/dist/_internal/server/features/payment-cases/disputes.js +241 -0
- package/dist/_internal/server/features/payment-cases/index.d.ts +9 -0
- package/dist/_internal/server/features/payment-cases/index.js +9 -0
- package/dist/_internal/server/features/payouts/actions.d.ts +28 -3
- package/dist/_internal/server/features/payouts/actions.js +84 -10
- package/dist/_internal/server/features/points/adjust.d.ts +61 -0
- package/dist/_internal/server/features/points/adjust.js +121 -0
- package/dist/_internal/server/features/points/award.d.ts +65 -0
- package/dist/_internal/server/features/points/award.js +145 -0
- package/dist/_internal/server/features/price-index/market.d.ts +33 -0
- package/dist/_internal/server/features/price-index/market.js +54 -1
- package/dist/_internal/server/features/products/data.js +40 -22
- package/dist/_internal/server/features/protection-claims/actions.d.ts +72 -0
- package/dist/_internal/server/features/protection-claims/actions.js +228 -0
- package/dist/_internal/server/features/protection-claims/index.d.ts +8 -0
- package/dist/_internal/server/features/protection-claims/index.js +8 -0
- package/dist/_internal/server/features/refunds/actions.d.ts +20 -0
- package/dist/_internal/server/features/refunds/actions.js +259 -17
- package/dist/_internal/server/features/refunds/capacity.d.ts +29 -0
- package/dist/_internal/server/features/refunds/capacity.js +37 -0
- package/dist/_internal/server/features/reviews/actions.js +3 -2
- package/dist/_internal/server/features/search/index-build/sources.js +20 -1
- package/dist/_internal/server/features/shipping/reconcile.d.ts +10 -1
- package/dist/_internal/server/features/shipping/reconcile.js +34 -3
- package/dist/_internal/server/features/shipping/reimbursement.d.ts +117 -0
- package/dist/_internal/server/features/shipping/reimbursement.js +223 -0
- package/dist/_internal/server/features/stores/tabs.d.ts +19 -4
- package/dist/_internal/server/features/stores/tabs.js +24 -4
- package/dist/_internal/server/functions/https.d.ts +31 -1
- package/dist/_internal/server/functions/https.js +52 -1
- package/dist/_internal/server/functions/scheduled.d.ts +72 -1
- package/dist/_internal/server/functions/scheduled.js +124 -1
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +62 -16
- package/dist/_internal/server/jobs/core/boxRollupReconcile.d.ts +46 -0
- package/dist/_internal/server/jobs/core/boxRollupReconcile.js +142 -0
- package/dist/_internal/server/jobs/core/dailyDataCleanup.js +149 -1
- package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +14 -0
- package/dist/_internal/server/jobs/core/dailyStatusDigest.js +79 -1
- package/dist/_internal/server/jobs/core/index.d.ts +2 -0
- package/dist/_internal/server/jobs/core/index.js +2 -0
- package/dist/_internal/server/jobs/core/marketPriceRollup.d.ts +64 -0
- package/dist/_internal/server/jobs/core/marketPriceRollup.js +153 -0
- package/dist/_internal/server/jobs/core/obligationSweep.d.ts +36 -0
- package/dist/_internal/server/jobs/core/obligationSweep.js +503 -0
- package/dist/_internal/server/jobs/core/paymentReconcile.d.ts +79 -0
- package/dist/_internal/server/jobs/core/paymentReconcile.js +614 -0
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +34 -0
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +35 -4
- package/dist/_internal/server/jobs/handlers/boxRollupReconcile.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/boxRollupReconcile.js +15 -0
- package/dist/_internal/server/jobs/handlers/countersReconcileNow.d.ts +65 -0
- package/dist/_internal/server/jobs/handlers/countersReconcileNow.js +89 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +5 -0
- package/dist/_internal/server/jobs/handlers/index.js +5 -0
- package/dist/_internal/server/jobs/handlers/marketPriceRollup.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/marketPriceRollup.js +2 -0
- package/dist/_internal/server/jobs/handlers/obligationSweep.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/obligationSweep.js +15 -0
- package/dist/_internal/server/jobs/handlers/onShipmentAllocationSync.js +30 -1
- package/dist/_internal/server/jobs/handlers/paymentReconcile.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/paymentReconcile.js +6 -0
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +71 -0
- package/dist/_internal/shared/checkout/coupon-discount.d.ts +73 -0
- package/dist/_internal/shared/checkout/coupon-discount.js +103 -0
- package/dist/_internal/shared/checkout/lanes.d.ts +42 -0
- package/dist/_internal/shared/checkout/lanes.js +46 -0
- package/dist/_internal/shared/checkout/order-math.d.ts +149 -1
- package/dist/_internal/shared/checkout/order-math.js +251 -3
- package/dist/_internal/shared/checkout/refundable-base.d.ts +116 -0
- package/dist/_internal/shared/checkout/refundable-base.js +122 -0
- package/dist/_internal/shared/features/auctions/config.d.ts +14 -1
- package/dist/_internal/shared/features/auctions/config.js +30 -1
- package/dist/_internal/shared/features/brands/schema.d.ts +42 -0
- package/dist/_internal/shared/features/brands/schema.js +18 -0
- package/dist/_internal/shared/features/orders/refund-copy.d.ts +22 -0
- package/dist/_internal/shared/features/orders/refund-copy.js +34 -0
- package/dist/_internal/shared/features/print/label-profiles.d.ts +198 -0
- package/dist/_internal/shared/features/print/label-profiles.js +350 -0
- package/dist/_internal/shared/features/products/to-product-item.js +33 -5
- package/dist/_internal/shared/fees/calculator.d.ts +31 -2
- package/dist/_internal/shared/fees/calculator.js +103 -5
- package/dist/_internal/shared/fees/india-states.d.ts +195 -0
- package/dist/_internal/shared/fees/india-states.js +190 -0
- package/dist/_internal/shared/fees/payout-hold.d.ts +80 -0
- package/dist/_internal/shared/fees/payout-hold.js +74 -0
- package/dist/_internal/shared/obligations/deadlines.d.ts +94 -0
- package/dist/_internal/shared/obligations/deadlines.js +155 -0
- package/dist/_internal/shared/shipping/quote.d.ts +96 -0
- package/dist/_internal/shared/shipping/quote.js +67 -0
- package/dist/_internal/shared/time/business-days.d.ts +91 -0
- package/dist/_internal/shared/time/business-days.js +185 -0
- package/dist/cli/index.js +0 -2
- package/dist/client.d.ts +10 -4
- package/dist/client.js +29 -3
- package/dist/configs/tailwind.d.ts +0 -12
- package/dist/configs/tailwind.js +28 -15
- package/dist/constants/api-endpoints.d.ts +51 -9
- package/dist/constants/api-endpoints.js +23 -7
- package/dist/constants/index.d.ts +1 -1
- package/dist/constants/index.js +1 -1
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/payment.d.ts +131 -0
- package/dist/features/about/components/AboutView.js +1 -1
- package/dist/features/about/components/DeveloperView.js +5 -2
- package/dist/features/about/components/FAQPageView.js +2 -1
- package/dist/features/about/components/FeesView.js +2 -1
- package/dist/features/about/components/HelpPageView.js +2 -1
- package/dist/features/about/components/HowAuctionsWorkView.js +2 -1
- package/dist/features/about/components/HowCheckoutWorksView.js +2 -1
- package/dist/features/about/components/HowEmiWorksView.js +2 -1
- package/dist/features/about/components/HowOffersWorkView.js +2 -1
- package/dist/features/about/components/HowOrdersWorkView.js +2 -1
- package/dist/features/about/components/HowPayoutsWorkView.js +2 -1
- package/dist/features/about/components/HowPreOrdersWorkView.js +2 -1
- package/dist/features/about/components/HowReviewsWorkView.js +2 -1
- package/dist/features/about/components/PolicyPageView.js +2 -1
- package/dist/features/about/components/ProseHero.d.ts +73 -0
- package/dist/features/about/components/ProseHero.js +18 -0
- package/dist/features/about/components/SecurityPrivacyView.js +2 -1
- package/dist/features/about/components/ShippingPolicyView.js +2 -1
- package/dist/features/about/components/TrackOrderView.js +2 -1
- package/dist/features/about/components/UnauthorizedView.js +1 -1
- package/dist/features/about/index.d.ts +2 -0
- package/dist/features/about/index.js +5 -0
- package/dist/features/account/actions/address-actions.d.ts +26 -2
- package/dist/features/account/actions/address-actions.js +25 -1
- package/dist/features/account/components/BuyerShoppingGuideView.js +1 -1
- package/dist/features/account/components/NotificationPreferencesPanel.js +1 -1
- package/dist/features/account/components/UserOrdersView.js +17 -0
- package/dist/features/account/components/UserSidebar.js +1 -1
- package/dist/features/account/hooks/useNotifications.js +29 -0
- package/dist/features/admin/actions/admin-coupon-actions.js +36 -0
- package/dist/features/admin/components/AdminBeysView.js +2 -2
- package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
- package/dist/features/admin/components/AdminBrandEditorView.js +32 -2
- package/dist/features/admin/components/AdminBundleEditorView.js +1 -1
- package/dist/features/admin/components/AdminCarouselEditorView.js +1 -1
- package/dist/features/admin/components/AdminCategoriesView.js +1 -1
- package/dist/features/admin/components/AdminCategoryEditorView.js +73 -17
- package/dist/features/admin/components/AdminContactEditorView.js +1 -1
- package/dist/features/admin/components/AdminCouponEditorView.js +26 -1
- package/dist/features/admin/components/AdminFaqEditorView.js +1 -1
- package/dist/features/admin/components/AdminFaqsView.js +2 -2
- package/dist/features/admin/components/AdminGatewayEventsView.d.ts +54 -0
- package/dist/features/admin/components/AdminGatewayEventsView.js +209 -0
- package/dist/features/admin/components/AdminGuideHubView.js +1 -1
- package/dist/features/admin/components/AdminMoneyCasesView.d.ts +60 -0
- package/dist/features/admin/components/AdminMoneyCasesView.js +287 -0
- package/dist/features/admin/components/AdminPartsView.js +2 -2
- package/dist/features/admin/components/AdminProductsView.js +75 -4
- package/dist/features/admin/components/AdminSidebar.js +2 -2
- package/dist/features/admin/components/AdminSiteSettingsView.js +65 -7
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +2 -0
- package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
- package/dist/features/admin/components/AdminSupportTicketsView.js +2 -2
- package/dist/features/admin/components/AdminTesterChecklistView.js +2 -2
- package/dist/features/admin/components/AdminUsersView.js +72 -1
- package/dist/features/admin/components/AdminViewCards.d.ts +3 -1
- package/dist/features/admin/components/AdminViewCards.js +4 -4
- package/dist/features/admin/components/DataListingView.d.ts +28 -0
- package/dist/features/admin/components/DataListingView.js +175 -14
- package/dist/features/admin/components/DataTable.d.ts +12 -1
- package/dist/features/admin/components/DataTable.js +3 -3
- package/dist/features/admin/components/OwnerQuickActions.d.ts +1 -1
- package/dist/features/admin/components/OwnerQuickActions.js +60 -2
- package/dist/features/admin/components/RecordOwnerQuickActions.d.ts +1 -1
- package/dist/features/admin/components/RecordOwnerQuickActions.js +61 -14
- package/dist/features/admin/components/analytics/AdminStatCard.d.ts +35 -1
- package/dist/features/admin/components/analytics/AdminStatCard.js +77 -2
- package/dist/features/admin/components/index.d.ts +4 -0
- package/dist/features/admin/components/index.js +6 -0
- package/dist/features/admin/constants/filter-tabs.d.ts +156 -0
- package/dist/features/admin/constants/filter-tabs.js +106 -0
- package/dist/features/admin/repository/site-settings.repository.d.ts +22 -0
- package/dist/features/admin/repository/site-settings.repository.js +82 -1
- package/dist/features/admin/schemas/admin-editor-forms.d.ts +21 -0
- package/dist/features/admin/schemas/admin-editor-forms.js +44 -0
- package/dist/features/admin/schemas/firestore.js +5 -1
- package/dist/features/admin/schemas/site-settings-form.js +30 -1
- package/dist/features/auctions/actions/bid-actions.js +13 -1
- package/dist/features/auctions/components/AuctionBottomActions.js +2 -2
- package/dist/features/auctions/components/AuctionDetailPageView.js +3 -1
- package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -0
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +5 -3
- package/dist/features/auctions/components/PlaceBidFormClient.d.ts +8 -1
- package/dist/features/auctions/components/PlaceBidFormClient.js +2 -2
- package/dist/features/audit-log/schemas/firestore.d.ts +28 -0
- package/dist/features/audit-log/schemas/firestore.js +14 -0
- package/dist/features/auth/permissions/constants.d.ts +17 -1
- package/dist/features/auth/permissions/constants.js +18 -0
- package/dist/features/blog/components/BlogPostView.js +1 -1
- package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +1 -1
- package/dist/features/categories/api/[id]/description-template/route.js +107 -1
- package/dist/features/categories/components/BrandDetailPageView.js +2 -2
- package/dist/features/categories/components/BreadcrumbTrail.js +7 -1
- package/dist/features/categories/components/BundleDetailView.js +1 -1
- package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
- package/dist/features/categories/components/CategoryForm.js +12 -1
- package/dist/features/categories/components/CategoryTemplatePicker.js +38 -5
- package/dist/features/categories/repository/market-price-index.repository.d.ts +123 -0
- package/dist/features/categories/repository/market-price-index.repository.js +105 -0
- package/dist/features/categories/repository/price-observation.repository.d.ts +166 -0
- package/dist/features/categories/repository/price-observation.repository.js +132 -0
- package/dist/features/events/components/EventSaleBanner.js +1 -1
- package/dist/features/events/components/EventStatusBadge.js +1 -1
- package/dist/features/faq/components/FAQAccordion.js +2 -1
- package/dist/features/faq/components/FAQCategorySidebar.js +2 -2
- package/dist/features/faq/components/FAQHelpfulButtons.js +4 -4
- package/dist/features/faq/components/RelatedFAQs.js +1 -1
- package/dist/features/filters/FilterFacetSection.js +1 -1
- package/dist/features/filters/SwitchFilter.js +1 -1
- package/dist/features/gateway-events/repository/gateway-events.repository.d.ts +117 -0
- package/dist/features/gateway-events/repository/gateway-events.repository.js +274 -0
- package/dist/features/gateway-events/schemas/firestore.d.ts +217 -0
- package/dist/features/gateway-events/schemas/firestore.js +125 -0
- package/dist/features/gateway-events/schemas/index.d.ts +81 -0
- package/dist/features/gateway-events/schemas/index.js +79 -0
- package/dist/features/grouped/components/GroupedListingDetailView.js +1 -1
- package/dist/features/homepage/components/AnnouncementBar.js +37 -1
- package/dist/features/homepage/components/AnnouncementBar.style.css +30 -0
- package/dist/features/homepage/components/BrandsSection.js +1 -1
- package/dist/features/homepage/components/CTABannerSection.js +1 -1
- package/dist/features/homepage/components/FeaturedBundlesSection.js +14 -24
- package/dist/features/homepage/components/HeroCarousel.js +2 -2
- package/dist/features/homepage/components/SocialPostCard.js +1 -1
- package/dist/features/inventory/components/AdminMoveLedgerView.d.ts +7 -0
- package/dist/features/inventory/components/AdminMoveLedgerView.js +157 -0
- package/dist/features/inventory/components/AdminStorageBoxesView.d.ts +11 -0
- package/dist/features/inventory/components/AdminStorageBoxesView.js +168 -0
- package/dist/features/inventory/components/ReceiveStationView.d.ts +39 -0
- package/dist/features/inventory/components/ReceiveStationView.js +413 -0
- package/dist/features/inventory/components/operator-message.d.ts +29 -0
- package/dist/features/inventory/components/operator-message.js +41 -0
- package/dist/features/inventory/index.d.ts +13 -0
- package/dist/features/inventory/index.js +28 -0
- package/dist/features/inventory/repository/inventory-movements.repository.d.ts +97 -0
- package/dist/features/inventory/repository/inventory-movements.repository.js +186 -0
- package/dist/features/inventory/repository/inventory-placements.repository.d.ts +179 -0
- package/dist/features/inventory/repository/inventory-placements.repository.js +345 -0
- package/dist/features/inventory/repository/storage-boxes.repository.d.ts +83 -0
- package/dist/features/inventory/repository/storage-boxes.repository.js +127 -0
- package/dist/features/inventory/schemas/firestore.d.ts +197 -0
- package/dist/features/inventory/schemas/firestore.js +159 -0
- package/dist/features/layout/AppLayoutShell.d.ts +12 -1
- package/dist/features/layout/AppLayoutShell.js +25 -12
- package/dist/features/layout/AutoBreadcrumbs.js +162 -3
- package/dist/features/layout/AutoBreadcrumbs.style.css +45 -0
- package/dist/features/layout/BottomNavbar.d.ts +1 -1
- package/dist/features/layout/BottomNavbar.js +2 -2
- package/dist/features/media/MediaAvatar.js +1 -1
- package/dist/features/media/MediaImage.d.ts +24 -4
- package/dist/features/media/MediaImage.js +44 -4
- package/dist/features/media/MediaLightbox.js +1 -1
- package/dist/features/media/modals/ImageCropModal.js +1 -1
- package/dist/features/media/modals/ImageEditor.js +1 -1
- package/dist/features/media/upload/MediaUploadField.js +91 -3
- package/dist/features/obligations/constants/policies.d.ts +92 -0
- package/dist/features/obligations/constants/policies.js +378 -0
- package/dist/features/obligations/repository/obligations.repository.d.ts +68 -0
- package/dist/features/obligations/repository/obligations.repository.js +158 -0
- package/dist/features/obligations/schemas/firestore.d.ts +160 -0
- package/dist/features/obligations/schemas/firestore.js +87 -0
- package/dist/features/orders/actions/order-actions.d.ts +43 -4
- package/dist/features/orders/actions/order-actions.js +60 -3
- package/dist/features/orders/actions/refund-actions.js +70 -10
- package/dist/features/orders/components/OrderCompletionPanel.d.ts +27 -0
- package/dist/features/orders/components/OrderCompletionPanel.js +192 -0
- package/dist/features/orders/components/OrdersList.js +2 -2
- package/dist/features/orders/components/RefundHistoryTable.js +3 -1
- package/dist/features/orders/components/index.d.ts +2 -0
- package/dist/features/orders/components/index.js +6 -0
- package/dist/features/orders/constants/transitions.d.ts +59 -0
- package/dist/features/orders/constants/transitions.js +104 -0
- package/dist/features/orders/repository/orders.repository.d.ts +109 -6
- package/dist/features/orders/repository/orders.repository.js +464 -21
- package/dist/features/orders/schemas/firestore.d.ts +270 -0
- package/dist/features/orders/schemas/firestore.js +24 -0
- package/dist/features/orders/schemas/index.d.ts +61 -0
- package/dist/features/orders/schemas/index.js +22 -0
- package/dist/features/orders/types/index.d.ts +79 -0
- package/dist/features/parts/components/PartsIndexPageView.js +8 -1
- package/dist/features/payment-cases/repository/payment-cases.repository.d.ts +170 -0
- package/dist/features/payment-cases/repository/payment-cases.repository.js +342 -0
- package/dist/features/payment-cases/schemas/firestore.d.ts +229 -0
- package/dist/features/payment-cases/schemas/firestore.js +105 -0
- package/dist/features/payment-cases/schemas/resolve-form.d.ts +97 -0
- package/dist/features/payment-cases/schemas/resolve-form.js +114 -0
- package/dist/features/payments/repository/payout.repository.d.ts +0 -1
- package/dist/features/payments/repository/payout.repository.js +0 -1
- package/dist/features/points/repository/points.repository.d.ts +122 -0
- package/dist/features/points/repository/points.repository.js +304 -1
- package/dist/features/points/schemas/adjust-form.d.ts +58 -0
- package/dist/features/points/schemas/adjust-form.js +63 -0
- package/dist/features/points/schemas/firestore.d.ts +108 -1
- package/dist/features/points/schemas/firestore.js +84 -0
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -3
- package/dist/features/pre-orders/components/PreOrderBadge.js +1 -1
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -1
- package/dist/features/price-index/components/PriceIndexToolView.d.ts +23 -4
- package/dist/features/price-index/components/PriceIndexToolView.js +71 -6
- package/dist/features/price-index/market-stats.d.ts +82 -0
- package/dist/features/price-index/market-stats.js +230 -0
- package/dist/features/print/components/BoxLabelPrintView.d.ts +25 -0
- package/dist/features/print/components/BoxLabelPrintView.js +66 -0
- package/dist/features/print/components/LabelProfilePicker.d.ts +13 -0
- package/dist/features/print/components/LabelProfilePicker.js +38 -0
- package/dist/features/print/components/labels.d.ts +117 -0
- package/dist/features/print/components/labels.js +258 -0
- package/dist/features/print/components/labels.style.css +46 -0
- package/dist/features/print/index.d.ts +6 -0
- package/dist/features/print/index.js +16 -0
- package/dist/features/products/columns/productTableColumns.js +5 -4
- package/dist/features/products/components/MarketplaceBundleCard.js +2 -2
- package/dist/features/products/components/MarketplacePrizeDrawCard.js +6 -6
- package/dist/features/products/components/PrizeDrawCollage.js +1 -1
- package/dist/features/products/components/PrizeDrawItemsEditor.js +1 -1
- package/dist/features/products/components/PrizeRevealModal.js +2 -2
- package/dist/features/products/components/ProductDetailPageView.js +18 -4
- package/dist/features/products/components/ProductForm.js +34 -23
- package/dist/features/products/components/ProductGrid.js +86 -62
- package/dist/features/products/constants/card-badges.d.ts +97 -0
- package/dist/features/products/constants/card-badges.js +100 -0
- package/dist/features/products/repository/products.repository.js +34 -1
- package/dist/features/products/schemas/firestore.d.ts +46 -3
- package/dist/features/products/schemas/firestore.js +21 -0
- package/dist/features/promotions/components/PromotionsView.js +1 -1
- package/dist/features/promotions/repository/claimed-coupons.repository.d.ts +32 -0
- package/dist/features/promotions/repository/claimed-coupons.repository.js +58 -0
- package/dist/features/promotions/schemas/firestore.js +30 -3
- package/dist/features/promotions/schemas/index.d.ts +6 -6
- package/dist/features/protection-claims/repository/protection-claims.repository.d.ts +54 -0
- package/dist/features/protection-claims/repository/protection-claims.repository.js +174 -0
- package/dist/features/protection-claims/schemas/firestore.d.ts +168 -0
- package/dist/features/protection-claims/schemas/firestore.js +130 -0
- package/dist/features/reviews/actions/review-actions.js +3 -2
- package/dist/features/reviews/components/ReviewModal.js +1 -1
- package/dist/features/reviews/components/ReviewsList.js +1 -1
- package/dist/features/reviews/schemas/firestore.d.ts +20 -1
- package/dist/features/scams/constants/scam-types.d.ts +2 -0
- package/dist/features/scams/constants/scam-types.js +18 -0
- package/dist/features/scams/schemas/report-form.d.ts +3 -3
- package/dist/features/scams/schemas/report-form.js +26 -1
- package/dist/features/search/components/Search.js +9 -9
- package/dist/features/search/components/SearchResultsClient.js +18 -3
- package/dist/features/search/components/SearchResultsPageView.d.ts +1 -6
- package/dist/features/search/components/SearchResultsPageView.js +2 -2
- package/dist/features/seller/actions/offer-actions.js +16 -1
- package/dist/features/seller/actions/seller-actions.js +14 -3
- package/dist/features/seller/components/CategoryInlineSelect.js +75 -11
- package/dist/features/seller/components/PrintCenterView.d.ts +5 -0
- package/dist/features/seller/components/PrintCenterView.js +41 -30
- package/dist/features/seller/components/SellerOrdersView.js +1 -1
- package/dist/features/seller/components/SellerPayoutRequestView.js +16 -5
- package/dist/features/seller/components/SellerPayoutSettingsView.js +1 -1
- package/dist/features/seller/components/SellerProductShell.d.ts +16 -0
- package/dist/features/seller/components/SellerProductShell.js +123 -13
- package/dist/features/seller/components/SellerReviewsView.js +4 -2
- package/dist/features/seller/components/SellerSidebar.js +1 -1
- package/dist/features/seller/schemas/coupon-form.d.ts +26 -0
- package/dist/features/seller/schemas/coupon-form.js +27 -0
- package/dist/features/seller/schemas/product-form.d.ts +3 -0
- package/dist/features/seller/schemas/product-form.js +5 -0
- package/dist/features/shell/FormShell.js +2 -2
- package/dist/features/shell/QuickFormDrawer.js +14 -0
- package/dist/features/shell/SectionForm.d.ts +19 -0
- package/dist/features/shell/SectionForm.js +133 -9
- package/dist/features/shell/SectionForm.style.css +54 -0
- package/dist/features/shipments/components/AdminShipmentsView.js +16 -1
- package/dist/features/shipments/repository/shipment-items.repository.d.ts +9 -0
- package/dist/features/shipments/repository/shipment-items.repository.js +14 -0
- package/dist/features/site-settings/components/ActionPermissionsManager.js +1 -1
- package/dist/features/sticker-trace/components/StickerCommitPanel.js +1 -1
- package/dist/features/store-extensions/schemas/report-review-form.d.ts +8 -8
- package/dist/features/stores/components/StoreGuideHubView.js +1 -1
- package/dist/features/stores/components/StoreHeader.js +1 -1
- package/dist/features/support/schemas/firestore.d.ts +73 -2
- package/dist/features/support/schemas/firestore.js +59 -0
- package/dist/index.d.ts +16 -24
- package/dist/index.js +38 -47
- package/dist/next/ErrorBoundary.js +1 -1
- package/dist/next/routing/route-map.d.ts +24 -0
- package/dist/next/routing/route-map.js +40 -0
- package/dist/providers/payment-manual/index.d.ts +15 -1
- package/dist/providers/payment-manual/index.js +37 -0
- package/dist/providers/payment-phonepe/index.d.ts +14 -1
- package/dist/providers/payment-phonepe/index.js +36 -0
- package/dist/providers/payment-razorpay/index.d.ts +44 -1
- package/dist/providers/payment-razorpay/index.js +99 -0
- package/dist/providers/shipping-shiprocket/index.d.ts +18 -0
- package/dist/providers/shipping-shiprocket/index.js +18 -0
- package/dist/schemas/registry.d.ts +44 -11
- package/dist/server-entry.d.ts +2 -0
- package/dist/server-entry.js +27 -0
- package/dist/server.d.ts +43 -0
- package/dist/server.js +98 -0
- package/dist/styles.css +418 -149
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +15 -12
- package/dist/tokens/themes/default-light.js +14 -11
- package/dist/tokens/tokens.css +106 -23
- package/dist/ui/DataTable.style.css +4 -4
- package/dist/ui/columns/cell-renderers.d.ts +20 -0
- package/dist/ui/columns/cell-renderers.js +26 -1
- package/dist/ui/columns/index.d.ts +1 -1
- package/dist/ui/columns/index.js +4 -1
- package/dist/ui/components/Badge.style.css +1 -1
- package/dist/ui/components/Breadcrumb.js +19 -1
- package/dist/ui/components/BulkActionBar.style.css +4 -4
- package/dist/ui/components/Button.style.css +1 -1
- package/dist/ui/components/Checkbox.style.css +1 -1
- package/dist/ui/components/FallbackShell.js +1 -1
- package/dist/ui/components/Form.d.ts +14 -1
- package/dist/ui/components/Form.js +2 -2
- package/dist/ui/components/FormField.js +18 -4
- package/dist/ui/components/FormField.style.css +43 -3
- package/dist/ui/components/GatedPrice.style.css +1 -1
- package/dist/ui/components/IconButton.style.css +1 -1
- package/dist/ui/components/Input.js +22 -1
- package/dist/ui/components/Input.style.css +38 -22
- package/dist/ui/components/ListingFilterDrawer.js +1 -1
- package/dist/ui/components/ListingToolbar.js +1 -1
- package/dist/ui/components/PaginatedSelect.js +0 -0
- package/dist/ui/components/Radio.style.css +1 -1
- package/dist/ui/components/Repeater.d.ts +53 -0
- package/dist/ui/components/Repeater.js +7 -0
- package/dist/ui/components/RichTextEditor.d.ts +20 -1
- package/dist/ui/components/RichTextEditor.js +23 -2
- package/dist/ui/components/Select.style.css +7 -21
- package/dist/ui/components/Semantic.js +27 -3
- package/dist/ui/components/TagInput.style.css +4 -9
- package/dist/ui/components/Textarea.style.css +4 -18
- package/dist/ui/components/Toggle.style.css +1 -1
- package/dist/ui/components/Typography.d.ts +3 -3
- package/dist/ui/components/Typography.js +15 -15
- package/dist/ui/components/ViewToggle.style.css +4 -4
- package/dist/ui/forms/AddAnotherToggle.d.ts +16 -0
- package/dist/ui/forms/AddAnotherToggle.js +56 -0
- package/dist/ui/forms/ColorPickerField.js +15 -2
- package/dist/ui/forms/FieldCheckbox.js +15 -2
- package/dist/ui/forms/FieldInput.d.ts +22 -1
- package/dist/ui/forms/FieldInput.js +19 -5
- package/dist/ui/forms/FieldLabel.d.ts +35 -0
- package/dist/ui/forms/FieldLabel.js +70 -0
- package/dist/ui/forms/FieldSelect.d.ts +4 -1
- package/dist/ui/forms/FieldSelect.js +27 -5
- package/dist/ui/forms/FieldTextarea.d.ts +4 -1
- package/dist/ui/forms/FieldTextarea.js +22 -5
- package/dist/ui/forms/FormShell.d.ts +17 -1
- package/dist/ui/forms/FormShell.js +36 -2
- package/dist/ui/forms/FormShell.style.css +41 -33
- package/dist/ui/forms/index.d.ts +5 -1
- package/dist/ui/forms/index.js +2 -0
- package/dist/ui/icons/icon-registry.d.ts +1 -0
- package/dist/ui/icons/icon-registry.js +17 -1
- package/dist/utils/id-generators.d.ts +80 -0
- package/dist/utils/id-generators.js +93 -0
- package/dist/utils/search-txt-builders.d.ts +12 -0
- package/dist/utils/search-txt-builders.js +17 -0
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +106 -5
- package/dist/features/loyalty/api/admin/loyalty/grant/route.d.ts +0 -12
- package/dist/features/loyalty/api/admin/loyalty/grant/route.js +0 -38
- package/dist/features/loyalty/api/balance/route.d.ts +0 -12
- package/dist/features/loyalty/api/balance/route.js +0 -41
- package/dist/features/loyalty/api/earn/route.d.ts +0 -12
- package/dist/features/loyalty/api/earn/route.js +0 -38
- package/dist/features/loyalty/api/history/route.d.ts +0 -12
- package/dist/features/loyalty/api/history/route.js +0 -58
- package/dist/features/loyalty/api/redeem/route.d.ts +0 -12
- package/dist/features/loyalty/api/redeem/route.js +0 -38
- package/dist/features/loyalty/columns/index.d.ts +0 -17
- package/dist/features/loyalty/columns/index.js +0 -40
- package/dist/features/loyalty/components/CoinsDisplay.d.ts +0 -12
- package/dist/features/loyalty/components/CoinsDisplay.js +0 -10
- package/dist/features/loyalty/components/index.d.ts +0 -1
- package/dist/features/loyalty/components/index.js +0 -1
- package/dist/features/loyalty/hooks/useLoyaltyBalance.d.ts +0 -4
- package/dist/features/loyalty/hooks/useLoyaltyBalance.js +0 -25
- package/dist/features/loyalty/index.d.ts +0 -6
- package/dist/features/loyalty/index.js +0 -6
- package/dist/features/loyalty/manifest.d.ts +0 -2
- package/dist/features/loyalty/manifest.js +0 -16
- package/dist/features/loyalty/messages/en.json +0 -19
- package/dist/features/loyalty/repository/loyalty.repository.d.ts +0 -8
- package/dist/features/loyalty/repository/loyalty.repository.js +0 -22
- package/dist/features/loyalty/schemas/index.d.ts +0 -85
- package/dist/features/loyalty/schemas/index.js +0 -40
- package/dist/features/loyalty/server.d.ts +0 -6
- package/dist/features/loyalty/server.js +0 -6
- package/dist/features/loyalty/types/index.d.ts +0 -31
- package/dist/features/loyalty/types/index.js +0 -1
- package/dist/features/loyalty/types/loyalty-config.d.ts +0 -7
- package/dist/features/loyalty/types/loyalty-config.js +0 -1
- package/dist/features/loyalty/types/loyalty-math.d.ts +0 -9
- package/dist/features/loyalty/types/loyalty-math.js +0 -27
- package/dist/features/products/components/ProductOwnerQuickActions.d.ts +0 -11
- package/dist/features/products/components/ProductOwnerQuickActions.js +0 -120
|
@@ -41,6 +41,13 @@
|
|
|
41
41
|
* @tag sideEffects:none
|
|
42
42
|
*/
|
|
43
43
|
import { z } from "zod";
|
|
44
|
+
/*
|
|
45
|
+
* The floor lives with the payout-hold resolver that enforces it at read
|
|
46
|
+
* time, so the validation message and the honoured behaviour cannot drift โ
|
|
47
|
+
* two copies of "7" is how `payoutHoldDays: 2` coexisted with a hardcoded 7
|
|
48
|
+
* for months (D28).
|
|
49
|
+
*/
|
|
50
|
+
import { PAYOUT_HOLD_FLOOR_DAYS } from "../../../_internal/shared/fees/payout-hold.js";
|
|
44
51
|
/** A percentage a human types into a settings box. */
|
|
45
52
|
const percent = (label) => z.coerce
|
|
46
53
|
.number({ invalid_type_error: `${label} must be a number.` })
|
|
@@ -102,7 +109,29 @@ export const siteSettingsFormSchema = z
|
|
|
102
109
|
gatewayFeePercent: percent("Gateway fee"),
|
|
103
110
|
platformFeeMax: money("Platform fee cap"),
|
|
104
111
|
minPayoutAmount: money("Minimum payout"),
|
|
105
|
-
|
|
112
|
+
/*
|
|
113
|
+
* ๐ `.min(PAYOUT_HOLD_FLOOR_DAYS)`, not `.min(0)` โ and the floor is
|
|
114
|
+
* not arbitrary.
|
|
115
|
+
*
|
|
116
|
+
* The hold must outlast every window during which money can still
|
|
117
|
+
* flow back OUT of the order: the 7-day return window
|
|
118
|
+
* (`returns.windowDays`) and the 7-day sale-protection claim window
|
|
119
|
+
* (`PROTECTION_CLAIM_WINDOW_HOURS.sale` = 168h). Allowing 0 let an
|
|
120
|
+
* admin release a seller's money before the buyer could even claim
|
|
121
|
+
* against protection WE had already sold and would have to fund โ
|
|
122
|
+
* and the stored value was seeded **2**, i.e. inside that window.
|
|
123
|
+
*
|
|
124
|
+
* `resolvePayoutHoldDays` already clamps up to the floor at read
|
|
125
|
+
* time, so behaviour is correct either way. This exists so the admin
|
|
126
|
+
* is TOLD, at the moment they try it, instead of setting 2 and
|
|
127
|
+
* believing it took effect.
|
|
128
|
+
*/
|
|
129
|
+
payoutHoldDays: z.coerce
|
|
130
|
+
.number()
|
|
131
|
+
.int()
|
|
132
|
+
.min(PAYOUT_HOLD_FLOOR_DAYS, `Payout hold must be at least ${PAYOUT_HOLD_FLOOR_DAYS} days โ it has to outlast the return window and the protection claim window, or a seller is paid before a buyer can claim.`)
|
|
133
|
+
.max(365)
|
|
134
|
+
.optional(),
|
|
106
135
|
codHandlingFee: money("COD handling fee"),
|
|
107
136
|
codDepositPercent: percent("COD deposit"),
|
|
108
137
|
})
|
|
@@ -312,7 +312,19 @@ export async function buyNowAuction(userId, userName, userEmail, input) {
|
|
|
312
312
|
// Replaces the old `bidsHaveStarted` gate. Buy Now used to vanish the instant
|
|
313
313
|
// anybody bid, eBay-style, which hid it on almost every real auction. What
|
|
314
314
|
// actually matters is whether it is still a better deal than the bidding.
|
|
315
|
-
|
|
315
|
+
/*
|
|
316
|
+
* ๐ `reservePrice` is passed HERE above all: this is the server-side money
|
|
317
|
+
* gate for a buyout. Omitting it is what let a Buy-Now below the seller's
|
|
318
|
+
* floor complete (D53) โ the reserve was enforced only in
|
|
319
|
+
* `auctionSettlement`, i.e. only on the competitive path.
|
|
320
|
+
*/
|
|
321
|
+
if (!isBuyNowAvailable({
|
|
322
|
+
buyNowPrice,
|
|
323
|
+
currentBid: standingBid,
|
|
324
|
+
isEnded: false,
|
|
325
|
+
isSold: product.isSold,
|
|
326
|
+
reservePrice: product.reservePrice,
|
|
327
|
+
})) {
|
|
316
328
|
throw new ValidationError(ERROR_MESSAGES.BID.BUY_NOW_UNAVAILABLE, {
|
|
317
329
|
code: BID_ERROR_CODES.BUY_NOW_UNAVAILABLE,
|
|
318
330
|
});
|
|
@@ -39,7 +39,7 @@ function formatCountdownLabel(remaining) {
|
|
|
39
39
|
* button can report an error or route to `/checkout?lane=auction`.
|
|
40
40
|
*/
|
|
41
41
|
export function AuctionBottomActions(props) {
|
|
42
|
-
const { currentBid, currency, bidCount, isEnded: ssrIsEnded, auctionEndDate, buyNowPrice } = props;
|
|
42
|
+
const { currentBid, currency, bidCount, isEnded: ssrIsEnded, auctionEndDate, buyNowPrice, reservePrice } = props;
|
|
43
43
|
/*
|
|
44
44
|
* Derived client-side โ see `useIsAuctionEnded`. This bar is a FIXED, always-
|
|
45
45
|
* visible row on mobile, so a stale "Place bid" here is the most prominent
|
|
@@ -55,7 +55,7 @@ export function AuctionBottomActions(props) {
|
|
|
55
55
|
const buyNowMeta = ACTION_META[ACTION_ID.BUY_NOW_AUCTION];
|
|
56
56
|
// Same single predicate the form and the card use. `!!props.onBuyNow` matters
|
|
57
57
|
// because the preview/demo mount passes no action.
|
|
58
|
-
const buyNowAvailable = isBuyNowAvailable({ buyNowPrice, currentBid, isEnded }) && !!props.onBuyNow;
|
|
58
|
+
const buyNowAvailable = isBuyNowAvailable({ buyNowPrice, currentBid, isEnded, reservePrice }) && !!props.onBuyNow;
|
|
59
59
|
useBottomActions(isEnded
|
|
60
60
|
? {}
|
|
61
61
|
: {
|
|
@@ -52,7 +52,7 @@ function toDescriptionHtml(raw) {
|
|
|
52
52
|
}
|
|
53
53
|
function renderAuctionInfoPanel(props) {
|
|
54
54
|
const { productId, storeId, title, currentBid, currency, bidCount, isEnded, endDate, buyNowPrice, buyNowAvailable, featured, freeShipping, condition, finalSale, category, categoryName, brand, brandSlug, productFeatures, features, descriptionHtml, safeSeller, storeHref } = props;
|
|
55
|
-
return (_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_LIVE_BADGE, children: "\uD83C\uDFF7\uFE0F Live Auction" }), _jsx(AuctionLiveStatusBadge, { auctionEndDate: endDate, initialIsEnded: isEnded })] }), _jsx(
|
|
55
|
+
return (_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_LIVE_BADGE, children: "\uD83C\uDFF7\uFE0F Live Auction" }), _jsx(AuctionLiveStatusBadge, { auctionEndDate: endDate, initialIsEnded: isEnded })] }), _jsx(Heading, { level: 1, className: "leading-snug", smSize: "2xl", color: "primary", size: "xl", weight: "bold", children: title }), _jsx(OwnerQuickActions, { resource: "PRODUCT", placement: "detail", recordLabel: title, storeId: storeId, editHref: String(ROUTES.STORE.PRODUCTS_EDIT(productId)) })] }), _jsxs(Div, { children: [_jsx(Text, { className: "mb-0.5", color: "muted", size: "xs", children: "Current bid" }), _jsx(LiveBidPrice, { productId: productId, currentBid: currentBid, bidCount: bidCount, currency: currency, isEnded: isEnded, priceSize: "2xl", badgeSize: "sm" }), endDate && !isEnded && (_jsxs(Text, { className: "mt-1.5", color: "muted", size: "sm", children: ["Ends in ", _jsx(Span, { weight: "medium", color: "muted", children: _jsx(CountdownDisplay, { targetDate: endDate, format: "auto", expiredLabel: "Ended" }) })] })), endDate && _jsxs(Text, { className: "mt-0.5", color: "faint", size: "xs", children: [isEnded ? "Ended" : "Ends", " ", endDate.toLocaleString()] })] }), buyNowAvailable && buyNowPrice !== null && (_jsxs(Row, { align: "center", gap: "sm", className: "border border-[var(--appkit-color-primary-200)] dark:border-[var(--appkit-color-primary-800)] bg-primary-50 dark:bg-primary-900/20", padding: "inlineSm", rounded: "lg", children: [_jsx(Span, { size: "xs", color: "muted", children: "Buy Now:" }), _jsx(Span, { size: "base", weight: "bold", className: "text-primary-700 dark:text-primary-300", children: _jsx(GatedPrice, { label: "Sign in to see the Buy Now price", children: formatCurrency(buyNowPrice, currency) }) }), _jsx(Span, { size: "xs", color: "faint", children: "\u2014 in \u201CPlace a bid\u201D" })] })), _jsx(ProductFeatureBadges, { featured: featured, freeShipping: freeShipping, condition: condition ?? undefined, finalSale: finalSale, labels: { featured: "Featured", fasterDelivery: "Faster Delivery", ratedSeller: "Rated Seller", condition: "Condition", conditionNew: "New", conditionUsed: "Used", conditionBroken: "For Parts", conditionRefurbished: "Refurbished", returnable: "Returnable", finalSale: "Final Sale", freeShipping: "Free Shipping", codAvailable: "Cash on Delivery", emiAvailable: "EMI Available", wishlistCount: (n) => `${n} wishlisted`, categoryProductCount: (n, cat) => `${n} in ${cat}` } }), (categoryName || category || brand) && (_jsxs(Row, { gap: "sm", wrap: true, children: [category && _jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(category)), className: "inline-flex items-center rounded-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-[var(--appkit-space-2-5)] py-[var(--appkit-space-1)] text-[length:var(--appkit-text-xs)] font-medium text-[var(--appkit-color-text-muted)] transition-colors hover:border-primary-300 hover:bg-primary-surface hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:text-primary-400", children: categoryName || category }), !category && categoryName && _jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", border: "subtle", rounded: "full", padding: "pill-sm-tall", surface: "muted", color: "muted", children: categoryName }), brand && brandSlug && _jsx(Link, { href: String(ROUTES.PUBLIC.BRAND_DETAIL(brandSlug)), className: "inline-flex items-center rounded-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-[var(--appkit-space-2-5)] py-[var(--appkit-space-1)] text-[length:var(--appkit-text-xs)] font-medium text-[var(--appkit-color-text-muted)] transition-colors hover:border-primary-300 hover:bg-primary-surface hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:text-primary-400", children: brand }), brand && !brandSlug && _jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", border: "subtle", rounded: "full", padding: "pill-sm-tall", surface: "muted", color: "muted", children: brand })] })), productFeatures && features.length > 0 && _jsx(FeatureBadgeList, { productFeatureIds: features, features: productFeatures }), !productFeatures && features.length > 0 && (_jsxs(Div, { border: "subtle", surface: "muted", padding: "inline", rounded: "xl", children: [_jsx(Text, { className: "mb-2 tracking-wide", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "About this item" }), _jsx(Ul, { spacing: "comfortable", size: "sm", color: "primary", children: features.map((f, i) => _jsxs(Li, { layout: "flex-start", gap: "2", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-primary-500", children: "\u2022" }), f] }, i)) })] })), 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: "Listed 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" })] }) }))] }));
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
58
|
* Store reviews for the auction's seller.
|
|
@@ -171,6 +171,8 @@ export async function AuctionDetailPageView({ id, initialAuction, onPlaceBid, on
|
|
|
171
171
|
currentBid,
|
|
172
172
|
isEnded,
|
|
173
173
|
isSold: p.isSold === true,
|
|
174
|
+
// D53 โ so the button is not offered for a buyout the server will refuse.
|
|
175
|
+
reservePrice: typeof p.reservePrice === "number" ? p.reservePrice : null,
|
|
174
176
|
});
|
|
175
177
|
const condition = typeof p.condition === "string" ? p.condition : null;
|
|
176
178
|
const featured = p.featured === true;
|
|
@@ -29,6 +29,17 @@ export interface MarketplaceAuctionCardData {
|
|
|
29
29
|
* (Root Cause #48).
|
|
30
30
|
*/
|
|
31
31
|
isSold?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* D53 โ the reserve, read by `isBuyNowAvailable` so a card cannot advertise
|
|
34
|
+
* a buyout the server will refuse.
|
|
35
|
+
*
|
|
36
|
+
* ๐ Declared late: the predicate already read `product.reservePrice` while
|
|
37
|
+
* this type did not carry it, so the card was a type error AND every
|
|
38
|
+
* docโcard mapper was free to drop it. That is the exact failure the
|
|
39
|
+
* `isSold` note directly above warns about โ a shared predicate reading a
|
|
40
|
+
* field the card shape does not guarantee.
|
|
41
|
+
*/
|
|
42
|
+
reservePrice?: number | null;
|
|
32
43
|
/**
|
|
33
44
|
* The seller. Absent from this hand-rolled type entirely until now, so the
|
|
34
45
|
* auction card could not show a seller even where every other card did โ
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
3
|
+
import { RecordOwnerQuickActions } from "../../admin/components/RecordOwnerQuickActions.js";
|
|
4
4
|
import { normalizeError } from "../../../errors/normalize.js";
|
|
5
5
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
6
6
|
import { useRouter } from "next/navigation.js";
|
|
@@ -123,6 +123,8 @@ export function MarketplaceAuctionCard({ product, buyoutPrice, className = "", v
|
|
|
123
123
|
currentBid: product.currentBid,
|
|
124
124
|
isEnded,
|
|
125
125
|
isSold: product.isSold === true,
|
|
126
|
+
// D53 โ a card must not advertise a buyout price the server refuses.
|
|
127
|
+
reservePrice: typeof product.reservePrice === "number" ? product.reservePrice : null,
|
|
126
128
|
})
|
|
127
129
|
? rawBuyoutPrice
|
|
128
130
|
: undefined;
|
|
@@ -192,7 +194,7 @@ export function MarketplaceAuctionCard({ product, buyoutPrice, className = "", v
|
|
|
192
194
|
const ownerActions = renderOwnerActions
|
|
193
195
|
? renderOwnerActions()
|
|
194
196
|
: product.id
|
|
195
|
-
? (_jsx(
|
|
197
|
+
? (_jsx(RecordOwnerQuickActions, { resource: "PRODUCT", recordId: String(product.id), storeId: product.storeId ? String(product.storeId) : undefined, recordLabel: product.title, placement: "card" }))
|
|
196
198
|
: null;
|
|
197
199
|
if (!ownerActions)
|
|
198
200
|
return card;
|
|
@@ -200,5 +202,5 @@ export function MarketplaceAuctionCard({ product, buyoutPrice, className = "", v
|
|
|
200
202
|
* Sibling of the card, never a child โ see the prop's docstring. `z-20`
|
|
201
203
|
* clears this card's own overlays, which all sit at `z-10`.
|
|
202
204
|
*/
|
|
203
|
-
return (_jsxs(Div, { className: "
|
|
205
|
+
return (_jsxs(Div, { className: "flex h-full flex-col", children: [card, _jsx(Div, { className: "flex justify-end px-[var(--appkit-space-3)] pb-[var(--appkit-space-3)]", children: ownerActions })] }));
|
|
204
206
|
}
|
|
@@ -40,12 +40,19 @@ export interface PlaceBidFormClientProps {
|
|
|
40
40
|
isEnded: boolean;
|
|
41
41
|
auctionEndDate: Date | null;
|
|
42
42
|
buyNowPrice: number | null;
|
|
43
|
+
/**
|
|
44
|
+
* The seller's floor (D53). Threaded so the Buy-Now control is not offered
|
|
45
|
+
* for a buyout the server will refuse โ `isBuyNowAvailable` now rejects
|
|
46
|
+
* `buyNowPrice < reservePrice`, and without this prop the button would
|
|
47
|
+
* render and then error on click.
|
|
48
|
+
*/
|
|
49
|
+
reservePrice?: number | null;
|
|
43
50
|
bidCount: number;
|
|
44
51
|
tags?: string[];
|
|
45
52
|
onPlaceBid: (input: PlaceBidInput) => Promise<BidActionEnvelope<unknown>>;
|
|
46
53
|
onBuyNow?: () => Promise<BidActionEnvelope<BuyNowSuccess>>;
|
|
47
54
|
}
|
|
48
|
-
export declare function PlaceBidFormClient({ productId, currentBid: ssrCurrentBid, startingBid, tiers, minBidIncrementOverride, currency, isEnded: ssrIsEnded, auctionEndDate, buyNowPrice, bidCount: ssrBidCount, tags, onPlaceBid, onBuyNow, }: PlaceBidFormClientProps): React.JSX.Element;
|
|
55
|
+
export declare function PlaceBidFormClient({ productId, currentBid: ssrCurrentBid, startingBid, tiers, minBidIncrementOverride, currency, isEnded: ssrIsEnded, auctionEndDate, buyNowPrice, reservePrice, bidCount: ssrBidCount, tags, onPlaceBid, onBuyNow, }: PlaceBidFormClientProps): React.JSX.Element;
|
|
49
56
|
/**
|
|
50
57
|
* `PlaceBidModalButton` โ opens a modal that hosts the same PlaceBidFormClient.
|
|
51
58
|
*
|
|
@@ -37,7 +37,7 @@ const __P = {
|
|
|
37
37
|
/** Feature-specific last resort. Authored copy, never derived from an error. */
|
|
38
38
|
const BID_FALLBACK = "Failed to place bid. Please try again.";
|
|
39
39
|
const BUY_NOW_FALLBACK = "Buy Now failed. Please try again.";
|
|
40
|
-
export function PlaceBidFormClient({ productId, currentBid: ssrCurrentBid, startingBid, tiers, minBidIncrementOverride, currency, isEnded: ssrIsEnded, auctionEndDate, buyNowPrice, bidCount: ssrBidCount, tags = [], onPlaceBid, onBuyNow, }) {
|
|
40
|
+
export function PlaceBidFormClient({ productId, currentBid: ssrCurrentBid, startingBid, tiers, minBidIncrementOverride, currency, isEnded: ssrIsEnded, auctionEndDate, buyNowPrice, reservePrice, bidCount: ssrBidCount, tags = [], onPlaceBid, onBuyNow, }) {
|
|
41
41
|
/*
|
|
42
42
|
* ๐ Derived here, not trusted from the server.
|
|
43
43
|
*
|
|
@@ -142,7 +142,7 @@ export function PlaceBidFormClient({ productId, currentBid: ssrCurrentBid, start
|
|
|
142
142
|
// `currentBid` here is the LIVE SSE price, so the button hides itself the
|
|
143
143
|
// moment another bidder passes the buyout price โ without a page reload, and
|
|
144
144
|
// without this component owning a second copy of the rule.
|
|
145
|
-
const buyNowAvailable = isBuyNowAvailable({ buyNowPrice, currentBid, isEnded }) && !!onBuyNow;
|
|
145
|
+
const buyNowAvailable = isBuyNowAvailable({ buyNowPrice, currentBid, isEnded, reservePrice }) && !!onBuyNow;
|
|
146
146
|
const schema = placeBidSchema(minBid, formatCurrency(minBid, currency));
|
|
147
147
|
async function submitBid(amount, setFieldError) {
|
|
148
148
|
try {
|
|
@@ -30,6 +30,20 @@ export declare const AdminAuditActionValues: {
|
|
|
30
30
|
* offer's own `statusHistory`.
|
|
31
31
|
*/
|
|
32
32
|
readonly OFFER_CANCEL: "offer_cancel";
|
|
33
|
+
/**
|
|
34
|
+
* Admin credited or debited a buyer's points by hand.
|
|
35
|
+
*
|
|
36
|
+
* ๐ Belongs here rather than only in the ledger, even though the ledger is
|
|
37
|
+
* already append-only and already records `actorUid` and `adminReason`. The
|
|
38
|
+
* two answer different questions: the ledger answers "why does THIS ACCOUNT
|
|
39
|
+
* have 53 points", this answers "what have admins done lately" โ and the
|
|
40
|
+
* second is the one you need when the account is not yet suspected.
|
|
41
|
+
*
|
|
42
|
+
* 1 point = โน1 of spendable discount, so a credit is a liability the platform
|
|
43
|
+
* must honour and a debit removes value a buyer already holds. That is the
|
|
44
|
+
* same class as `payout_mark_paid` and `coupon_update`, which are both here.
|
|
45
|
+
*/
|
|
46
|
+
readonly POINTS_ADJUST: "points_adjust";
|
|
33
47
|
};
|
|
34
48
|
export type AdminAuditAction = (typeof AdminAuditActionValues)[keyof typeof AdminAuditActionValues];
|
|
35
49
|
export interface AdminAuditLogDocument extends BaseDocument {
|
|
@@ -69,5 +83,19 @@ export declare const ADMIN_AUDIT_LOG_FIELDS: {
|
|
|
69
83
|
* offer's own `statusHistory`.
|
|
70
84
|
*/
|
|
71
85
|
readonly OFFER_CANCEL: "offer_cancel";
|
|
86
|
+
/**
|
|
87
|
+
* Admin credited or debited a buyer's points by hand.
|
|
88
|
+
*
|
|
89
|
+
* ๐ Belongs here rather than only in the ledger, even though the ledger is
|
|
90
|
+
* already append-only and already records `actorUid` and `adminReason`. The
|
|
91
|
+
* two answer different questions: the ledger answers "why does THIS ACCOUNT
|
|
92
|
+
* have 53 points", this answers "what have admins done lately" โ and the
|
|
93
|
+
* second is the one you need when the account is not yet suspected.
|
|
94
|
+
*
|
|
95
|
+
* 1 point = โน1 of spendable discount, so a credit is a liability the platform
|
|
96
|
+
* must honour and a debit removes value a buyer already holds. That is the
|
|
97
|
+
* same class as `payout_mark_paid` and `coupon_update`, which are both here.
|
|
98
|
+
*/
|
|
99
|
+
readonly POINTS_ADJUST: "points_adjust";
|
|
72
100
|
};
|
|
73
101
|
};
|
|
@@ -28,6 +28,20 @@ export const AdminAuditActionValues = {
|
|
|
28
28
|
* offer's own `statusHistory`.
|
|
29
29
|
*/
|
|
30
30
|
OFFER_CANCEL: "offer_cancel",
|
|
31
|
+
/**
|
|
32
|
+
* Admin credited or debited a buyer's points by hand.
|
|
33
|
+
*
|
|
34
|
+
* ๐ Belongs here rather than only in the ledger, even though the ledger is
|
|
35
|
+
* already append-only and already records `actorUid` and `adminReason`. The
|
|
36
|
+
* two answer different questions: the ledger answers "why does THIS ACCOUNT
|
|
37
|
+
* have 53 points", this answers "what have admins done lately" โ and the
|
|
38
|
+
* second is the one you need when the account is not yet suspected.
|
|
39
|
+
*
|
|
40
|
+
* 1 point = โน1 of spendable discount, so a credit is a liability the platform
|
|
41
|
+
* must honour and a debit removes value a buyer already holds. That is the
|
|
42
|
+
* same class as `payout_mark_paid` and `coupon_update`, which are both here.
|
|
43
|
+
*/
|
|
44
|
+
POINTS_ADJUST: "points_adjust",
|
|
31
45
|
};
|
|
32
46
|
export const ADMIN_AUDIT_LOG_FIELDS = {
|
|
33
47
|
ACTOR_UID: "actorUid",
|
|
@@ -37,7 +37,23 @@ export type Permission = "admin:dashboard:view" | "admin:users:read" | "admin:us
|
|
|
37
37
|
* mechanism โ and revoking it is a permission change, which the admin audit
|
|
38
38
|
* log already records.
|
|
39
39
|
*/
|
|
40
|
-
| "tester:admin-surfaces" | "admin:events:read" | "admin:events:write" | "admin:events:delete" | "admin:event-entries:read" | "admin:event-entries:write" | "admin:support-tickets:read" | "admin:support-tickets:write" | "admin:shipments:read" | "admin:shipments:write" | "admin:catalogue:read" | "admin:catalogue:write" | "admin:grouped-listings:read" | "admin:grouped-listings:write" | "admin:support-tickets:assign" | "admin:support-tickets:close" | "admin:scammers:read" | "admin:scammers:write" | "admin:scammers:verify" | "admin:scammers:delete" | "admin:sessions:read" | "admin:sessions:delete" | "admin:notifications:read" | "admin:notifications:write" | "admin:carts:read" | "admin:wishlists:read" | "admin:feature-flags:read" | "admin:feature-flags:write" | "admin:team:read" | "admin:team:write" | "admin:maintenance:view-server-errors" | "admin:maintenance:view-client-errors" | "admin:maintenance:view-function-errors" | "admin:maintenance:view-cloud-logs" | "admin:maintenance:view-payment-rollbacks" | "admin:maintenance:run-analysis" | "admin:maintenance:purge-errors"
|
|
40
|
+
| "tester:admin-surfaces" | "admin:events:read" | "admin:events:write" | "admin:events:delete" | "admin:event-entries:read" | "admin:event-entries:write" | "admin:support-tickets:read" | "admin:support-tickets:write" | "admin:shipments:read" | "admin:shipments:write" | "admin:catalogue:read" | "admin:catalogue:write" | "admin:inventory:read" | "admin:inventory:write" | "admin:grouped-listings:read" | "admin:grouped-listings:write" | "admin:support-tickets:assign" | "admin:support-tickets:close" | "admin:scammers:read" | "admin:scammers:write" | "admin:scammers:verify" | "admin:scammers:delete" | "admin:sessions:read" | "admin:sessions:delete" | "admin:notifications:read" | "admin:notifications:write" | "admin:carts:read" | "admin:wishlists:read" | "admin:feature-flags:read" | "admin:feature-flags:write" | "admin:team:read" | "admin:team:write" | "admin:maintenance:view-server-errors" | "admin:maintenance:view-client-errors" | "admin:maintenance:view-function-errors" | "admin:maintenance:view-cloud-logs" | "admin:maintenance:view-payment-rollbacks" | "admin:maintenance:run-analysis" | "admin:maintenance:purge-errors" | "admin:maintenance:view-gateway-events" | "admin:maintenance:view-obligations" | "admin:payment-cases:read" | "admin:payment-cases:write" | "admin:protection-claims:read" | "admin:protection-claims:write"
|
|
41
|
+
/**
|
|
42
|
+
* Credit or debit a buyer's points by hand.
|
|
43
|
+
*
|
|
44
|
+
* ๐ WRITE ONLY, with no matching `:read`, and that asymmetry is deliberate:
|
|
45
|
+
* a buyer's balance and ledger are already visible on the admin user detail
|
|
46
|
+
* page under the permissions that get you there. What needs its own gate is
|
|
47
|
+
* the act of CREATING SPENDABLE MONEY โ 1 point = โน1 against a future order,
|
|
48
|
+
* so a credit is a liability the platform must honour.
|
|
49
|
+
*
|
|
50
|
+
* Granted to no employee bundle. `createRouteHandler` lets an effective admin
|
|
51
|
+
* through without consulting the array at all, so this exists to be the thing
|
|
52
|
+
* an employee bundle would have to name explicitly โ and nothing names it.
|
|
53
|
+
* Same reasoning as `admin:payment-cases:*`: a queue an analyst may read is
|
|
54
|
+
* different from a decision that moves money.
|
|
55
|
+
*/
|
|
56
|
+
| "admin:points:write";
|
|
41
57
|
/**
|
|
42
58
|
* Granular user actions that can be soft-banned individually.
|
|
43
59
|
* A user may have multiple simultaneous soft bans of different types.
|
|
@@ -262,6 +262,16 @@ export const PERMISSION_GROUPS = {
|
|
|
262
262
|
"admin:maintenance:view-cloud-logs",
|
|
263
263
|
"admin:maintenance:view-payment-rollbacks",
|
|
264
264
|
"admin:maintenance:run-analysis",
|
|
265
|
+
/*
|
|
266
|
+
* The two new diagnostics surfaces DO belong to this role โ a stuck
|
|
267
|
+
* gateway event and an overdue obligation are exactly what a maintenance
|
|
268
|
+
* employee should be able to look at.
|
|
269
|
+
*
|
|
270
|
+
* ๐ `admin:payment-cases:*` and `admin:protection-claims:*` deliberately
|
|
271
|
+
* are NOT here. Those decide money and carry external deadlines.
|
|
272
|
+
*/
|
|
273
|
+
"admin:maintenance:view-gateway-events",
|
|
274
|
+
"admin:maintenance:view-obligations",
|
|
265
275
|
],
|
|
266
276
|
};
|
|
267
277
|
// ============================================================================
|
|
@@ -284,6 +294,9 @@ export const ROUTE_PERMISSION_MAP = {
|
|
|
284
294
|
"/admin/payouts": "admin:payouts:read",
|
|
285
295
|
"/admin/audit-log": "admin:audit-log:read",
|
|
286
296
|
"/admin/shipments": "admin:shipments:read",
|
|
297
|
+
"/admin/inventory": "admin:inventory:read",
|
|
298
|
+
"/admin/inventory/boxes": "admin:inventory:read",
|
|
299
|
+
"/admin/inventory/movements": "admin:inventory:read",
|
|
287
300
|
"/admin/catalogue-approvals": "admin:catalogue:read",
|
|
288
301
|
"/admin/grouped-listings": "admin:grouped-listings:read",
|
|
289
302
|
"/admin/categories": "admin:categories:read",
|
|
@@ -326,6 +339,11 @@ export const ROUTE_PERMISSION_MAP = {
|
|
|
326
339
|
"/admin/maintenance/cloud-logs": "admin:maintenance:view-cloud-logs",
|
|
327
340
|
"/admin/maintenance/payment-rollbacks": "admin:maintenance:view-payment-rollbacks",
|
|
328
341
|
"/admin/maintenance/analysis": "admin:maintenance:run-analysis",
|
|
342
|
+
"/admin/maintenance/gateway-events": "admin:maintenance:view-gateway-events",
|
|
343
|
+
"/admin/maintenance/obligations": "admin:maintenance:view-obligations",
|
|
344
|
+
// Payment protection โ admin-only, see the permission union's own ๐ note.
|
|
345
|
+
"/admin/money-cases": "admin:payment-cases:read",
|
|
346
|
+
"/admin/protection-claims": "admin:protection-claims:read",
|
|
329
347
|
};
|
|
330
348
|
/**
|
|
331
349
|
* Every capability, as a runtime value.
|
|
@@ -56,5 +56,5 @@ export function BlogPostView({ slug, initialData, labels = {}, renderImage, rend
|
|
|
56
56
|
})
|
|
57
57
|
: "";
|
|
58
58
|
const coverImageUrl = getMediaUrl(post.coverImage);
|
|
59
|
-
return (_jsxs(Div, { className: `min-h-screen ${className}`, children: [coverImageUrl && (_jsxs(Div, { className: `relative h-72 md:h-96 ${__O.hidden}`, children: [renderImage ? (renderImage(post)) : (_jsx(MediaImage, { src: coverImageUrl, alt: post.title, size: "hero" })), _jsx(Scrim, { direction: "bottom-up", intensity: "subtle", className: "absolute inset-0" })] })), _jsxs(Div, { className: "max-w-3xl mx-auto", paddingY: "y-3xl", paddingX: "x-md", children: [renderBlogPostHeader(post, date, labels), post.youtubeId && /^[A-Za-z0-9_-]{6,20}$/.test(post.youtubeId) && (_jsx(Div, { className: "mb-8", children: _jsx(Iframe, { src: `https://www.youtube-nocookie.com/embed/${post.youtubeId}`, title: `${post.title} โ video`, aspect: "video", rounded: "lg" }) })), post.tags && post.tags.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mb-8", children: post.tags.map((tag) => (_jsxs(Link, { href: `${String(ROUTES.BLOG.LIST)}?tags=${encodeURIComponent(tag)}`, className: "inline-block px-[var(--appkit-space-3)] py-[var(--appkit-space-1)] rounded-full bg-[var(--appkit-color-surface
|
|
59
|
+
return (_jsxs(Div, { className: `min-h-screen ${className}`, children: [coverImageUrl && (_jsxs(Div, { className: `relative h-72 md:h-96 ${__O.hidden}`, children: [renderImage ? (renderImage(post)) : (_jsx(MediaImage, { src: coverImageUrl, alt: post.title, size: "hero" })), _jsx(Scrim, { direction: "bottom-up", intensity: "subtle", className: "absolute inset-0" })] })), _jsxs(Div, { className: "max-w-3xl mx-auto", paddingY: "y-3xl", paddingX: "x-md", children: [renderBlogPostHeader(post, date, labels), post.youtubeId && /^[A-Za-z0-9_-]{6,20}$/.test(post.youtubeId) && (_jsx(Div, { className: "mb-8", children: _jsx(Iframe, { src: `https://www.youtube-nocookie.com/embed/${post.youtubeId}`, title: `${post.title} โ video`, aspect: "video", rounded: "lg" }) })), post.tags && post.tags.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mb-8", children: post.tags.map((tag) => (_jsxs(Link, { href: `${String(ROUTES.BLOG.LIST)}?tags=${encodeURIComponent(tag)}`, className: "inline-block px-[var(--appkit-space-3)] py-[var(--appkit-space-1)] rounded-full bg-[var(--appkit-color-surface-elevated)] hover:bg-primary/10 text-[var(--appkit-color-text-muted)] hover:text-primary text-[length:var(--appkit-text-xs)] font-medium transition-colors", children: ["#", tag] }, tag))) })), renderAuthorBio && _jsx(Div, { className: "mb-6", children: renderAuthorBio(post) }), _jsx(Div, { surface: "card", padding: "xl", className: "mb-12", children: renderContent ? renderContent(post) : (_jsx(RichText, { html: normalizeRichTextHtml(post.content ?? ""), proseClass: "prose max-w-none dark:prose-invert" })) }), _jsxs(Stack, { gap: "xl", children: [renderBlogPostRelated(related, labels?.relatedTitle ?? "Related Posts", renderRelatedCard), renderBlogPostRelated(relatedByTags, labels?.relatedByTagsTitle ?? "You might also like", renderRelatedCard), renderBlogPostRelated(relatedByAuthor, labels?.relatedByAuthorTitle ?? `More from ${post.authorName}`, renderRelatedCard)] }), renderBackButton && _jsx(Div, { border: "default", className: "mt-10 border-t", padding: "t-xl", children: renderBackButton() })] })] }));
|
|
60
60
|
}
|
|
@@ -81,5 +81,5 @@ export function AdminCatalogueApprovalsView() {
|
|
|
81
81
|
}, children: "Reject" }), _jsx(Button, { isLoading: approveMutation.isPending, onClick: () => {
|
|
82
82
|
approveMutation.mutate(selected.id);
|
|
83
83
|
setSelected(null);
|
|
84
|
-
}, children: "Approve" })] })) : null }), _jsx(Modal, { isOpen: !!rejectTarget, onClose: () => setRejectTarget(null), title: "Reject this catalogue listing?", size: "sm", children: _jsxs(Stack, { gap: "md", children: [_jsx(Text, { variant: "secondary", children: "The owner will see this reason." }), _jsx(Textarea, { value: rejectReason, onChange: (e) => setRejectReason(e.target.value), rows: 3, placeholder: "Reason for rejection" }), _jsx(Button, { isLoading: rejectMutation.isPending, disabled: !rejectReason.trim(), variant: "danger", onClick: () => rejectMutation.mutate(), children: "Reject" })] }) })] }));
|
|
84
|
+
}, children: "Approve" })] })) : null }), _jsx(Modal, { isOpen: !!rejectTarget, onClose: () => setRejectTarget(null), title: "Reject this catalogue listing?", size: "sm", children: _jsxs(Stack, { gap: "md", children: [_jsx(Text, { variant: "secondary", children: "The owner will see this reason." }), _jsx(Textarea, { label: "Reason for rejection", value: rejectReason, onChange: (e) => setRejectReason(e.target.value), rows: 3, placeholder: "Reason for rejection" }), _jsx(Button, { isLoading: rejectMutation.isPending, disabled: !rejectReason.trim(), variant: "danger", onClick: () => rejectMutation.mutate(), children: "Reject" })] }) })] }));
|
|
85
85
|
}
|
|
@@ -51,7 +51,46 @@ import { serverLogger } from "../../../../../monitoring/index.js";
|
|
|
51
51
|
import { categoriesRepository } from "../../../repository/categories.repository.js";
|
|
52
52
|
import { usedPlaceholders } from "../../../../../_internal/shared/templating/placeholders.js";
|
|
53
53
|
import { getCompositionsForCategory } from "../../../../../_internal/server/features/parts/data.js";
|
|
54
|
+
import { getBeysForCategory } from "../../../../../_internal/server/features/beys/data.js";
|
|
54
55
|
import { PART_BREAKDOWN_SLOT, formatPartBreakdown, stripSlotLine, } from "../../../../parts/utils/part-breakdown.js";
|
|
56
|
+
/**
|
|
57
|
+
* โโ The TAXONOMY slots โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
58
|
+
*
|
|
59
|
+
* Measured across the seeded bodies: 45 `{{title}}` ยท 21 `{{siteName}}` ยท
|
|
60
|
+
* 18 `{{series}}` ยท 17 `{{category}}` ยท 13 `{{condition}}` ยท 6 `{{brand}}` ยท
|
|
61
|
+
* 5 `{{partBreakdown}}` ยท 3 `{{categoryPath}}`. The seller form supplies four
|
|
62
|
+
* of those from the draft it is holding (title, brand, condition, siteName)
|
|
63
|
+
* and this route supplied exactly one (`partBreakdown`) โ so
|
|
64
|
+
* **`{{category}}`, `{{categoryPath}}`, `{{series}}` and `{{system}}` could
|
|
65
|
+
* never resolve on any listing**, and the picker reported "4 of 9 slots could
|
|
66
|
+
* not be filled" on every single category, forever.
|
|
67
|
+
*
|
|
68
|
+
* All four are facts about the CATEGORY, not the draft, so the form cannot
|
|
69
|
+
* compute them and this is the only place that can. They ride the existing
|
|
70
|
+
* response exactly as `partBreakdown` does.
|
|
71
|
+
*
|
|
72
|
+
* ๐ `series` and `system` are REAL FIELDS, not invented from the tree.
|
|
73
|
+
* `BeyDocument.series` is "the retail series" (`Beyblade Burst QuadStrike`)
|
|
74
|
+
* and `BeyDocument.system` is "the hardware generation" (`4D System`,
|
|
75
|
+
* `Hybrid Wheel System`) โ which is why the seeded body renders them as two
|
|
76
|
+
* separate rows. A leaf pairs with a bey through `BeyDocument.categoryId`,
|
|
77
|
+
* and `getBeysForCategory` is the inverse of exactly that.
|
|
78
|
+
*
|
|
79
|
+
* ๐ Resolved against the LEAF, never an ancestor โ a bey describes one
|
|
80
|
+
* model, so inheriting a line's would tell every listing on that line it is
|
|
81
|
+
* the model that happened to join to the line node.
|
|
82
|
+
*/
|
|
83
|
+
const TAXONOMY_SLOTS = ["category", "categoryPath", "series", "system"];
|
|
84
|
+
/** Slots that need the bey read. Checked before paying for it. */
|
|
85
|
+
const BEY_SLOTS = ["series", "system"];
|
|
86
|
+
/**
|
|
87
|
+
* `Spinning Tops โบ Beyblade X โบ Attack Types โบ Dran Sword`.
|
|
88
|
+
*
|
|
89
|
+
* A chevron rather than a slash: the body renders it inside
|
|
90
|
+
* `<li><strong>Category:</strong> โฆ</li>` next to prose, and a slash there
|
|
91
|
+
* reads as a URL.
|
|
92
|
+
*/
|
|
93
|
+
const CATEGORY_PATH_SEPARATOR = " โบ ";
|
|
55
94
|
/**
|
|
56
95
|
* The variants a caller may ask for.
|
|
57
96
|
*
|
|
@@ -172,6 +211,10 @@ async function resolveInherited(parentIds, variant, seed) {
|
|
|
172
211
|
* that it came from the line.
|
|
173
212
|
*/
|
|
174
213
|
const byId = new Map(ancestors.map((a) => [a.id, a]));
|
|
214
|
+
// See `Inherited.ancestorNames` โ before the loop, which may break early.
|
|
215
|
+
out.ancestorNames = nearestFirst
|
|
216
|
+
.map((pid) => byId.get(pid)?.name?.trim())
|
|
217
|
+
.filter((n) => Boolean(n));
|
|
175
218
|
for (const pid of nearestFirst) {
|
|
176
219
|
const d = byId.get(pid);
|
|
177
220
|
if (!d)
|
|
@@ -208,11 +251,12 @@ export async function GET(request, context) {
|
|
|
208
251
|
* referenced, so the per-field merge below cannot mutate the document the
|
|
209
252
|
* repository cached.
|
|
210
253
|
*/
|
|
211
|
-
const { template, inheritedFrom, inheritedFromName, defaults } = await resolveInherited(parentIds, variant, {
|
|
254
|
+
const { template, inheritedFrom, inheritedFromName, defaults, ancestorNames } = await resolveInherited(parentIds, variant, {
|
|
212
255
|
template: pickTemplate(leaf, variant),
|
|
213
256
|
inheritedFrom: null,
|
|
214
257
|
inheritedFromName: null,
|
|
215
258
|
defaults: { ...(leaf.productDefaults ?? {}) },
|
|
259
|
+
ancestorNames: [],
|
|
216
260
|
});
|
|
217
261
|
/*
|
|
218
262
|
* ๐ `placeholders` is RE-DERIVED here and not trusted from the stored
|
|
@@ -256,6 +300,68 @@ export async function GET(request, context) {
|
|
|
256
300
|
else
|
|
257
301
|
body = stripSlotLine(body, PART_BREAKDOWN_SLOT);
|
|
258
302
|
}
|
|
303
|
+
/*
|
|
304
|
+
* โโ The taxonomy slots โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
305
|
+
*
|
|
306
|
+
* See TAXONOMY_SLOTS. `category` and `categoryPath` are free โ the leaf
|
|
307
|
+
* and its ancestors are already in hand โ so they are built
|
|
308
|
+
* unconditionally and the `placeholders` check below decides whether they
|
|
309
|
+
* are sent.
|
|
310
|
+
*
|
|
311
|
+
* The bey read is gated on the body actually asking, the same way the
|
|
312
|
+
* composition read is: nothing outside the Beyblade lines carries
|
|
313
|
+
* `{{series}}`/`{{system}}`, so a TCG set or a Hot Wheels casting pays
|
|
314
|
+
* nothing for a concept it does not have.
|
|
315
|
+
*/
|
|
316
|
+
if (template) {
|
|
317
|
+
const taxonomy = {
|
|
318
|
+
category: (leaf.name ?? "").trim(),
|
|
319
|
+
// Root-first: `ancestorNames` is nearest-first, so reverse it and put
|
|
320
|
+
// the leaf on the end. This is the order a breadcrumb reads in.
|
|
321
|
+
categoryPath: [...ancestorNames]
|
|
322
|
+
.reverse()
|
|
323
|
+
.concat((leaf.name ?? "").trim())
|
|
324
|
+
.filter(Boolean)
|
|
325
|
+
.join(CATEGORY_PATH_SEPARATOR),
|
|
326
|
+
};
|
|
327
|
+
if (BEY_SLOTS.some((s) => placeholders.includes(s))) {
|
|
328
|
+
const beys = await getBeysForCategory(id);
|
|
329
|
+
/*
|
|
330
|
+
* The first pairing only, matching `formatPartBreakdown`'s rule and
|
|
331
|
+
* for the same reason: 22 leaves pair with more than one bey (a
|
|
332
|
+
* remake shares a model's name), and concatenating two retail series
|
|
333
|
+
* would describe a release that does not exist.
|
|
334
|
+
*/
|
|
335
|
+
const bey = beys[0];
|
|
336
|
+
taxonomy.series = (bey?.series ?? "").trim();
|
|
337
|
+
taxonomy.system = (bey?.system ?? "").trim();
|
|
338
|
+
}
|
|
339
|
+
for (const slot of TAXONOMY_SLOTS) {
|
|
340
|
+
if (!placeholders.includes(slot))
|
|
341
|
+
continue;
|
|
342
|
+
const value = taxonomy[slot] ?? "";
|
|
343
|
+
if (value) {
|
|
344
|
+
slots[slot] = value;
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
/*
|
|
348
|
+
* ๐ ABSENCE REMOVES THE LINE โ `partBreakdown`'s contract, applied
|
|
349
|
+
* here for the same reason: `interpolate` resolves an unfilled slot
|
|
350
|
+
* to an empty string, so `<li><strong>System:</strong> {{system}}</li>`
|
|
351
|
+
* would render an empty bullet that reads as broken data.
|
|
352
|
+
*
|
|
353
|
+
* ๐ KNOWN CONSEQUENCE, stated rather than guarded against (as the
|
|
354
|
+
* strip helper's own header does): `{{series}}` appears both as a
|
|
355
|
+
* standalone row AND mid-sentence ("from the {{series}} line"), so a
|
|
356
|
+
* leaf with no paired bey loses that whole sentence instead of
|
|
357
|
+
* printing "from the line". Losing a sentence is the better of the
|
|
358
|
+
* two, and the seller sees the picker's note either way โ but a
|
|
359
|
+
* template author adding an inline slot should know the line goes
|
|
360
|
+
* with it.
|
|
361
|
+
*/
|
|
362
|
+
body = stripSlotLine(body, slot);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
259
365
|
return NextResponse.json({
|
|
260
366
|
success: true,
|
|
261
367
|
data: {
|
|
@@ -177,7 +177,7 @@ export async function BrandDetailPageView({ slug, initialBrand }) {
|
|
|
177
177
|
const ldFaq = brand?.faqs && brand.faqs.length > 0
|
|
178
178
|
? faqJsonLd(brand.faqs.map((f) => ({ question: f.question, answer: f.answer })))
|
|
179
179
|
: null;
|
|
180
|
-
return (_jsxs(Main, { children: [_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(ldBreadcrumb) } }), _jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(ldCollection) } }), ldFaq && (_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(ldFaq) } })), _jsxs(Section, { className: `relative ${__O.hidden} ${hasCover ? "min-h-[220px] md:min-h-[280px]" : "bg-[var(--appkit-color-bg)]"}`, children: [hasCover && (_jsxs(_Fragment, { children: [_jsx(Div, { className: "absolute inset-0", children: _jsx(MediaImage, { src: coverImage, alt: "", size: "banner" }) }), _jsx(Div, { surface: "overlay-md", className: "absolute inset-0" })] })), !hasCover && (_jsx(DynamicBgDiv, { color: brandColor, className: "absolute inset-0 opacity-10" })), _jsxs(Div, { className: "relative z-10 max-w-7xl mx-auto", paddingY: hasCover ? "y-3xl" : "y-xl", padding: "x-md", children: [_jsxs(Nav, { layout: "flex", gap: "2xs", textSize: "sm", className: "mb-4", "aria-label": "Breadcrumb", children: [_jsx(Link, { href: String(ROUTES.HOME), className: hasCover ? "text-white/70 hover:text-white transition-colors" : "text-[var(--appkit-color-text-muted)] hover:text-primary-600 dark:hover:text-primary-400 transition-colors", children: "Home" }), _jsx(Span, { className: hasCover ? "text-white/40" : "text-zinc-400", children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.BRANDS), className: hasCover ? "text-white/70 hover:text-white transition-colors" : "text-[var(--appkit-color-text-muted)] hover:text-primary-600 dark:hover:text-primary-400 transition-colors", children: "Brands" }), _jsx(Span, { className: hasCover ? "text-white/40" : "text-zinc-400", children: "/" }), _jsx(Span, { weight: "medium", className: hasCover ? "text-white" : "text-[var(--appkit-color-text)]", children: brand?.name ?? slug })] }), _jsxs(Row, { className: "mb-3", align: "center", gap: "md", children: [brand?.display?.icon && (_jsx(Span, { className: "leading-none", size: "5xl", children: brand.display.icon })), _jsxs(
|
|
180
|
+
return (_jsxs(Main, { children: [_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(ldBreadcrumb) } }), _jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(ldCollection) } }), ldFaq && (_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(ldFaq) } })), _jsxs(Section, { className: `relative ${__O.hidden} ${hasCover ? "min-h-[220px] md:min-h-[280px]" : "bg-[var(--appkit-color-bg)]"}`, children: [hasCover && (_jsxs(_Fragment, { children: [_jsx(Div, { className: "absolute inset-0", children: _jsx(MediaImage, { src: coverImage, alt: "", size: "banner" }) }), _jsx(Div, { surface: "overlay-md", className: "absolute inset-0" })] })), !hasCover && (_jsx(DynamicBgDiv, { color: brandColor, className: "absolute inset-0 opacity-10" })), _jsxs(Div, { className: "relative z-10 max-w-7xl mx-auto", paddingY: hasCover ? "y-3xl" : "y-xl", padding: "x-md", children: [_jsxs(Nav, { layout: "flex", gap: "2xs", textSize: "sm", className: "mb-4", "aria-label": "Breadcrumb", children: [_jsx(Link, { href: String(ROUTES.HOME), className: hasCover ? "text-white/70 hover:text-white transition-colors" : "text-[var(--appkit-color-text-muted)] hover:text-primary-600 dark:hover:text-primary-400 transition-colors", children: "Home" }), _jsx(Span, { className: hasCover ? "text-white/40" : "text-zinc-400", children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.BRANDS), className: hasCover ? "text-white/70 hover:text-white transition-colors" : "text-[var(--appkit-color-text-muted)] hover:text-primary-600 dark:hover:text-primary-400 transition-colors", children: "Brands" }), _jsx(Span, { className: hasCover ? "text-white/40" : "text-zinc-400", children: "/" }), _jsx(Span, { weight: "medium", className: hasCover ? "text-white" : "text-[var(--appkit-color-text)]", children: brand?.name ?? slug })] }), _jsxs(Row, { className: "mb-3", align: "center", gap: "md", children: [brand?.display?.icon && (_jsx(Span, { className: "leading-none", size: "5xl", children: brand.display.icon })), _jsxs(Stack, { gap: "xs", className: "min-w-0", children: [_jsx(Heading, { color: "inverse", level: 1, className: `${hasCover ? "" : "text-[var(--appkit-color-text)]"}`, size: "3xl", mdSize: "4xl", weight: "bold", children: brand?.name ?? slug }), brand?.id && (_jsx(RecordOwnerQuickActions, { resource: "BRAND", recordId: brand.id, placement: "detail",
|
|
181
181
|
/* See CategoryDetailPageView โ ghost ink is invisible on the cover hero. */
|
|
182
|
-
onMedia: hasCover, className: "mb-2", recordLabel: brand.name ?? slug })),
|
|
182
|
+
onMedia: hasCover, className: "mb-2", recordLabel: brand.name ?? slug })), brand?.description && typeof brand.description === "string" && !brand.description.startsWith("{") && (_jsx(Text, { color: hasCover ? "inverse" : "muted", className: "max-w-2xl mt-1", size: "base", children: brand.description }))] })] }), _jsxs(Row, { gap: "sm", wrap: true, className: "mt-3", children: [(counts.products ?? 0) > 0 && (_jsxs(Span, { layout: "inline-flex", gap: "xs", color: "inverse", size: "xs", weight: "medium", className: `${hasCover ? "bg-[rgba(255,255,255,0.2)] backdrop-blur-sm" : "bg-primary/10 text-primary-700 dark:text-primary-400"}`, rounded: "full", padding: "pill-sm-tall", children: [counts.products.toLocaleString(), " ", counts.products === 1 ? "product" : "products"] })), (counts.auctions ?? 0) > 0 && (_jsxs(Span, { layout: "inline-flex", gap: "xs", color: hasCover ? "inverse" : "warning", surface: hasCover ? undefined : "warning-surface", size: "xs", weight: "medium", className: hasCover ? "bg-[rgba(255,255,255,0.2)] backdrop-blur-sm" : "", rounded: "full", padding: "pill-sm-tall", children: [counts.auctions.toLocaleString(), " ", counts.auctions === 1 ? "auction" : "auctions"] })), (counts["pre-orders"] ?? 0) > 0 && (_jsxs(Span, { layout: "inline-flex", gap: "xs", color: hasCover ? "inverse" : "info", surface: hasCover ? undefined : "info-surface", size: "xs", weight: "medium", className: hasCover ? "bg-[rgba(255,255,255,0.2)] backdrop-blur-sm" : "", rounded: "full", padding: "pill-sm-tall", children: [counts["pre-orders"].toLocaleString(), " ", counts["pre-orders"] === 1 ? "pre-order" : "pre-orders"] })), totalItems === 0 && (_jsx(Span, { size: "sm", className: hasCover ? "text-white/60" : "text-zinc-400", children: "No items listed yet" }))] })] })] }), (brand?.brandWebsite || brand?.brandCountry || brand?.brandFounded) && (_jsx(Section, { border: "subtle", surface: "default", className: "border-b", padding: "y-md", children: _jsx(Container, { size: "xl", children: _jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 2, size: "sm", weight: "semibold", color: "muted", transform: "uppercase", children: "About this brand" }), _jsxs(Dl, { divide: "subtle", rounded: "xl", border: "subtle", className: "overflow-hidden max-w-lg", children: [brand?.brandWebsite && (_jsxs(Row, { gap: "md", oddEven: "zebra", surface: "default", padding: "inline", children: [_jsx(Dt, { className: "w-32 flex-shrink-0", color: "primary", weight: "medium", children: "Website" }), _jsx(Dd, { className: "flex-1", children: _jsx(Anchor, { href: brand.brandWebsite, tone: "brand", underline: "hover", children: brand.brandWebsite }) })] })), brand?.brandCountry && (_jsxs(Row, { gap: "md", oddEven: "zebra", surface: "default", padding: "inline", children: [_jsx(Dt, { className: "w-32 flex-shrink-0", color: "primary", weight: "medium", children: "Country" }), _jsx(Dd, { className: "flex-1", color: "muted", children: brand.brandCountry })] })), brand?.brandFounded && (_jsxs(Row, { gap: "md", oddEven: "zebra", surface: "default", padding: "inline", children: [_jsx(Dt, { className: "w-32 flex-shrink-0", color: "primary", weight: "medium", children: "Founded" }), _jsx(Dd, { className: "flex-1", color: "muted", children: brand.brandFounded })] }))] })] }) }) })), brandContentBody && brandContentBody.trim().length > 0 && (_jsx(Section, { padding: "y-lg", children: _jsx(Container, { size: "xl", children: _jsx(RichTextRenderer, { html: brandContentBody }) }) })), _jsx(CategoryHighlightsAndFaqSection, { highlights: brand?.highlights, faqs: brand?.faqs }), _jsx(Section, { padding: "y-lg", children: _jsx(Container, { size: "xl", children: brandName ? (_jsx(BrandDetailTabs, { brandName: brandName, initialProductsData: productsResult ?? undefined, initialBundles: brandBundles, counts: counts, totals: totals, enabledListingTypes: enabledListingTypes(settings), enabledCategoryTypes: enabledCategoryTypes(settings) })) : (_jsx(Text, { paddingY: "3xl", color: "muted", size: "sm", align: "start", children: "Brand not found." })) }) }), groupedListings.length > 0 && (_jsx(Section, { padding: "y-lg", children: _jsx(Container, { size: "xl", children: _jsx(GroupedListingsCarousel, { groups: groupedListings }) }) })), relatedBrands.length > 0 && (_jsx(Section, { border: "subtle", surface: "default", className: "border-t", padding: "y-lg", children: _jsxs(Container, { size: "xl", children: [_jsx(Heading, { level: 2, className: "mb-4", size: "xl", weight: "semibold", children: "Related Brands" }), _jsx(CategoryGrid, { categories: relatedBrands, getHref: (b) => String(ROUTES.PUBLIC.BRAND_DETAIL(b.slug)) })] }) }))] }));
|
|
183
183
|
}
|
|
@@ -66,7 +66,13 @@ export function BreadcrumbTrail({ crumbs, category, rootLabel = "All Categories"
|
|
|
66
66
|
* missing and gave them no way to reach it.
|
|
67
67
|
*/
|
|
68
68
|
const leadCount = hasCollapsed ? split.lead.length : 0;
|
|
69
|
-
return (
|
|
69
|
+
return (
|
|
70
|
+
/*
|
|
71
|
+
* No marker class here โ it lives on the `<Breadcrumb>` primitive this
|
|
72
|
+
* renders below, which is also what the scam registry's pages use
|
|
73
|
+
* directly. One owner; see `Breadcrumb.tsx`.
|
|
74
|
+
*/
|
|
75
|
+
_jsxs(Div, { className: className, children: [_jsxs(Row, { align: "center", gap: "xs", wrap: true, children: [_jsx(Breadcrumb, { items: visible.slice(0, leadCount), tone: tone }), hasCollapsed && (_jsxs(Details, { tone: "card", padding: "sm", rounded: "lg", children: [_jsx(Summary, { size: "xs", color: "muted", ariaLabel: `Show ${split.collapsed.length} hidden category levels`, children: `โฆ ${split.collapsed.length} more` }), _jsx(Div, { padding: "t-xs", children: _jsx(Stack, { align: "start", gap: "xs", children: split.collapsed.map((c) => (_jsx(TextLink, { href: c.url ?? rootHref, size: "xs", children: c.name }, c.url ?? c.name))) }) })] })), _jsx(Breadcrumb, { items: hasCollapsed ? visible.slice(leadCount) : visible, tone: tone })] }), alt.mode === "inline" && (_jsxs(Span, { size: "xs", color: "muted", children: ["Also in", " ", alt.items.map((a, i) => (_jsxs(React.Fragment, { children: [i > 0 && " ยท ", _jsx(TextLink, { href: a.url ?? rootHref, size: "xs", children: a.name })] }, a.url ?? a.name)))] })), alt.mode === "dropdown" && (_jsxs(Details, { tone: "card", padding: "sm", rounded: "lg", children: [_jsx(Summary, { size: "xs", color: "muted", ariaLabel: "Other categories this listing is filed under", children: `Also in ${alt.items.length} more` }), _jsx(Div, { padding: "t-xs", children: _jsx(Stack, { align: "start", gap: "xs", children: alt.items.map((a) => (_jsx(TextLink, { href: a.url ?? rootHref, size: "xs", children: a.name }, a.url ?? a.name))) }) })] }))] }));
|
|
70
76
|
}
|
|
71
77
|
function fromCrumb(c) {
|
|
72
78
|
return c.url ? { label: c.name, href: c.url } : { label: c.name };
|
|
@@ -26,7 +26,7 @@ export function BundleDetailView({ bundle, members = [], onBuyNow, onAddToCart,
|
|
|
26
26
|
? formatCurrency(bundle.bundlePrice, "INR")
|
|
27
27
|
: BUNDLE_COPY.detail.priceFallback;
|
|
28
28
|
const discount = computeBundleDiscount(bundle.bundlePrice, bundle.bundleOriginalTotal);
|
|
29
|
-
return (_jsxs(Main, { children: [_jsx(Section, { padding: "y-2xl", children: _jsx(Container, { size: "xl", children: _jsxs(Stack, { gap: "lg", children: [_jsxs(Stack, { gap: "lg", direction: "md-row", align: "start", children: [_jsx(Div, { className: "w-full md:w-2/5", children: members.length > 0 ? (_jsx(BundleCollage, { members: members })) : (_jsx(Div, { className: `aspect-video w-full ${__O.hidden}`, rounded: "2xl", surface: "subtle", children: _jsx(Div, { className: "h-full w-full", children: _jsx(MediaImage, { src: cover, alt: bundle.name, size: "hero", fallback: PLACEHOLDER_EMOJI }) }) })) }), _jsxs(Stack, { gap: "md", className: "flex-1", children: [_jsx(
|
|
29
|
+
return (_jsxs(Main, { children: [_jsx(Section, { padding: "y-2xl", children: _jsx(Container, { size: "xl", children: _jsxs(Stack, { gap: "lg", children: [_jsxs(Stack, { gap: "lg", direction: "md-row", align: "start", children: [_jsx(Div, { className: "w-full md:w-2/5", children: members.length > 0 ? (_jsx(BundleCollage, { members: members })) : (_jsx(Div, { className: `aspect-video w-full ${__O.hidden}`, rounded: "2xl", surface: "subtle", children: _jsx(Div, { className: "h-full w-full", children: _jsx(MediaImage, { src: cover, alt: bundle.name, size: "hero", fallback: PLACEHOLDER_EMOJI }) }) })) }), _jsxs(Stack, { gap: "md", className: "flex-1", children: [_jsx(Heading, { level: 1, size: "3xl", weight: "semibold", color: "primary", children: bundle.name }), _jsx(RecordOwnerQuickActions, { resource: "BUNDLE", recordId: String(bundle.id), placement: "detail", recordLabel: String(bundle.name) }), _jsxs(Row, { gap: "sm", align: "center", wrap: true, children: [_jsx(Text, { size: "lg", weight: "bold", children: _jsx(GatedPrice, { label: "Sign in to see the bundle price", children: priceLabel }) }), discount && (
|
|
30
30
|
// Both the struck-through total and the "N% off" badge are
|
|
31
31
|
// derived from the bundle price, so they disclose it even
|
|
32
32
|
// though the badge carries no currency symbol.
|