@mohasinac/appkit 4.52.5 → 4.53.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 +4 -4
- package/dist/_internal/client/features/sticker-trace/canvas-codec.d.ts +2 -0
- package/dist/_internal/client/features/sticker-trace/canvas-codec.js +148 -0
- package/dist/_internal/server/features/auctions/actions.js +1 -1
- package/dist/_internal/server/features/categories/data.js +23 -7
- package/dist/_internal/server/features/checkout/actions.js +10 -3
- package/dist/_internal/server/features/checkout/data.d.ts +15 -0
- package/dist/_internal/server/features/checkout/data.js +20 -3
- package/dist/_internal/server/features/lottery/actions.js +9 -1
- package/dist/_internal/server/features/lottery/og.d.ts +40 -0
- package/dist/_internal/server/features/lottery/og.js +79 -0
- package/dist/_internal/server/features/messages/actions.js +4 -0
- package/dist/_internal/server/features/offers/adapters.js +17 -3
- package/dist/_internal/server/features/orders/actions.js +7 -2
- package/dist/_internal/server/features/raffle/actions.d.ts +19 -0
- package/dist/_internal/server/features/raffle/actions.js +25 -0
- package/dist/_internal/server/features/reviews/actions.js +1 -1
- package/dist/_internal/server/features/reviews/data.d.ts +1 -1
- package/dist/_internal/server/features/search/index-build/artifact-store.d.ts +89 -0
- package/dist/_internal/server/features/search/index-build/artifact-store.js +208 -0
- package/dist/_internal/server/features/search/index-build/build.d.ts +57 -0
- package/dist/_internal/server/features/search/index-build/build.js +285 -0
- package/dist/_internal/server/features/search/index-build/sources.d.ts +53 -0
- package/dist/_internal/server/features/search/index-build/sources.js +385 -0
- package/dist/_internal/server/features/search/search-sources.d.ts +0 -15
- package/dist/_internal/server/features/search/search-sources.js +142 -7
- package/dist/_internal/server/features/seo/robots.js +21 -1
- package/dist/_internal/server/features/seo/sitemap.js +1 -1
- package/dist/_internal/server/features/shared/listing-data-factory.js +16 -4
- package/dist/_internal/server/features/site-settings/adapters.d.ts +1 -1
- package/dist/_internal/server/features/site-settings/adapters.js +26 -0
- package/dist/_internal/server/features/sticker-trace/actions.d.ts +109 -0
- package/dist/_internal/server/features/sticker-trace/actions.js +172 -0
- package/dist/_internal/server/features/sticker-trace/adapters.d.ts +80 -0
- package/dist/_internal/server/features/sticker-trace/adapters.js +174 -0
- package/dist/_internal/server/features/sticker-trace/build-cut-file.d.ts +26 -0
- package/dist/_internal/server/features/sticker-trace/build-cut-file.js +127 -0
- package/dist/_internal/server/features/sticker-trace/coordinator.d.ts +27 -0
- package/dist/_internal/server/features/sticker-trace/coordinator.js +169 -0
- package/dist/_internal/server/features/sticker-trace/fanout.d.ts +43 -0
- package/dist/_internal/server/features/sticker-trace/fanout.js +180 -0
- package/dist/_internal/server/features/sticker-trace/finalizer.d.ts +25 -0
- package/dist/_internal/server/features/sticker-trace/finalizer.js +123 -0
- package/dist/_internal/server/features/sticker-trace/mosaic-inputs.d.ts +30 -0
- package/dist/_internal/server/features/sticker-trace/mosaic-inputs.js +112 -0
- package/dist/_internal/server/features/sticker-trace/progress.d.ts +81 -0
- package/dist/_internal/server/features/sticker-trace/progress.js +198 -0
- package/dist/_internal/server/features/sticker-trace/promote.d.ts +23 -0
- package/dist/_internal/server/features/sticker-trace/promote.js +193 -0
- package/dist/_internal/server/features/sticker-trace/shard.d.ts +50 -0
- package/dist/_internal/server/features/sticker-trace/shard.js +174 -0
- package/dist/_internal/server/features/sticker-trace/sheet-actions.d.ts +141 -0
- package/dist/_internal/server/features/sticker-trace/sheet-actions.js +279 -0
- package/dist/_internal/server/features/sticker-trace/storage.d.ts +135 -0
- package/dist/_internal/server/features/sticker-trace/storage.js +282 -0
- package/dist/_internal/server/functions/scheduled.d.ts +2 -1
- package/dist/_internal/server/functions/scheduled.js +25 -1
- package/dist/_internal/server/jobs/core/_event-ref.d.ts +51 -0
- package/dist/_internal/server/jobs/core/_event-ref.js +63 -0
- package/dist/_internal/server/jobs/core/assignSpinPrize.d.ts +18 -0
- package/dist/_internal/server/jobs/core/assignSpinPrize.js +77 -16
- package/dist/_internal/server/jobs/core/auctionSettlement.js +13 -4
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +44 -15
- package/dist/_internal/server/jobs/core/bundleStockSync.js +3 -4
- package/dist/_internal/server/jobs/core/cleanupRtdbEvents.js +44 -0
- package/dist/_internal/server/jobs/core/event-draw-reasons.d.ts +78 -0
- package/dist/_internal/server/jobs/core/event-draw-reasons.js +133 -0
- package/dist/_internal/server/jobs/core/listingProcessor.js +28 -8
- package/dist/_internal/server/jobs/core/onOrderCreate.js +12 -1
- package/dist/_internal/server/jobs/core/onScamReportCreate.js +13 -2
- package/dist/_internal/server/jobs/core/onScamReportRejected.js +8 -2
- package/dist/_internal/server/jobs/core/onScamReportVerified.js +8 -2
- package/dist/_internal/server/jobs/core/onStoreWrite.js +11 -4
- package/dist/_internal/server/jobs/core/prizeDrawAssignWinner.js +5 -4
- package/dist/_internal/server/jobs/core/prizeDrawExpiryReveal.js +1 -4
- package/dist/_internal/server/jobs/core/prizeDrawSoldOutReveal.js +1 -2
- package/dist/_internal/server/jobs/core/promotions.js +7 -4
- package/dist/_internal/server/jobs/core/searchIndexBuild.d.ts +7 -0
- package/dist/_internal/server/jobs/core/searchIndexBuild.js +211 -0
- package/dist/_internal/server/jobs/core/triggerEventRaffle.d.ts +35 -0
- package/dist/_internal/server/jobs/core/triggerEventRaffle.js +213 -31
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +20 -14
- package/dist/_internal/server/jobs/handlers/assignSpinPrize.d.ts +8 -0
- package/dist/_internal/server/jobs/handlers/assignSpinPrize.js +15 -15
- 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/onCategoryWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/onProductWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/onReviewWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/onScamReportUpdate.js +18 -0
- package/dist/_internal/server/jobs/handlers/onStoreWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/searchIndexBuild.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/searchIndexBuild.js +2 -0
- package/dist/_internal/server/jobs/handlers/triggerEventRaffle.d.ts +8 -0
- package/dist/_internal/server/jobs/handlers/triggerEventRaffle.js +15 -6
- package/dist/_internal/shared/actions/action-registry.js +29 -0
- package/dist/_internal/shared/cache/revalidate-targets.d.ts +0 -1
- package/dist/_internal/shared/cache/revalidate-targets.js +10 -8
- package/dist/_internal/shared/features/events/config.d.ts +14 -0
- package/dist/_internal/shared/features/events/config.js +14 -0
- package/dist/_internal/shared/features/notifications/action-url.js +8 -0
- package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
- package/dist/_internal/shared/features/sticker-trace/codec.d.ts +81 -0
- package/dist/_internal/shared/features/sticker-trace/codec.js +30 -0
- package/dist/_internal/shared/features/sticker-trace/config.d.ts +81 -0
- package/dist/_internal/shared/features/sticker-trace/config.js +177 -0
- package/dist/_internal/shared/features/sticker-trace/cut-contour.d.ts +20 -0
- package/dist/_internal/shared/features/sticker-trace/cut-contour.js +60 -0
- package/dist/_internal/shared/features/sticker-trace/export/build-export-set.d.ts +65 -0
- package/dist/_internal/shared/features/sticker-trace/export/build-export-set.js +176 -0
- package/dist/_internal/shared/features/sticker-trace/export/cut-svg.d.ts +56 -0
- package/dist/_internal/shared/features/sticker-trace/export/cut-svg.js +120 -0
- package/dist/_internal/shared/features/sticker-trace/export/machine-profiles.d.ts +92 -0
- package/dist/_internal/shared/features/sticker-trace/export/machine-profiles.js +153 -0
- package/dist/_internal/shared/features/sticker-trace/export/nesting.d.ts +51 -0
- package/dist/_internal/shared/features/sticker-trace/export/nesting.js +110 -0
- package/dist/_internal/shared/features/sticker-trace/export/page-sizes.d.ts +68 -0
- package/dist/_internal/shared/features/sticker-trace/export/page-sizes.js +223 -0
- package/dist/_internal/shared/features/sticker-trace/export/part-tiling.d.ts +51 -0
- package/dist/_internal/shared/features/sticker-trace/export/part-tiling.js +178 -0
- package/dist/_internal/shared/features/sticker-trace/export/simplify-budget.d.ts +26 -0
- package/dist/_internal/shared/features/sticker-trace/export/simplify-budget.js +134 -0
- package/dist/_internal/shared/features/sticker-trace/export/vectorise-art.d.ts +40 -0
- package/dist/_internal/shared/features/sticker-trace/export/vectorise-art.js +195 -0
- package/dist/_internal/shared/features/sticker-trace/index.d.ts +2 -0
- package/dist/_internal/shared/features/sticker-trace/index.js +59 -0
- package/dist/_internal/shared/features/sticker-trace/math/catmull-rom.d.ts +11 -0
- package/dist/_internal/shared/features/sticker-trace/math/catmull-rom.js +66 -0
- package/dist/_internal/shared/features/sticker-trace/math/edt.d.ts +27 -0
- package/dist/_internal/shared/features/sticker-trace/math/edt.js +165 -0
- package/dist/_internal/shared/features/sticker-trace/math/label.d.ts +15 -0
- package/dist/_internal/shared/features/sticker-trace/math/label.js +156 -0
- package/dist/_internal/shared/features/sticker-trace/math/marching-squares.d.ts +16 -0
- package/dist/_internal/shared/features/sticker-trace/math/marching-squares.js +242 -0
- package/dist/_internal/shared/features/sticker-trace/math/morphology.d.ts +46 -0
- package/dist/_internal/shared/features/sticker-trace/math/morphology.js +168 -0
- package/dist/_internal/shared/features/sticker-trace/math/rasterize-path.d.ts +88 -0
- package/dist/_internal/shared/features/sticker-trace/math/rasterize-path.js +286 -0
- package/dist/_internal/shared/features/sticker-trace/math/rdp.d.ts +10 -0
- package/dist/_internal/shared/features/sticker-trace/math/rdp.js +74 -0
- package/dist/_internal/shared/features/sticker-trace/resume.d.ts +50 -0
- package/dist/_internal/shared/features/sticker-trace/resume.js +160 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cluster.d.ts +20 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cluster.js +132 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cross-profile.d.ts +28 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cross-profile.js +120 -0
- package/dist/_internal/shared/features/sticker-trace/trace/flood.d.ts +21 -0
- package/dist/_internal/shared/features/sticker-trace/trace/flood.js +104 -0
- package/dist/_internal/shared/features/sticker-trace/trace/geometry.d.ts +3 -0
- package/dist/_internal/shared/features/sticker-trace/trace/geometry.js +140 -0
- package/dist/_internal/shared/features/sticker-trace/trace/line-filter.d.ts +15 -0
- package/dist/_internal/shared/features/sticker-trace/trace/line-filter.js +138 -0
- package/dist/_internal/shared/features/sticker-trace/trace/merge.d.ts +27 -0
- package/dist/_internal/shared/features/sticker-trace/trace/merge.js +187 -0
- package/dist/_internal/shared/features/sticker-trace/trace/paper.d.ts +32 -0
- package/dist/_internal/shared/features/sticker-trace/trace/paper.js +147 -0
- package/dist/_internal/shared/features/sticker-trace/trace/prefilter.d.ts +30 -0
- package/dist/_internal/shared/features/sticker-trace/trace/prefilter.js +125 -0
- package/dist/_internal/shared/features/sticker-trace/trace/quantise.d.ts +10 -0
- package/dist/_internal/shared/features/sticker-trace/trace/quantise.js +153 -0
- package/dist/_internal/shared/features/sticker-trace/trace/ridge.d.ts +88 -0
- package/dist/_internal/shared/features/sticker-trace/trace/ridge.js +344 -0
- package/dist/_internal/shared/features/sticker-trace/trace/segment.d.ts +10 -0
- package/dist/_internal/shared/features/sticker-trace/trace/segment.js +251 -0
- package/dist/_internal/shared/features/sticker-trace/types.d.ts +197 -0
- package/dist/_internal/shared/features/sticker-trace/types.js +49 -0
- package/dist/_internal/shared/listing-types/_registry.d.ts +11 -0
- package/dist/_internal/shared/listing-types/art/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/config.js +1 -0
- package/dist/_internal/shared/listing-types/auction/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/auction/config.js +1 -0
- package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/classified/config.js +1 -0
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/digital-code/config.js +1 -0
- package/dist/_internal/shared/listing-types/feature-flags.d.ts +7 -0
- package/dist/_internal/shared/listing-types/feature-flags.js +9 -0
- package/dist/_internal/shared/listing-types/live/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/live/config.js +1 -0
- package/dist/_internal/shared/listing-types/pre-order/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/pre-order/config.js +1 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.js +1 -0
- package/dist/_internal/shared/listing-types/standard/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/standard/config.js +1 -0
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/config.js +1 -0
- package/dist/_internal/shared/media/limits.d.ts +12 -2
- package/dist/_internal/shared/media/limits.js +12 -2
- package/dist/_internal/shared/search/artifact-url.d.ts +35 -0
- package/dist/_internal/shared/search/artifact-url.js +119 -0
- package/dist/_internal/shared/search/index-record.d.ts +68 -0
- package/dist/_internal/shared/search/index-record.js +96 -0
- package/dist/_internal/shared/search/match.d.ts +65 -0
- package/dist/_internal/shared/search/match.js +263 -0
- package/dist/client.d.ts +8 -7
- package/dist/client.js +12 -5
- package/dist/configs/eslint.js +22 -2
- package/dist/constants/api-endpoints.d.ts +68 -0
- package/dist/constants/api-endpoints.js +32 -0
- package/dist/constants/field-names.d.ts +7 -1
- package/dist/constants/field-names.js +36 -1
- package/dist/contracts/repository.d.ts +8 -7
- package/dist/contracts/search.d.ts +2 -2
- package/dist/contracts/table.d.ts +3 -3
- package/dist/contracts/table.js +3 -3
- package/dist/core/contact-submissions.repository.js +2 -2
- package/dist/core/integration-keys.js +7 -1
- package/dist/core/newsletter.repository.js +2 -2
- package/dist/core/site-config.js +1 -1
- package/dist/errors/error-codes.d.ts +30 -0
- package/dist/errors/error-codes.js +30 -0
- package/dist/errors/error-display-map.js +40 -1
- package/dist/features/account/api/[userId]/addresses/route.js +1 -1
- package/dist/features/account/components/UserBidsView.js +1 -1
- package/dist/features/account/components/index.d.ts +0 -8
- package/dist/features/account/components/index.js +0 -4
- package/dist/features/addresses/repository/addresses.repository.d.ts +17 -6
- package/dist/features/addresses/repository/addresses.repository.js +65 -9
- package/dist/features/addresses/schemas/firestore.d.ts +17 -6
- package/dist/features/admin/actions/notification-actions.js +15 -6
- package/dist/features/admin/api/bids/route.js +1 -1
- package/dist/features/admin/api/coupons/route.js +1 -1
- package/dist/features/admin/api/products/route.js +1 -1
- package/dist/features/admin/api/reviews/route.js +1 -1
- package/dist/features/admin/components/AdminAdEditorView.js +19 -5
- package/dist/features/admin/components/AdminAuditLogView.js +1 -1
- package/dist/features/admin/components/AdminBlogEditorView.js +0 -1
- package/dist/features/admin/components/AdminBlogView.js +1 -1
- package/dist/features/admin/components/AdminBrandsView.js +17 -1
- package/dist/features/admin/components/AdminCategoryEditorView.js +0 -1
- package/dist/features/admin/components/AdminContactView.js +1 -1
- package/dist/features/admin/components/AdminEmployeeEditorView.js +1 -3
- package/dist/features/admin/components/AdminNewsletterView.js +1 -1
- package/dist/features/admin/components/AdminOrdersView.js +9 -2
- package/dist/features/admin/components/AdminPayoutsView.js +1 -1
- package/dist/features/admin/components/AdminPrizeDrawsView.js +11 -0
- package/dist/features/admin/components/AdminProductEditorView.d.ts +10 -1
- package/dist/features/admin/components/AdminProductEditorView.js +24 -37
- package/dist/features/admin/components/AdminProductsView.js +10 -3
- package/dist/features/admin/components/AdminScammersView.js +1 -1
- package/dist/features/admin/components/AdminSectionsView.js +21 -5
- package/dist/features/admin/components/AdminSessionsView.js +1 -1
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +22 -1
- package/dist/features/admin/components/AdminTeamView.js +1 -1
- package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +0 -1
- package/dist/features/admin/components/AdminUsersView.js +1 -1
- package/dist/features/admin/components/DataListingView.d.ts +2 -1
- package/dist/features/admin/components/DataListingView.js +9 -4
- package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +0 -2
- package/dist/features/admin/hooks/useAdminListing.d.ts +1 -1
- package/dist/features/admin/repository/site-settings.repository.js +8 -3
- package/dist/features/admin/schemas/firestore.d.ts +62 -1
- package/dist/features/admin/schemas/firestore.js +32 -0
- package/dist/features/admin/types/index.d.ts +1 -1
- package/dist/features/auctions/actions/bid-actions.d.ts +2 -2
- package/dist/features/auctions/actions/bid-actions.js +16 -4
- package/dist/features/auctions/api/route.js +1 -1
- package/dist/features/auctions/components/AuctionBottomActions.js +4 -0
- package/dist/features/auctions/repository/bid.repository.d.ts +46 -4
- package/dist/features/auctions/repository/bid.repository.js +114 -13
- package/dist/features/auctions/schemas/firestore.d.ts +24 -4
- package/dist/features/auctions/schemas/firestore.js +1 -0
- package/dist/features/auth/actions/profile-actions.js +30 -4
- package/dist/features/auth/components/index.d.ts +0 -1
- package/dist/features/auth/components/index.js +0 -1
- package/dist/features/auth/repository/session.repository.d.ts +17 -3
- package/dist/features/auth/repository/session.repository.js +46 -5
- package/dist/features/auth/repository/token.repository.d.ts +27 -4
- package/dist/features/auth/repository/token.repository.js +65 -11
- package/dist/features/auth/repository/user.repository.d.ts +33 -7
- package/dist/features/auth/repository/user.repository.js +100 -15
- package/dist/features/auth/schemas/firestore.d.ts +63 -12
- package/dist/features/auth/schemas/firestore.js +11 -0
- package/dist/features/before-after/api/route.js +1 -1
- package/dist/features/blog/components/BlogListView.js +16 -3
- package/dist/features/blog/components/BlogPostView.js +1 -1
- package/dist/features/blog/schemas/index.d.ts +2 -2
- package/dist/features/cart/api/route.js +1 -1
- package/dist/features/catalogue/repository/catalogue.repository.d.ts +7 -7
- package/dist/features/catalogue/repository/catalogue.repository.js +28 -10
- package/dist/features/catalogue/schemas/firestore.d.ts +11 -0
- package/dist/features/categories/api/route.js +10 -10
- package/dist/features/categories/components/CategoryDetailPageView.js +35 -5
- package/dist/features/categories/components/CategorySelectorCreate.js +0 -1
- package/dist/features/categories/components/index.d.ts +0 -2
- package/dist/features/categories/components/index.js +0 -1
- package/dist/features/categories/repository/categories.repository.d.ts +1 -0
- package/dist/features/categories/repository/categories.repository.js +31 -1
- package/dist/features/categories/schemas/index.d.ts +2 -2
- package/dist/features/categories/utils/taxonomy-visual.d.ts +21 -0
- package/dist/features/categories/utils/taxonomy-visual.js +58 -0
- package/dist/features/checkout/actions/checkout-value-otp-actions.js +8 -1
- package/dist/features/collections/api/[slug]/route.js +3 -3
- package/dist/features/collections/api/route.js +1 -1
- package/dist/features/consultation/api/route.js +1 -1
- package/dist/features/consultation/repository/consultations.repository.js +1 -1
- package/dist/features/consultation/types/index.d.ts +1 -1
- package/dist/features/contact/components/ContactForm.js +1 -3
- package/dist/features/corporate/api/route.js +1 -1
- package/dist/features/corporate/repository/corporate.repository.js +1 -1
- package/dist/features/corporate/types/index.d.ts +1 -1
- package/dist/features/cron/jobs/auction-expiry.job.js +1 -1
- package/dist/features/cron/jobs/preorder-reminder.job.js +1 -1
- package/dist/features/events/actions/event-actions.d.ts +14 -0
- package/dist/features/events/actions/event-actions.js +82 -3
- package/dist/features/events/api/[id]/route.js +2 -2
- package/dist/features/events/components/AdminEventEditorView.js +22 -3
- package/dist/features/events/components/AdminEventsView.js +32 -8
- package/dist/features/events/components/EventRafflesSection.d.ts +34 -1
- package/dist/features/events/components/EventRafflesSection.js +52 -3
- package/dist/features/events/components/SpinWheelView.d.ts +2 -2
- package/dist/features/events/components/SpinWheelView.js +41 -4
- package/dist/features/events/repository/event-entry.repository.d.ts +14 -2
- package/dist/features/events/repository/event-entry.repository.js +41 -7
- package/dist/features/events/schemas/firestore.d.ts +17 -4
- package/dist/features/events/types/index.d.ts +37 -0
- package/dist/features/faq/repository/faqs.repository.js +1 -1
- package/dist/features/faq/schemas/index.d.ts +5 -2
- package/dist/features/faq/schemas/index.js +6 -0
- package/dist/features/faq/types/index.d.ts +0 -1
- package/dist/features/grouped/components/GroupedListingEditorView.js +17 -2
- package/dist/features/homepage/api/carousel/[id]/route.js +1 -1
- package/dist/features/homepage/api/carousel/route.js +4 -4
- package/dist/features/homepage/api/route.js +2 -2
- package/dist/features/homepage/api/sections/route.js +1 -1
- package/dist/features/homepage/components/AnnouncementBar.d.ts +1 -9
- package/dist/features/homepage/components/AnnouncementBar.js +13 -19
- package/dist/features/homepage/components/MarketplaceHomepageView.js +6 -1
- package/dist/features/homepage/components/index.d.ts +0 -2
- package/dist/features/homepage/components/index.js +0 -1
- package/dist/features/homepage/repository/homepage.repository.js +1 -1
- package/dist/features/homepage/schemas/firestore.d.ts +6 -0
- package/dist/features/homepage/schemas/index.d.ts +10 -10
- package/dist/features/layout/AppLayoutShell.d.ts +11 -0
- package/dist/features/layout/AppLayoutShell.js +64 -12
- package/dist/features/layout/BottomActionsContext.d.ts +16 -0
- package/dist/features/layout/BottomActionsContext.js +5 -0
- package/dist/features/layout/BottomChrome.js +48 -9
- package/dist/features/layout/BottomNavbar.d.ts +14 -0
- package/dist/features/layout/BottomNavbar.js +43 -3
- package/dist/features/layout/MainNavbar.d.ts +11 -0
- package/dist/features/layout/NavbarLayout.d.ts +3 -0
- package/dist/features/layout/NavbarLayout.js +88 -11
- package/dist/features/layout/SideActionDock.d.ts +1 -0
- package/dist/features/layout/SideActionDock.js +219 -0
- package/dist/features/layout/TitleBarLayout.js +1 -1
- package/dist/features/layout/cta-anchor.d.ts +31 -0
- package/dist/features/layout/cta-anchor.js +31 -0
- package/dist/features/layout/hooks/useBottomActions.d.ts +7 -0
- package/dist/features/layout/hooks/useBottomActions.js +6 -1
- package/dist/features/layout/index.d.ts +9 -1
- package/dist/features/layout/index.js +9 -1
- package/dist/features/layout/useCtaReveal.d.ts +24 -0
- package/dist/features/layout/useCtaReveal.js +82 -0
- package/dist/features/layout/useHoldToOpen.d.ts +41 -0
- package/dist/features/layout/useHoldToOpen.js +84 -0
- package/dist/features/lottery/repository/lottery-entry.repository.d.ts +18 -3
- package/dist/features/lottery/repository/lottery-entry.repository.js +48 -6
- package/dist/features/lottery/schemas/firestore.d.ts +33 -5
- package/dist/features/loyalty/api/balance/route.js +1 -1
- package/dist/features/loyalty/api/history/route.js +1 -1
- package/dist/features/media/MediaImage.js +0 -1
- package/dist/features/media/MediaPickerModal.js +7 -1
- package/dist/features/media/modals/ImageEditor.js +5 -1
- package/dist/features/media/modals/VideoThumbnailSelector.js +17 -1
- package/dist/features/media/repository/media-assets.repository.d.ts +19 -0
- package/dist/features/media/upload/CameraCapture.js +16 -1
- package/dist/features/media/upload/ImageUpload.js +42 -4
- package/dist/features/media/upload/MediaUploadField.js +69 -13
- package/dist/features/media/upload/downscale-image.d.ts +56 -0
- package/dist/features/media/upload/downscale-image.js +150 -0
- package/dist/features/messages/components/ConversationThreadView.js +45 -2
- package/dist/features/messages/components/MessageSellerButton.d.ts +15 -1
- package/dist/features/messages/components/MessageSellerButton.js +10 -2
- package/dist/features/messages/schemas/firestore.d.ts +15 -0
- package/dist/features/orders/hooks/useOrders.js +4 -2
- package/dist/features/orders/repository/orders.repository.d.ts +15 -4
- package/dist/features/orders/repository/orders.repository.js +52 -20
- package/dist/features/orders/schemas/firestore.d.ts +15 -4
- package/dist/features/orders/schemas/index.d.ts +8 -8
- package/dist/features/orders/types/index.d.ts +2 -2
- package/dist/features/payments/repository/payments.repository.js +2 -2
- package/dist/features/payments/repository/payout.repository.d.ts +23 -6
- package/dist/features/payments/repository/payout.repository.js +63 -23
- package/dist/features/payments/repository/saved-payment-methods.repository.d.ts +17 -6
- package/dist/features/payments/repository/saved-payment-methods.repository.js +59 -11
- package/dist/features/payments/schemas/firestore.d.ts +14 -3
- package/dist/features/payments/schemas/saved-methods-firestore.d.ts +12 -1
- package/dist/features/pre-orders/api/[slug]/route.js +1 -1
- package/dist/features/pre-orders/api/admin/route.js +1 -1
- package/dist/features/pre-orders/api/route.js +1 -1
- package/dist/features/pre-orders/repository/pre-orders.repository.d.ts +3 -3
- package/dist/features/pre-orders/repository/pre-orders.repository.js +6 -6
- package/dist/features/products/api/[id]/route.js +1 -1
- package/dist/features/products/components/ListingBottomActions.js +4 -0
- package/dist/features/products/components/ProductDetailPageView.js +2 -1
- package/dist/features/products/components/ProductGalleryClient.js +2 -2
- package/dist/features/products/components/ProductGrid.js +12 -1
- package/dist/features/products/components/index.d.ts +0 -2
- package/dist/features/products/components/index.js +0 -1
- package/dist/features/products/config/listing-type-listing-config.d.ts +0 -3
- package/dist/features/products/config/listing-type-listing-config.js +27 -2
- package/dist/features/products/constants/listing-tabs.d.ts +9 -0
- package/dist/features/products/constants/listing-tabs.js +3 -2
- package/dist/features/products/hooks/useProducts.js +2 -2
- package/dist/features/products/repository/products.repository.js +13 -1
- package/dist/features/products/schemas/index.d.ts +2 -2
- package/dist/features/products/types/index.d.ts +1 -1
- package/dist/features/promotions/api/route.js +1 -1
- package/dist/features/reviews/actions/review-actions.d.ts +6 -6
- package/dist/features/reviews/actions/review-actions.js +22 -8
- package/dist/features/reviews/components/ReviewDetailPageView.js +13 -1
- package/dist/features/reviews/components/ReviewsIndexPageView.js +21 -4
- package/dist/features/reviews/repository/reviews.repository.d.ts +19 -7
- package/dist/features/reviews/repository/reviews.repository.js +63 -12
- package/dist/features/reviews/schemas/firestore.d.ts +13 -2
- package/dist/features/reviews/schemas/index.d.ts +2 -2
- package/dist/features/scams/actions/scam-actions.js +16 -4
- package/dist/features/search/components/SearchResultsPageView.js +2 -1
- package/dist/features/search/hooks/useSearchIndex.d.ts +34 -0
- package/dist/features/search/hooks/useSearchIndex.js +172 -0
- package/dist/features/search/repository/search.repository.js +2 -2
- package/dist/features/seller/actions/offer-actions.d.ts +5 -5
- package/dist/features/seller/actions/offer-actions.js +38 -8
- package/dist/features/seller/actions/seller-actions.js +34 -7
- package/dist/features/seller/api/coupons/route.js +1 -1
- package/dist/features/seller/api/products/route.js +1 -1
- package/dist/features/seller/api/store/route.js +1 -1
- package/dist/features/seller/components/SellerBidsView.js +1 -1
- package/dist/features/seller/components/SellerCouponsView.js +1 -1
- package/dist/features/seller/components/SellerListingTypeView.js +9 -1
- package/dist/features/seller/components/SellerOrdersView.js +1 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +0 -1
- package/dist/features/seller/components/SellerPayoutsView.js +1 -1
- package/dist/features/seller/components/SellerProductShell.js +0 -1
- package/dist/features/seller/components/SellerProductsView.js +1 -1
- package/dist/features/seller/components/SellerShippingView.js +0 -1
- package/dist/features/seller/components/SellerStorefrontView.js +0 -1
- package/dist/features/seller/components/index.d.ts +0 -4
- package/dist/features/seller/components/index.js +0 -2
- package/dist/features/seller/repository/offer.repository.d.ts +15 -3
- package/dist/features/seller/repository/offer.repository.js +43 -7
- package/dist/features/seller/schemas/firestore.d.ts +14 -3
- package/dist/features/seller/schemas/index.d.ts +4 -4
- package/dist/features/seller/schemas/order-forms.d.ts +39 -0
- package/dist/features/seller/schemas/order-forms.js +37 -0
- package/dist/features/shell/FormShell.js +6 -2
- package/dist/features/shell/QuickFormDrawer.js +15 -1
- package/dist/features/shipments/components/AdminShipmentEditorView.js +0 -1
- package/dist/features/shipments/components/AdminShipmentsView.js +1 -1
- package/dist/features/sticker-trace/components/StickerCommitPanel.d.ts +30 -0
- package/dist/features/sticker-trace/components/StickerCommitPanel.js +93 -0
- package/dist/features/sticker-trace/components/StickerPrintPanel.d.ts +33 -0
- package/dist/features/sticker-trace/components/StickerPrintPanel.js +104 -0
- package/dist/features/sticker-trace/components/StickerRetryPanel.d.ts +20 -0
- package/dist/features/sticker-trace/components/StickerRetryPanel.js +128 -0
- package/dist/features/sticker-trace/components/StickerRunHistoryPanel.d.ts +45 -0
- package/dist/features/sticker-trace/components/StickerRunHistoryPanel.js +84 -0
- package/dist/features/sticker-trace/components/StickerTraceStudio.d.ts +27 -0
- package/dist/features/sticker-trace/components/StickerTraceStudio.js +171 -0
- package/dist/features/sticker-trace/constants/help-content.d.ts +23 -0
- package/dist/features/sticker-trace/constants/help-content.js +172 -0
- package/dist/features/sticker-trace/hooks/useLiveTrace.d.ts +27 -0
- package/dist/features/sticker-trace/hooks/useLiveTrace.js +160 -0
- package/dist/features/sticker-trace/hooks/useStickerTraceProgress.d.ts +22 -0
- package/dist/features/sticker-trace/hooks/useStickerTraceProgress.js +106 -0
- package/dist/features/sticker-trace/repository/sticker-sheets.repository.d.ts +113 -0
- package/dist/features/sticker-trace/repository/sticker-sheets.repository.js +146 -0
- package/dist/features/sticker-trace/repository/sticker-trace-runs.repository.d.ts +132 -0
- package/dist/features/sticker-trace/repository/sticker-trace-runs.repository.js +174 -0
- package/dist/features/sticker-trace/schemas/firestore.d.ts +248 -0
- package/dist/features/sticker-trace/schemas/firestore.js +79 -0
- package/dist/features/sticker-trace/server.d.ts +8 -0
- package/dist/features/sticker-trace/server.js +51 -0
- package/dist/features/stores/actions/store-query-actions.d.ts +2 -2
- package/dist/features/stores/actions/store-query-actions.js +7 -2
- package/dist/features/stores/api/[storeSlug]/auctions/route.js +3 -3
- package/dist/features/stores/api/[storeSlug]/products/route.js +3 -3
- package/dist/features/stores/api/[storeSlug]/reviews/route.js +1 -1
- package/dist/features/stores/api/[storeSlug]/route.js +1 -1
- package/dist/features/stores/components/StoreNavTabs.js +17 -2
- package/dist/features/stores/manifest.js +8 -4
- package/dist/features/support/repository/support.repository.d.ts +14 -3
- package/dist/features/support/repository/support.repository.js +93 -13
- package/dist/features/support/schemas/firestore.d.ts +16 -5
- package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.js +61 -19
- package/dist/features/tester/seed-data/authored/buying__browsing-search.js +19 -3
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +243 -0
- package/dist/features/tester/seed-data/authored/content-discovery__events.js +36 -10
- package/dist/features/tester/seed-data/authored/content-discovery__overflowing-pill-rows.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__overflowing-pill-rows.js +209 -0
- package/dist/features/tester/seed-data/authored/design-ux__header-brand-mark-centring.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__header-brand-mark-centring.js +90 -0
- package/dist/features/tester/seed-data/authored/index.js +8 -0
- package/dist/features/tester/seed-data/authored/selling__media-limits.js +19 -17
- package/dist/features/tester/seed-data/authored/selling__product-upload-details.js +10 -5
- package/dist/features/tester/seed-data/authored/tools__sticker-tracer.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-tracer.js +283 -0
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +192 -22
- package/dist/index.d.ts +10 -23
- package/dist/index.js +27 -19
- package/dist/next/api/routeHandler.js +9 -0
- package/dist/next/routing/require-record.d.ts +13 -0
- package/dist/next/routing/require-record.js +62 -0
- package/dist/next/routing/route-map.d.ts +4 -4
- package/dist/next/routing/route-map.js +25 -3
- package/dist/providers/db-firebase/base.d.ts +4 -2
- package/dist/providers/db-firebase/base.js +21 -5
- package/dist/providers/db-firebase/base.repository.d.ts +11 -9
- package/dist/providers/db-firebase/base.repository.js +19 -0
- package/dist/providers/db-firebase/rtdb-paths.d.ts +12 -0
- package/dist/providers/db-firebase/rtdb-paths.js +12 -0
- package/dist/react/ErrorBoundary.js +6 -1
- package/dist/react/hooks/realtime-event-constants.d.ts +1 -0
- package/dist/react/hooks/realtime-event-constants.js +8 -0
- package/dist/react/hooks/useEntityDelete.js +5 -1
- package/dist/react/hooks/useMessage.js +5 -1
- package/dist/repositories/index.d.ts +2 -2
- package/dist/repositories/index.js +6 -1
- package/dist/schemas/registry.d.ts +13 -20
- package/dist/schemas/registry.js +31 -14
- package/dist/schemas/webhooks/google-oauth.d.ts +2 -2
- package/dist/security/encrypted.d.ts +117 -0
- package/dist/security/encrypted.js +100 -0
- package/dist/security/index.d.ts +5 -2
- package/dist/security/index.js +16 -2
- package/dist/security/pii-accessors.d.ts +71 -0
- package/dist/security/pii-accessors.js +150 -0
- package/dist/security/pii-encrypt.d.ts +0 -8
- package/dist/security/pii-encrypt.js +22 -15
- package/dist/security/pii-mask.d.ts +18 -0
- package/dist/security/pii-mask.js +27 -0
- package/dist/seed/_helpers/search-txt-wrappers.d.ts +6 -6
- package/dist/seed/_helpers/search-txt-wrappers.js +22 -0
- package/dist/seed/addresses-seed-data.d.ts +2 -2
- package/dist/seed/authenticity-knowledge-seed-data.d.ts +34 -0
- package/dist/seed/authenticity-knowledge-seed-data.js +1277 -0
- package/dist/seed/bids-seed-data.d.ts +2 -2
- package/dist/seed/bids-seed-data.js +23 -2
- package/dist/seed/events-seed-data.d.ts +2 -2
- package/dist/seed/events-seed-data.js +5 -0
- package/dist/seed/faq-seed-data.js +175 -5
- package/dist/seed/homepage-sections-seed-data.js +39 -23
- package/dist/seed/index.d.ts +1 -0
- package/dist/seed/index.js +1 -0
- package/dist/seed/lottery-entries-seed-data.d.ts +2 -2
- package/dist/seed/offers-seed-data.d.ts +2 -2
- package/dist/seed/offers-seed-data.js +1 -1
- package/dist/seed/orders-seed-data.d.ts +2 -2
- package/dist/seed/payouts-seed-data.d.ts +2 -2
- package/dist/seed/payouts-seed-data.js +1 -1
- package/dist/seed/reviews-seed-data.d.ts +1 -2
- package/dist/seed/seed-purpose.js +7 -0
- package/dist/seed/sessions-seed-data.d.ts +2 -2
- package/dist/seed/sessions-seed-data.js +5 -0
- package/dist/seed/site-settings-seed-data.js +1 -1
- package/dist/seed/support-tickets-seed-data.d.ts +2 -2
- package/dist/seed/support-tickets-seed-data.js +1 -1
- package/dist/seed/users-seed-data.d.ts +2 -2
- package/dist/seed/users-seed-data.js +1 -1
- package/dist/seo/json-ld.js +5 -1
- package/dist/server.d.ts +18 -3
- package/dist/server.js +59 -3
- package/dist/styles.css +237 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Button.js +7 -1
- package/dist/ui/components/FilterChipGroup.d.ts +11 -0
- package/dist/ui/components/FilterChipGroup.js +1 -1
- package/dist/ui/components/ImageGallery.js +6 -1
- package/dist/ui/components/ListingLayout.js +14 -8
- package/dist/ui/components/OverflowRow.d.ts +92 -0
- package/dist/ui/components/OverflowRow.js +203 -0
- package/dist/ui/components/OverflowRow.style.css +235 -0
- package/dist/ui/components/RecordDetailModal.js +14 -1
- package/dist/ui/components/RowActionMenu.js +5 -1
- package/dist/ui/components/SideDrawer.js +5 -1
- package/dist/ui/components/SideModal.js +9 -1
- package/dist/ui/components/TabBarShell.d.ts +12 -1
- package/dist/ui/components/TabBarShell.js +3 -2
- package/dist/ui/components/Tabs.js +36 -24
- package/dist/ui/components/Toast.d.ts +3 -24
- package/dist/ui/components/Toast.js +2 -19
- package/dist/ui/components/TopBannerPortal.d.ts +15 -0
- package/dist/ui/components/TopBannerPortal.js +19 -0
- package/dist/ui/components/UnsavedChangesModal.js +5 -1
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/components/row-collapse.d.ts +15 -0
- package/dist/ui/components/row-collapse.js +127 -0
- package/dist/ui/components/toast-context.d.ts +63 -0
- package/dist/ui/components/toast-context.js +48 -0
- package/dist/ui/components/top-banner-slot.d.ts +37 -0
- package/dist/ui/components/top-banner-slot.js +45 -0
- package/dist/ui/icons/icon-registry.d.ts +6 -0
- package/dist/ui/icons/icon-registry.js +17 -1
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1 -0
- package/dist/utils/array.helper.d.ts +2 -2
- package/dist/utils/array.helper.js +5 -5
- package/dist/utils/id-generators.d.ts +6 -0
- package/dist/utils/id-generators.js +10 -0
- package/dist/utils/media-url.js +0 -2
- package/dist/utils/search-txt-builders.d.ts +28 -4
- package/dist/utils/search-txt-builders.js +41 -1
- package/dist/validation/schemas.d.ts +8 -8
- package/package.json +6 -2
- package/scripts/seed-cli.mjs +3 -0
- package/dist/features/account/components/UserAddressesView.d.ts +0 -13
- package/dist/features/account/components/UserAddressesView.js +0 -5
- package/dist/features/account/components/UserNotificationsView.d.ts +0 -15
- package/dist/features/account/components/UserNotificationsView.js +0 -12
- package/dist/features/account/components/UserSettingsView.d.ts +0 -16
- package/dist/features/account/components/UserSettingsView.js +0 -13
- package/dist/features/account/components/UserSupportView.d.ts +0 -3
- package/dist/features/account/components/UserSupportView.js +0 -166
- package/dist/features/admin/components/DemoSeedView.d.ts +0 -11
- package/dist/features/admin/components/DemoSeedView.js +0 -5
- package/dist/features/auth/components/AuthStatusPanel.d.ts +0 -10
- package/dist/features/auth/components/AuthStatusPanel.js +0 -22
- package/dist/features/categories/components/CategoryProductsView.d.ts +0 -45
- package/dist/features/categories/components/CategoryProductsView.js +0 -21
- package/dist/features/homepage/components/HowItWorksInfoView.d.ts +0 -36
- package/dist/features/homepage/components/HowItWorksInfoView.js +0 -10
- package/dist/features/layout/BottomActions.d.ts +0 -1
- package/dist/features/layout/BottomActions.js +0 -311
- package/dist/features/products/components/ProductsView.d.ts +0 -6
- package/dist/features/products/components/ProductsView.js +0 -5
- package/dist/features/seller/components/SellerStoreView.d.ts +0 -8
- package/dist/features/seller/components/SellerStoreView.js +0 -8
|
@@ -29,6 +29,10 @@ export function ListingBottomActions({ listingType, anchorId, price, currency, u
|
|
|
29
29
|
})),
|
|
30
30
|
infoLabel,
|
|
31
31
|
desktop: "after-scroll",
|
|
32
|
+
// The element the CTA scrolls to IS this page's inline buy panel, so
|
|
33
|
+
// it doubles as the dock's reveal gate — no extra prop at any of the
|
|
34
|
+
// five listing types that share this registrar.
|
|
35
|
+
ctaAnchorId: anchorId,
|
|
32
36
|
});
|
|
33
37
|
return null;
|
|
34
38
|
}
|
|
@@ -24,6 +24,7 @@ const CLS_BUNDLE_ROW = "flex items-center justify-between gap-[var(--appkit-spac
|
|
|
24
24
|
const CLS_BUNDLE_LABEL = "text-[length:var(--appkit-text-xs)] text-success dark:text-success font-medium uppercase tracking-wide mb-0.5";
|
|
25
25
|
const CLS_BUNDLE_CTA = "flex-shrink-0 rounded-lg bg-success-solid hover:brightness-110 px-[var(--appkit-space-3)] py-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-xs)] font-semibold text-success-on-solid transition-colors";
|
|
26
26
|
import { ROUTES } from "../../../next/routing/route-map.js";
|
|
27
|
+
import { ctaAnchorProps } from "../../layout/cta-anchor.js";
|
|
27
28
|
import { ContextualTrail } from "../../categories/components/ContextualTrail.js";
|
|
28
29
|
import { productCrumbs, withTrailHead } from "../../categories/utils/breadcrumb-chain.js";
|
|
29
30
|
import { getDefaultCurrency } from "../../../core/baseline-resolver.js";
|
|
@@ -319,7 +320,7 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
|
|
|
319
320
|
categoryProductCount: (n, cat) => `${n} in ${cat}`,
|
|
320
321
|
} }), productFeatures && features.length > 0 && (_jsx(FeatureBadgeList, { productFeatureIds: features, features: productFeatures })), !productFeatures && features.length > 0 && (_jsxs(Div, { border: "subtle", surface: "muted", padding: "inline", rounded: "xl", children: [_jsx(Text, { className: "mb-2 tracking-wide", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "About this product" }), _jsx(Ul, { spacing: "comfortable", size: "sm", color: "primary", children: features.map((f, i) => (_jsxs(Li, { layout: "flex-start", gap: "2", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-primary-500", children: "\u2022" }), f] }, i))) })] })), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-[length:var(--appkit-text-sm)] leading-relaxed text-[var(--appkit-color-text-muted)] line-clamp-4" })), safeSeller && (_jsx(Div, { className: `${__P.p3}`, border: "subtle", rounded: "xl", surface: "muted", children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] tracking-wide mb-0.5", color: "faint", transform: "uppercase", children: "Sold by" }), _jsx(Text, { size: "sm", weight: "semibold", color: "primary", children: safeSeller }), typeof p.storeRating === "number" && p.storeRating > 0 && (_jsx(Row, { gap: "xs", align: "center", className: "mt-0.5", children: _jsxs(Text, { size: "xs", color: "muted", children: [_jsx(Span, { className: "text-warning", "aria-hidden": "true", children: "\u2605" }), " ", p.storeRating.toFixed(1), typeof p.storeReviewCount === "number" &&
|
|
321
322
|
p.storeReviewCount > 0 &&
|
|
322
|
-
` · ${p.storeReviewCount} reviews`] }) }))] }), _jsxs(Row, { gap: "xs", align: "center", className: "shrink-0", children: [storeId && _jsx(MessageSellerButton, { storeId: storeId }), storeHref && (_jsx(Link, { href: storeHref, className: "rounded-lg bg-primary/10 dark:bg-primary/20 px-[var(--appkit-space-3)] py-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-xs)] font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] })] }) }))] })), renderActions: () => (_jsxs(Stack, { className: `${__P.p5}`, border: "subtle", gap: "md", rounded: "xl", surface: "muted", children: [price !== null && (_jsxs(Div, { children: [_jsx(PriceDisplay, { amount: price, originalAmount: originalPrice ?? undefined, currency: currency, variant: "detail" }), _jsx(MarketPriceAnchor, { band: priceBand?.byListingType?.[normalizeListingType(p)] ?? null, windowDays: priceBand?.windowDays ?? null, currency: currency, price: price }), inStock && effectiveStock !== null && effectiveStock <= 3 && (_jsxs(Text, { className: "mt-1 text-warning", size: "xs", children: ["Only ", effectiveStock, " left \u2014 order soon!"] })), inStock && effectiveStock !== null && effectiveStock > 3 && effectiveStock <= 10 && (_jsxs(Text, { className: "mt-1", color: "muted", size: "xs", children: [effectiveStock, " in stock"] }))] })), _jsxs(Stack, { gap: "sm", children: [renderPrimaryActions ? (renderPrimaryActions({
|
|
323
|
+
` · ${p.storeReviewCount} reviews`] }) }))] }), _jsxs(Row, { gap: "xs", align: "center", className: "shrink-0", children: [storeId && _jsx(MessageSellerButton, { storeId: storeId, productId: product.id }), storeHref && (_jsx(Link, { href: storeHref, className: "rounded-lg bg-primary/10 dark:bg-primary/20 px-[var(--appkit-space-3)] py-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-xs)] font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] })] }) }))] })), renderActions: () => (_jsxs(Stack, { className: `${__P.p5}`, border: "subtle", gap: "md", rounded: "xl", surface: "muted", children: [price !== null && (_jsxs(Div, { children: [_jsx(PriceDisplay, { amount: price, originalAmount: originalPrice ?? undefined, currency: currency, variant: "detail" }), _jsx(MarketPriceAnchor, { band: priceBand?.byListingType?.[normalizeListingType(p)] ?? null, windowDays: priceBand?.windowDays ?? null, currency: currency, price: price }), inStock && effectiveStock !== null && effectiveStock <= 3 && (_jsxs(Text, { className: "mt-1 text-warning", size: "xs", children: ["Only ", effectiveStock, " left \u2014 order soon!"] })), inStock && effectiveStock !== null && effectiveStock > 3 && effectiveStock <= 10 && (_jsxs(Text, { className: "mt-1", color: "muted", size: "xs", children: [effectiveStock, " in stock"] }))] })), _jsxs(Stack, { gap: "sm", ...ctaAnchorProps(), children: [renderPrimaryActions ? (renderPrimaryActions({
|
|
323
324
|
productId: product.id,
|
|
324
325
|
productSlug: product.slug ?? slug,
|
|
325
326
|
productTitle: product.title,
|
|
@@ -31,7 +31,7 @@ export function ProductGalleryClient({ images, video, productName }) {
|
|
|
31
31
|
return (_jsx(Div, { className: `${__O.hidden}`, border: "subtle", rounded: "xl", surface: "muted", children: _jsx(Row, { className: "aspect-square text-[var(--appkit-color-border)] dark:text-[var(--appkit-color-border-subtle)]", align: "center", justify: "center", children: _jsx(PlaceholderSvg, {}) }) }));
|
|
32
32
|
}
|
|
33
33
|
const activeSlide = slides[activeIndex] ?? slides[0];
|
|
34
|
-
return (_jsxs(Stack, { gap: "3", children: [_jsxs(Div, { rounded: "xl", className: "overflow-hidden border border-[var(--appkit-color-border-subtle)] cursor-zoom-in aspect-square w-full relative", onClick: () => setLightboxIndex(activeIndex), role: "button", tabIndex: 0, onKeyDown: (e) => {
|
|
34
|
+
return (_jsxs(Stack, { gap: "3", children: [_jsxs(Div, { rounded: "xl", surface: "muted", className: "overflow-hidden border border-[var(--appkit-color-border-subtle)] cursor-zoom-in aspect-square w-full relative", onClick: () => setLightboxIndex(activeIndex), role: "button", tabIndex: 0, onKeyDown: (e) => {
|
|
35
35
|
if (e.key === "Enter" || e.key === " ")
|
|
36
36
|
setLightboxIndex(activeIndex);
|
|
37
37
|
}, "aria-label": activeSlide.kind === "video"
|
|
@@ -42,7 +42,7 @@ export function ProductGalleryClient({ images, video, productName }) {
|
|
|
42
42
|
: "Product video"
|
|
43
43
|
: productName
|
|
44
44
|
? `${productName} — image ${activeIndex + 1}`
|
|
45
|
-
: `Product image ${activeIndex + 1}`, size: "gallery", className: "transition-transform duration-300 hover:scale-105" }), activeSlide.kind === "video" && (_jsx(Row, { className: "absolute inset-0 pointer-events-none", align: "center", justify: "center", children: _jsx(Row, { surface: "overlay-sm", rounded: "full", className: "h-16 w-16 text-white", align: "center", justify: "center", children: _jsx(Play, { className: "h-7 w-7 fill-current", "aria-hidden": "true" }) }) }))] }), slides.length > 1 && (_jsx(Div, { layout: "flex", gap: "2", className: `${__O.xAuto}`, padding: "b-2xs", children: slides.map((slide, i) => (_jsxs(Button, { variant: "ghost", type: "button", onClick: () => setActiveIndex(i), rounded: "lg", paddingX: "none", paddingY: "none", className: `relative flex-shrink-0 h-16 w-16 overflow-hidden border-2 transition-all${i === activeIndex
|
|
45
|
+
: `Product image ${activeIndex + 1}`, size: "gallery", objectFit: "contain", className: "transition-transform duration-300 hover:scale-105" }), activeSlide.kind === "video" && (_jsx(Row, { className: "absolute inset-0 pointer-events-none", align: "center", justify: "center", children: _jsx(Row, { surface: "overlay-sm", rounded: "full", className: "h-16 w-16 text-white", align: "center", justify: "center", children: _jsx(Play, { className: "h-7 w-7 fill-current", "aria-hidden": "true" }) }) }))] }), slides.length > 1 && (_jsx(Div, { layout: "flex", gap: "2", className: `${__O.xAuto}`, padding: "b-2xs", children: slides.map((slide, i) => (_jsxs(Button, { variant: "ghost", type: "button", onClick: () => setActiveIndex(i), rounded: "lg", paddingX: "none", paddingY: "none", className: `relative flex-shrink-0 h-16 w-16 overflow-hidden border-2 transition-all${i === activeIndex
|
|
46
46
|
? " border-primary-500"
|
|
47
47
|
: " border-transparent opacity-60 hover:opacity-100"}`, "aria-label": slide.kind === "video" ? "View video" : `View image ${i + 1}`, "aria-current": i === activeIndex ? "true" : undefined, children: [_jsx(MediaImage, { src: slide.kind === "video" ? slide.poster : slide.src, alt: slide.kind === "video" ? "Video thumbnail" : `Thumbnail ${i + 1}`, size: "thumbnail" }), slide.kind === "video" && (_jsx(Row, { surface: "overlay-xs", className: "absolute inset-0 pointer-events-none", align: "center", justify: "center", children: _jsx(Play, { className: "h-5 w-5 text-white fill-current", "aria-hidden": "true" }) }))] }, i))) })), slides.length > 1 && (
|
|
48
48
|
// audit-content-alignment-ok: functional image-counter label under the gallery, not page content
|
|
@@ -165,7 +165,18 @@ function safeHref(href) {
|
|
|
165
165
|
if (!href)
|
|
166
166
|
return undefined;
|
|
167
167
|
// drop any href that would navigate to a literal "/undefined" segment
|
|
168
|
-
|
|
168
|
+
/*
|
|
169
|
+
* A SEGMENT that is literally "undefined"/"null" means an interpolation
|
|
170
|
+
* produced one — `/products/${maybeUndefined}`.
|
|
171
|
+
*
|
|
172
|
+
* Tested with a regex rather than `.includes("/undefined")`, which kills two
|
|
173
|
+
* birds: a regex literal is not a string Literal node, so the route-literal
|
|
174
|
+
* rule has nothing to flag and the eslint-disable that used to sit here is
|
|
175
|
+
* gone; and `.includes` matched any slug CONTAINING the word, so a real
|
|
176
|
+
* listing at `/products/undefined-sequence-bey` was silently dropped from
|
|
177
|
+
* the grid. The anchors make it a whole-segment test.
|
|
178
|
+
*/
|
|
179
|
+
if (/\/(?:undefined|null)(?:\/|$)/.test(href))
|
|
169
180
|
return undefined;
|
|
170
181
|
return href;
|
|
171
182
|
}
|
|
@@ -32,8 +32,6 @@ export { FeatureBadge, FeatureBadgeList } from "./FeatureBadge";
|
|
|
32
32
|
export type { FeatureBadgeProps, FeatureBadgeListProps, } from "./FeatureBadge";
|
|
33
33
|
export { ProductFeaturesProvider, useProductFeatures, } from "./ProductFeaturesContext";
|
|
34
34
|
export type { ProductFeaturesProviderProps } from "./ProductFeaturesContext";
|
|
35
|
-
export { ProductsView } from "./ProductsView";
|
|
36
|
-
export type { ProductsViewProps } from "./ProductsView";
|
|
37
35
|
export { ProductDetailView } from "./ProductDetailView";
|
|
38
36
|
export type { ProductDetailViewProps } from "./ProductDetailView";
|
|
39
37
|
export { AuctionDetailView } from "./AuctionDetailView";
|
|
@@ -21,7 +21,6 @@ export { ProductFeaturesSelector } from "./ProductFeaturesSelector.js";
|
|
|
21
21
|
export { ProductFeatureBadges } from "./ProductFeatureBadges.js";
|
|
22
22
|
export { FeatureBadge, FeatureBadgeList } from "./FeatureBadge.js";
|
|
23
23
|
export { ProductFeaturesProvider, useProductFeatures, } from "./ProductFeaturesContext.js";
|
|
24
|
-
export { ProductsView } from "./ProductsView.js";
|
|
25
24
|
export { ProductDetailView } from "./ProductDetailView.js";
|
|
26
25
|
export { AuctionDetailView } from "./AuctionDetailView.js";
|
|
27
26
|
export { PreOrderDetailView } from "./PreOrderDetailView.js";
|
|
@@ -11,11 +11,8 @@ export interface ListingTypeListingRow {
|
|
|
11
11
|
image?: string;
|
|
12
12
|
}
|
|
13
13
|
interface ListingTypeListingResponse {
|
|
14
|
-
/** Admin route shape. */
|
|
15
14
|
items?: JsonArray;
|
|
16
15
|
total?: number;
|
|
17
|
-
/** Seller route shape. */
|
|
18
|
-
products?: JsonArray;
|
|
19
16
|
meta?: {
|
|
20
17
|
total?: number;
|
|
21
18
|
};
|
|
@@ -55,8 +55,15 @@ export function buildListingTypeListingConfig(type, opts = {}) {
|
|
|
55
55
|
endpoint: isSeller ? SELLER_ENDPOINTS.PRODUCTS : ADMIN_ENDPOINTS.PRODUCTS,
|
|
56
56
|
// The type's own sort set, not a copy-pasted three-option array.
|
|
57
57
|
sortOptions: [...plugin.sortOptions],
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
mapRows: (response) =>
|
|
59
|
+
/*
|
|
60
|
+
* `items` only. The `?? response.products` fallback is gone because both
|
|
61
|
+
* endpoints this config reads (`/api/admin/products`, `/api/store/products`)
|
|
62
|
+
* now emit the canonical key — verified before removing it. A defence
|
|
63
|
+
* against a shape that no longer exists reads as though the shape still
|
|
64
|
+
* might, which is how two spellings stay alive forever.
|
|
65
|
+
*/
|
|
66
|
+
toRecordArray(response.items).map((item, index) => ({
|
|
60
67
|
id: toStringValue(item.id, `${type}-${index}`),
|
|
61
68
|
primary: toStringValue(item.title ?? item.productTitle, "Untitled listing"),
|
|
62
69
|
secondary: [
|
|
@@ -82,5 +89,23 @@ export function buildListingTypeListingConfig(type, opts = {}) {
|
|
|
82
89
|
// These are products filtered by listingType — reuse the real product
|
|
83
90
|
// editor rather than leaving rows non-navigable.
|
|
84
91
|
rowHrefTemplate: String(isSeller ? ROUTES.STORE.PRODUCTS_EDIT("{id}") : ROUTES.ADMIN.PRODUCTS_EDIT("{id}")),
|
|
92
|
+
/*
|
|
93
|
+
* Create, with THIS type preselected.
|
|
94
|
+
*
|
|
95
|
+
* All five pages this factory backs (art, classified, digital-codes, live,
|
|
96
|
+
* stickers) had no create control of any kind. `?listingType=` is read by
|
|
97
|
+
* the create page and passed to the editor as `initialListingType`, so an
|
|
98
|
+
* admin landing from the Art list starts on an art listing rather than on
|
|
99
|
+
* `standard` — which, on a type-scoped list, would create a row that
|
|
100
|
+
* immediately vanishes from the page it was created on.
|
|
101
|
+
*
|
|
102
|
+
* 🛑 A `primaryAction.href` rather than a `toolbarExtra` node: this is a
|
|
103
|
+
* `.ts` factory and cannot author JSX, which is the structural reason
|
|
104
|
+
* these five screens went without.
|
|
105
|
+
*/
|
|
106
|
+
primaryAction: {
|
|
107
|
+
label: `Add ${plugin.typeLabel}`,
|
|
108
|
+
href: `${String(isSeller ? ROUTES.STORE.PRODUCTS_NEW : ROUTES.ADMIN.PRODUCTS_NEW)}?${PRODUCT_FIELDS.LISTING_TYPE}=${encodeURIComponent(type)}`,
|
|
109
|
+
},
|
|
85
110
|
};
|
|
86
111
|
}
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* relevant array explicitly — those are genuinely different collections.
|
|
21
21
|
*/
|
|
22
22
|
import type { ListingType } from "../types";
|
|
23
|
+
import type { IconKey } from "../../../ui/icons/icon-registry";
|
|
23
24
|
export interface ListingTab {
|
|
24
25
|
id: string;
|
|
25
26
|
label: string;
|
|
@@ -31,6 +32,14 @@ export interface ListingTab {
|
|
|
31
32
|
collection?: "bundles";
|
|
32
33
|
/** Set when the tab queries a non-product entity (e.g. `stores`). */
|
|
33
34
|
entity?: "stores";
|
|
35
|
+
/**
|
|
36
|
+
* Leading glyph, carried from `ListingTypePlugin.iconKey`.
|
|
37
|
+
*
|
|
38
|
+
* Only set on tabs backed by ONE listing type. The combined Art & Stickers
|
|
39
|
+
* tab leaves it unset on purpose: it spans two types with two different
|
|
40
|
+
* glyphs, and picking either would claim the tab is only that one.
|
|
41
|
+
*/
|
|
42
|
+
iconName?: IconKey;
|
|
34
43
|
}
|
|
35
44
|
/**
|
|
36
45
|
* The types the generic `/products` browse page spans — the GENERAL CATALOGUE,
|
|
@@ -58,7 +58,8 @@ export const ART_STICKERS_LISTING_TYPES = ["art", "stickers"];
|
|
|
58
58
|
* straight into `sieveFilter("listingType", EQ, id)`. Never a display label.
|
|
59
59
|
*/
|
|
60
60
|
function chipTab(type) {
|
|
61
|
-
|
|
61
|
+
const plugin = pluginFor(type);
|
|
62
|
+
return { id: type, label: plugin.chipLabel, listingType: type, iconName: plugin.iconKey };
|
|
62
63
|
}
|
|
63
64
|
/**
|
|
64
65
|
* A ROUTE-BACKED tab — `id` is the plugin's `tabSlug`, because it doubles as
|
|
@@ -67,7 +68,7 @@ function chipTab(type) {
|
|
|
67
68
|
*/
|
|
68
69
|
function pluralTab(type) {
|
|
69
70
|
const plugin = pluginFor(type);
|
|
70
|
-
return { id: plugin.tabSlug, label: plugin.pluralLabel, listingType: type };
|
|
71
|
+
return { id: plugin.tabSlug, label: plugin.pluralLabel, listingType: type, iconName: plugin.iconKey };
|
|
71
72
|
}
|
|
72
73
|
/**
|
|
73
74
|
* Art and stickers share the combined `/art` browse page, so category/brand/
|
|
@@ -57,8 +57,8 @@ export function useProducts(params = {}, opts) {
|
|
|
57
57
|
sp.set(LISTING_PARAM_NAMES.sorts.long, params.sort);
|
|
58
58
|
if (params.page)
|
|
59
59
|
sp.set("page", String(params.page));
|
|
60
|
-
if (params.
|
|
61
|
-
sp.set("pageSize", String(params.
|
|
60
|
+
if (params.pageSize)
|
|
61
|
+
sp.set("pageSize", String(params.pageSize));
|
|
62
62
|
if (params.featured !== undefined)
|
|
63
63
|
sp.set("featured", String(params.featured));
|
|
64
64
|
if (params.minBid !== undefined)
|
|
@@ -6,7 +6,14 @@ import { increment, serverTimestamp } from "../../../contracts/field-ops.js";
|
|
|
6
6
|
// classified branch to a generic 500 — Root Cause #53.
|
|
7
7
|
import { DatabaseError } from "../../../errors/index.js";
|
|
8
8
|
import { BaseRepository, prepareForFirestore, parseSieveDateValue, } from "../../../providers/db-firebase/index.js";
|
|
9
|
-
|
|
9
|
+
/*
|
|
10
|
+
* The DEFINING module, not the `core` barrel — Root Cause #18. `core/index.ts`
|
|
11
|
+
* re-exports `unitOfWork`, which imports this very repository, so reaching
|
|
12
|
+
* `cacheManager` through the barrel closed a six-module import cycle
|
|
13
|
+
* (`audit-import-cycles` component 2). `CacheManager.ts` imports nothing from
|
|
14
|
+
* here, so the deep path has one direction only.
|
|
15
|
+
*/
|
|
16
|
+
import { cacheManager } from "../../../core/CacheManager.js";
|
|
10
17
|
import { serverLogger } from "../../../monitoring/index.js";
|
|
11
18
|
import { generateUniqueId, slugify, generateBarcodeId } from "../../../utils/index.js";
|
|
12
19
|
import { parseSearchTxtQuery } from "../../../utils/search-txt.js";
|
|
@@ -1198,6 +1205,11 @@ export class ProductRepository extends BaseRepository {
|
|
|
1198
1205
|
baseQuery = baseQuery.where(PRODUCT_FIELDS.STORE_ID, "==", opts.storeId);
|
|
1199
1206
|
}
|
|
1200
1207
|
// Longest term first — only ONE may become the array-contains clause.
|
|
1208
|
+
// audit-listing-search-ok: builder, not an entry point. The empty guard is
|
|
1209
|
+
// `if (plan.empty) return emptySearchResult()` in `list()` (~line 1783),
|
|
1210
|
+
// which is one of only two callers of this private method; the other,
|
|
1211
|
+
// `countByListingTypes`, declares no `search` in its opts type and so
|
|
1212
|
+
// structurally cannot pass one.
|
|
1201
1213
|
const searchTxt = parseSearchTxtQuery(opts?.search ?? "");
|
|
1202
1214
|
if (searchTxt.length > 0) {
|
|
1203
1215
|
// Firestore permits a single array operator per query, so when a search
|
|
@@ -623,7 +623,6 @@ export declare const productListParamsSchema: z.ZodObject<{
|
|
|
623
623
|
status?: "published" | "draft" | "in_review" | "archived" | undefined;
|
|
624
624
|
page?: number | undefined;
|
|
625
625
|
q?: string | undefined;
|
|
626
|
-
perPage?: number | undefined;
|
|
627
626
|
listingType?: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live" | undefined;
|
|
628
627
|
category?: string | undefined;
|
|
629
628
|
storeId?: string | undefined;
|
|
@@ -632,12 +631,12 @@ export declare const productListParamsSchema: z.ZodObject<{
|
|
|
632
631
|
minPrice?: number | undefined;
|
|
633
632
|
maxPrice?: number | undefined;
|
|
634
633
|
inStock?: boolean | undefined;
|
|
634
|
+
perPage?: number | undefined;
|
|
635
635
|
}, {
|
|
636
636
|
sort?: string | undefined;
|
|
637
637
|
status?: "published" | "draft" | "in_review" | "archived" | undefined;
|
|
638
638
|
page?: number | undefined;
|
|
639
639
|
q?: string | undefined;
|
|
640
|
-
perPage?: number | undefined;
|
|
641
640
|
listingType?: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live" | undefined;
|
|
642
641
|
category?: string | undefined;
|
|
643
642
|
storeId?: string | undefined;
|
|
@@ -646,4 +645,5 @@ export declare const productListParamsSchema: z.ZodObject<{
|
|
|
646
645
|
minPrice?: number | undefined;
|
|
647
646
|
maxPrice?: number | undefined;
|
|
648
647
|
inStock?: boolean | undefined;
|
|
648
|
+
perPage?: number | undefined;
|
|
649
649
|
}>;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Auth and rate-limit stay in consumer server-action wrappers.
|
|
6
6
|
*/
|
|
7
7
|
import type { FirebaseSieveResult } from "../../../providers/db-firebase";
|
|
8
|
-
import type { ReviewDocument } from "../schemas";
|
|
8
|
+
import type { ReviewPlain, ReviewDocument } from "../schemas";
|
|
9
9
|
export interface CreateReviewActionInput {
|
|
10
10
|
productId: string;
|
|
11
11
|
rating: number;
|
|
@@ -22,7 +22,7 @@ export interface UpdateReviewActionInput {
|
|
|
22
22
|
images?: string[];
|
|
23
23
|
videoUrl?: string | null;
|
|
24
24
|
}
|
|
25
|
-
export declare function createReview(userId: string, input: CreateReviewActionInput): Promise<
|
|
25
|
+
export declare function createReview(userId: string, input: CreateReviewActionInput): Promise<ReviewPlain>;
|
|
26
26
|
export declare function updateReview(userId: string, reviewId: string, input: UpdateReviewActionInput): Promise<ReviewDocument | null>;
|
|
27
27
|
export declare function deleteReview(userId: string, reviewId: string): Promise<void>;
|
|
28
28
|
export declare function adminUpdateReview(adminId: string, reviewId: string, input: UpdateReviewActionInput): Promise<ReviewDocument | null>;
|
|
@@ -35,13 +35,13 @@ export declare function voteReviewHelpful(reviewId: string, helpful: boolean, us
|
|
|
35
35
|
counted: boolean;
|
|
36
36
|
helpfulCount: number;
|
|
37
37
|
}>;
|
|
38
|
-
export declare function listReviewsByProduct(productId: string, page?: number, pageSize?: number): Promise<FirebaseSieveResult<
|
|
38
|
+
export declare function listReviewsByProduct(productId: string, page?: number, pageSize?: number): Promise<FirebaseSieveResult<ReviewPlain>>;
|
|
39
39
|
export declare function listAdminReviews(params?: {
|
|
40
40
|
filters?: string;
|
|
41
41
|
sorts?: string;
|
|
42
42
|
page?: number;
|
|
43
43
|
pageSize?: number;
|
|
44
|
-
}): Promise<FirebaseSieveResult<
|
|
45
|
-
export declare function listReviewsBySeller(sellerId: string): Promise<
|
|
46
|
-
export declare function getHomepageReviews(): Promise<
|
|
44
|
+
}): Promise<FirebaseSieveResult<ReviewPlain>>;
|
|
45
|
+
export declare function listReviewsBySeller(sellerId: string): Promise<ReviewPlain[]>;
|
|
46
|
+
export declare function getHomepageReviews(): Promise<ReviewPlain[]>;
|
|
47
47
|
export declare function getReviewById(id: string): Promise<ReviewDocument | null>;
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
import { sortBy } from "@mohasinac/appkit";
|
|
8
8
|
import { AuthorizationError, NotFoundError, ValidationError, } from "../../../errors/index.js";
|
|
9
9
|
import { serverLogger } from "../../../monitoring/index.js";
|
|
10
|
-
import { maskPublicReview } from "../../../security/index.js";
|
|
11
10
|
import { finalizeStagedMediaArray, finalizeStagedMediaUrl, } from "../../media/finalize.js";
|
|
12
11
|
import { reviewRepository } from "../repository/reviews.repository.js";
|
|
13
12
|
import { safeRead } from "../../../errors/safe-read.js";
|
|
@@ -29,7 +28,7 @@ export async function createReview(userId, input) {
|
|
|
29
28
|
uid: userId,
|
|
30
29
|
productId: input.productId,
|
|
31
30
|
});
|
|
32
|
-
return reviewRepository.
|
|
31
|
+
return reviewRepository.createReview({
|
|
33
32
|
productId: input.productId,
|
|
34
33
|
productTitle: product.title,
|
|
35
34
|
listingType: product.listingType,
|
|
@@ -162,10 +161,14 @@ export async function listReviewsByProduct(productId, page = 1, pageSize = 10) {
|
|
|
162
161
|
page,
|
|
163
162
|
pageSize,
|
|
164
163
|
});
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
164
|
+
/*
|
|
165
|
+
* No second mask. `reviewRepository.listAll` returns `ReviewPlain` already
|
|
166
|
+
* masked by `maskSieveResult`, so `maskPublicReview` here would mask an
|
|
167
|
+
* already-masked name — and worse, it was being handed ciphertext before
|
|
168
|
+
* that method was converted, where `maskName`'s `hasEncPrefix` guard answers
|
|
169
|
+
* "Anonymous" for every row.
|
|
170
|
+
*/
|
|
171
|
+
return result;
|
|
169
172
|
}
|
|
170
173
|
export async function listAdminReviews(params) {
|
|
171
174
|
const sieve = {
|
|
@@ -199,11 +202,22 @@ export async function listReviewsBySeller(sellerId) {
|
|
|
199
202
|
return reviewBatches
|
|
200
203
|
.flat()
|
|
201
204
|
.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
|
|
202
|
-
|
|
205
|
+
/*
|
|
206
|
+
* `maskedReview`, not `maskPublicReview`.
|
|
207
|
+
*
|
|
208
|
+
* These come from `findApprovedByStore`, a `find*` method that returns raw
|
|
209
|
+
* documents — only the three `list*` methods mask. `maskPublicReview`
|
|
210
|
+
* calls `maskName`, which refuses ciphertext by design and answers
|
|
211
|
+
* "Anonymous", so this public list showed every reviewer as Anonymous.
|
|
212
|
+
* `maskedReview` decrypts first, then masks.
|
|
213
|
+
*/
|
|
214
|
+
.map((item) => reviewRepository.maskedReview(item));
|
|
203
215
|
}
|
|
204
216
|
export async function getHomepageReviews() {
|
|
205
217
|
const reviews = await reviewRepository.findFeatured(18);
|
|
206
|
-
|
|
218
|
+
// `findFeatured` returns raw documents — see the note above on why
|
|
219
|
+
// `maskPublicReview` cannot be used on them.
|
|
220
|
+
return reviews.map((item) => reviewRepository.maskedReview(item));
|
|
207
221
|
}
|
|
208
222
|
export async function getReviewById(id) {
|
|
209
223
|
return reviewRepository.findById(id);
|
|
@@ -11,7 +11,19 @@ export async function ReviewDetailPageView({ id }) {
|
|
|
11
11
|
// become the same `null` a removed review produces, which the "Review not
|
|
12
12
|
// found" branch below already handles.
|
|
13
13
|
const doc = await reviewRepository.findById(id);
|
|
14
|
-
|
|
14
|
+
/*
|
|
15
|
+
* 🛑 MASKED, not the raw document.
|
|
16
|
+
*
|
|
17
|
+
* `findById` returns ciphertext since `mapDoc` stopped decrypting, and
|
|
18
|
+
* `ReviewDetailShell` calls `maskName(review.userName)` — which refuses
|
|
19
|
+
* ciphertext by design and answers "Anonymous". So this page rendered every
|
|
20
|
+
* reviewer as "Anonymous". `maskedReview` decrypts and then masks, which is
|
|
21
|
+
* what the shell was always assuming it had been handed.
|
|
22
|
+
*
|
|
23
|
+
* The `as Review` cast is what hid it: it erased the brand, so nothing in
|
|
24
|
+
* the type system could object.
|
|
25
|
+
*/
|
|
26
|
+
const review = (doc ? reviewRepository.maskedReview(doc) : null);
|
|
15
27
|
// storeId === storeSlug for stores in this project (pure slug IDs)
|
|
16
28
|
const storeSlug = doc?.storeId ?? null;
|
|
17
29
|
if (!review || review.status !== "approved") {
|
|
@@ -31,20 +31,37 @@ function buildReviewFilters(params) {
|
|
|
31
31
|
parts.push(sieveFilter("createdAt", SIEVE_OP.GTE, dateFrom));
|
|
32
32
|
if (dateTo)
|
|
33
33
|
parts.push(sieveFilter("createdAt", SIEVE_OP.LTE, dateTo));
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
/*
|
|
35
|
+
* 🛑 `q` is deliberately NOT a filter clause, and emitting it as one was a
|
|
36
|
+
* live defect rather than an untidy spelling.
|
|
37
|
+
*
|
|
38
|
+
* `productTitle@=*` is a case-insensitive operator the Firebase adapter
|
|
39
|
+
* THROWS on, and the Sieve processor runs `throwExceptions: false` — so the
|
|
40
|
+
* throw became silence and **every clause and the sort were discarded with
|
|
41
|
+
* it**. `/reviews?q=anything` therefore returned the whole table, newest-ish,
|
|
42
|
+
* ignoring rating, verified, date range and vote filters too.
|
|
43
|
+
*
|
|
44
|
+
* `/api/reviews` fixed exactly this and passes `q` to `listAll` as a
|
|
45
|
+
* `{ search }` OPT (array-contains over `searchTxt`, which Sieve cannot
|
|
46
|
+
* express). This SSR view queries the same collection and never got the
|
|
47
|
+
* back-port — Root Cause #99, which says in as many words: when fixing a
|
|
48
|
+
* filter in an API route, grep for the SSR view that queries the same
|
|
49
|
+
* collection. It is also why the view could not self-correct: it hands its
|
|
50
|
+
* result down as `initialData`, and `staleTime: Infinity` freezes an
|
|
51
|
+
* unfiltered first paint for that query key forever (Root Cause #30).
|
|
52
|
+
*/
|
|
37
53
|
return parts.join(",");
|
|
38
54
|
}
|
|
39
55
|
export async function ReviewsIndexPageView({ searchParams = {} }) {
|
|
40
56
|
const sort = sp(searchParams, "sort") || "-createdAt";
|
|
41
57
|
const page = Number(sp(searchParams, "page")) || 1;
|
|
42
58
|
const filters = buildReviewFilters(searchParams);
|
|
59
|
+
const q = sp(searchParams, "q");
|
|
43
60
|
// audit-public-test-data-ok: `ReviewDocument` carries no `isTestData` field —
|
|
44
61
|
// tsc rejects the filter outright, which is the honest signal that reviews
|
|
45
62
|
// have no sandbox concept to strip. A review OF a sandbox product is not
|
|
46
63
|
// flagged today; that is a seed-schema gap, not something a cast should hide.
|
|
47
|
-
const result = await safeRead(() => reviewRepository.listAll({ filters, sorts: sort, page, pageSize: 12 }), { route: "/reviews", key: "reviews.listAll", fallback: null });
|
|
64
|
+
const result = await safeRead(() => reviewRepository.listAll({ filters, sorts: sort, page, pageSize: 12 }, q ? { search: q } : undefined), { route: "/reviews", key: "reviews.listAll", fallback: null });
|
|
48
65
|
const initialData = result
|
|
49
66
|
? {
|
|
50
67
|
items: result.items,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { JsonValue } from "../../../schemas/types";
|
|
2
2
|
import type { FirebaseSieveResult, SieveModel } from "../../../providers/db-firebase";
|
|
3
3
|
import { BaseRepository, parseSieveDateValue } from "../../../providers/db-firebase";
|
|
4
|
-
import { type ReviewCreateInput, type ReviewDocument } from "../schemas";
|
|
4
|
+
import { type ReviewCreateInput, type ReviewDocument, type ReviewPlain } from "../schemas";
|
|
5
5
|
import type { ReviewStatus } from "../types";
|
|
6
6
|
export interface ReviewRatingAggregate {
|
|
7
7
|
count: number;
|
|
@@ -9,7 +9,7 @@ export interface ReviewRatingAggregate {
|
|
|
9
9
|
}
|
|
10
10
|
declare class ReviewRepository extends BaseRepository<ReviewDocument> {
|
|
11
11
|
constructor();
|
|
12
|
-
private
|
|
12
|
+
private maskSieveResult;
|
|
13
13
|
/**
|
|
14
14
|
* Declared, not hand-rolled.
|
|
15
15
|
*
|
|
@@ -24,8 +24,20 @@ declare class ReviewRepository extends BaseRepository<ReviewDocument> {
|
|
|
24
24
|
protected piiFields: readonly ["userName"];
|
|
25
25
|
protected piiIndexMap: Record<string, string>;
|
|
26
26
|
protected mapDoc<D = ReviewDocument>(snap: import("../../../providers/db-firebase").DocumentSnapshot): D;
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
/** Plaintext PII. **Opt-in and named** — shows up in review and in a grep. */
|
|
28
|
+
revealReview(doc: ReviewDocument): ReviewPlain;
|
|
29
|
+
/** As `revealReview`, for a list read. */
|
|
30
|
+
revealReviews(docs: readonly ReviewDocument[]): ReviewPlain[];
|
|
31
|
+
/**
|
|
32
|
+
* Masked PII — **the default for any public surface.** Decrypts first, then
|
|
33
|
+
* masks: `maskName` returns "Anonymous" for a ciphertext input by design, so
|
|
34
|
+
* handing it a stored `userName` would anonymise every reviewer.
|
|
35
|
+
*/
|
|
36
|
+
maskedReview(doc: ReviewDocument): ReviewPlain;
|
|
37
|
+
/** As `maskedReview`, for a list read. */
|
|
38
|
+
maskedReviews(docs: readonly ReviewDocument[]): ReviewPlain[];
|
|
39
|
+
createReview(input: ReviewCreateInput): Promise<ReviewPlain>;
|
|
40
|
+
update(reviewId: string, data: Partial<ReviewPlain>): Promise<ReviewDocument>;
|
|
29
41
|
findByProduct(productId: string): Promise<ReviewDocument[]>;
|
|
30
42
|
/**
|
|
31
43
|
* Approved reviews for a product, newest first.
|
|
@@ -196,8 +208,8 @@ declare class ReviewRepository extends BaseRepository<ReviewDocument> {
|
|
|
196
208
|
parseValue: typeof parseSieveDateValue;
|
|
197
209
|
};
|
|
198
210
|
};
|
|
199
|
-
listForProduct(productId: string, model: SieveModel): Promise<FirebaseSieveResult<
|
|
200
|
-
listForStore(storeId: string, model: SieveModel): Promise<FirebaseSieveResult<
|
|
211
|
+
listForProduct(productId: string, model: SieveModel): Promise<FirebaseSieveResult<ReviewPlain>>;
|
|
212
|
+
listForStore(storeId: string, model: SieveModel): Promise<FirebaseSieveResult<ReviewPlain>>;
|
|
201
213
|
/**
|
|
202
214
|
* Derived on every write path via `applyWriteHooks`.
|
|
203
215
|
*
|
|
@@ -207,7 +219,7 @@ declare class ReviewRepository extends BaseRepository<ReviewDocument> {
|
|
|
207
219
|
protected buildSearchTxtFor(data: Record<string, JsonValue>): string[] | null;
|
|
208
220
|
listAll(model: SieveModel, opts?: {
|
|
209
221
|
search?: string;
|
|
210
|
-
}): Promise<FirebaseSieveResult<
|
|
222
|
+
}): Promise<FirebaseSieveResult<ReviewPlain>>;
|
|
211
223
|
}
|
|
212
224
|
declare const reviewRepository: ReviewRepository;
|
|
213
225
|
export { ReviewRepository, reviewRepository };
|