@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
|
@@ -4,7 +4,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
|
4
4
|
import { useRouter } from "next/navigation.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { FormShell, SectionForm, useSectionFormNav, useFormShell } from "../../shell/index.js";
|
|
7
|
-
import { FormShellContext, useFormShellState, applyZodIssues, FormErrorSummary } from "../../../ui/forms/index.js";
|
|
7
|
+
import { FormShellContext, useFormShellState, applyZodIssues, FormErrorSummary, AddAnotherToggle, addAnotherSubmitLabel, } from "../../../ui/forms/index.js";
|
|
8
8
|
import { Alert, Button, Div, FormField, FormGroup, Heading, Section, Stack, TagInput, Text, Toggle, useToast, Row } from "../../../ui/index.js";
|
|
9
9
|
import { ImageUpload, MediaUploadField, MediaUploadList, useMediaUpload } from "../../media/index.js";
|
|
10
10
|
import { StoreAddressSelectorCreate } from "../../stores/components/StoreAddressSelectorCreate.js";
|
|
@@ -15,6 +15,9 @@ import { pluginFor } from "../../../_internal/shared/listing-types/_registry.js"
|
|
|
15
15
|
import { DEFAULT_MIN_OFFER_PERCENT } from "../../../_internal/shared/features/offers/config.js";
|
|
16
16
|
import { PRODUCT_MAX_IMAGES, PRODUCT_MAX_VIDEOS, PRODUCT_IMAGE_INDEX_MAX, } from "../../../_internal/shared/media/limits.js";
|
|
17
17
|
import { isFinalSale } from "../../products/constants/final-sale.js";
|
|
18
|
+
// The one `ProductImage[] | string[]` → `string[]` normaliser — a value
|
|
19
|
+
// import, needed at runtime by `galleryFields` below.
|
|
20
|
+
import { productImageUrls } from "../../products/schemas/firestore.js";
|
|
18
21
|
import { ProductFeaturesSelector } from "../../products/components/ProductFeaturesSelector.js";
|
|
19
22
|
import { normalizeError } from "../../../errors/normalize.js";
|
|
20
23
|
/**
|
|
@@ -143,7 +146,20 @@ function StepBasic({ values, onChange, renderCategorySelector, renderBrandSelect
|
|
|
143
146
|
: /* And back again drops the count, for the same reason. */
|
|
144
147
|
{ isLot: false, lotSize: undefined }), label: values.isLot ? "A lot of several items" : "A single item", size: "sm" }), values.isLot && (_jsx(FormField, { name: "lotSize", label: "How many?", type: "number", value: values.lotSize != null ? String(values.lotSize) : "", onChange: (v) => onChange({ lotSize: v ? Number(v) : undefined }), placeholder: "optional" }))] }), _jsx(Text, { size: "xs", color: "muted", children: values.isLot
|
|
145
148
|
? "A lot files under a category rather than one model, because a category is a collection — naming one model would claim every item in the pile is that model."
|
|
146
|
-
: "A single item can be filed against the exact bey or part it is, so buyers searching that name find it." })] }), _jsxs(FormGroup, { columns: 2, children: [renderCategorySelector ? (
|
|
149
|
+
: "A single item can be filed against the exact bey or part it is, so buyers searching that name find it." })] }), _jsxs(FormGroup, { columns: 2, children: [renderCategorySelector ? (
|
|
150
|
+
/*
|
|
151
|
+
* 🛑 ONE element, not a Fragment. `.appkit-form-group` is
|
|
152
|
+
* `display: grid` (Form.style.css), and a Fragment renders no DOM
|
|
153
|
+
* node — so `<>{label}{picker}</>` handed the grid THREE children
|
|
154
|
+
* instead of two. At `md:grid-cols-2` that put the word "Category"
|
|
155
|
+
* alone in the left cell, the picker in the right cell, and pushed
|
|
156
|
+
* Condition onto its own row: three different label layouts in one
|
|
157
|
+
* section, from one pair of angle brackets.
|
|
158
|
+
*
|
|
159
|
+
* `FormField` (the else branch, and Condition beside it) renders its
|
|
160
|
+
* own single wrapper, which is why only this branch was affected.
|
|
161
|
+
*/
|
|
162
|
+
_jsxs(Div, { children: [_jsx(Text, { className: "text-[var(--appkit-color-text)] mb-1", size: "sm", weight: "medium", children: "Category" }), renderCategorySelector({
|
|
147
163
|
value: values.category ?? "",
|
|
148
164
|
onChange: (v) => onChange({ category: v }),
|
|
149
165
|
isLot: values.isLot === true,
|
|
@@ -170,7 +186,7 @@ function StepBasic({ values, onChange, renderCategorySelector, renderBrandSelect
|
|
|
170
186
|
context: templateContext,
|
|
171
187
|
isDescriptionDirty,
|
|
172
188
|
onApply: onChange,
|
|
173
|
-
}), _jsx(FormField, { name: "description", label: "Description", type: "textarea", value: description, onChange: (v) => onChange({ description: v }), placeholder: "Describe your listing in detail\u2026" }), renderBrandSelector ? (_jsxs(_Fragment, { children: [_jsx(Text, { className: "text-[var(--appkit-color-text)] mb-1", size: "sm", weight: "medium", children: "Brand" }), renderBrandSelector({ value: values.brand ?? "", onChange: (v) => onChange({ brand: v }) })] })) : (_jsx(FormField, { name: "brand", label: "Brand", type: "text", value: values.brand ?? "", onChange: (v) => onChange({ brand: v }), placeholder: "e.g. Pok\u00E9mon Company" })), _jsx(TagInput, { label: "Tags", value: values.tags ?? [], onChange: (tags) => onChange({ tags }), placeholder: "pokemon, psa9, charizard, holo" }), _jsx(BarcodeField, { value: values.barcodeId ?? "", onChange: (v) => onChange({ barcodeId: v || undefined }), onScan: (v) => onChange({ barcodeId: v }), helperText: "Leave blank to auto-generate. Scan a pre-printed sticker to link it." })] }));
|
|
189
|
+
}), _jsx(FormField, { name: "description", label: "Description", type: "textarea", value: description, onChange: (v) => onChange({ description: v }), placeholder: "Describe your listing in detail\u2026" }), renderBrandSelector ? (_jsxs(_Fragment, { children: [_jsx(Text, { className: "text-[var(--appkit-color-text)] mb-1", size: "sm", weight: "medium", children: "Brand" }), renderBrandSelector({ value: values.brand ?? "", onChange: (v) => onChange({ brand: v }) })] })) : (_jsx(FormField, { name: "brand", label: "Brand", type: "text", value: values.brand ?? "", onChange: (v) => onChange({ brand: v }), placeholder: "e.g. Pok\u00E9mon Company" })), _jsx(TagInput, { label: "Tags", value: values.tags ?? [], onChange: (tags) => onChange({ tags }), placeholder: "pokemon, psa9, charizard, holo" }), _jsx(FormField, { name: "sku", label: "SKU", type: "text", value: values.sku ?? "", onChange: (v) => onChange({ sku: v || undefined }), placeholder: "LIR-BURS-001", hint: "Your own stock code. Leave blank and one is generated from the category." }), _jsx(BarcodeField, { value: values.barcodeId ?? "", onChange: (v) => onChange({ barcodeId: v || undefined }), onScan: (v) => onChange({ barcodeId: v }), helperText: "Leave blank to auto-generate. Scan a pre-printed sticker to link it." })] }));
|
|
174
190
|
}
|
|
175
191
|
// ── Step 1b: Details — the inherited-but-editable fields (C2c) ───────────────
|
|
176
192
|
const AUTHENTICITY_OPTIONS = [
|
|
@@ -211,13 +227,21 @@ function StepMedia({ values, onChange, storeSlug = "store", }) {
|
|
|
211
227
|
/*
|
|
212
228
|
* One control for both media kinds.
|
|
213
229
|
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
230
|
+
* This seeds from `images` + `video` and splits them again on write.
|
|
231
|
+
* Collapsing the two into one stored `media[]` would be a Firestore
|
|
232
|
+
* migration touching cards, detail, cart, orders and search; the input
|
|
233
|
+
* surface is what needed fixing.
|
|
234
|
+
*
|
|
235
|
+
* 🛑 `images` IS NOT `string[]` AT RUNTIME. This comment asserted it was,
|
|
236
|
+
* and the line below mapped each entry as a URL — but
|
|
237
|
+
* `ProductDocument.images` has been `ProductImage[]` (objects) since A6, so
|
|
238
|
+
* the seller's own gallery tiles rendered `MediaImage`'s 📦 placeholder
|
|
239
|
+
* instead of their photos. Same defect as `ProductForm`, same cause: a cast
|
|
240
|
+
* at the seeding boundary claims `Partial<ProductItem>` while the document
|
|
241
|
+
* holds objects. `productImageUrls` accepts both shapes.
|
|
218
242
|
*/
|
|
219
243
|
const galleryFields = [
|
|
220
|
-
...(values.images
|
|
244
|
+
...productImageUrls(values.images).map((url) => ({ url, type: "image" })),
|
|
221
245
|
...(values.video?.url
|
|
222
246
|
? [{
|
|
223
247
|
url: values.video.url,
|
|
@@ -508,7 +532,18 @@ productId, onSave, onPublish, onDiscard, isLoading = false, storeSlug, renderCat
|
|
|
508
532
|
* yet — it needs the sections — so it is composed in below. That ordering is
|
|
509
533
|
* why the original `wizardShellCtx` existed; only its contents change.
|
|
510
534
|
*/
|
|
511
|
-
const { shellCtx: baseShellCtx, setFieldError, clearErrors, validate } =
|
|
535
|
+
const { shellCtx: baseShellCtx, setFieldError, clearErrors, validate, markSubmitAttempted } =
|
|
536
|
+
/*
|
|
537
|
+
* 🛑 "Create & add another" OFFERED ONLY IN CREATE MODE. Editing an
|
|
538
|
+
* existing listing and then "adding another" would have to mean "save this
|
|
539
|
+
* one, then start a blank one" — a different action, and not one anybody
|
|
540
|
+
* reaches for while fixing a typo. The toggle hides itself on edit too,
|
|
541
|
+
* but gating the OFFER means the branch below cannot be reached from edit
|
|
542
|
+
* at all rather than relying on a component to hide.
|
|
543
|
+
*/
|
|
544
|
+
useFormShellState(sellerProductSchema, undefined, {
|
|
545
|
+
allowAddAnother: mode === "create",
|
|
546
|
+
});
|
|
512
547
|
const [stepError, setStepError] = useState(null);
|
|
513
548
|
const { isDirty, markDirty, markClean } = useFormShell();
|
|
514
549
|
const router = useRouter();
|
|
@@ -546,6 +581,33 @@ productId, onSave, onPublish, onDiscard, isLoading = false, storeSlug, renderCat
|
|
|
546
581
|
else
|
|
547
582
|
router.back();
|
|
548
583
|
}, [onDiscard, router]);
|
|
584
|
+
/*
|
|
585
|
+
* ── "Create & add another": what survives, and what must not ──────────────
|
|
586
|
+
*
|
|
587
|
+
* 🛑 AN ALLOW-LIST, NOT A DELETE-LIST. The obvious implementation is
|
|
588
|
+
* `{ ...draft, title: "", images: [] }` — spread the last one and blank the
|
|
589
|
+
* bits that look item-specific. That is the deny-list shape this codebase
|
|
590
|
+
* has been bitten by all session (Root Cause #70: a public payload built by
|
|
591
|
+
* spreading a document and deleting three keys published everything nobody
|
|
592
|
+
* thought to delete). Here it would carry the previous listing's barcode,
|
|
593
|
+
* its SKU, its slug, its SEO title, its stock count and its video into the
|
|
594
|
+
* next record — and `barcodeId` and `slug` are UNIQUE, so the second save
|
|
595
|
+
* would either collide or silently overwrite the first listing.
|
|
596
|
+
*
|
|
597
|
+
* So the next draft is built from NOTHING plus the four fields a batch
|
|
598
|
+
* genuinely shares. A field added to the draft type later is excluded by
|
|
599
|
+
* default, which is the direction that cannot lose data.
|
|
600
|
+
*
|
|
601
|
+
* `listingType` and the store are PROPS, not draft fields, so they persist
|
|
602
|
+
* without being listed — they are part of which editor is mounted.
|
|
603
|
+
*/
|
|
604
|
+
const nextDraftForAnother = useCallback((saved) => ({
|
|
605
|
+
status: "draft",
|
|
606
|
+
condition: saved.condition ?? "new",
|
|
607
|
+
category: saved.category,
|
|
608
|
+
brand: saved.brand,
|
|
609
|
+
}), []);
|
|
610
|
+
const addAnother = baseShellCtx.addAnother;
|
|
549
611
|
// `silent` suppresses the success toast — used by the debounced auto-save
|
|
550
612
|
// effect above so it doesn't pop a "Saved." toast every couple of seconds
|
|
551
613
|
// while the seller is still typing. The manual "Save Draft"/"Save Changes"
|
|
@@ -567,6 +629,30 @@ productId, onSave, onPublish, onDiscard, isLoading = false, storeSlug, renderCat
|
|
|
567
629
|
return;
|
|
568
630
|
}
|
|
569
631
|
applyZodIssues(result.issues ?? [], setFieldError);
|
|
632
|
+
/*
|
|
633
|
+
* 🛑 WITHOUT THIS THE TOAST IS A LIE — Root Cause #74, regressed here.
|
|
634
|
+
*
|
|
635
|
+
* `<FormErrorSummary>` early-returns `null` unless `ctx.submitAttempted`,
|
|
636
|
+
* and the per-field inline errors gate on `touched` — so on a field the
|
|
637
|
+
* seller never visited, nothing renders either. This form's Save and
|
|
638
|
+
* Publish are `type="button"` with `onClick`, which fires no native
|
|
639
|
+
* submit event, so nothing was marking the attempt. The result was a
|
|
640
|
+
* toast reading "Fix the highlighted errors and try again" with
|
|
641
|
+
* **nothing highlighted anywhere on the page** — four of them stacked up
|
|
642
|
+
* in the reported screenshot, and no way to find a single field.
|
|
643
|
+
*
|
|
644
|
+
* CLAUDE.md states the rule exactly: "Marking the attempt has to happen
|
|
645
|
+
* where an attempt happens", and a `type="button"` submit must call this
|
|
646
|
+
* itself. It is marked only on the FAILURE path: a save that succeeds
|
|
647
|
+
* has no errors to reveal, and flipping the flag anyway would arm the
|
|
648
|
+
* summary for every later keystroke.
|
|
649
|
+
*
|
|
650
|
+
* Marked even when `silent` (auto-save). The summary is the only durable
|
|
651
|
+
* record of what is wrong — auto-save deliberately suppresses its toast
|
|
652
|
+
* to avoid one every two seconds, so suppressing the summary too would
|
|
653
|
+
* leave the seller with no signal at all.
|
|
654
|
+
*/
|
|
655
|
+
markSubmitAttempted();
|
|
570
656
|
if (!silent) {
|
|
571
657
|
showToast(saveFailureMessage(result.code, (result.issues ?? []).length), "error");
|
|
572
658
|
}
|
|
@@ -576,7 +662,7 @@ productId, onSave, onPublish, onDiscard, isLoading = false, storeSlug, renderCat
|
|
|
576
662
|
if (!silent)
|
|
577
663
|
showToast("Failed to save.", "error");
|
|
578
664
|
}
|
|
579
|
-
}, [draft, onSave, markClean, clearErrors, setFieldError, showToast]);
|
|
665
|
+
}, [draft, onSave, markClean, clearErrors, setFieldError, showToast, markSubmitAttempted]);
|
|
580
666
|
const handleAutoSave = useCallback(async () => {
|
|
581
667
|
try {
|
|
582
668
|
await handleSave(true);
|
|
@@ -605,17 +691,41 @@ productId, onSave, onPublish, onDiscard, isLoading = false, storeSlug, renderCat
|
|
|
605
691
|
if (result.ok) {
|
|
606
692
|
markClean();
|
|
607
693
|
clearErrors();
|
|
694
|
+
/*
|
|
695
|
+
* 🛑 THE TOAST NAMES WHAT WAS PUBLISHED, because the form is about to
|
|
696
|
+
* be empty. "Published." over a blank form reads as though the thing
|
|
697
|
+
* on screen vanished; "Published Dran Sword. Next one — category and
|
|
698
|
+
* condition kept." says what happened and what was kept, which is the
|
|
699
|
+
* only confirmation the seller gets that their work landed.
|
|
700
|
+
*/
|
|
701
|
+
if (addAnother) {
|
|
702
|
+
const title = draft.title?.trim();
|
|
703
|
+
setDraft(nextDraftForAnother(draft));
|
|
704
|
+
/*
|
|
705
|
+
* `markClean()` ran above, and the fresh draft must stay clean:
|
|
706
|
+
* `update()` marks dirty, and `setDraft` here deliberately bypasses
|
|
707
|
+
* it. Otherwise the 2-second create-mode auto-save effect fires on
|
|
708
|
+
* the empty draft and writes a second, blank listing.
|
|
709
|
+
*/
|
|
710
|
+
showToast(title
|
|
711
|
+
? `Published ${title}. Next one — category and condition kept.`
|
|
712
|
+
: "Published. Next one — category and condition kept.", "success");
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
608
715
|
showToast("Published.", "success");
|
|
609
716
|
return;
|
|
610
717
|
}
|
|
611
718
|
applyZodIssues(result.issues ?? [], setFieldError);
|
|
719
|
+
// See the note on the same call in `handleSave` — without this the
|
|
720
|
+
// "Fix the highlighted errors" toast points at nothing (Root Cause #74).
|
|
721
|
+
markSubmitAttempted();
|
|
612
722
|
showToast(saveFailureMessage(result.code, (result.issues ?? []).length), "error");
|
|
613
723
|
}
|
|
614
724
|
catch (err) {
|
|
615
725
|
void normalizeError(err);
|
|
616
726
|
showToast("Failed to publish.", "error");
|
|
617
727
|
}
|
|
618
|
-
}, [draft, onPublish, markClean, clearErrors, setFieldError, showToast]);
|
|
728
|
+
}, [draft, onPublish, markClean, clearErrors, setFieldError, showToast, addAnother, nextDraftForAnother, markSubmitAttempted]);
|
|
619
729
|
const listingTypeLabel = pluginForMode(listingType).typeLabel;
|
|
620
730
|
const typeSpecificSection = TYPE_SPECIFIC_SECTIONS[listingType] ?? null;
|
|
621
731
|
const sections = [
|
|
@@ -749,7 +859,7 @@ productId, onSave, onPublish, onDiscard, isLoading = false, storeSlug, renderCat
|
|
|
749
859
|
}) }) }) }));
|
|
750
860
|
}
|
|
751
861
|
if (mode === "create") {
|
|
752
|
-
return (_jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, previewSlot: previewSlot, splitPreview: !!previewSlot, renderBottomBar: () => (_jsxs(Div, { className: "flex-shrink-0 border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", children: [_jsx(FormShellContext.Provider, { value: shellCtx, children: _jsx(Div, { paddingX: "x-5", padding: "y-sm", children: _jsx(FormErrorSummary, {}) }) }),
|
|
862
|
+
return (_jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, previewSlot: previewSlot, splitPreview: !!previewSlot, renderBottomBar: () => (_jsxs(Div, { className: "flex-shrink-0 border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", children: [_jsx(FormShellContext.Provider, { value: shellCtx, children: _jsx(Div, { paddingX: "x-5", padding: "y-sm", children: _jsx(FormErrorSummary, {}) }) }), _jsxs(Div, { paddingX: "x-5", padding: "b-sm", children: [_jsx(FormShellContext.Provider, { value: shellCtx, children: _jsx(AddAnotherToggle, { noun: listingTypeLabel.toLowerCase(), isCreate: mode === "create" }) }), _jsxs(Row, { gap: "sm", justify: "between", wrap: true, children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: () => void handleSave(), disabled: isLoading || !draft.title?.trim(), children: "Save as draft & finish later" }), _jsx(Button, { variant: "primary", onClick: () => void handlePublish(), isLoading: isLoading, disabled: isLoading, children: addAnotherSubmitLabel(`Publish ${listingTypeLabel}`, addAnother) })] })] }), stepError && (_jsx(Text, { className: "text-[var(--appkit-color-error)] px-[1.25rem] pb-[0.75rem]", size: "sm", children: stepError }))] })), children: _jsx(FormShellContext.Provider, { value: shellCtx, children: _jsx(SectionForm, { sections: sections, values: draft, onChange: update, onSubmit: handlePublish, schema: sellerProductSchema, openIds: openIds, onOpenChange: setOpenIds, isLoading: isLoading, hideActions: true }) }) }));
|
|
753
863
|
}
|
|
754
864
|
// Edit mode — FormShell with section nav + full form
|
|
755
865
|
const editSections = [
|
|
@@ -759,5 +869,5 @@ productId, onSave, onPublish, onDiscard, isLoading = false, storeSlug, renderCat
|
|
|
759
869
|
return (_jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, sections: editSections, onSaveDraft: handleSave, onPublish: handlePublish, saveLabel: "Save Changes", publishLabel: "Update", previewSlot: previewSlot, footerTopSlot: _jsx(FormShellContext.Provider, { value: shellCtx, children: _jsx(FormErrorSummary, {}) }), children: _jsx(FormShellContext.Provider, { value: shellCtx, children: _jsxs(Stack, { gap: "lg", children: [_jsxs(Section, { id: "basic", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Basic Info" }), _jsx(StepBasic, { values: draft, onChange: update, renderCategorySelector: renderCategorySelector, renderBrandSelector: renderBrandSelector, renderTemplateSelector: renderTemplateSelector })] }), _jsxs(Section, { id: "media", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Media" }), _jsx(StepMedia, { values: draft, onChange: update, storeSlug: storeSlug })] }), typeSpecificSection && (_jsxs(Section, { id: typeSpecificSection.id, children: [_jsx(Heading, { level: 3, className: "mb-4", children: typeSpecificSection.sectionHeading ?? typeSpecificSection.label }), typeSpecificSection.render({ values: draft, onChange: update, errors: {} }), mode === "edit" &&
|
|
760
870
|
listingType === "digital-code" &&
|
|
761
871
|
productId &&
|
|
762
|
-
renderDigitalContentPool?.(productId)] })), _jsxs(Section, { id: "pricing", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Pricing" }), _jsx(StepPricing, { values: draft, onChange: update, listingType: listingType })] }), _jsxs(Section, { id: "shipping", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Shipping" }), _jsx(StepShipping, { values: draft, onChange: update, renderAddressSelector: renderAddressSelector })] }), _jsxs(Section, { id: "returns", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Returns" }), _jsx(StepReturns, { values: draft, onChange: update })] }), _jsxs(Section, { id: "publish", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Publish" }), _jsx(StepPublish, { values: draft, onChange: update }), onSaveAsTemplate && (_jsxs(Div, { className: "mt-4 border-t border-[var(--appkit-color-border)]", padding: "t-md", children: [_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onSaveAsTemplate(draft), children: "Save as Template" }), _jsx(Text, { className: "mt-1 text-[var(--appkit-color-
|
|
872
|
+
renderDigitalContentPool?.(productId)] })), _jsxs(Section, { id: "pricing", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Pricing" }), _jsx(StepPricing, { values: draft, onChange: update, listingType: listingType })] }), _jsxs(Section, { id: "shipping", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Shipping" }), _jsx(StepShipping, { values: draft, onChange: update, renderAddressSelector: renderAddressSelector })] }), _jsxs(Section, { id: "returns", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Returns" }), _jsx(StepReturns, { values: draft, onChange: update })] }), _jsxs(Section, { id: "publish", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Publish" }), _jsx(StepPublish, { values: draft, onChange: update }), onSaveAsTemplate && (_jsxs(Div, { className: "mt-4 border-t border-[var(--appkit-color-border)]", padding: "t-md", children: [_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onSaveAsTemplate(draft), children: "Save as Template" }), _jsx(Text, { className: "mt-1 text-[var(--appkit-color-text-muted)]", size: "xs", children: "Save these settings as a reusable template for future listings." })] }))] })] }) }) }));
|
|
763
873
|
}
|
|
@@ -188,6 +188,8 @@ export function SellerReviewsView({ reviewsApiBase = SELLER_ENDPOINTS.REVIEWS, r
|
|
|
188
188
|
const config = {
|
|
189
189
|
portal: "seller",
|
|
190
190
|
title: "Reviews",
|
|
191
|
+
// The page authors its own visible <h1>, so the shell must not add a second.
|
|
192
|
+
hideHeader: true,
|
|
191
193
|
searchPlaceholder: "Search product, reviewer, or comment…",
|
|
192
194
|
emptyLabel: "No reviews found.",
|
|
193
195
|
filterKeys: ["rating", "replied"],
|
|
@@ -226,7 +228,7 @@ export function SellerReviewsView({ reviewsApiBase = SELLER_ENDPOINTS.REVIEWS, r
|
|
|
226
228
|
setBulkReplyOpen(true);
|
|
227
229
|
},
|
|
228
230
|
})),
|
|
229
|
-
renderCards: (rows, _view, selection, isLoading) => (_jsx(Stack, { gap: "md", children: isLoading ? (_jsx(Div, { className: "text-center", padding: "y-xl", children: _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "Loading reviews\u2026" }) })) : rows.length === 0 ? (_jsx(Div, { className: "text-center", padding: "y-3xl", children: _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "No reviews found." }) })) : (rows.map((review) => (_jsx(Div, { className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", rounded: "lg", padding: "md", children: _jsxs(Row, { align: "start", justify: "between", gap: "3", wrap: true, children: [_jsxs(Row, { align: "start", className: "flex-1 min-w-0", gap: "3", children: [_jsx(Checkbox, { checked: selection.selectedIds.includes(review.id), onChange: () => selection.toggleSelect(review.id), "aria-label": "Select review" }), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsx(Text, { className: "truncate", weight: "medium", children: review.productTitle }), _jsxs(Row, { className: "mt-1", align: "center", gap: "sm", wrap: true, children: [_jsx(Stars, { rating: review.rating }), _jsxs(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: ["by ", review.userName] }), review.verified && _jsx(Badge, { variant: "success", children: "Verified" }), statusBadge(review.status), _jsx(Badge, { variant: review.sellerReply ? "success" : "warning", children: review.sellerReply ? "Store replied" : "Awaiting store reply" })] }), review.title && _jsx(Text, { className: "mt-2", weight: "medium", children: review.title }), _jsx(Text, { className: "mt-1 text-[var(--appkit-color-text-
|
|
231
|
+
renderCards: (rows, _view, selection, isLoading) => (_jsx(Stack, { gap: "md", children: isLoading ? (_jsx(Div, { className: "text-center", padding: "y-xl", children: _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "Loading reviews\u2026" }) })) : rows.length === 0 ? (_jsx(Div, { className: "text-center", padding: "y-3xl", children: _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "No reviews found." }) })) : (rows.map((review) => (_jsx(Div, { className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", rounded: "lg", padding: "md", children: _jsxs(Row, { align: "start", justify: "between", gap: "3", wrap: true, children: [_jsxs(Row, { align: "start", className: "flex-1 min-w-0", gap: "3", children: [_jsx(Checkbox, { checked: selection.selectedIds.includes(review.id), onChange: () => selection.toggleSelect(review.id), "aria-label": "Select review" }), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsx(Text, { className: "truncate", weight: "medium", children: review.productTitle }), _jsxs(Row, { className: "mt-1", align: "center", gap: "sm", wrap: true, children: [_jsx(Stars, { rating: review.rating }), _jsxs(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: ["by ", review.userName] }), review.verified && _jsx(Badge, { variant: "success", children: "Verified" }), statusBadge(review.status), _jsx(Badge, { variant: review.sellerReply ? "success" : "warning", children: review.sellerReply ? "Store replied" : "Awaiting store reply" })] }), review.title && _jsx(Text, { className: "mt-2", weight: "medium", children: review.title }), _jsx(Text, { className: "mt-1 text-[var(--appkit-color-text-muted)] line-clamp-3", size: "sm", children: review.comment }), review.sellerReply && (_jsxs(Div, { className: "mt-2 pl-[0.75rem] border-l-2 border-[var(--appkit-color-primary)]", children: [_jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: "Store reply:" }), _jsx(Text, { size: "sm", children: review.sellerReply })] }))] })] }), _jsxs(Row, { className: "flex-shrink-0", gap: "sm", children: [_jsx(Button, { variant: "outline", size: "sm", onClick: () => openReply(review), children: review.sellerReply ? "Edit Reply" : ACTIONS.STORE["reply-review"].label }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setContestTarget(review), children: ACTIONS.STORE["contest-review"].label }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setFeedbackTarget(review), children: ACTIONS.STORE["buyer-feedback"].label })] })] }) }, review.id)))) })),
|
|
230
232
|
};
|
|
231
|
-
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(SideDrawer, { isOpen: !!replyTarget, onClose: () => setReplyTarget(null), title: replyTarget?.sellerReply ? "Edit Reply" : "Reply to Review", mode: "create", children: _jsxs(Stack, { gap: "md", className: `${__P.p4}`, children: [replyTarget && (_jsxs(Div, { className: `${__P.p3} bg-[var(--appkit-color-
|
|
233
|
+
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(SideDrawer, { isOpen: !!replyTarget, onClose: () => setReplyTarget(null), title: replyTarget?.sellerReply ? "Edit Reply" : "Reply to Review", mode: "create", children: _jsxs(Stack, { gap: "md", className: `${__P.p4}`, children: [replyTarget && (_jsxs(Div, { className: `${__P.p3} bg-[var(--appkit-color-bg)]`, rounded: "default", children: [_jsx(Stars, { rating: replyTarget.rating }), _jsx(Text, { className: "mt-1", size: "sm", children: replyTarget.comment })] })), replyError && _jsx(Alert, { variant: "error", children: replyError }), _jsx(ReviewTextForm, { schema: reviewReplySchema, values: replyDraft, onChange: (partial) => setReplyDraft((d) => ({ ...d, ...partial })), onSubmit: () => void handleReplySave(refetchReviews), submitLabel: replyTarget?.sellerReply ? "Update Reply" : "Post Reply", onCancel: () => setReplyTarget(null), isLoading: replySaving, scope: "store:review-reply" })] }) }), _jsx(Modal, { isOpen: bulkReplyOpen, onClose: () => setBulkReplyOpen(false), title: "Bulk reply to selected reviews", children: _jsx(Stack, { gap: "md", padding: "2xs", children: _jsx(ReviewTextForm, { schema: reviewBulkReplySchema, values: bulkDraft, onChange: (partial) => setBulkDraft((d) => ({ ...d, ...partial })), onSubmit: () => void submitBulkReply(), submitLabel: "Send reply", onCancel: () => setBulkReplyOpen(false), isLoading: bulkSaving, scope: "store:review-bulk-reply" }) }) }), _jsx(Modal, { isOpen: !!contestTarget, onClose: () => setContestTarget(null), title: "Contest this review", children: _jsxs(Stack, { gap: "md", padding: "2xs", children: [_jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "Flag this review for admin investigation." }), _jsx(ReviewTextForm, { schema: reviewContestSchema, values: contestDraft, onChange: (partial) => setContestDraft((d) => ({ ...d, ...partial })), onSubmit: () => void submitContest(refetchReviews), submitLabel: "Submit", onCancel: () => setContestTarget(null), scope: "store:review-contest" })] }) }), _jsx(Modal, { isOpen: !!feedbackTarget, onClose: () => setFeedbackTarget(null), title: "Send feedback to buyer", children: _jsx(Stack, { gap: "md", padding: "2xs", children: _jsx(ReviewTextForm, { schema: reviewFeedbackSchema, values: feedbackDraft, onChange: (partial) => setFeedbackDraft((d) => ({ ...d, ...partial })), onSubmit: () => void submitFeedback(), submitLabel: "Send", onCancel: () => setFeedbackTarget(null), scope: "store:review-feedback" }) }) })] }));
|
|
232
234
|
}
|
|
@@ -84,7 +84,7 @@ export function StoreSidebar({ items, groups, activeHref, storeName, storeLogoUR
|
|
|
84
84
|
const navContent = groups ? (_jsx(GroupsContent, { groups: groups, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) : (_jsx(FlatContent, { items: items, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close }));
|
|
85
85
|
if (variant === "sidebar") {
|
|
86
86
|
const handleToggle = onToggle ?? close;
|
|
87
|
-
return (_jsxs(_Fragment, { children: [
|
|
87
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Div, { className: `hidden lg:flex fixed ${rail.edgeClass} z-40 transition-transform duration-300 top-[var(--header-height,3.5rem)] h-[calc(100vh-var(--header-height,3.5rem))] w-[18rem] ${desktopOpen ? "translate-x-0" : rail.collapsedTranslateClass}`, children: [_jsxs(Stack, { border: "default", surface: "sidePanel", className: `flex-1 ${rail.borderClass} ${__O.hidden}`, shadow: "xl", children: [_jsx(Div, { border: "bottom-subtle", paddingY: "y-sm-tall", className: "shrink-0", padding: "x-md", children: _jsxs(Row, { className: "min-w-0", align: "center", gap: "3", children: [storeLogoURL ? (_jsx(Div, { className: CLS_STORE_AVATAR, children: _jsx(MediaImage, { src: storeLogoURL, alt: storeName ?? "", size: "thumbnail" }) })) : (_jsx(Div, { className: CLS_STORE_FALLBACK, children: storeName?.[0]?.toUpperCase() })), _jsx(Text, { className: CLS_STORE_NAME, children: storeName || panelTitle })] }) }), _jsx(Div, { className: `flex-1 ${__O.yAuto}`, children: navContent }), renderFooter && _jsx(Div, { border: "top", padding: "inline", children: renderFooter() })] }), _jsx(SidebarCollapseToggle, { expanded: desktopOpen, onToggle: handleToggle, edge: hand })] }), _jsx(Div, { className: "lg:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: panelTitle, children: groups ? (_jsx(GroupsContent, { groups: groups, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) : (_jsx(FlatContent, { items: items, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) }) })] }));
|
|
88
88
|
}
|
|
89
89
|
return (_jsxs(_Fragment, { children: [mounted && mobileOpen &&
|
|
90
90
|
createPortal(_jsx(DrawerPanel, { title: panelTitle, onClose: close, children: navContent }), document.body), _jsx(Div, { className: "lg:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: panelTitle, children: groups ? (_jsx(GroupsContent, { groups: groups, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) : (_jsx(FlatContent, { items: items, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) }) })] }));
|
|
@@ -200,6 +200,16 @@ export declare const adminCouponFormSchema: z.ZodEffects<z.ZodObject<{
|
|
|
200
200
|
buyQuantity: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
201
201
|
getQuantity: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
202
202
|
currentUsage: z.ZodOptional<z.ZodNumber>;
|
|
203
|
+
tiers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
204
|
+
minAmount: z.ZodNumber;
|
|
205
|
+
discountValue: z.ZodNumber;
|
|
206
|
+
}, "strip", z.ZodTypeAny, {
|
|
207
|
+
minAmount: number;
|
|
208
|
+
discountValue: number;
|
|
209
|
+
}, {
|
|
210
|
+
minAmount: number;
|
|
211
|
+
discountValue: number;
|
|
212
|
+
}>, "many">>;
|
|
203
213
|
firstTimeUserOnly: z.ZodBoolean;
|
|
204
214
|
appliesToAuctions: z.ZodBoolean;
|
|
205
215
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -218,6 +228,10 @@ export declare const adminCouponFormSchema: z.ZodEffects<z.ZodObject<{
|
|
|
218
228
|
appliesToAuctions: boolean;
|
|
219
229
|
value?: string | undefined;
|
|
220
230
|
description?: string | undefined;
|
|
231
|
+
tiers?: {
|
|
232
|
+
minAmount: number;
|
|
233
|
+
discountValue: number;
|
|
234
|
+
}[] | undefined;
|
|
221
235
|
currentUsage?: number | undefined;
|
|
222
236
|
maxDiscount?: string | undefined;
|
|
223
237
|
buyQuantity?: string | undefined;
|
|
@@ -238,6 +252,10 @@ export declare const adminCouponFormSchema: z.ZodEffects<z.ZodObject<{
|
|
|
238
252
|
appliesToAuctions: boolean;
|
|
239
253
|
value?: string | undefined;
|
|
240
254
|
description?: string | undefined;
|
|
255
|
+
tiers?: {
|
|
256
|
+
minAmount: number;
|
|
257
|
+
discountValue: number;
|
|
258
|
+
}[] | undefined;
|
|
241
259
|
currentUsage?: number | undefined;
|
|
242
260
|
maxDiscount?: string | undefined;
|
|
243
261
|
buyQuantity?: string | undefined;
|
|
@@ -258,6 +276,10 @@ export declare const adminCouponFormSchema: z.ZodEffects<z.ZodObject<{
|
|
|
258
276
|
appliesToAuctions: boolean;
|
|
259
277
|
value?: string | undefined;
|
|
260
278
|
description?: string | undefined;
|
|
279
|
+
tiers?: {
|
|
280
|
+
minAmount: number;
|
|
281
|
+
discountValue: number;
|
|
282
|
+
}[] | undefined;
|
|
261
283
|
currentUsage?: number | undefined;
|
|
262
284
|
maxDiscount?: string | undefined;
|
|
263
285
|
buyQuantity?: string | undefined;
|
|
@@ -278,6 +300,10 @@ export declare const adminCouponFormSchema: z.ZodEffects<z.ZodObject<{
|
|
|
278
300
|
appliesToAuctions: boolean;
|
|
279
301
|
value?: string | undefined;
|
|
280
302
|
description?: string | undefined;
|
|
303
|
+
tiers?: {
|
|
304
|
+
minAmount: number;
|
|
305
|
+
discountValue: number;
|
|
306
|
+
}[] | undefined;
|
|
281
307
|
currentUsage?: number | undefined;
|
|
282
308
|
maxDiscount?: string | undefined;
|
|
283
309
|
buyQuantity?: string | undefined;
|
|
@@ -246,6 +246,33 @@ export const adminCouponFormSchema = couponFormBase
|
|
|
246
246
|
section: "limits", order: 5, row: "pair", derived: true, tier: "t3-mirror",
|
|
247
247
|
label: "Current usage", help: "Updated by orders.",
|
|
248
248
|
}),
|
|
249
|
+
/*
|
|
250
|
+
* ── Tiered discounts ────────────────────────────────────────────────────
|
|
251
|
+
*
|
|
252
|
+
* 🛑 `CouponDocument.tiers` has existed since the collection shipped and
|
|
253
|
+
* had NO editor on either portal — and `getTieredDiscount`, its helper,
|
|
254
|
+
* had zero callers, so even a hand-seeded tier was ignored by the
|
|
255
|
+
* discount calculation. Both halves are fixed together: wiring an editor
|
|
256
|
+
* to a field nothing reads would hand an admin a control that does
|
|
257
|
+
* nothing, which is the defect this audit keeps removing rather than
|
|
258
|
+
* adding.
|
|
259
|
+
*
|
|
260
|
+
* 🛑 `when` limits it to the two types that HAVE a `discount.value` for a
|
|
261
|
+
* tier to replace. A BOGO's value lives in `bxgy` and free shipping is a
|
|
262
|
+
* shipping-line waiver, so a tier on either would be meaningless — and an
|
|
263
|
+
* input that cannot affect the outcome is worse than an absent one.
|
|
264
|
+
*/
|
|
265
|
+
tiers: annotate(z
|
|
266
|
+
.array(z.object({
|
|
267
|
+
minAmount: z.number().min(0, "Spend threshold cannot be negative"),
|
|
268
|
+
discountValue: z.number().min(0, "Discount cannot be negative"),
|
|
269
|
+
}))
|
|
270
|
+
.max(6, "At most 6 tiers")
|
|
271
|
+
.optional(), {
|
|
272
|
+
section: "limits", order: 6, row: "full", label: "Spend tiers",
|
|
273
|
+
when: (v) => v.type === "percentage" || v.type === "fixed",
|
|
274
|
+
help: "Replaces the discount value once the order reaches a threshold. The highest matching tier wins.",
|
|
275
|
+
}),
|
|
249
276
|
firstTimeUserOnly: annotate(z.boolean(), {
|
|
250
277
|
section: "scope", order: 3, row: "quarter", label: "First-time users only",
|
|
251
278
|
}),
|
|
@@ -85,6 +85,7 @@ export declare const productDraftSchema: z.ZodObject<{
|
|
|
85
85
|
seoTitle: z.ZodOptional<z.ZodString>;
|
|
86
86
|
seoDescription: z.ZodOptional<z.ZodString>;
|
|
87
87
|
barcodeId: z.ZodOptional<z.ZodString>;
|
|
88
|
+
sku: z.ZodOptional<z.ZodString>;
|
|
88
89
|
startingBid: z.ZodOptional<z.ZodNumber>;
|
|
89
90
|
reservePrice: z.ZodOptional<z.ZodNumber>;
|
|
90
91
|
buyNowPrice: z.ZodOptional<z.ZodNumber>;
|
|
@@ -175,6 +176,7 @@ export declare const productDraftSchema: z.ZodObject<{
|
|
|
175
176
|
seoTitle: z.ZodOptional<z.ZodString>;
|
|
176
177
|
seoDescription: z.ZodOptional<z.ZodString>;
|
|
177
178
|
barcodeId: z.ZodOptional<z.ZodString>;
|
|
179
|
+
sku: z.ZodOptional<z.ZodString>;
|
|
178
180
|
startingBid: z.ZodOptional<z.ZodNumber>;
|
|
179
181
|
reservePrice: z.ZodOptional<z.ZodNumber>;
|
|
180
182
|
buyNowPrice: z.ZodOptional<z.ZodNumber>;
|
|
@@ -265,6 +267,7 @@ export declare const productDraftSchema: z.ZodObject<{
|
|
|
265
267
|
seoTitle: z.ZodOptional<z.ZodString>;
|
|
266
268
|
seoDescription: z.ZodOptional<z.ZodString>;
|
|
267
269
|
barcodeId: z.ZodOptional<z.ZodString>;
|
|
270
|
+
sku: z.ZodOptional<z.ZodString>;
|
|
268
271
|
startingBid: z.ZodOptional<z.ZodNumber>;
|
|
269
272
|
reservePrice: z.ZodOptional<z.ZodNumber>;
|
|
270
273
|
buyNowPrice: z.ZodOptional<z.ZodNumber>;
|
|
@@ -87,6 +87,11 @@ export const productDraftSchema = z
|
|
|
87
87
|
seoTitle: z.string().optional(),
|
|
88
88
|
seoDescription: z.string().optional(),
|
|
89
89
|
barcodeId: z.string().optional(),
|
|
90
|
+
/*
|
|
91
|
+
* The human stock key. Separate from barcodeId because they are two keys
|
|
92
|
+
* with opposite requirements — see ProductDocument.sku.
|
|
93
|
+
*/
|
|
94
|
+
sku: z.string().max(64).optional(),
|
|
90
95
|
// Auction
|
|
91
96
|
startingBid: z.number().optional(),
|
|
92
97
|
reservePrice: z.number().optional(),
|
|
@@ -6,7 +6,7 @@ import { Button } from "../../ui/components/Button.js";
|
|
|
6
6
|
import { IconButton } from "../../ui/components/IconButton.js";
|
|
7
7
|
import { classNames } from "../../ui/style.helper.js";
|
|
8
8
|
import { FORM_ACTION_META, FORM_ACTION_ID } from "../products/constants/action-defs.js";
|
|
9
|
-
import { ActionRow, Div, OverflowRow, Row, Span, Stack, Text } from "../../ui/index.js";
|
|
9
|
+
import { ActionRow, Div, Heading, OverflowRow, Row, Span, Stack, Text } from "../../ui/index.js";
|
|
10
10
|
/**
|
|
11
11
|
* Carries the `schema` prop passed to `<FormShell>` down to any nested
|
|
12
12
|
* `<SectionForm>` that doesn't declare its own `schema`/`SectionDef.schema` —
|
|
@@ -122,7 +122,7 @@ export function FormShell({ isOpen, onClose, title, breadcrumb, schema, isDirty
|
|
|
122
122
|
};
|
|
123
123
|
if (!isOpen)
|
|
124
124
|
return null;
|
|
125
|
-
return (_jsxs(FormSchemaContext.Provider, { value: schema, children: [_jsx(Div, { surface: "overlay-sm", className: "fixed inset-0 backdrop-blur-[2px]", style: { zIndex: "calc(var(--appkit-z-modal) - 1)" }, "aria-hidden": "true", onClick: attemptClose }), _jsxs(Div, { layout: "flex", ref: panelRef, role: "dialog", "aria-modal": "true", "aria-label": title, className: "fixed top-0 bottom-0 left-0 right-0 lg:left-[10%] lg:right-[10%] [flex-direction:column] bg-[var(--appkit-color-surface)]", shadow: "2xl", style: { zIndex: "var(--appkit-z-modal)" }, children: [_jsxs(Row, { gap: "sm", paddingX: "x-5", className: "flex-shrink-0 sticky top-0 z-10 border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", padding: "y-sm", children: [previewMode ? (_jsxs(Button, { variant: "ghost", type: "button", onClick: () => setPreviewMode(false), "aria-label": "Back to edit", gap: "xs", rounded: "lg", textSize: "sm", textColor: "muted", className: "flex-shrink-0", children: [_jsx(ArrowLeft, { className: "w-4 h-4" }), _jsx(Span, { className: "hidden sm:inline", children: "Back to Edit" })] })) : (_jsx(IconButton, { type: "button", onClick: attemptClose, "aria-label": "Close", variant: "ghost", rounded: "lg", className: "text-[var(--appkit-color-text-muted)] flex-shrink-0", children: _jsx(X, { className: "w-5 h-5" }) })), _jsxs(Div, { className: "flex-1 min-w-0", children: [breadcrumb && (_jsx(Text, { className: "text-[var(--appkit-color-text-muted)] truncate mb-0.5", size: "xs", children: breadcrumb })), _jsx(
|
|
125
|
+
return (_jsxs(FormSchemaContext.Provider, { value: schema, children: [_jsx(Div, { surface: "overlay-sm", className: "fixed inset-0 backdrop-blur-[2px]", style: { zIndex: "calc(var(--appkit-z-modal) - 1)" }, "aria-hidden": "true", onClick: attemptClose }), _jsxs(Div, { layout: "flex", ref: panelRef, role: "dialog", "aria-modal": "true", "aria-label": title, className: "fixed top-0 bottom-0 left-0 right-0 lg:left-[10%] lg:right-[10%] [flex-direction:column] bg-[var(--appkit-color-surface)]", shadow: "2xl", style: { zIndex: "var(--appkit-z-modal)" }, children: [_jsxs(Row, { gap: "sm", paddingX: "x-5", className: "flex-shrink-0 sticky top-0 z-10 border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", padding: "y-sm", children: [previewMode ? (_jsxs(Button, { variant: "ghost", type: "button", onClick: () => setPreviewMode(false), "aria-label": "Back to edit", gap: "xs", rounded: "lg", textSize: "sm", textColor: "muted", className: "flex-shrink-0", children: [_jsx(ArrowLeft, { className: "w-4 h-4" }), _jsx(Span, { className: "hidden sm:inline", children: "Back to Edit" })] })) : (_jsx(IconButton, { type: "button", onClick: attemptClose, "aria-label": "Close", variant: "ghost", rounded: "lg", className: "text-[var(--appkit-color-text-muted)] flex-shrink-0", children: _jsx(X, { className: "w-5 h-5" }) })), _jsxs(Div, { className: "flex-1 min-w-0", children: [breadcrumb && (_jsx(Text, { className: "text-[var(--appkit-color-text-muted)] truncate mb-0.5", size: "xs", children: breadcrumb })), _jsx(Heading, { level: 1, className: "text-[var(--appkit-color-text)] truncate", size: "sm", weight: "semibold", children: previewMode ? `Preview — ${title}` : title })] }), _jsx(Row, { gap: "xs", className: "flex-shrink-0", children: previewMode ? null : (_jsxs(_Fragment, { children: [previewSlot && (_jsxs(Button, { variant: "outline", type: "button", onClick: () => setPreviewMode(true), gap: "xs", rounded: "lg", paddingX: "sm", textSize: "sm", textColor: "muted", children: [_jsx(Eye, { className: "w-4 h-4" }), _jsx(Span, { className: "hidden sm:inline", children: "Preview" })] })), onSaveDraft && (_jsx(Button, { variant: "outline", size: "sm", onClick: handleSaveDraft, disabled: isLoading || savingDraft || publishing, isLoading: savingDraft, children: saveLabel })), onPublish && (_jsx(Button, { variant: "primary", size: "sm", onClick: handlePublish, disabled: isLoading || savingDraft || publishing, isLoading: publishing, children: publishLabel }))] })) })] }), _jsxs(Div, { layout: "flex", className: `flex-1 ${__O.hidden}`, children: [sections && sections.length > 0 && !previewMode && (_jsx("nav", { "aria-label": "Form sections", className: "hidden lg:flex flex-col flex-shrink-0 w-48 border-r border-[var(--appkit-color-border)] py-[var(--appkit-space-4)] px-[var(--appkit-space-3)] gap-[var(--appkit-space-1)] overflow-y-auto", children: sections.map((sec) => (_jsx(Button, { variant: "ghost", type: "button", onClick: () => scrollToSection(sec.id), rounded: "lg", paddingX: "sm", paddingY: "xs", textSize: "sm", textColor: "muted", justify: "start", className: "text-left", children: sec.label }, sec.id))) })), sections && sections.length > 0 && !previewMode && (_jsx(Row, { gap: "px", className: "lg:hidden fixed top-[var(--form-shell-topbar-h,57px)] left-0 right-0 z-10 px-[1.25rem] bg-[var(--appkit-color-surface)] border-b border-[var(--appkit-color-border)]", padding: "y-xs", children: _jsx(OverflowRow, { items: sections.map((sec) => ({
|
|
126
126
|
id: sec.id,
|
|
127
127
|
label: sec.label,
|
|
128
128
|
onSelect: () => scrollToSection(sec.id),
|
|
@@ -203,6 +203,20 @@ export function QuickFormDrawer({ isOpen, onClose, title, fields, defaultValues,
|
|
|
203
203
|
submitAttempted,
|
|
204
204
|
submitAttemptCount,
|
|
205
205
|
markSubmitAttempted: () => setSubmitAttemptCount((n) => n + 1),
|
|
206
|
+
/*
|
|
207
|
+
* 🛑 Not offered here. This drawer's whole purpose is the 1-3 field
|
|
208
|
+
* inline edit opened from a picker's "+ Create new" — it CLOSES on
|
|
209
|
+
* success and auto-selects what it just made, which is the opposite of
|
|
210
|
+
* staying put. "Add another" would have to mean "create a second one you
|
|
211
|
+
* did not ask for and cannot select", so the control has no coherent
|
|
212
|
+
* meaning in this shell.
|
|
213
|
+
*
|
|
214
|
+
* Also note this context backs ONLY `<FormErrorSummary>` — the comment
|
|
215
|
+
* above says so — so even a `true` here would reach no submit handler.
|
|
216
|
+
*/
|
|
217
|
+
addAnotherEnabled: false,
|
|
218
|
+
addAnother: false,
|
|
219
|
+
setAddAnother: () => { },
|
|
206
220
|
}), [liveErrors, submitting, submitAttempted, submitAttemptCount]);
|
|
207
221
|
if (!isOpen)
|
|
208
222
|
return null;
|
|
@@ -2,6 +2,7 @@ import { type ReactNode } from "react";
|
|
|
2
2
|
import type { JsonValue } from "@mohasinac/appkit/client";
|
|
3
3
|
import type { ZodTypeAny } from "zod";
|
|
4
4
|
import { type FormShellStep } from "../../ui/forms/FormShell";
|
|
5
|
+
import { type LabelPlacement } from "../../ui/forms/FieldLabel";
|
|
5
6
|
/**
|
|
6
7
|
* A collapsible form segment. Replaces `StepDef` — the differences are the
|
|
7
8
|
* point, not incidental:
|
|
@@ -33,6 +34,24 @@ export interface SectionDef<T extends object = Record<string, JsonValue>> {
|
|
|
33
34
|
* `CollapsibleSection.keepMounted`.
|
|
34
35
|
*/
|
|
35
36
|
keepMounted?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* How every field in THIS section labels itself: `"above"` (the default),
|
|
39
|
+
* `"inline"`, or `"hidden"`.
|
|
40
|
+
*
|
|
41
|
+
* 🛑 A SECTION-LEVEL DECISION, which is the whole reason it lives here
|
|
42
|
+
* rather than on each field. One field labelling above beside one labelling
|
|
43
|
+
* inline reads as broken rather than as varied, and the choice is really
|
|
44
|
+
* about a section's density — a 12-field address block wants inline, a
|
|
45
|
+
* 3-field settings panel wants above. The field-level prop exists as an
|
|
46
|
+
* escape hatch and should stay unused.
|
|
47
|
+
*
|
|
48
|
+
* `"hidden"` renders the label to assistive technology and hides it visually
|
|
49
|
+
* (`sr-only`, never `display: none`, which would remove it from the
|
|
50
|
+
* accessibility tree and produce the unlabelled field it was meant to
|
|
51
|
+
* avoid). It is for fields whose purpose is obvious from context, NOT a way
|
|
52
|
+
* to suppress the unlabelled-field count.
|
|
53
|
+
*/
|
|
54
|
+
labelPlacement?: LabelPlacement;
|
|
36
55
|
render: (props: {
|
|
37
56
|
values: T;
|
|
38
57
|
onChange: (partial: Partial<T>) => void;
|