@mohasinac/appkit 4.62.0 โ 4.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-stamp.json +3 -3
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +8 -29
- package/dist/_internal/client/features/layout/filterNavItems.d.ts +28 -0
- package/dist/_internal/client/features/layout/filterNavItems.js +35 -0
- package/dist/_internal/server/features/ads/booking.d.ts +118 -0
- package/dist/_internal/server/features/ads/booking.js +326 -0
- package/dist/_internal/server/features/checkout/actions.d.ts +129 -9
- package/dist/_internal/server/features/checkout/actions.js +850 -79
- package/dist/_internal/server/features/checkout/expand-order-items.d.ts +1 -2
- package/dist/_internal/server/features/checkout/expand-order-items.js +32 -0
- package/dist/_internal/server/features/checkout/freeze-parts.d.ts +50 -0
- package/dist/_internal/server/features/checkout/freeze-parts.js +94 -0
- package/dist/_internal/server/features/checkout/value-otp-gate.d.ts +55 -0
- package/dist/_internal/server/features/checkout/value-otp-gate.js +60 -0
- package/dist/_internal/server/features/dashboard/attention.d.ts +128 -0
- package/dist/_internal/server/features/dashboard/attention.js +183 -0
- package/dist/_internal/server/features/dashboard/data.d.ts +47 -0
- package/dist/_internal/server/features/dashboard/data.js +82 -0
- package/dist/_internal/server/features/inventory/reservations.d.ts +99 -0
- package/dist/_internal/server/features/inventory/reservations.js +273 -0
- package/dist/_internal/server/features/invoicing/allocate.d.ts +63 -0
- package/dist/_internal/server/features/invoicing/allocate.js +162 -0
- package/dist/_internal/server/features/invoicing/credit-note.d.ts +57 -0
- package/dist/_internal/server/features/invoicing/credit-note.js +126 -0
- package/dist/_internal/server/features/invoicing/gstr1.d.ts +74 -0
- package/dist/_internal/server/features/invoicing/gstr1.js +251 -0
- package/dist/_internal/server/features/invoicing/issue.d.ts +96 -0
- package/dist/_internal/server/features/invoicing/issue.js +202 -0
- package/dist/_internal/server/features/offers/destinations.d.ts +40 -0
- package/dist/_internal/server/features/offers/destinations.js +65 -0
- package/dist/_internal/server/features/orders/actions.d.ts +8 -1
- package/dist/_internal/server/features/orders/actions.js +81 -8
- package/dist/_internal/server/features/orders/adapters.js +54 -0
- package/dist/_internal/server/features/orders/amend-delivery.d.ts +56 -0
- package/dist/_internal/server/features/orders/amend-delivery.js +124 -0
- package/dist/_internal/server/features/orders/balance.d.ts +89 -0
- package/dist/_internal/server/features/orders/balance.js +256 -0
- package/dist/_internal/server/features/orders/cancellation-refund.d.ts +15 -9
- package/dist/_internal/server/features/orders/cancellation-refund.js +15 -9
- package/dist/_internal/server/features/points/award.js +46 -4
- package/dist/_internal/server/features/pricing/actions.d.ts +58 -0
- package/dist/_internal/server/features/pricing/actions.js +144 -0
- package/dist/_internal/server/features/refunds/actions.js +26 -0
- package/dist/_internal/server/features/shipping/book-split.d.ts +86 -0
- package/dist/_internal/server/features/shipping/book-split.js +130 -0
- package/dist/_internal/server/features/shipping/book.d.ts +61 -0
- package/dist/_internal/server/features/shipping/book.js +176 -0
- package/dist/_internal/server/features/shipping/courier-block.d.ts +69 -0
- package/dist/_internal/server/features/shipping/courier-block.js +264 -0
- package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
- package/dist/_internal/server/features/site-settings/adapters.js +29 -0
- package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
- package/dist/_internal/server/features/stores/adapters.js +65 -0
- package/dist/_internal/server/functions/scheduled.d.ts +2 -1
- package/dist/_internal/server/functions/scheduled.js +95 -2
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +11 -2
- package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +4 -0
- package/dist/_internal/server/jobs/core/dailyStatusDigest.js +19 -2
- package/dist/_internal/server/jobs/core/index.d.ts +2 -1
- package/dist/_internal/server/jobs/core/index.js +2 -1
- package/dist/_internal/server/jobs/core/jobRunners.js +45 -0
- package/dist/_internal/server/jobs/core/onJobCreated.d.ts +30 -7
- package/dist/_internal/server/jobs/core/onJobCreated.js +78 -45
- package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +7 -0
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +65 -0
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +33 -0
- package/dist/_internal/server/jobs/core/reservationExpiry.d.ts +17 -0
- package/dist/_internal/server/jobs/core/reservationExpiry.js +40 -0
- package/dist/_internal/server/jobs/core/runJobOnce.d.ts +48 -0
- package/dist/_internal/server/jobs/core/runJobOnce.js +195 -0
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +25 -2
- package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
- package/dist/_internal/server/jobs/handlers/index.js +1 -0
- package/dist/_internal/server/jobs/handlers/onOrderStatusChange.js +17 -0
- package/dist/_internal/server/jobs/handlers/reservationExpiry.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/reservationExpiry.js +2 -0
- package/dist/_internal/server/notifications/channel-health.d.ts +26 -3
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +296 -0
- package/dist/_internal/shared/checkout/coupon-discount.d.ts +43 -1
- package/dist/_internal/shared/checkout/coupon-discount.js +26 -1
- package/dist/_internal/shared/checkout/order-math.d.ts +174 -0
- package/dist/_internal/shared/checkout/order-math.js +159 -0
- package/dist/_internal/shared/checkout/refundable-base.d.ts +25 -0
- package/dist/_internal/shared/checkout/refundable-base.js +13 -1
- package/dist/_internal/shared/checkout/rules/index.d.ts +1 -1
- package/dist/_internal/shared/checkout/rules/index.js +1 -1
- package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +18 -0
- package/dist/_internal/shared/checkout/rules/payment-gate.js +25 -0
- package/dist/_internal/shared/checkout/split.d.ts +75 -0
- package/dist/_internal/shared/checkout/split.js +120 -0
- package/dist/_internal/shared/content/disclaimers.d.ts +88 -0
- package/dist/_internal/shared/content/disclaimers.js +217 -0
- package/dist/_internal/shared/content/published-values.d.ts +93 -0
- package/dist/_internal/shared/content/published-values.js +206 -0
- package/dist/_internal/shared/features/admin/integrations.d.ts +139 -0
- package/dist/_internal/shared/features/admin/integrations.js +263 -0
- package/dist/_internal/shared/features/dashboard/hub-sections.d.ts +72 -0
- package/dist/_internal/shared/features/dashboard/hub-sections.js +75 -0
- package/dist/_internal/shared/features/emi/choice.d.ts +98 -0
- package/dist/_internal/shared/features/emi/choice.js +69 -0
- package/dist/_internal/shared/features/emi/group.d.ts +84 -0
- package/dist/_internal/shared/features/emi/group.js +126 -0
- package/dist/_internal/shared/features/ledger/posting.d.ts +107 -0
- package/dist/_internal/shared/features/ledger/posting.js +165 -0
- package/dist/_internal/shared/features/ledger/reports.d.ts +76 -0
- package/dist/_internal/shared/features/ledger/reports.js +127 -0
- package/dist/_internal/shared/features/ledger/rules.d.ts +170 -0
- package/dist/_internal/shared/features/ledger/rules.js +221 -0
- package/dist/_internal/shared/features/offers/coordination.d.ts +122 -0
- package/dist/_internal/shared/features/offers/coordination.js +80 -0
- package/dist/_internal/shared/features/orders/delivery-snapshot.d.ts +114 -0
- package/dist/_internal/shared/features/orders/delivery-snapshot.js +116 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.d.ts +113 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.js +181 -0
- package/dist/_internal/shared/features/orders/refund-copy.d.ts +1 -1
- package/dist/_internal/shared/features/orders/refund-copy.js +18 -1
- package/dist/_internal/shared/features/payouts/pay-period.d.ts +91 -0
- package/dist/_internal/shared/features/payouts/pay-period.js +104 -0
- package/dist/_internal/shared/features/points/accepts.d.ts +29 -0
- package/dist/_internal/shared/features/points/accepts.js +49 -0
- package/dist/_internal/shared/features/pricing/rate-registry.d.ts +150 -0
- package/dist/_internal/shared/features/pricing/rate-registry.js +246 -0
- package/dist/_internal/shared/features/shipping/parcel.d.ts +123 -0
- package/dist/_internal/shared/features/shipping/parcel.js +139 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.d.ts +91 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.js +108 -0
- package/dist/_internal/shared/features/site-settings/fees.d.ts +16 -8
- package/dist/_internal/shared/features/site-settings/fees.js +12 -8
- package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
- package/dist/_internal/shared/fees/calculator.d.ts +33 -1
- package/dist/_internal/shared/fees/calculator.js +32 -2
- package/dist/_internal/shared/fees/explain.d.ts +81 -0
- package/dist/_internal/shared/fees/explain.js +101 -0
- package/dist/_internal/shared/history/index.d.ts +1 -1
- package/dist/_internal/shared/history/index.js +1 -1
- package/dist/_internal/shared/history/types.d.ts +7 -1
- package/dist/_internal/shared/history/types.js +25 -0
- package/dist/client.d.ts +21 -0
- package/dist/client.js +43 -0
- package/dist/constants/api-endpoints.d.ts +114 -0
- package/dist/constants/api-endpoints.js +55 -0
- package/dist/constants/field-names.d.ts +42 -0
- package/dist/constants/field-names.js +52 -0
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/shipping.d.ts +45 -0
- package/dist/contracts/shipping.js +15 -0
- package/dist/features/about/components/AboutView.js +1 -1
- package/dist/features/account/components/BuyerAuctionsGuideView.js +4 -1
- package/dist/features/account/components/UserOrdersView.js +47 -35
- package/dist/features/admin/components/AdminCouponEditorView.js +17 -0
- package/dist/features/admin/components/AdminIntegrationsView.d.ts +55 -0
- package/dist/features/admin/components/AdminIntegrationsView.js +74 -0
- package/dist/features/admin/components/AdminInvoicingView.d.ts +2 -0
- package/dist/features/admin/components/AdminInvoicingView.js +65 -0
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +33 -1
- package/dist/features/admin/components/AdminOrderEditorView.js +81 -3
- package/dist/features/admin/components/AdminOrdersGuideView.js +23 -2
- package/dist/features/admin/components/AdminOrdersView.js +86 -5
- package/dist/features/admin/components/OwnerQuickActions.js +24 -2
- package/dist/features/admin/constants/filter-tabs.d.ts +6 -0
- package/dist/features/admin/constants/filter-tabs.js +6 -0
- package/dist/features/admin/constants/site-settings-tabs.d.ts +1 -1
- package/dist/features/admin/hooks/useAdminListingData.js +16 -0
- package/dist/features/admin/schemas/admin-user-form.d.ts +2 -2
- package/dist/features/admin/schemas/firestore.d.ts +62 -0
- package/dist/features/admin/schemas/firestore.js +5 -0
- package/dist/features/ads/schemas/booking-write.d.ts +120 -0
- package/dist/features/ads/schemas/booking-write.js +75 -0
- package/dist/features/ads/schemas/creative-form.d.ts +18 -0
- package/dist/features/ads/schemas/creative-form.js +51 -0
- package/dist/features/ads/schemas/firestore.d.ts +140 -0
- package/dist/features/ads/schemas/firestore.js +109 -0
- package/dist/features/auctions/repository/bid.repository.js +3 -1
- package/dist/features/audit-log/schemas/firestore.d.ts +140 -0
- package/dist/features/audit-log/schemas/firestore.js +89 -0
- package/dist/features/auth/actions/profile-actions.d.ts +69 -1
- package/dist/features/auth/actions/profile-actions.js +62 -1
- package/dist/features/auth/permissions/constants.js +13 -0
- package/dist/features/auth/schemas/firestore.d.ts +16 -2
- package/dist/features/auth/schemas/firestore.js +2 -1
- package/dist/features/blog/actions/blog-actions.d.ts +6 -0
- package/dist/features/blog/actions/blog-actions.js +17 -2
- package/dist/features/blog/api/route.js +4 -1
- package/dist/features/blog/columns/index.js +5 -0
- package/dist/features/blog/components/BlogIndexPageView.js +2 -1
- package/dist/features/blog/repository/blog.repository.d.ts +4 -0
- package/dist/features/blog/repository/blog.repository.js +5 -0
- package/dist/features/blog/schemas/blog-form.d.ts +3 -0
- package/dist/features/blog/schemas/blog-form.js +1 -0
- package/dist/features/blog/schemas/firestore.d.ts +38 -1
- package/dist/features/blog/schemas/firestore.js +23 -0
- package/dist/features/blog/schemas/index.d.ts +6 -0
- package/dist/features/blog/schemas/index.js +2 -0
- package/dist/features/blog/types/index.d.ts +2 -0
- package/dist/features/cart/components/CartPriceBreakdown.d.ts +25 -1
- package/dist/features/cart/components/CartPriceBreakdown.js +29 -6
- package/dist/features/cart/components/PointsTenderPicker.d.ts +61 -0
- package/dist/features/cart/components/PointsTenderPicker.js +15 -0
- package/dist/features/cart/components/StoreAddonsPicker.js +2 -1
- package/dist/features/cart/components/index.d.ts +2 -0
- package/dist/features/cart/components/index.js +1 -0
- package/dist/features/cart/repository/cart.repository.d.ts +33 -0
- package/dist/features/cart/repository/cart.repository.js +47 -0
- package/dist/features/cart/schemas/firestore.d.ts +116 -0
- package/dist/features/contact/email.d.ts +27 -10
- package/dist/features/contact/email.js +20 -3
- package/dist/features/dashboard/components/DashboardHubView.d.ts +83 -0
- package/dist/features/dashboard/components/DashboardHubView.js +56 -0
- package/dist/features/dashboard/components/DashboardSectionsClient.d.ts +23 -0
- package/dist/features/dashboard/components/DashboardSectionsClient.js +66 -0
- package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.d.ts +55 -0
- package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.js +175 -0
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.d.ts +62 -0
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.js +108 -0
- package/dist/features/dispute-reasons/schemas/firestore.d.ts +62 -0
- package/dist/features/dispute-reasons/schemas/firestore.js +40 -0
- package/dist/features/events/components/EventSaleBanner.js +1 -1
- package/dist/features/faq/components/FAQAccordion.d.ts +13 -1
- package/dist/features/faq/components/FAQAccordion.js +29 -4
- package/dist/features/faq/components/FAQPageContent.js +2 -2
- package/dist/features/gateway-events/schemas/index.d.ts +2 -2
- package/dist/features/homepage/schemas/index.d.ts +8 -8
- package/dist/features/inventory/schemas/stock-reservation.d.ts +114 -0
- package/dist/features/inventory/schemas/stock-reservation.js +103 -0
- package/dist/features/invoicing/schemas/firestore.d.ts +112 -0
- package/dist/features/invoicing/schemas/firestore.js +45 -0
- package/dist/features/invoicing/utils/financial-year.d.ts +43 -0
- package/dist/features/invoicing/utils/financial-year.js +53 -0
- package/dist/features/jobs/actions/enqueue-job.js +18 -1
- package/dist/features/jobs/repository/jobs.repository.d.ts +62 -1
- package/dist/features/jobs/repository/jobs.repository.js +84 -1
- package/dist/features/jobs/schemas/firestore.d.ts +80 -0
- package/dist/features/jobs/schemas/firestore.js +37 -0
- package/dist/features/layout/AppLayoutShell.d.ts +9 -1
- package/dist/features/layout/AppLayoutShell.js +12 -4
- package/dist/features/layout/BottomActions.js +2 -1
- package/dist/features/layout/BottomNavbar.d.ts +10 -2
- package/dist/features/layout/SideActionDock.js +52 -2
- package/dist/features/layout/TitleBarLayout.js +13 -4
- package/dist/features/layout/TitleBarLayout.style.css +59 -0
- package/dist/features/layout/useCtaReveal.d.ts +16 -1
- package/dist/features/layout/useCtaReveal.js +17 -26
- package/dist/features/ledger/repository/journal.repository.d.ts +110 -0
- package/dist/features/ledger/repository/journal.repository.js +312 -0
- package/dist/features/ledger/schemas/expenses.d.ts +87 -0
- package/dist/features/ledger/schemas/expenses.js +27 -0
- package/dist/features/ledger/schemas/firestore.d.ts +183 -0
- package/dist/features/ledger/schemas/firestore.js +69 -0
- package/dist/features/lottery/schemas/zod.d.ts +6 -6
- package/dist/features/media/MediaImage.js +22 -1
- package/dist/features/media/upload/ImageUpload.js +1 -1
- package/dist/features/obligations/constants/policies.js +24 -1
- package/dist/features/orders/components/BalancePaymentPanel.d.ts +12 -0
- package/dist/features/orders/components/BalancePaymentPanel.js +94 -0
- package/dist/features/orders/components/OrderPaymentSummary.js +10 -1
- package/dist/features/orders/components/OrderProvenanceCard.d.ts +8 -0
- package/dist/features/orders/components/OrderProvenanceCard.js +185 -0
- package/dist/features/orders/components/RaiseDisputeForm.d.ts +14 -0
- package/dist/features/orders/components/RaiseDisputeForm.js +119 -0
- package/dist/features/orders/components/RefundRequestView.js +19 -1
- package/dist/features/orders/components/index.d.ts +4 -0
- package/dist/features/orders/components/index.js +2 -0
- package/dist/features/orders/constants/order-lane-tabs.d.ts +69 -0
- package/dist/features/orders/constants/order-lane-tabs.js +88 -0
- package/dist/features/orders/repository/orders.repository.d.ts +85 -1
- package/dist/features/orders/repository/orders.repository.js +205 -6
- package/dist/features/orders/schemas/balance.d.ts +40 -0
- package/dist/features/orders/schemas/balance.js +47 -0
- package/dist/features/orders/schemas/firestore.d.ts +398 -1
- package/dist/features/orders/schemas/firestore.js +43 -0
- package/dist/features/orders/schemas/index.d.ts +56 -8
- package/dist/features/orders/schemas/index.js +12 -0
- package/dist/features/orders/types/index.d.ts +47 -0
- package/dist/features/orders/utils/courier-block.d.ts +25 -0
- package/dist/features/orders/utils/courier-block.js +23 -0
- package/dist/features/payment-cases/schemas/firestore.d.ts +26 -1
- package/dist/features/payment-cases/schemas/firestore.js +1 -0
- package/dist/features/payments/repository/payout.repository.js +3 -2
- package/dist/features/payments/schemas/firestore.d.ts +92 -1
- package/dist/features/payments/schemas/firestore.js +23 -0
- package/dist/features/pricing/components/AdminPricingView.d.ts +13 -0
- package/dist/features/pricing/components/AdminPricingView.js +157 -0
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
- package/dist/features/products/components/ProductDetailPageView.d.ts +17 -1
- package/dist/features/products/components/ProductDetailPageView.js +2 -2
- package/dist/features/products/schemas/firestore.d.ts +26 -1
- package/dist/features/products/schemas/firestore.js +2 -0
- package/dist/features/products/schemas/index.d.ts +2 -2
- package/dist/features/products/schemas/product-features.validators.d.ts +10 -10
- package/dist/features/promotions/actions/coupon-stacking.d.ts +30 -3
- package/dist/features/promotions/actions/coupon-stacking.js +21 -2
- package/dist/features/promotions/components/CouponCard.js +13 -0
- package/dist/features/promotions/constants/coupon-help.d.ts +2 -2
- package/dist/features/promotions/constants/coupon-help.js +9 -1
- package/dist/features/promotions/schemas/firestore.d.ts +24 -0
- package/dist/features/promotions/schemas/firestore.js +4 -0
- package/dist/features/promotions/types/index.d.ts +19 -1
- package/dist/features/reviews/repository/reviews.repository.d.ts +14 -0
- package/dist/features/reviews/repository/reviews.repository.js +16 -0
- package/dist/features/scams/components/ScamProfileView.js +2 -2
- package/dist/features/scams/components/ScamRegistryView.js +2 -2
- package/dist/features/scams/repository/scammer.repository.js +2 -1
- package/dist/features/scams/schemas/firestore.d.ts +2 -1
- package/dist/features/scams/schemas/firestore.js +2 -1
- package/dist/features/search/action-index/tab-entries.js +1 -1
- package/dist/features/seller/actions/offer-actions.js +56 -0
- package/dist/features/seller/actions/seller-actions.d.ts +1 -1
- package/dist/features/seller/actions/seller-actions.js +37 -3
- package/dist/features/seller/components/DispatchForm.d.ts +11 -0
- package/dist/features/seller/components/DispatchForm.js +190 -0
- package/dist/features/seller/components/SellerOrdersView.js +221 -27
- package/dist/features/seller/components/index.d.ts +1 -0
- package/dist/features/seller/components/index.js +1 -0
- package/dist/features/seller/hooks/useSellerListingData.js +25 -0
- package/dist/features/seller/repository/offer.repository.js +4 -3
- package/dist/features/seller/schemas/firestore.d.ts +23 -2
- package/dist/features/seller/schemas/firestore.js +3 -2
- package/dist/features/seller/schemas/index.d.ts +4 -4
- package/dist/features/seller/schemas/order-forms.d.ts +61 -4
- package/dist/features/seller/schemas/order-forms.js +41 -8
- package/dist/features/shipments/schemas/firestore.d.ts +25 -0
- package/dist/features/shipments/schemas/validation.d.ts +4 -4
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.d.ts +82 -0
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.js +145 -0
- package/dist/features/shipping-boxes/schemas/firestore.d.ts +80 -0
- package/dist/features/shipping-boxes/schemas/firestore.js +53 -0
- package/dist/features/store-extensions/schemas/report-create-form.d.ts +2 -2
- package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +2 -2
- package/dist/features/stores/components/StoreOrdersGuideView.js +6 -1
- package/dist/features/stores/repository/store.repository.d.ts +18 -0
- package/dist/features/stores/repository/store.repository.js +27 -1
- package/dist/features/stores/schemas/firestore.d.ts +112 -0
- package/dist/features/stores/schemas/firestore.js +20 -0
- package/dist/features/stores/schemas/index.d.ts +6 -6
- package/dist/features/stores/types/index.d.ts +19 -0
- package/dist/features/support/repository/support.repository.js +72 -6
- package/dist/features/support/schemas/firestore.d.ts +17 -0
- package/dist/features/support/schemas/index.d.ts +8 -8
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +33 -1
- package/dist/next/routing/route-map.d.ts +112 -0
- package/dist/next/routing/route-map.js +63 -0
- package/dist/providers/shipping-shiprocket/index.d.ts +27 -1
- package/dist/providers/shipping-shiprocket/index.js +84 -1
- package/dist/react/contexts/SessionContext.d.ts +17 -1
- package/dist/schemas/registry.d.ts +69 -34
- package/dist/schemas/sieve.d.ts +2 -2
- package/dist/security/pii-schemas.d.ts +1 -1
- package/dist/security/pii-schemas.js +45 -0
- package/dist/server-entry.d.ts +2 -2
- package/dist/server-entry.js +8 -1
- package/dist/server.d.ts +36 -1
- package/dist/server.js +183 -1
- package/dist/styles.css +412 -80
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +1 -0
- package/dist/tokens/themes/default-light.js +1 -0
- package/dist/tokens/themes/required.d.ts +1 -1
- package/dist/tokens/themes/required.js +1 -0
- package/dist/tokens/tokens.css +15 -0
- package/dist/ui/components/Button.d.ts +10 -1
- package/dist/ui/components/Button.js +25 -3
- package/dist/ui/components/Chart.d.ts +63 -0
- package/dist/ui/components/Chart.js +169 -0
- package/dist/ui/components/Chart.style.css +214 -0
- package/dist/ui/components/Disclaimer.d.ts +19 -0
- package/dist/ui/components/Disclaimer.js +83 -0
- package/dist/ui/components/OverflowRow.js +54 -2
- package/dist/ui/components/OverflowRow.style.css +38 -0
- package/dist/ui/components/RichTextEditor.js +99 -8
- package/dist/ui/components/chart-spec.d.ts +68 -0
- package/dist/ui/components/chart-spec.js +140 -0
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/components/surface-tokens.d.ts +1 -1
- package/dist/ui/components/surface-tokens.js +9 -0
- package/dist/ui/components/tabs-overflow.js +64 -11
- package/dist/ui/components/toolbar-collapse.d.ts +13 -0
- package/dist/ui/components/toolbar-collapse.js +10 -1
- package/dist/ui/index.d.ts +8 -0
- package/dist/ui/index.js +9 -0
- package/dist/ui/rich-text/RichText.d.ts +10 -1
- package/dist/ui/rich-text/RichText.js +33 -2
- package/dist/ui/rich-text/RichText.style.css +83 -79
- package/dist/ui/rich-text/RichTextRenderer.d.ts +30 -1
- package/dist/ui/rich-text/RichTextRenderer.js +34 -2
- package/dist/ui/rich-text/chart-blocks.d.ts +62 -0
- package/dist/ui/rich-text/chart-blocks.js +87 -0
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +1834 -1822
|
@@ -6,6 +6,8 @@ import { blogRepository } from "../repository/blog.repository.js";
|
|
|
6
6
|
import { coerceMediaField, getMediaUrl } from "../../../utils/index.js";
|
|
7
7
|
import { hidePublicTestData } from "../../../_internal/server/features/tester/visibility.js";
|
|
8
8
|
import { finalizeStagedMediaField, finalizeStagedMediaObject, finalizeStagedMediaObjectArray, } from "../../media/finalize.js";
|
|
9
|
+
// Defining module, not the `../schemas` barrel โ Root Cause #18.
|
|
10
|
+
import { BLOG_DEFAULT_PUBLIC_SORT } from "../schemas/firestore.js";
|
|
9
11
|
// --- Schemas --------------------------------------------------------------
|
|
10
12
|
const singleImageMediaSchema = z
|
|
11
13
|
.union([
|
|
@@ -33,6 +35,11 @@ export const createBlogPostSchema = z.object({
|
|
|
33
35
|
category: z.enum(["news", "tips", "guides", "updates", "community"]),
|
|
34
36
|
tags: z.array(z.string()).default([]),
|
|
35
37
|
isFeatured: z.boolean().default(false),
|
|
38
|
+
// `.default(false)` is required, not cosmetic: `isPinned` is the first key of
|
|
39
|
+
// the public default sort, and Firestore excludes a document that lacks an
|
|
40
|
+
// `orderBy` field (Root Cause #100). A create that omitted it would write a
|
|
41
|
+
// post that cannot appear on its own index.
|
|
42
|
+
isPinned: z.boolean().default(false),
|
|
36
43
|
status: z.enum(["draft", "published", "archived"]).default("draft"),
|
|
37
44
|
coverImage: singleImageMediaSchema,
|
|
38
45
|
contentImages: z.array(mediaFieldSchema).max(10).optional().default([]),
|
|
@@ -108,8 +115,16 @@ export async function getFeaturedBlogPosts(count = 3) {
|
|
|
108
115
|
return hidePublicTestData(result.items);
|
|
109
116
|
}
|
|
110
117
|
export async function getLatestBlogPosts(count = 5) {
|
|
111
|
-
const result = await blogRepository.listPublished({}, { sorts:
|
|
112
|
-
|
|
118
|
+
const result = await blogRepository.listPublished({}, { sorts: BLOG_DEFAULT_PUBLIC_SORT, page: 1, pageSize: count });
|
|
119
|
+
/*
|
|
120
|
+
* ๐ `hidePublicTestData` was MISSING here while its sibling
|
|
121
|
+
* `getFeaturedBlogPosts` has always had it. This function feeds the homepage
|
|
122
|
+
* `blog-articles` section, so the seeded sandbox post was reaching the
|
|
123
|
+
* busiest public page on the site โ the exact shape
|
|
124
|
+
* `audit-public-test-data-leak` exists to block, in the one blog path it
|
|
125
|
+
* does not scan.
|
|
126
|
+
*/
|
|
127
|
+
return hidePublicTestData(result.items);
|
|
113
128
|
}
|
|
114
129
|
export async function getBlogPostById(id) {
|
|
115
130
|
return blogRepository.findById(id);
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* ```
|
|
10
10
|
*/
|
|
11
11
|
import { blogRepository } from "../repository/blog.repository.js";
|
|
12
|
+
import { BLOG_DEFAULT_PUBLIC_SORT } from "../schemas/firestore.js";
|
|
12
13
|
import { NextResponse } from "next/server.js";
|
|
13
14
|
import { getProviders } from "../../../contracts/index.js";
|
|
14
15
|
import { normalizeError } from "../../../errors/normalize.js";
|
|
@@ -34,7 +35,9 @@ export async function GET(request) {
|
|
|
34
35
|
const pageSize = url.searchParams.has("perPage")
|
|
35
36
|
? numParam(url, "perPage", 20)
|
|
36
37
|
: numParam(url, "pageSize", 20);
|
|
37
|
-
|
|
38
|
+
// Must be the SAME constant the SSR view uses โ the view's result becomes
|
|
39
|
+
// this route's `initialData` under `staleTime: Infinity` (Root Cause #30).
|
|
40
|
+
const sort = param(url, "sort") ?? BLOG_DEFAULT_PUBLIC_SORT;
|
|
38
41
|
const parts = [];
|
|
39
42
|
const category = param(url, "category");
|
|
40
43
|
if (category)
|
|
@@ -25,6 +25,11 @@ export const blogAdminColumns = [
|
|
|
25
25
|
header: "Featured",
|
|
26
26
|
render: (p) => (p.isFeatured ? "Yes" : "No"),
|
|
27
27
|
},
|
|
28
|
+
{
|
|
29
|
+
key: "isPinned",
|
|
30
|
+
header: "Pinned",
|
|
31
|
+
render: (p) => (p.isPinned ? "Yes" : "No"),
|
|
32
|
+
},
|
|
28
33
|
{
|
|
29
34
|
key: "readTimeMinutes",
|
|
30
35
|
header: "Read Time",
|
|
@@ -3,6 +3,7 @@ import { blogRepository } from "../../../repositories/index.js";
|
|
|
3
3
|
import { Container, Heading, Main, Section } from "../../../ui/index.js";
|
|
4
4
|
import { AdSlot } from "../../homepage/components/AdSlot.js";
|
|
5
5
|
import { BlogIndexListing } from "./BlogIndexListing.js";
|
|
6
|
+
import { BLOG_DEFAULT_PUBLIC_SORT } from "../schemas/firestore.js";
|
|
6
7
|
import { safeRead } from "../../../errors/safe-read.js";
|
|
7
8
|
import { hidePublicTestData } from "../../../_internal/server/features/tester/visibility.js";
|
|
8
9
|
function sp(params, key) {
|
|
@@ -10,7 +11,7 @@ function sp(params, key) {
|
|
|
10
11
|
return Array.isArray(v) ? v[0] ?? "" : v ?? "";
|
|
11
12
|
}
|
|
12
13
|
export async function BlogIndexPageView({ searchParams = {} }) {
|
|
13
|
-
const sort = sp(searchParams, "sort") ||
|
|
14
|
+
const sort = sp(searchParams, "sort") || BLOG_DEFAULT_PUBLIC_SORT;
|
|
14
15
|
const page = Number(sp(searchParams, "page")) || 1;
|
|
15
16
|
const pageSize = Number(sp(searchParams, "pageSize")) || 24;
|
|
16
17
|
const category = sp(searchParams, "category");
|
|
@@ -223,6 +223,11 @@ BlogRepository.SIEVE_FIELDS = {
|
|
|
223
223
|
authorName: { canFilter: true, canSort: true },
|
|
224
224
|
authorId: { canFilter: true, canSort: false },
|
|
225
225
|
isFeatured: { canFilter: true, canSort: false },
|
|
226
|
+
// canSort because it is the FIRST key of the default sort
|
|
227
|
+
// `-isPinned,-publishedAt`. A `canSort: false` field is silently dropped by
|
|
228
|
+
// sievejs (Root Cause #63), which would leave the index ordered by date
|
|
229
|
+
// alone and the pin doing nothing, with no error anywhere.
|
|
230
|
+
isPinned: { canFilter: true, canSort: true },
|
|
226
231
|
readTimeMinutes: { canFilter: true, canSort: true },
|
|
227
232
|
views: { canFilter: true, canSort: true },
|
|
228
233
|
publishedAt: { canFilter: true, canSort: true, parseValue: parseSieveDateValue },
|
|
@@ -47,6 +47,7 @@ export declare const blogDraftSchema: z.ZodObject<{
|
|
|
47
47
|
publishedAt: z.ZodString;
|
|
48
48
|
authorName: z.ZodString;
|
|
49
49
|
isFeatured: z.ZodBoolean;
|
|
50
|
+
isPinned: z.ZodBoolean;
|
|
50
51
|
}, "strip", z.ZodTypeAny, {
|
|
51
52
|
status: "published" | "draft" | "archived";
|
|
52
53
|
title: string;
|
|
@@ -60,6 +61,7 @@ export declare const blogDraftSchema: z.ZodObject<{
|
|
|
60
61
|
excerpt: string;
|
|
61
62
|
coverImage: string;
|
|
62
63
|
authorName: string;
|
|
64
|
+
isPinned: boolean;
|
|
63
65
|
metaTitle: string;
|
|
64
66
|
metaDescription: string;
|
|
65
67
|
}, {
|
|
@@ -75,6 +77,7 @@ export declare const blogDraftSchema: z.ZodObject<{
|
|
|
75
77
|
excerpt: string;
|
|
76
78
|
coverImage: string;
|
|
77
79
|
authorName: string;
|
|
80
|
+
isPinned: boolean;
|
|
78
81
|
metaTitle: string;
|
|
79
82
|
metaDescription: string;
|
|
80
83
|
}>;
|
|
@@ -97,4 +97,5 @@ export const blogDraftSchema = z.object({
|
|
|
97
97
|
}),
|
|
98
98
|
authorName: annotate(z.string(), { section: "publish", order: 3, row: "pair" }),
|
|
99
99
|
isFeatured: annotate(z.boolean(), { section: "publish", order: 4, row: "quarter" }),
|
|
100
|
+
isPinned: annotate(z.boolean(), { section: "publish", order: 5, row: "quarter" }),
|
|
100
101
|
});
|
|
@@ -29,6 +29,23 @@ export interface BlogPostDocument extends BaseDocument {
|
|
|
29
29
|
category: BlogPostCategory;
|
|
30
30
|
tags: string[];
|
|
31
31
|
isFeatured: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Keeps the post at the top of the blog index and the homepage
|
|
34
|
+
* `blog-articles` section, above newer posts.
|
|
35
|
+
*
|
|
36
|
+
* ๐ REQUIRED, not optional, and that is load-bearing. The default sort is
|
|
37
|
+
* `-isPinned,-publishedAt`, and Firestore EXCLUDES a document that lacks an
|
|
38
|
+
* `orderBy` field (Root Cause #100) โ so an optional `isPinned` would drop
|
|
39
|
+
* every pre-existing post out of its own index, silently, with a 200.
|
|
40
|
+
* A `mapDoc` default cannot rescue it either: that is a read-side fixup and
|
|
41
|
+
* a query never sees it (Root Cause #101). Every row needs a real `false`
|
|
42
|
+
* written, which is why the seed carries it explicitly.
|
|
43
|
+
*
|
|
44
|
+
* Distinct from `isFeatured` on purpose: featured drives the badge and the
|
|
45
|
+
* featured-card treatment, and there are several featured posts. Overloading
|
|
46
|
+
* it would make "featured" and "first" the same decision.
|
|
47
|
+
*/
|
|
48
|
+
isPinned: boolean;
|
|
32
49
|
status: BlogPostStatus;
|
|
33
50
|
publishedAt?: Date;
|
|
34
51
|
authorId: string;
|
|
@@ -40,7 +57,25 @@ export interface BlogPostDocument extends BaseDocument {
|
|
|
40
57
|
metaDescription?: string;
|
|
41
58
|
}
|
|
42
59
|
export declare const BLOG_POSTS_COLLECTION: "blogPosts";
|
|
43
|
-
export declare const BLOG_POSTS_INDEXED_FIELDS: readonly ["searchTxt", "status", "publishedAt", "isFeatured", "category", "slug"];
|
|
60
|
+
export declare const BLOG_POSTS_INDEXED_FIELDS: readonly ["searchTxt", "status", "publishedAt", "isFeatured", "isPinned", "category", "slug"];
|
|
61
|
+
/**
|
|
62
|
+
* The default ordering for every PUBLIC blog surface โ the `/blog` index, the
|
|
63
|
+
* `/api/blog` route that refetches it, and the homepage `blog-articles` feed.
|
|
64
|
+
*
|
|
65
|
+
* ๐ ONE constant, three consumers, deliberately. The SSR view hands its result
|
|
66
|
+
* to the listing hook as `initialData`, and that hook sets `staleTime: Infinity`
|
|
67
|
+
* when given SSR data โ so if the route's default sort differed from the view's
|
|
68
|
+
* by even a character, the first paint would be frozen in one order while the
|
|
69
|
+
* query key described another (Root Cause #30). Three literals is how that
|
|
70
|
+
* drift happens; one import is how it cannot.
|
|
71
|
+
*
|
|
72
|
+
* `isPinned` leads so pinned posts sit above newer ones. Needs the composite
|
|
73
|
+
* indexes on (status, isPinned DESC, publishedAt DESC) and its category /
|
|
74
|
+
* isFeatured / searchTxt variants โ a multi-field sieve sort becomes two
|
|
75
|
+
* `orderBy` calls, and a missing index is a silent FAILED_PRECONDITION that
|
|
76
|
+
* every caller swallows into an empty page (Root Cause #2 / #59).
|
|
77
|
+
*/
|
|
78
|
+
export declare const BLOG_DEFAULT_PUBLIC_SORT: "-isPinned,-publishedAt";
|
|
44
79
|
export declare const BLOG_POST_FIELDS: {
|
|
45
80
|
/** Word-prefix search tokens. Derived on write by `buildSearchTxtFor`. */
|
|
46
81
|
readonly SEARCH_TXT: "searchTxt";
|
|
@@ -56,6 +91,7 @@ export declare const BLOG_POST_FIELDS: {
|
|
|
56
91
|
readonly CATEGORY: "category";
|
|
57
92
|
readonly TAGS: "tags";
|
|
58
93
|
readonly IS_FEATURED: "isFeatured";
|
|
94
|
+
readonly IS_PINNED: "isPinned";
|
|
59
95
|
readonly STATUS: "status";
|
|
60
96
|
readonly PUBLISHED_AT: "publishedAt";
|
|
61
97
|
readonly AUTHOR_ID: "authorId";
|
|
@@ -89,6 +125,7 @@ export type BlogPostUpdateInput = Partial<Omit<BlogPostDocument, "id" | "created
|
|
|
89
125
|
export declare const blogPostQueryHelpers: {
|
|
90
126
|
readonly published: () => readonly ["status", "==", BlogPostStatus];
|
|
91
127
|
readonly featured: () => readonly ["isFeatured", "==", true];
|
|
128
|
+
readonly pinned: () => readonly ["isPinned", "==", true];
|
|
92
129
|
readonly byCategory: (category: BlogPostCategory) => readonly ["category", "==", BlogPostCategory];
|
|
93
130
|
readonly bySlug: (slug: string) => readonly ["slug", "==", string];
|
|
94
131
|
readonly byAuthor: (authorId: string) => readonly ["authorId", "==", string];
|
|
@@ -14,9 +14,28 @@ export const BLOG_POSTS_INDEXED_FIELDS = [
|
|
|
14
14
|
"status",
|
|
15
15
|
"publishedAt",
|
|
16
16
|
"isFeatured",
|
|
17
|
+
"isPinned",
|
|
17
18
|
"category",
|
|
18
19
|
"slug",
|
|
19
20
|
];
|
|
21
|
+
/**
|
|
22
|
+
* The default ordering for every PUBLIC blog surface โ the `/blog` index, the
|
|
23
|
+
* `/api/blog` route that refetches it, and the homepage `blog-articles` feed.
|
|
24
|
+
*
|
|
25
|
+
* ๐ ONE constant, three consumers, deliberately. The SSR view hands its result
|
|
26
|
+
* to the listing hook as `initialData`, and that hook sets `staleTime: Infinity`
|
|
27
|
+
* when given SSR data โ so if the route's default sort differed from the view's
|
|
28
|
+
* by even a character, the first paint would be frozen in one order while the
|
|
29
|
+
* query key described another (Root Cause #30). Three literals is how that
|
|
30
|
+
* drift happens; one import is how it cannot.
|
|
31
|
+
*
|
|
32
|
+
* `isPinned` leads so pinned posts sit above newer ones. Needs the composite
|
|
33
|
+
* indexes on (status, isPinned DESC, publishedAt DESC) and its category /
|
|
34
|
+
* isFeatured / searchTxt variants โ a multi-field sieve sort becomes two
|
|
35
|
+
* `orderBy` calls, and a missing index is a silent FAILED_PRECONDITION that
|
|
36
|
+
* every caller swallows into an empty page (Root Cause #2 / #59).
|
|
37
|
+
*/
|
|
38
|
+
export const BLOG_DEFAULT_PUBLIC_SORT = "-isPinned,-publishedAt";
|
|
20
39
|
export const BLOG_POST_FIELDS = {
|
|
21
40
|
/** Word-prefix search tokens. Derived on write by `buildSearchTxtFor`. */
|
|
22
41
|
SEARCH_TXT: "searchTxt",
|
|
@@ -32,6 +51,7 @@ export const BLOG_POST_FIELDS = {
|
|
|
32
51
|
CATEGORY: "category",
|
|
33
52
|
TAGS: "tags",
|
|
34
53
|
IS_FEATURED: "isFeatured",
|
|
54
|
+
IS_PINNED: "isPinned",
|
|
35
55
|
STATUS: "status",
|
|
36
56
|
PUBLISHED_AT: "publishedAt",
|
|
37
57
|
AUTHOR_ID: "authorId",
|
|
@@ -64,6 +84,7 @@ export const DEFAULT_BLOG_POST_DATA = {
|
|
|
64
84
|
category: "news",
|
|
65
85
|
tags: [],
|
|
66
86
|
isFeatured: false,
|
|
87
|
+
isPinned: false,
|
|
67
88
|
status: "draft",
|
|
68
89
|
authorId: "",
|
|
69
90
|
authorName: "",
|
|
@@ -80,6 +101,7 @@ export const BLOG_POST_PUBLIC_FIELDS = [
|
|
|
80
101
|
"category",
|
|
81
102
|
"tags",
|
|
82
103
|
"isFeatured",
|
|
104
|
+
"isPinned",
|
|
83
105
|
"status",
|
|
84
106
|
"publishedAt",
|
|
85
107
|
"authorName",
|
|
@@ -94,6 +116,7 @@ export const BLOG_POST_PUBLIC_FIELDS = [
|
|
|
94
116
|
export const blogPostQueryHelpers = {
|
|
95
117
|
published: () => ["status", "==", "published"],
|
|
96
118
|
featured: () => ["isFeatured", "==", true],
|
|
119
|
+
pinned: () => ["isPinned", "==", true],
|
|
97
120
|
byCategory: (category) => ["category", "==", category],
|
|
98
121
|
bySlug: (slug) => ["slug", "==", slug],
|
|
99
122
|
byAuthor: (authorId) => ["authorId", "==", authorId],
|
|
@@ -99,6 +99,7 @@ export declare const blogPostFirestoreSchema: z.ZodObject<{
|
|
|
99
99
|
category: z.ZodString;
|
|
100
100
|
tags: z.ZodArray<z.ZodString, "many">;
|
|
101
101
|
isFeatured: z.ZodBoolean;
|
|
102
|
+
isPinned: z.ZodBoolean;
|
|
102
103
|
status: z.ZodEnum<["draft", "published", "archived"]>;
|
|
103
104
|
publishedAt: z.ZodOptional<z.ZodUnion<[z.ZodDate, z.ZodString, z.ZodObject<{
|
|
104
105
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
@@ -134,6 +135,7 @@ export declare const blogPostFirestoreSchema: z.ZodObject<{
|
|
|
134
135
|
authorId: string;
|
|
135
136
|
authorName: string;
|
|
136
137
|
readTimeMinutes: number;
|
|
138
|
+
isPinned: boolean;
|
|
137
139
|
publishedAt?: string | Date | z.objectOutputType<{
|
|
138
140
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
139
141
|
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
@@ -187,6 +189,7 @@ export declare const blogPostFirestoreSchema: z.ZodObject<{
|
|
|
187
189
|
authorId: string;
|
|
188
190
|
authorName: string;
|
|
189
191
|
readTimeMinutes: number;
|
|
192
|
+
isPinned: boolean;
|
|
190
193
|
publishedAt?: string | Date | z.objectInputType<{
|
|
191
194
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
192
195
|
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
@@ -343,6 +346,7 @@ export declare const blogPostSchema: z.ZodObject<{
|
|
|
343
346
|
category: z.ZodEnum<["news", "tips", "guides", "updates", "community"]>;
|
|
344
347
|
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
345
348
|
isFeatured: z.ZodOptional<z.ZodBoolean>;
|
|
349
|
+
isPinned: z.ZodOptional<z.ZodBoolean>;
|
|
346
350
|
status: z.ZodEnum<["draft", "published", "archived"]>;
|
|
347
351
|
publishedAt: z.ZodOptional<z.ZodString>;
|
|
348
352
|
authorId: z.ZodOptional<z.ZodString>;
|
|
@@ -401,6 +405,7 @@ export declare const blogPostSchema: z.ZodObject<{
|
|
|
401
405
|
authorId?: string | undefined;
|
|
402
406
|
authorName?: string | undefined;
|
|
403
407
|
readTimeMinutes?: number | undefined;
|
|
408
|
+
isPinned?: boolean | undefined;
|
|
404
409
|
authorAvatar?: string | undefined;
|
|
405
410
|
metaTitle?: string | undefined;
|
|
406
411
|
metaDescription?: string | undefined;
|
|
@@ -430,6 +435,7 @@ export declare const blogPostSchema: z.ZodObject<{
|
|
|
430
435
|
authorId?: string | undefined;
|
|
431
436
|
authorName?: string | undefined;
|
|
432
437
|
readTimeMinutes?: number | undefined;
|
|
438
|
+
isPinned?: boolean | undefined;
|
|
433
439
|
additionalImages?: {
|
|
434
440
|
type: "video" | "image" | "file";
|
|
435
441
|
url: string;
|
|
@@ -18,6 +18,7 @@ export const blogPostFirestoreSchema = z.object({
|
|
|
18
18
|
category: z.string(),
|
|
19
19
|
tags: z.array(z.string()),
|
|
20
20
|
isFeatured: z.boolean(),
|
|
21
|
+
isPinned: z.boolean(),
|
|
21
22
|
status: blogPostStatusEnumSchema,
|
|
22
23
|
publishedAt: firestoreDateSchema.optional(),
|
|
23
24
|
authorId: z.string(),
|
|
@@ -72,6 +73,7 @@ export const blogPostSchema = z.object({
|
|
|
72
73
|
category: blogPostCategorySchema,
|
|
73
74
|
tags: z.array(z.string()).optional(),
|
|
74
75
|
isFeatured: z.boolean().optional(),
|
|
76
|
+
isPinned: z.boolean().optional(),
|
|
75
77
|
status: blogPostStatusSchema,
|
|
76
78
|
publishedAt: z.string().optional(),
|
|
77
79
|
authorId: z.string().optional(),
|
|
@@ -15,6 +15,8 @@ export interface BlogPost {
|
|
|
15
15
|
category: BlogPostCategory;
|
|
16
16
|
tags?: string[];
|
|
17
17
|
isFeatured?: boolean;
|
|
18
|
+
/** Keeps the post above newer ones on the blog index and homepage. */
|
|
19
|
+
isPinned?: boolean;
|
|
18
20
|
status: BlogPostStatus;
|
|
19
21
|
publishedAt?: string;
|
|
20
22
|
authorId?: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import type { FeeDerivations } from "../../../_internal/shared/fees/explain";
|
|
2
3
|
/**
|
|
3
4
|
* The aggregate price breakdown shown in the cart's expandable preview and in
|
|
4
5
|
* the checkout Order Summary.
|
|
@@ -32,6 +33,11 @@ export interface CartPriceBreakdownStore {
|
|
|
32
33
|
supportsShippingProtection: boolean;
|
|
33
34
|
supportsSaleProtection: boolean;
|
|
34
35
|
hasFinalSaleItem: boolean;
|
|
36
|
+
/** D46/D47 + decision 22 โ whether this seller accepts points, and how many. */
|
|
37
|
+
acceptsPoints: boolean;
|
|
38
|
+
pointsApplied: number;
|
|
39
|
+
/** S5a โ handling + extra shipping legs for this store's order. */
|
|
40
|
+
sharedPurchaseFee: number;
|
|
35
41
|
}
|
|
36
42
|
/** Mirrors `CheckoutPricingPreview` without importing server code. */
|
|
37
43
|
export interface CartPriceBreakdownData {
|
|
@@ -46,7 +52,15 @@ export interface CartPriceBreakdownData {
|
|
|
46
52
|
couponDiscount: number;
|
|
47
53
|
platformFee: number;
|
|
48
54
|
gstOnFee: number;
|
|
55
|
+
/** S5a โ handling + extra shipping legs across the cart. */
|
|
56
|
+
sharedPurchaseFee: number;
|
|
49
57
|
total: number;
|
|
58
|
+
/** D46/D47 โ points applied across every accepting store. */
|
|
59
|
+
pointsApplied: number;
|
|
60
|
+
/** What the buyer actually pays: `total โ pointsApplied`. */
|
|
61
|
+
amountDue: number;
|
|
62
|
+
/** Their remaining balance, for the toggle's own label. */
|
|
63
|
+
pointsBalance: number;
|
|
50
64
|
stores: CartPriceBreakdownStore[];
|
|
51
65
|
}
|
|
52
66
|
export interface CartPriceBreakdownProps {
|
|
@@ -73,5 +87,15 @@ export interface CartPriceBreakdownProps {
|
|
|
73
87
|
errorNote?: React.ReactNode;
|
|
74
88
|
isLoading?: boolean;
|
|
75
89
|
className?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Per-line "why am I paying this" disclosures, built by the
|
|
92
|
+
* `explain*` helpers in `_internal/shared/fees/explain`.
|
|
93
|
+
*
|
|
94
|
+
* ๐ Optional, and an absent entry renders no disclosure rather than a
|
|
95
|
+
* placeholder. The cart renders this breakdown for a signed-out guest with
|
|
96
|
+
* no server preview at all โ a line that cannot be explained must say
|
|
97
|
+
* nothing, never "we could not work this out", which reads as a fault.
|
|
98
|
+
*/
|
|
99
|
+
derivations?: FeeDerivations;
|
|
76
100
|
}
|
|
77
|
-
export declare function CartPriceBreakdown({ preview, itemCount, currency, unavailableNote, fallbackSubtotal, errorNote, isLoading, className, }: CartPriceBreakdownProps): React.JSX.Element;
|
|
101
|
+
export declare function CartPriceBreakdown({ preview, itemCount, currency, unavailableNote, fallbackSubtotal, errorNote, isLoading, className, derivations, }: CartPriceBreakdownProps): React.JSX.Element;
|
|
@@ -1,15 +1,34 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Div, Row, Stack, Text } from "../../../ui/index.js";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { Details, Div, Row, Stack, Summary, Text } from "../../../ui/index.js";
|
|
4
4
|
import { formatCurrency } from "../../../utils/number.formatter.js";
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The "how is this calculated?" disclosure under a fee line.
|
|
7
|
+
*
|
|
8
|
+
* ๐ Collapsed by default, and that is the whole design. An unexplained charge
|
|
9
|
+
* is untrustworthy, but five expanded derivations turn the Order Summary into
|
|
10
|
+
* a wall of arithmetic at the moment a buyer is deciding to pay. The
|
|
11
|
+
* obligation is that the answer is *available at the point of the charge* โ
|
|
12
|
+
* not that it is shouted.
|
|
13
|
+
*
|
|
14
|
+
* A native `<details>` rather than a tooltip or a modal: it works before
|
|
15
|
+
* hydration, it is keyboard-reachable for free, and it does not cover the
|
|
16
|
+
* number it is explaining.
|
|
17
|
+
*/
|
|
18
|
+
function Derivation({ derivation }) {
|
|
19
|
+
return (_jsxs(Details, { tone: "muted", padding: "sm", rounded: "md", children: [_jsx(Summary, { size: "xs", color: "muted", children: "How is this calculated?" }), _jsxs(Stack, { gap: "xs", className: "pt-[var(--appkit-space-2)]", children: [_jsx(Text, { size: "xs", color: "muted", children: derivation.summary }), derivation.steps.map((step, i) => (_jsx(Text, { size: "xs", color: "faint", className: "tabular-nums", children: step }, i)))] })] }));
|
|
20
|
+
}
|
|
21
|
+
function Line({ label, amount, tone = "muted", strong = false, derivation, }) {
|
|
22
|
+
const row = (_jsxs(Row, { align: "center", justify: "between", gap: "sm", className: "min-w-0", children: [_jsx(Text, { size: "sm", color: tone, weight: strong ? "semibold" : undefined, className: "min-w-0", truncate: 1, children: label }), _jsx(Text, { size: "sm", color: tone, weight: strong ? "semibold" : undefined, className: "flex-shrink-0 tabular-nums", children: amount })] }));
|
|
23
|
+
if (!derivation)
|
|
24
|
+
return row;
|
|
25
|
+
return (_jsxs(Stack, { gap: "xs", children: [row, _jsx(Derivation, { derivation: derivation })] }));
|
|
7
26
|
}
|
|
8
27
|
/** "Shipping (2 stores)" โ only qualifies when more than one store contributes. */
|
|
9
28
|
function withStoreCount(label, count) {
|
|
10
29
|
return count > 1 ? `${label} (${count} stores)` : label;
|
|
11
30
|
}
|
|
12
|
-
export function CartPriceBreakdown({ preview, itemCount, currency = "INR", unavailableNote, fallbackSubtotal = 0, errorNote, isLoading = false, className = "", }) {
|
|
31
|
+
export function CartPriceBreakdown({ preview, itemCount, currency = "INR", unavailableNote, fallbackSubtotal = 0, errorNote, isLoading = false, className = "", derivations, }) {
|
|
13
32
|
const money = (value) => formatCurrency(value, currency);
|
|
14
33
|
if (!preview) {
|
|
15
34
|
return (_jsxs(Stack, { gap: "xs", className: className, children: [_jsx(Line, { label: itemCount !== undefined ? `Subtotal (${itemCount} item${itemCount !== 1 ? "s" : ""})` : "Subtotal", amount: money(fallbackSubtotal) }), (errorNote ?? unavailableNote) && (_jsx(Text, { size: "xs", color: errorNote ? "error" : "muted", children: errorNote ?? unavailableNote }))] }));
|
|
@@ -21,5 +40,9 @@ export function CartPriceBreakdown({ preview, itemCount, currency = "INR", unava
|
|
|
21
40
|
const subtotalLabel = itemCount !== undefined
|
|
22
41
|
? `Subtotal (${itemCount} item${itemCount !== 1 ? "s" : ""}${storeCount > 1 ? `, ${storeCount} stores` : ""})`
|
|
23
42
|
: "Subtotal";
|
|
24
|
-
return (_jsxs(Stack, { gap: "xs", className: className, children: [_jsx(Line, { label: subtotalLabel, amount: money(preview.subtotal) }), preview.shippingFee > 0 && (_jsx(Line, { label: withStoreCount("Shipping", storeCount), amount: money(preview.shippingFee) })), preview.codHandlingFee > 0 && (_jsx(Line, { label: "COD handling fee", amount: money(preview.codHandlingFee) })), preview.giftWrapFee > 0 && (_jsx(Line, { label: withStoreCount("Gift wrap", countCharged((s) => s.giftWrapFee)), amount: money(preview.giftWrapFee) })), preview.shipmentProtectionFee > 0 && (_jsx(Line, { label: withStoreCount("Shipment protection", countCharged((s) => s.shipmentProtectionFee)), amount: money(preview.shipmentProtectionFee) })), preview.saleProtectionFee > 0 && (_jsx(Line, { label: withStoreCount("Sale protection", countCharged((s) => s.saleProtectionFee)), amount: money(preview.saleProtectionFee) })), preview.emiSurcharge > 0 && (_jsx(Line, { label: "EMI surcharge", amount: money(preview.emiSurcharge) })), preview.platformFee > 0 && _jsx(Line, { label: "Platform fee", amount: money(preview.platformFee) }), preview.gstOnFee > 0 && (_jsx(Line, { label: "GST on platform fee", amount: money(preview.gstOnFee) })), preview.couponDiscount > 0 && (_jsx(Line, { label: "Coupon discount", amount: `โ${money(preview.couponDiscount)}`, tone: "success" })), _jsx(Div, { border: "top-subtle", paddingY: "t-sm", children: _jsx(Line, { label: "Total", amount: money(preview.total), tone: "primary", strong:
|
|
43
|
+
return (_jsxs(Stack, { gap: "xs", className: className, children: [_jsx(Line, { label: subtotalLabel, amount: money(preview.subtotal) }), preview.shippingFee > 0 && (_jsx(Line, { label: withStoreCount("Shipping", storeCount), amount: money(preview.shippingFee) })), preview.codHandlingFee > 0 && (_jsx(Line, { label: "COD handling fee", amount: money(preview.codHandlingFee), derivation: derivations?.codHandlingFee })), preview.giftWrapFee > 0 && (_jsx(Line, { label: withStoreCount("Gift wrap", countCharged((s) => s.giftWrapFee)), amount: money(preview.giftWrapFee) })), preview.shipmentProtectionFee > 0 && (_jsx(Line, { label: withStoreCount("Shipment protection", countCharged((s) => s.shipmentProtectionFee)), amount: money(preview.shipmentProtectionFee) })), preview.saleProtectionFee > 0 && (_jsx(Line, { label: withStoreCount("Sale protection", countCharged((s) => s.saleProtectionFee)), amount: money(preview.saleProtectionFee) })), preview.emiSurcharge > 0 && (_jsx(Line, { label: "EMI surcharge", amount: money(preview.emiSurcharge), derivation: derivations?.emiSurcharge })), preview.sharedPurchaseFee > 0 && (_jsx(Line, { label: withStoreCount("Split delivery", countCharged((s) => s.sharedPurchaseFee)), amount: money(preview.sharedPurchaseFee) })), preview.platformFee > 0 && (_jsx(Line, { label: "Platform fee", amount: money(preview.platformFee), derivation: derivations?.platformFee })), preview.gstOnFee > 0 && (_jsx(Line, { label: "GST on platform fee", amount: money(preview.gstOnFee), derivation: derivations?.gstOnFee })), preview.couponDiscount > 0 && (_jsx(Line, { label: "Coupon discount", amount: `โ${money(preview.couponDiscount)}`, tone: "success" })), _jsx(Div, { border: "top-subtle", paddingY: "t-sm", children: _jsx(Line, { label: "Total", amount: money(preview.total), tone: "primary", strong: preview.pointsApplied <= 0 }) }), preview.pointsApplied > 0 && (_jsxs(_Fragment, { children: [_jsx(Line, { label: `Points applied (${preview.pointsApplied.toLocaleString("en-IN")} pts)`, amount: `โ${money(preview.pointsApplied)}`, tone: "success" }), _jsx(Div, { border: "top-subtle", paddingY: "t-sm", children: _jsx(Line, { label: "Amount due", amount: money(preview.amountDue), tone: "primary", strong: true }) })] })), preview.pointsApplied > 0 && preview.pointsBalance > preview.pointsApplied && (_jsxs(Text, { size: "xs", color: "muted", children: [(preview.pointsBalance - preview.pointsApplied).toLocaleString("en-IN"), " points stay in your balance \u2014 up to half of an order can be paid with points."] })), preview.pointsApplied === 0 && preview.pointsBalance > 0 && (_jsx(Text, { size: "xs", color: "muted", children: preview.stores.some((s) => s.acceptsPoints)
|
|
44
|
+
? "Your points could not be applied to this order."
|
|
45
|
+
: storeCount > 1
|
|
46
|
+
? "None of these sellers accepts points."
|
|
47
|
+
: "This seller does not accept points." })), preview.gstAmount > 0 && (_jsxs(Text, { size: "xs", color: "muted", children: ["Includes GST of ", money(preview.gstAmount)] })), errorNote ? (_jsx(Text, { size: "xs", color: "error", children: errorNote })) : (isLoading && (_jsx(Text, { size: "xs", color: "muted", children: "Updating\u2026" })))] }));
|
|
25
48
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* "Pay with my points" โ one checkbox for the whole cart (D46/D47).
|
|
4
|
+
*
|
|
5
|
+
* ## Why ONE control for the cart, where add-ons get one per store
|
|
6
|
+
*
|
|
7
|
+
* An add-on is a thing the buyer buys from a particular seller, so choosing it
|
|
8
|
+
* per seller is the only coherent shape. Points are the buyer's own balance:
|
|
9
|
+
* they do not belong to a seller, and asking "how many of your points would you
|
|
10
|
+
* like to spend at each of these three shops" is a question nobody wants to
|
|
11
|
+
* answer. So the buyer opts in once and the server spends what it can, in group
|
|
12
|
+
* order, at the sellers who accept them (decision 22).
|
|
13
|
+
*
|
|
14
|
+
* ## ๐ A checkbox and NOT a number input, deliberately
|
|
15
|
+
*
|
|
16
|
+
* Decision 24: tick it and as many points as the 50% cap allows are applied;
|
|
17
|
+
* whatever cannot be applied stays in the balance for a later order. Nothing is
|
|
18
|
+
* forfeited, so there is no amount worth agonising over โ and more importantly,
|
|
19
|
+
* an amount the client can send is an amount the client can lie about. The
|
|
20
|
+
* figure is always derived server-side from the live balance.
|
|
21
|
+
*
|
|
22
|
+
* ## It renders nothing when there is nothing to offer
|
|
23
|
+
*
|
|
24
|
+
* A zero balance gets no control at all rather than a disabled one. A disabled
|
|
25
|
+
* checkbox beside "0 points" is an advertisement, and the place to advertise
|
|
26
|
+
* the programme is the points page, not the cart of somebody who cannot use it.
|
|
27
|
+
*/
|
|
28
|
+
export interface PointsTenderPickerProps {
|
|
29
|
+
/** Current cart flag. */
|
|
30
|
+
value: boolean;
|
|
31
|
+
onChange: (next: boolean) => void;
|
|
32
|
+
/**
|
|
33
|
+
* The buyer's live balance, in points (1 point = โน1).
|
|
34
|
+
*
|
|
35
|
+
* ๐ Zero when the cart has not opted in, because the server only reads a
|
|
36
|
+
* balance it is going to use โ so this cannot be relied on to decide whether
|
|
37
|
+
* to RENDER. `hasBalance` below exists for that.
|
|
38
|
+
*/
|
|
39
|
+
balance: number;
|
|
40
|
+
/**
|
|
41
|
+
* Points actually applied to this cart, from the server preview. Undefined
|
|
42
|
+
* while the preview is in flight.
|
|
43
|
+
*/
|
|
44
|
+
applied?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Whether the buyer has ANY points, independent of the opt-in state.
|
|
47
|
+
*
|
|
48
|
+
* Separate from `balance` for the reason above: with the toggle off the
|
|
49
|
+
* preview returns `pointsBalance: 0`, so a control gated on `balance > 0`
|
|
50
|
+
* could never be switched back on once switched off โ a one-way door, the
|
|
51
|
+
* `BackToTop` failure in Root Cause #41.
|
|
52
|
+
*/
|
|
53
|
+
hasBalance: boolean;
|
|
54
|
+
/** No store in the cart accepts points โ the control says so instead of hiding. */
|
|
55
|
+
noAcceptingStore?: boolean;
|
|
56
|
+
currency?: string;
|
|
57
|
+
disabled?: boolean;
|
|
58
|
+
disabledReason?: string;
|
|
59
|
+
className?: string;
|
|
60
|
+
}
|
|
61
|
+
export declare function PointsTenderPicker({ value, onChange, balance, applied, hasBalance, noAcceptingStore, currency, disabled, disabledReason, className, }: PointsTenderPickerProps): React.JSX.Element | null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Div, Row, Stack, Text } from "../../../ui/index.js";
|
|
4
|
+
import { IconBox } from "../../../ui/components/IconBox.js";
|
|
5
|
+
import { Icon } from "../../../ui/components/Icon.js";
|
|
6
|
+
import { FieldCheckbox } from "../../../ui/forms/FieldCheckbox.js";
|
|
7
|
+
import { formatCurrency } from "../../../utils/number.formatter.js";
|
|
8
|
+
export function PointsTenderPicker({ value, onChange, balance, applied, hasBalance, noAcceptingStore = false, currency = "INR", disabled = false, disabledReason, className = "", }) {
|
|
9
|
+
if (!hasBalance)
|
|
10
|
+
return null;
|
|
11
|
+
const shownBalance = value ? balance : 0;
|
|
12
|
+
return (_jsx(Div, { surface: "muted", rounded: "lg", padding: "sm", className: className, children: _jsxs(Stack, { gap: "xs", children: [_jsxs(Row, { align: "center", gap: "sm", className: "min-w-0", children: [_jsx(IconBox, { size: "sm", tone: "brand", rounded: "lg", children: _jsx(Icon, { name: "points", size: "sm" }) }), _jsx(Div, { className: "min-w-0 flex-1", children: _jsx(FieldCheckbox, { name: "useAllPoints", label: "Pay with my points", checked: value, onChange: onChange, disabled: disabled || noAcceptingStore }) })] }), noAcceptingStore ? (_jsx(Text, { size: "xs", color: "muted", children: "Points cannot be used with the seller(s) in this cart." })) : disabled && disabledReason ? (_jsx(Text, { size: "xs", color: "muted", children: disabledReason })) : value && applied !== undefined ? (applied > 0 ? (_jsxs(Text, { size: "xs", color: "muted", children: [applied.toLocaleString("en-IN"), " points applied (", formatCurrency(applied, currency), ")", shownBalance > applied
|
|
13
|
+
? ` ยท ${(shownBalance - applied).toLocaleString("en-IN")} left over`
|
|
14
|
+
: ""] })) : (_jsx(Text, { size: "xs", color: "muted", children: "No points could be applied to this order." }))) : (_jsx(Text, { size: "xs", color: "muted", children: "Up to half of an order can be paid with points." }))] }) }));
|
|
15
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Gift, ShieldAlert, ShieldCheck, ShieldOff } from "lucide-react";
|
|
4
4
|
import { Div, Row, Stack, Text } from "../../../ui/index.js";
|
|
5
|
+
import { Disclaimer } from "../../../ui/components/Disclaimer.js";
|
|
5
6
|
import { IconBox } from "../../../ui/components/IconBox.js";
|
|
6
7
|
import { FieldCheckbox } from "../../../ui/forms/FieldCheckbox.js";
|
|
7
8
|
import { FieldTextarea } from "../../../ui/forms/FieldTextarea.js";
|
|
@@ -54,5 +55,5 @@ export function StoreAddonsPicker({ storeId, storeSubtotal, value, onChange, rat
|
|
|
54
55
|
? "This seller does not offer shipment or sale protection."
|
|
55
56
|
: shippingDeclined
|
|
56
57
|
? "This seller does not offer shipment protection."
|
|
57
|
-
: "This seller does not offer sale protection." })] })), saleBlockedByFinalSale && (_jsxs(Row, { gap: "sm", align: "start", className: "min-w-0", children: [_jsx(IconBox, { size: "sm", tone: "muted", children: _jsx(ShieldOff, { size: 14 }) }), _jsx(Text, { size: "xs", color: "muted", className: "flex-1 min-w-0", children: "Sale protection is not available \u2014 this basket contains a final-sale item. Shipment protection is unaffected." })] }))] }));
|
|
58
|
+
: "This seller does not offer sale protection." })] })), saleBlockedByFinalSale && (_jsxs(Row, { gap: "sm", align: "start", className: "min-w-0", children: [_jsx(IconBox, { size: "sm", tone: "muted", children: _jsx(ShieldOff, { size: 14 }) }), _jsx(Text, { size: "xs", color: "muted", className: "flex-1 min-w-0", children: "Sale protection is not available \u2014 this basket contains a final-sale item. Shipment protection is unaffected." })] })), (shippingOffered || saleOffered) && _jsx(Disclaimer, { id: "protection-cover", inline: true })] }));
|
|
58
59
|
}
|
|
@@ -7,6 +7,8 @@ export { CartSummary } from "./CartSummary";
|
|
|
7
7
|
export type { CartSummaryProps } from "./CartSummary";
|
|
8
8
|
export { StoreAddonsPicker, hasAnyStoreAddon } from "./StoreAddonsPicker";
|
|
9
9
|
export type { StoreAddonsPickerProps, StoreAddonsValue, StoreAddonsRates, } from "./StoreAddonsPicker";
|
|
10
|
+
export { PointsTenderPicker } from "./PointsTenderPicker";
|
|
11
|
+
export type { PointsTenderPickerProps } from "./PointsTenderPicker";
|
|
10
12
|
export { CartPriceBreakdown } from "./CartPriceBreakdown";
|
|
11
13
|
export type { CartPriceBreakdownProps, CartPriceBreakdownData, CartPriceBreakdownStore, } from "./CartPriceBreakdown";
|
|
12
14
|
export { CheckoutView } from "./CheckoutView";
|
|
@@ -3,6 +3,7 @@ export { CartGroupLineRow } from "./CartGroupLineRow.js";
|
|
|
3
3
|
export { CartView } from "./CartView.js";
|
|
4
4
|
export { CartSummary } from "./CartSummary.js";
|
|
5
5
|
export { StoreAddonsPicker, hasAnyStoreAddon } from "./StoreAddonsPicker.js";
|
|
6
|
+
export { PointsTenderPicker } from "./PointsTenderPicker.js";
|
|
6
7
|
export { CartPriceBreakdown } from "./CartPriceBreakdown.js";
|
|
7
8
|
export { CheckoutView } from "./CheckoutView.js";
|
|
8
9
|
export { CheckoutAddressStep } from "./CheckoutAddressStep.js";
|
|
@@ -129,6 +129,39 @@ export declare class CartRepository extends BaseRepository<CartDocument> {
|
|
|
129
129
|
* and keeping both shapes around invites readers that handle only one.
|
|
130
130
|
*/
|
|
131
131
|
setStoreAddons(userId: string, storeId: string, addons: CartStoreAddons | null): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Opt the cart in or out of paying with points (D46/D47, decision 24).
|
|
134
|
+
*
|
|
135
|
+
* ๐ A BOOLEAN, and the schema deliberately has no numeric sibling. Opt in
|
|
136
|
+
* and the server applies as many points as the 50% cap allows; whatever
|
|
137
|
+
* cannot be applied stays in the balance for a later order. A client-supplied
|
|
138
|
+
* amount is a client-supplied discount, which is the whole reason
|
|
139
|
+
* `storeAddons` is the source of truth for add-on fees rather than a request
|
|
140
|
+
* body.
|
|
141
|
+
*
|
|
142
|
+
* Written with the same `set(..., { merge: true })` as its neighbours so a
|
|
143
|
+
* concurrent add-on or selection write is not clobbered.
|
|
144
|
+
*
|
|
145
|
+
* ๐ Opting OUT deletes the field rather than writing `false` โ absent and
|
|
146
|
+
* `false` mean the same thing to every reader (`cart.useAllPoints === true`),
|
|
147
|
+
* and keeping both shapes invites a reader that handles only one. Same
|
|
148
|
+
* reasoning as `setStoreAddons` directly above.
|
|
149
|
+
*/
|
|
150
|
+
/**
|
|
151
|
+
* Set or clear the instalment plan.
|
|
152
|
+
*
|
|
153
|
+
* ๐ `null` DELETES the field rather than storing `{ optIn: false }`. The
|
|
154
|
+
* schema's rule is that absent means "no instalments", so a second
|
|
155
|
+
* representation of the same state is one more thing every reader has to
|
|
156
|
+
* get right (Root Cause #42's shape). `tenureMonths` is stored verbatim and
|
|
157
|
+
* validated against the live `emi.tenureOptions` at order time โ the admin
|
|
158
|
+
* can change those options after a cart was saved, so validating here would
|
|
159
|
+
* freeze a tenure that is no longer offered.
|
|
160
|
+
*/
|
|
161
|
+
setEmiPlan(userId: string, plan: {
|
|
162
|
+
tenureMonths: number;
|
|
163
|
+
} | null): Promise<void>;
|
|
164
|
+
setUseAllPoints(userId: string, useAllPoints: boolean): Promise<void>;
|
|
132
165
|
/**
|
|
133
166
|
* Cloud Functions: return refs of stale carts not updated within TTL.
|
|
134
167
|
*/
|