@mohasinac/appkit 3.2.20 → 3.3.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.
Files changed (190) hide show
  1. package/dist/_internal/server/features/checkout/actions.d.ts +2 -0
  2. package/dist/_internal/server/features/checkout/actions.js +239 -190
  3. package/dist/_internal/server/functions/scheduled.d.ts +2 -1
  4. package/dist/_internal/server/functions/scheduled.js +9 -1
  5. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +8 -11
  6. package/dist/_internal/server/jobs/core/emiInstallmentReminder.d.ts +8 -0
  7. package/dist/_internal/server/jobs/core/emiInstallmentReminder.js +78 -0
  8. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.d.ts +2 -2
  9. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +15 -10
  10. package/dist/_internal/server/jobs/handlers/emiInstallmentReminder.d.ts +2 -0
  11. package/dist/_internal/server/jobs/handlers/emiInstallmentReminder.js +2 -0
  12. package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
  13. package/dist/_internal/server/jobs/handlers/index.js +2 -0
  14. package/dist/_internal/server/providers/index.d.ts +4 -4
  15. package/dist/_internal/server/providers/index.js +4 -4
  16. package/dist/_internal/server/providers/payment/razorpay-mock.d.ts +3 -2
  17. package/dist/_internal/server/providers/payment/razorpay-mock.js +3 -1
  18. package/dist/_internal/server/providers/resolve.d.ts +10 -13
  19. package/dist/_internal/server/providers/resolve.js +9 -15
  20. package/dist/_internal/shared/actions/action-registry.js +28 -0
  21. package/dist/_internal/shared/checkout/rules/_defaults.js +1 -0
  22. package/dist/_internal/shared/checkout/rules/_registry.js +4 -0
  23. package/dist/_internal/shared/checkout/rules/art.rule.d.ts +9 -0
  24. package/dist/_internal/shared/checkout/rules/art.rule.js +5 -0
  25. package/dist/_internal/shared/checkout/rules/auction.rule.js +1 -0
  26. package/dist/_internal/shared/checkout/rules/classified.rule.js +1 -0
  27. package/dist/_internal/shared/checkout/rules/index.d.ts +2 -0
  28. package/dist/_internal/shared/checkout/rules/index.js +2 -0
  29. package/dist/_internal/shared/checkout/rules/stickers.rule.d.ts +9 -0
  30. package/dist/_internal/shared/checkout/rules/stickers.rule.js +5 -0
  31. package/dist/_internal/shared/checkout/rules/types.d.ts +6 -0
  32. package/dist/_internal/shared/features/checkout/config.d.ts +16 -1
  33. package/dist/_internal/shared/features/checkout/config.js +16 -1
  34. package/dist/_internal/shared/features/emi/schedule.d.ts +63 -0
  35. package/dist/_internal/shared/features/emi/schedule.js +62 -0
  36. package/dist/_internal/shared/fees/calculator.d.ts +53 -0
  37. package/dist/_internal/shared/fees/calculator.js +40 -0
  38. package/dist/_internal/shared/listing-types/_registry.d.ts +22 -66
  39. package/dist/_internal/shared/listing-types/_registry.js +19 -2
  40. package/dist/_internal/shared/listing-types/art/config.d.ts +15 -0
  41. package/dist/_internal/shared/listing-types/art/config.js +14 -0
  42. package/dist/_internal/shared/listing-types/art/ctas.d.ts +1 -0
  43. package/dist/_internal/shared/listing-types/art/ctas.js +3 -0
  44. package/dist/_internal/shared/listing-types/art/og.d.ts +1 -0
  45. package/dist/_internal/shared/listing-types/art/og.js +1 -0
  46. package/dist/_internal/shared/listing-types/art/schema.d.ts +2 -0
  47. package/dist/_internal/shared/listing-types/art/schema.js +3 -0
  48. package/dist/_internal/shared/listing-types/art/seed-factory.d.ts +1 -0
  49. package/dist/_internal/shared/listing-types/art/seed-factory.js +1 -0
  50. package/dist/_internal/shared/listing-types/auction/config.d.ts +8 -0
  51. package/dist/_internal/shared/listing-types/auction/config.js +6 -0
  52. package/dist/_internal/shared/listing-types/capabilities.js +17 -0
  53. package/dist/_internal/shared/listing-types/classified/config.d.ts +8 -0
  54. package/dist/_internal/shared/listing-types/classified/config.js +6 -0
  55. package/dist/_internal/shared/listing-types/digital-code/config.d.ts +8 -0
  56. package/dist/_internal/shared/listing-types/digital-code/config.js +6 -0
  57. package/dist/_internal/shared/listing-types/live/config.d.ts +8 -0
  58. package/dist/_internal/shared/listing-types/live/config.js +6 -0
  59. package/dist/_internal/shared/listing-types/pre-order/config.d.ts +8 -0
  60. package/dist/_internal/shared/listing-types/pre-order/config.js +6 -0
  61. package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +8 -0
  62. package/dist/_internal/shared/listing-types/prize-draw/config.js +6 -0
  63. package/dist/_internal/shared/listing-types/standard/config.d.ts +8 -0
  64. package/dist/_internal/shared/listing-types/standard/config.js +6 -0
  65. package/dist/_internal/shared/listing-types/stickers/config.d.ts +15 -0
  66. package/dist/_internal/shared/listing-types/stickers/config.js +14 -0
  67. package/dist/_internal/shared/listing-types/stickers/ctas.d.ts +1 -0
  68. package/dist/_internal/shared/listing-types/stickers/ctas.js +3 -0
  69. package/dist/_internal/shared/listing-types/stickers/og.d.ts +1 -0
  70. package/dist/_internal/shared/listing-types/stickers/og.js +1 -0
  71. package/dist/_internal/shared/listing-types/stickers/schema.d.ts +2 -0
  72. package/dist/_internal/shared/listing-types/stickers/schema.js +3 -0
  73. package/dist/_internal/shared/listing-types/stickers/seed-factory.d.ts +1 -0
  74. package/dist/_internal/shared/listing-types/stickers/seed-factory.js +1 -0
  75. package/dist/client.d.ts +7 -2
  76. package/dist/client.js +4 -2
  77. package/dist/constants/field-names.d.ts +2 -6
  78. package/dist/constants/field-names.js +2 -6
  79. package/dist/contracts/index.d.ts +4 -2
  80. package/dist/contracts/index.js +6 -0
  81. package/dist/contracts/payment.d.ts +14 -9
  82. package/dist/contracts/payment.js +11 -1
  83. package/dist/contracts/shipping.d.ts +14 -9
  84. package/dist/contracts/shipping.js +11 -1
  85. package/dist/features/about/components/PublicProfileView.js +3 -6
  86. package/dist/features/admin/components/AdminAddressBookView.d.ts +11 -0
  87. package/dist/features/admin/components/AdminAddressBookView.js +30 -0
  88. package/dist/features/admin/components/AdminArtView.d.ts +3 -0
  89. package/dist/features/admin/components/AdminArtView.js +45 -0
  90. package/dist/features/admin/components/AdminSiteConfigGuideView.js +1 -1
  91. package/dist/features/admin/components/AdminSiteSettingsView.js +14 -9
  92. package/dist/features/admin/components/AdminStickersView.d.ts +3 -0
  93. package/dist/features/admin/components/AdminStickersView.js +45 -0
  94. package/dist/features/admin/components/index.d.ts +6 -0
  95. package/dist/features/admin/components/index.js +4 -0
  96. package/dist/features/admin/schemas/firestore.d.ts +19 -11
  97. package/dist/features/admin/schemas/firestore.js +12 -2
  98. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +3 -2
  99. package/dist/features/auth/hooks/useAuth.js +35 -9
  100. package/dist/features/auth/schemas/firestore.d.ts +2 -6
  101. package/dist/features/cart/schemas/firestore.d.ts +3 -2
  102. package/dist/features/consultation/schemas/index.d.ts +2 -2
  103. package/dist/features/loyalty/schemas/index.d.ts +6 -6
  104. package/dist/features/orders/repository/orders.repository.d.ts +20 -2
  105. package/dist/features/orders/repository/orders.repository.js +34 -5
  106. package/dist/features/orders/schemas/firestore.d.ts +33 -7
  107. package/dist/features/orders/schemas/firestore.js +1 -1
  108. package/dist/features/orders/schemas/index.d.ts +176 -31
  109. package/dist/features/orders/schemas/index.js +20 -6
  110. package/dist/features/orders/types/index.d.ts +3 -3
  111. package/dist/features/payments/repository/payout.repository.js +2 -2
  112. package/dist/features/payments/schemas/firestore.d.ts +3 -3
  113. package/dist/features/payments/schemas/firestore.js +2 -2
  114. package/dist/features/payments/schemas/index.d.ts +5 -5
  115. package/dist/features/payments/schemas/index.js +2 -2
  116. package/dist/features/products/api/[id]/route.js +4 -1
  117. package/dist/features/products/api/route.js +4 -1
  118. package/dist/features/products/components/CompareOverlay.js +7 -9
  119. package/dist/features/products/components/ProductDetailPageView.d.ts +3 -1
  120. package/dist/features/products/components/ProductDetailPageView.js +2 -2
  121. package/dist/features/products/components/ProductForm.js +18 -7
  122. package/dist/features/products/components/ProductGrid.js +7 -12
  123. package/dist/features/products/components/ShowGroupSection.js +3 -5
  124. package/dist/features/products/components/SublistingCarouselSection.js +3 -6
  125. package/dist/features/products/constants/listing-tabs.d.ts +32 -0
  126. package/dist/features/products/constants/listing-tabs.js +8 -0
  127. package/dist/features/products/index.d.ts +1 -1
  128. package/dist/features/products/index.js +3 -1
  129. package/dist/features/products/schemas/firestore.d.ts +20 -1
  130. package/dist/features/products/schemas/firestore.js +2 -0
  131. package/dist/features/products/schemas/index.d.ts +48 -0
  132. package/dist/features/products/schemas/index.js +9 -0
  133. package/dist/features/products/schemas/product-features.d.ts +1 -1
  134. package/dist/features/products/types/index.d.ts +5 -3
  135. package/dist/features/products/utils/listing-type.d.ts +6 -0
  136. package/dist/features/products/utils/listing-type.js +3 -0
  137. package/dist/features/reviews/api/[id]/route.js +5 -4
  138. package/dist/features/seller/actions/seller-actions.d.ts +29 -14
  139. package/dist/features/seller/actions/seller-actions.js +101 -27
  140. package/dist/features/seller/components/SellerArtView.d.ts +7 -0
  141. package/dist/features/seller/components/SellerArtView.js +114 -0
  142. package/dist/features/seller/components/SellerOrdersView.js +38 -1
  143. package/dist/features/seller/components/SellerProductShell.d.ts +5 -1
  144. package/dist/features/seller/components/SellerProductShell.js +69 -59
  145. package/dist/features/seller/components/SellerShippingView.js +6 -25
  146. package/dist/features/seller/components/SellerStickersView.d.ts +7 -0
  147. package/dist/features/seller/components/SellerStickersView.js +114 -0
  148. package/dist/features/seller/components/index.d.ts +4 -0
  149. package/dist/features/seller/components/index.js +2 -0
  150. package/dist/features/seller/messages/en.json +1 -1
  151. package/dist/features/seller/schemas/index.d.ts +7 -7
  152. package/dist/features/seller/schemas/index.js +1 -1
  153. package/dist/features/seller/types/index.d.ts +1 -1
  154. package/dist/features/stores/components/StoreDetailLayoutView.js +18 -2
  155. package/dist/features/stores/schemas/firestore.d.ts +7 -1
  156. package/dist/features/stores/schemas/index.d.ts +19 -16
  157. package/dist/features/stores/schemas/index.js +1 -1
  158. package/dist/index.d.ts +21 -36
  159. package/dist/index.js +27 -39
  160. package/dist/next/routing/route-map.d.ts +22 -0
  161. package/dist/next/routing/route-map.js +10 -0
  162. package/dist/providers/payment-manual/index.d.ts +40 -0
  163. package/dist/providers/payment-manual/index.js +91 -0
  164. package/dist/providers/payment-razorpay/index.d.ts +4 -2
  165. package/dist/providers/payment-razorpay/index.js +4 -1
  166. package/dist/providers/shipping-manual/index.d.ts +22 -0
  167. package/dist/providers/shipping-manual/index.js +47 -0
  168. package/dist/providers.d.ts +2 -2
  169. package/dist/providers.js +5 -3
  170. package/dist/schemas/registry.d.ts +129 -70
  171. package/dist/schemas/registry.js +0 -4
  172. package/dist/security/pii-encrypt.js +0 -7
  173. package/dist/security/pii-redact.js +0 -1
  174. package/dist/seed/conversations-seed-data.js +2 -2
  175. package/dist/seed/faq-seed-data.js +7 -7
  176. package/dist/seed/grouped-listings-seed-data.d.ts +2 -0
  177. package/dist/seed/index.d.ts +2 -0
  178. package/dist/seed/index.js +2 -0
  179. package/dist/seed/manifest.js +20 -16
  180. package/dist/seed/payouts-seed-data.js +5 -5
  181. package/dist/seed/products-art-seed-data.d.ts +11 -0
  182. package/dist/seed/products-art-seed-data.js +125 -0
  183. package/dist/seed/products-preorders-seed-data.d.ts +2 -0
  184. package/dist/seed/products-stickers-seed-data.d.ts +11 -0
  185. package/dist/seed/products-stickers-seed-data.js +125 -0
  186. package/dist/seed/site-settings-seed-data.js +13 -4
  187. package/dist/seed/stores-seed-data.js +11 -11
  188. package/dist/server.d.ts +7 -15
  189. package/dist/server.js +17 -42
  190. package/package.json +1 -1
@@ -0,0 +1,62 @@
1
+ /**
2
+ * EMI (installment) eligibility + schedule computation — pure functions,
3
+ * no I/O. Consumed by checkout (buyer-facing quote + order creation) and by
4
+ * the seller/admin installment-collection UI (schedule display).
5
+ *
6
+ * Eligibility: a per-seller checkout group qualifies for EMI when the
7
+ * site-wide flag, the seller's own opt-in, AND the subtotal threshold are
8
+ * all satisfied — matching the existing COD deposit pattern of gating on
9
+ * `siteSettings.payment.codEnabled`.
10
+ *
11
+ * Schedule: the buyer pays `tokenPercent`% up front (the "token"), then the
12
+ * remaining principal plus a surcharge (the buyer's cost for spreading
13
+ * payment across `tenureMonths`, split between platform and seller per
14
+ * `surchargeSellerSharePercent`) across equal monthly installments, each
15
+ * due on `billingDay` (1–10) of the month, starting the month after
16
+ * purchase. All money amounts are in paise (integer).
17
+ */
18
+ /**
19
+ * `settings.enabled` is the site-wide toggle (`siteSettings.emi.enabled`).
20
+ * `sellerEmiEnabled` is the seller's own opt-in (`StoreDocument.emiEnabled`).
21
+ * Both must be true, in addition to the subtotal threshold.
22
+ */
23
+ export function checkEmiEligibility(sellerSubtotal, sellerEmiEnabled, settings) {
24
+ if (!settings.enabled)
25
+ return { eligible: false, reason: "site_disabled" };
26
+ if (!sellerEmiEnabled)
27
+ return { eligible: false, reason: "seller_disabled" };
28
+ if (sellerSubtotal <= settings.minOrderValueInPaise)
29
+ return { eligible: false, reason: "below_minimum" };
30
+ return { eligible: true };
31
+ }
32
+ /**
33
+ * `purchaseDate` defaults to now; the first installment always falls in the
34
+ * calendar month AFTER purchase, regardless of which day of the current
35
+ * month the purchase happens on.
36
+ */
37
+ export function computeEmiSchedule(sellerSubtotal, tenureMonths, settings, purchaseDate = new Date()) {
38
+ const tokenAmount = Math.round(sellerSubtotal * (settings.tokenPercent / 100));
39
+ const principalRemaining = sellerSubtotal - tokenAmount;
40
+ const surchargeAmount = Math.round(principalRemaining * (settings.surchargePercentPerMonth / 100) * tenureMonths);
41
+ const surchargeSellerShare = Math.round(surchargeAmount * (settings.surchargeSellerSharePercent / 100));
42
+ const surchargePlatformShare = surchargeAmount - surchargeSellerShare;
43
+ const totalToInstall = principalRemaining + surchargeAmount;
44
+ const baseInstallment = Math.floor(totalToInstall / tenureMonths);
45
+ const remainder = totalToInstall - baseInstallment * tenureMonths;
46
+ const billingDay = Math.min(Math.max(settings.billingDay, 1), 10);
47
+ const installments = [];
48
+ for (let i = 1; i <= tenureMonths; i++) {
49
+ const dueDate = new Date(Date.UTC(purchaseDate.getUTCFullYear(), purchaseDate.getUTCMonth() + i, billingDay));
50
+ // Last installment absorbs the rounding remainder so the sum is exact.
51
+ const amount = i === tenureMonths ? baseInstallment + remainder : baseInstallment;
52
+ installments.push({ index: i, dueDate, amount });
53
+ }
54
+ return {
55
+ tokenAmount,
56
+ surchargeAmount,
57
+ surchargeSellerShare,
58
+ surchargePlatformShare,
59
+ installments,
60
+ remainingBalance: totalToInstall,
61
+ };
62
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Shared fee calculator — single source of truth for platform commission,
3
+ * gateway fee, GST, and COD handling fee math. Replaces the ~5 duplicated
4
+ * (and in the payout case, inconsistent) formulas that used to live
5
+ * separately in checkout actions, refund actions, and the two payout
6
+ * eligibility jobs.
7
+ *
8
+ * Two distinct fee shapes:
9
+ * - `computeCheckoutFees` — what the BUYER pays on top of the subtotal
10
+ * (platform fee + GST on that fee). The gateway fee is absorbed by the
11
+ * platform, never passed through to the buyer.
12
+ * - `computePayoutDeduction` — what's deducted from the SELLER's payout
13
+ * (platform fee + gateway fee + GST on the platform fee).
14
+ *
15
+ * All money amounts are in paise (integer).
16
+ */
17
+ export interface FeeCommissionRates {
18
+ platformFeePercent: number;
19
+ gstPercent: number;
20
+ /** Rupee floor (not paise) — matches the existing `minimumTransactionFee` doc convention. */
21
+ minimumTransactionFee?: number;
22
+ gatewayFeePercent?: number;
23
+ }
24
+ export interface CheckoutFees {
25
+ /** Platform commission in paise. */
26
+ platformFee: number;
27
+ /** GST on the platform fee, in paise. */
28
+ gstOnFee: number;
29
+ /** platformFee + gstOnFee, floored at minimumTransactionFee. */
30
+ totalFee: number;
31
+ }
32
+ export declare function computeCheckoutFees(subtotal: number, commissions: FeeCommissionRates): CheckoutFees;
33
+ export interface PayoutDeduction {
34
+ /** Platform commission in paise. */
35
+ platformFee: number;
36
+ /** Payment gateway cost, absorbed by the platform from the seller's share, in paise. */
37
+ gatewayFee: number;
38
+ /** GST on the platform fee, in paise. */
39
+ gstOnFee: number;
40
+ /** platformFee + gatewayFee + gstOnFee. */
41
+ totalDeduction: number;
42
+ /** grossAmount - totalDeduction, floored at 0. */
43
+ netAmount: number;
44
+ }
45
+ export declare function computePayoutDeduction(grossAmount: number, commissions: FeeCommissionRates): PayoutDeduction;
46
+ export interface CodHandlingFeeRates {
47
+ /** Optional so existing `siteSettings` documents saved before this field existed don't produce NaN — falls back to ₹200 (20000 paise). */
48
+ codHandlingFeeMinInPaise?: number;
49
+ /** Optional for the same reason — falls back to 10%. */
50
+ codHandlingFeePercent?: number;
51
+ }
52
+ /** COD handling fee charged to the buyer: max(fixed floor, subtotal × percent). */
53
+ export declare function computeCodHandlingFee(subtotal: number, rates: CodHandlingFeeRates): number;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Shared fee calculator — single source of truth for platform commission,
3
+ * gateway fee, GST, and COD handling fee math. Replaces the ~5 duplicated
4
+ * (and in the payout case, inconsistent) formulas that used to live
5
+ * separately in checkout actions, refund actions, and the two payout
6
+ * eligibility jobs.
7
+ *
8
+ * Two distinct fee shapes:
9
+ * - `computeCheckoutFees` — what the BUYER pays on top of the subtotal
10
+ * (platform fee + GST on that fee). The gateway fee is absorbed by the
11
+ * platform, never passed through to the buyer.
12
+ * - `computePayoutDeduction` — what's deducted from the SELLER's payout
13
+ * (platform fee + gateway fee + GST on the platform fee).
14
+ *
15
+ * All money amounts are in paise (integer).
16
+ */
17
+ export function computeCheckoutFees(subtotal, commissions) {
18
+ const platformFee = Math.round(subtotal * (commissions.platformFeePercent / 100));
19
+ const gstOnFee = Math.round(platformFee * (commissions.gstPercent / 100));
20
+ const minimumTransactionFeeInPaise = Math.round((commissions.minimumTransactionFee ?? 0) * 100);
21
+ const totalFee = Math.max(platformFee + gstOnFee, minimumTransactionFeeInPaise);
22
+ return { platformFee, gstOnFee, totalFee };
23
+ }
24
+ export function computePayoutDeduction(grossAmount, commissions) {
25
+ const platformFee = Math.round(grossAmount * (commissions.platformFeePercent / 100));
26
+ const gatewayFee = Math.round(grossAmount * ((commissions.gatewayFeePercent ?? 0) / 100));
27
+ const gstOnFee = Math.round(platformFee * (commissions.gstPercent / 100));
28
+ const totalDeduction = platformFee + gatewayFee + gstOnFee;
29
+ const netAmount = Math.max(0, grossAmount - totalDeduction);
30
+ return { platformFee, gatewayFee, gstOnFee, totalDeduction, netAmount };
31
+ }
32
+ const DEFAULT_COD_HANDLING_FEE_MIN_IN_PAISE = 20000;
33
+ const DEFAULT_COD_HANDLING_FEE_PERCENT = 10;
34
+ /** COD handling fee charged to the buyer: max(fixed floor, subtotal × percent). */
35
+ export function computeCodHandlingFee(subtotal, rates) {
36
+ const minInPaise = rates.codHandlingFeeMinInPaise ?? DEFAULT_COD_HANDLING_FEE_MIN_IN_PAISE;
37
+ const percent = rates.codHandlingFeePercent ?? DEFAULT_COD_HANDLING_FEE_PERCENT;
38
+ const percentFee = Math.round(subtotal * (percent / 100));
39
+ return Math.max(minInPaise, percentFee);
40
+ }
@@ -14,71 +14,27 @@ export interface ListingTypePlugin {
14
14
  listingType: ListingType;
15
15
  slugPrefix: string;
16
16
  cartLine: "single-product" | "blocked" | "bundle-expand";
17
- }
18
- export declare const LISTING_TYPE_REGISTRY: {
19
- readonly standard: {
20
- listingType: "standard";
21
- slugPrefix: string;
22
- cartLine: "single-product";
23
- };
24
- readonly auction: {
25
- listingType: "auction";
26
- slugPrefix: string;
27
- cartLine: "blocked";
28
- };
29
- readonly "pre-order": {
30
- listingType: "pre-order";
31
- slugPrefix: string;
32
- cartLine: "single-product";
33
- };
34
- readonly "prize-draw": {
35
- listingType: "prize-draw";
36
- slugPrefix: string;
37
- cartLine: "single-product";
38
- };
39
- readonly classified: {
40
- listingType: "classified";
41
- slugPrefix: string;
42
- cartLine: "blocked";
17
+ /** Public detail-page href builder — replaces the ad-hoc per-type href pickers duplicated across card/link components. */
18
+ detailRoute: (idOrSlug: string) => string;
19
+ /** Card-grid badge shown for time-sensitive/action-required types (auction/pre-order); undefined = no badge. */
20
+ badge?: {
21
+ label: string;
22
+ className: string;
43
23
  };
44
- readonly "digital-code": {
45
- listingType: "digital-code";
46
- slugPrefix: string;
47
- cartLine: "single-product";
48
- };
49
- readonly live: {
50
- listingType: "live";
51
- slugPrefix: string;
52
- cartLine: "single-product";
53
- };
54
- };
55
- export declare function pluginFor(type: ListingType): {
56
- listingType: "standard";
57
- slugPrefix: string;
58
- cartLine: "single-product";
59
- } | {
60
- listingType: "auction";
61
- slugPrefix: string;
62
- cartLine: "blocked";
63
- } | {
64
- listingType: "pre-order";
65
- slugPrefix: string;
66
- cartLine: "single-product";
67
- } | {
68
- listingType: "prize-draw";
69
- slugPrefix: string;
70
- cartLine: "single-product";
71
- } | {
72
- listingType: "classified";
73
- slugPrefix: string;
74
- cartLine: "blocked";
75
- } | {
76
- listingType: "digital-code";
77
- slugPrefix: string;
78
- cartLine: "single-product";
79
- } | {
80
- listingType: "live";
81
- slugPrefix: string;
82
- cartLine: "single-product";
83
- };
24
+ /** Seller create/edit form price-field label. */
25
+ priceLabel: string;
26
+ /** Human label for the listing type (breadcrumbs/titles). */
27
+ typeLabel: string;
28
+ /** Whether the seller create/edit form shows a Stock Quantity field. */
29
+ showsStockQuantity: boolean;
30
+ }
31
+ export declare const LISTING_TYPE_REGISTRY: Record<ListingType, ListingTypePlugin>;
32
+ export declare function pluginFor(type: ListingType): ListingTypePlugin;
33
+ /**
34
+ * Infer a listing type from a product slug/id by matching its registered
35
+ * `slugPrefix` — replaces ad-hoc `id.startsWith("auction-")` chains in
36
+ * contexts (guest carts, unauthenticated payloads) that don't carry an
37
+ * explicit `listingType` field. Falls back to "standard" when no prefix matches.
38
+ */
39
+ export declare function detectListingTypeFromSlug(slug: string): ListingType;
84
40
  export { LISTING_TYPE_CAPABILITIES };
@@ -16,9 +16,13 @@ import * as prizeDraw from "./prize-draw/config";
16
16
  import * as classified from "./classified/config";
17
17
  import * as digitalCode from "./digital-code/config";
18
18
  import * as live from "./live/config";
19
+ // EMI/art-stickers session — printed-only physical-goods types.
20
+ import * as art from "./art/config";
21
+ import * as stickers from "./stickers/config";
19
22
  import { LISTING_TYPE_CAPABILITIES } from "./capabilities";
20
23
  // SB-UNI-D — bundle entry removed; bundles are a categoryType, not a listingType.
21
24
  // SB-UNI-F 2026-05-13 — classified / digital-code / live added.
25
+ // EMI/art-stickers session — art / stickers added.
22
26
  export const LISTING_TYPE_REGISTRY = {
23
27
  standard: standard.config,
24
28
  auction: auction.config,
@@ -27,12 +31,25 @@ export const LISTING_TYPE_REGISTRY = {
27
31
  classified: classified.config,
28
32
  "digital-code": digitalCode.config,
29
33
  live: live.config,
34
+ art: art.config,
35
+ stickers: stickers.config,
30
36
  };
31
- // Returns undefined for "bundle" — bundles are CategoryDocument, not in this registry.
32
- // Callers must null-check: `pluginFor(lt) ?? fallbackBehavior`.
33
37
  export function pluginFor(type) {
34
38
  return LISTING_TYPE_REGISTRY[type];
35
39
  }
40
+ /**
41
+ * Infer a listing type from a product slug/id by matching its registered
42
+ * `slugPrefix` — replaces ad-hoc `id.startsWith("auction-")` chains in
43
+ * contexts (guest carts, unauthenticated payloads) that don't carry an
44
+ * explicit `listingType` field. Falls back to "standard" when no prefix matches.
45
+ */
46
+ export function detectListingTypeFromSlug(slug) {
47
+ for (const plugin of Object.values(LISTING_TYPE_REGISTRY)) {
48
+ if (plugin.slugPrefix && slug.startsWith(plugin.slugPrefix))
49
+ return plugin.listingType;
50
+ }
51
+ return "standard";
52
+ }
36
53
  // Re-export the capability map so consumers can pull both surfaces from
37
54
  // the same module path.
38
55
  export { LISTING_TYPE_CAPABILITIES };
@@ -0,0 +1,15 @@
1
+ export declare const LISTING_TYPE: "art";
2
+ export declare const capability: import("../capabilities").ListingTypeCapability;
3
+ export declare const config: {
4
+ listingType: "art";
5
+ slugPrefix: string;
6
+ cartLine: "single-product";
7
+ detailRoute: (idOrSlug: string) => string;
8
+ badge: {
9
+ label: string;
10
+ className: string;
11
+ } | undefined;
12
+ priceLabel: string;
13
+ typeLabel: string;
14
+ showsStockQuantity: boolean;
15
+ };
@@ -0,0 +1,14 @@
1
+ import { LISTING_TYPE_CAPABILITIES } from "../capabilities";
2
+ import { ROUTES } from "../../../../next/routing/route-map";
3
+ export const LISTING_TYPE = "art";
4
+ export const capability = LISTING_TYPE_CAPABILITIES.art;
5
+ export const config = {
6
+ listingType: LISTING_TYPE,
7
+ slugPrefix: "art-",
8
+ cartLine: "single-product",
9
+ detailRoute: (idOrSlug) => String(ROUTES.PUBLIC.PRODUCT_DETAIL(idOrSlug)),
10
+ badge: undefined,
11
+ priceLabel: "Price (₹)",
12
+ typeLabel: "Art Print",
13
+ showsStockQuantity: true,
14
+ };
@@ -0,0 +1 @@
1
+ export declare const ctas: readonly string[];
@@ -0,0 +1,3 @@
1
+ // Art listings reuse the standard "Add to Cart" / "Buy Now" CTAs — no
2
+ // bespoke CTA set needed (mirrors classified/digital-code/live placeholders).
3
+ export const ctas = [];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { ProductDocument } from "../../../../features/products/schemas/firestore";
2
+ export declare function isArtProduct(doc: ProductDocument): boolean;
@@ -0,0 +1,3 @@
1
+ export function isArtProduct(doc) {
2
+ return doc.listingType === "art";
3
+ }
@@ -4,4 +4,12 @@ export declare const config: {
4
4
  listingType: "auction";
5
5
  slugPrefix: string;
6
6
  cartLine: "blocked";
7
+ detailRoute: (idOrSlug: string) => string;
8
+ badge: {
9
+ label: string;
10
+ className: string;
11
+ };
12
+ priceLabel: string;
13
+ typeLabel: string;
14
+ showsStockQuantity: boolean;
7
15
  };
@@ -1,8 +1,14 @@
1
1
  import { LISTING_TYPE_CAPABILITIES } from "../capabilities";
2
+ import { ROUTES } from "../../../../next/routing/route-map";
2
3
  export const LISTING_TYPE = "auction";
3
4
  export const capability = LISTING_TYPE_CAPABILITIES.auction;
4
5
  export const config = {
5
6
  listingType: LISTING_TYPE,
6
7
  slugPrefix: "auction-",
7
8
  cartLine: "blocked",
9
+ detailRoute: (idOrSlug) => String(ROUTES.PUBLIC.AUCTION_DETAIL(idOrSlug)),
10
+ badge: { label: "Auction", className: "bg-warning-surface text-white" },
11
+ priceLabel: "Suggested Retail Price (₹)",
12
+ typeLabel: "Auction",
13
+ showsStockQuantity: false,
8
14
  };
@@ -68,6 +68,23 @@ export const LISTING_TYPE_CAPABILITIES = {
68
68
  requiresJurisdictionCheck: true,
69
69
  hasInstantFulfillment: false,
70
70
  },
71
+ // Art/stickers session — printed-only physical goods, standard-like checkout.
72
+ art: {
73
+ canAddToCart: true,
74
+ canBid: false,
75
+ supportsShipping: true,
76
+ requiresVendorVerified: false,
77
+ requiresJurisdictionCheck: false,
78
+ hasInstantFulfillment: false,
79
+ },
80
+ stickers: {
81
+ canAddToCart: true,
82
+ canBid: false,
83
+ supportsShipping: true,
84
+ requiresVendorVerified: false,
85
+ requiresJurisdictionCheck: false,
86
+ hasInstantFulfillment: false,
87
+ },
71
88
  };
72
89
  export function capabilityFor(type) {
73
90
  return LISTING_TYPE_CAPABILITIES[type];
@@ -4,4 +4,12 @@ export declare const config: {
4
4
  listingType: "classified";
5
5
  slugPrefix: string;
6
6
  cartLine: "blocked";
7
+ detailRoute: (idOrSlug: string) => string;
8
+ badge: {
9
+ label: string;
10
+ className: string;
11
+ } | undefined;
12
+ priceLabel: string;
13
+ typeLabel: string;
14
+ showsStockQuantity: boolean;
7
15
  };
@@ -1,8 +1,14 @@
1
1
  import { LISTING_TYPE_CAPABILITIES } from "../capabilities";
2
+ import { ROUTES } from "../../../../next/routing/route-map";
2
3
  export const LISTING_TYPE = "classified";
3
4
  export const capability = LISTING_TYPE_CAPABILITIES.classified;
4
5
  export const config = {
5
6
  listingType: LISTING_TYPE,
6
7
  slugPrefix: "classified-",
7
8
  cartLine: "blocked",
9
+ detailRoute: (idOrSlug) => String(ROUTES.PUBLIC.PRODUCT_DETAIL(idOrSlug)),
10
+ badge: undefined,
11
+ priceLabel: "Asking Price (₹)",
12
+ typeLabel: "Classified",
13
+ showsStockQuantity: true,
8
14
  };
@@ -4,4 +4,12 @@ export declare const config: {
4
4
  listingType: "digital-code";
5
5
  slugPrefix: string;
6
6
  cartLine: "single-product";
7
+ detailRoute: (idOrSlug: string) => string;
8
+ badge: {
9
+ label: string;
10
+ className: string;
11
+ } | undefined;
12
+ priceLabel: string;
13
+ typeLabel: string;
14
+ showsStockQuantity: boolean;
7
15
  };
@@ -1,8 +1,14 @@
1
1
  import { LISTING_TYPE_CAPABILITIES } from "../capabilities";
2
+ import { ROUTES } from "../../../../next/routing/route-map";
2
3
  export const LISTING_TYPE = "digital-code";
3
4
  export const capability = LISTING_TYPE_CAPABILITIES["digital-code"];
4
5
  export const config = {
5
6
  listingType: LISTING_TYPE,
6
7
  slugPrefix: "digitalcode-",
7
8
  cartLine: "single-product",
9
+ detailRoute: (idOrSlug) => String(ROUTES.PUBLIC.PRODUCT_DETAIL(idOrSlug)),
10
+ badge: undefined,
11
+ priceLabel: "Price per Code (₹)",
12
+ typeLabel: "Digital Code",
13
+ showsStockQuantity: false,
8
14
  };
@@ -4,4 +4,12 @@ export declare const config: {
4
4
  listingType: "live";
5
5
  slugPrefix: string;
6
6
  cartLine: "single-product";
7
+ detailRoute: (idOrSlug: string) => string;
8
+ badge: {
9
+ label: string;
10
+ className: string;
11
+ } | undefined;
12
+ priceLabel: string;
13
+ typeLabel: string;
14
+ showsStockQuantity: boolean;
7
15
  };
@@ -1,8 +1,14 @@
1
1
  import { LISTING_TYPE_CAPABILITIES } from "../capabilities";
2
+ import { ROUTES } from "../../../../next/routing/route-map";
2
3
  export const LISTING_TYPE = "live";
3
4
  export const capability = LISTING_TYPE_CAPABILITIES.live;
4
5
  export const config = {
5
6
  listingType: LISTING_TYPE,
6
7
  slugPrefix: "live-",
7
8
  cartLine: "single-product",
9
+ detailRoute: (idOrSlug) => String(ROUTES.PUBLIC.PRODUCT_DETAIL(idOrSlug)),
10
+ badge: undefined,
11
+ priceLabel: "Price (₹)",
12
+ typeLabel: "Live Item",
13
+ showsStockQuantity: true,
8
14
  };
@@ -4,4 +4,12 @@ export declare const config: {
4
4
  listingType: "pre-order";
5
5
  slugPrefix: string;
6
6
  cartLine: "single-product";
7
+ detailRoute: (idOrSlug: string) => string;
8
+ badge: {
9
+ label: string;
10
+ className: string;
11
+ };
12
+ priceLabel: string;
13
+ typeLabel: string;
14
+ showsStockQuantity: boolean;
7
15
  };
@@ -1,8 +1,14 @@
1
1
  import { LISTING_TYPE_CAPABILITIES } from "../capabilities";
2
+ import { ROUTES } from "../../../../next/routing/route-map";
2
3
  export const LISTING_TYPE = "pre-order";
3
4
  export const capability = LISTING_TYPE_CAPABILITIES["pre-order"];
4
5
  export const config = {
5
6
  listingType: LISTING_TYPE,
6
7
  slugPrefix: "preorder-",
7
8
  cartLine: "single-product",
9
+ detailRoute: (idOrSlug) => String(ROUTES.PUBLIC.PRE_ORDER_DETAIL(idOrSlug)),
10
+ badge: { label: "Pre-Order", className: "bg-info-surface text-white" },
11
+ priceLabel: "Pre-Order Price (₹)",
12
+ typeLabel: "Pre-Order",
13
+ showsStockQuantity: false,
8
14
  };
@@ -4,4 +4,12 @@ export declare const config: {
4
4
  listingType: "prize-draw";
5
5
  slugPrefix: string;
6
6
  cartLine: "single-product";
7
+ detailRoute: (idOrSlug: string) => string;
8
+ badge: {
9
+ label: string;
10
+ className: string;
11
+ } | undefined;
12
+ priceLabel: string;
13
+ typeLabel: string;
14
+ showsStockQuantity: boolean;
7
15
  };
@@ -1,8 +1,14 @@
1
1
  import { LISTING_TYPE_CAPABILITIES } from "../capabilities";
2
+ import { ROUTES } from "../../../../next/routing/route-map";
2
3
  export const LISTING_TYPE = "prize-draw";
3
4
  export const capability = LISTING_TYPE_CAPABILITIES["prize-draw"];
4
5
  export const config = {
5
6
  listingType: LISTING_TYPE,
6
7
  slugPrefix: "prizedraw-",
7
8
  cartLine: "single-product",
9
+ detailRoute: (idOrSlug) => String(ROUTES.PUBLIC.PRODUCT_DETAIL(idOrSlug)),
10
+ badge: undefined,
11
+ priceLabel: "Price (₹)",
12
+ typeLabel: "Prize Draw",
13
+ showsStockQuantity: false,
8
14
  };
@@ -4,4 +4,12 @@ export declare const config: {
4
4
  listingType: "standard";
5
5
  slugPrefix: string;
6
6
  cartLine: "single-product";
7
+ detailRoute: (idOrSlug: string) => string;
8
+ badge: {
9
+ label: string;
10
+ className: string;
11
+ } | undefined;
12
+ priceLabel: string;
13
+ typeLabel: string;
14
+ showsStockQuantity: boolean;
7
15
  };
@@ -1,8 +1,14 @@
1
1
  import { LISTING_TYPE_CAPABILITIES } from "../capabilities";
2
+ import { ROUTES } from "../../../../next/routing/route-map";
2
3
  export const LISTING_TYPE = "standard";
3
4
  export const capability = LISTING_TYPE_CAPABILITIES.standard;
4
5
  export const config = {
5
6
  listingType: LISTING_TYPE,
6
7
  slugPrefix: "product-",
7
8
  cartLine: "single-product",
9
+ detailRoute: (idOrSlug) => String(ROUTES.PUBLIC.PRODUCT_DETAIL(idOrSlug)),
10
+ badge: undefined,
11
+ priceLabel: "Price (₹)",
12
+ typeLabel: "Product",
13
+ showsStockQuantity: true,
8
14
  };
@@ -0,0 +1,15 @@
1
+ export declare const LISTING_TYPE: "stickers";
2
+ export declare const capability: import("../capabilities").ListingTypeCapability;
3
+ export declare const config: {
4
+ listingType: "stickers";
5
+ slugPrefix: string;
6
+ cartLine: "single-product";
7
+ detailRoute: (idOrSlug: string) => string;
8
+ badge: {
9
+ label: string;
10
+ className: string;
11
+ } | undefined;
12
+ priceLabel: string;
13
+ typeLabel: string;
14
+ showsStockQuantity: boolean;
15
+ };
@@ -0,0 +1,14 @@
1
+ import { LISTING_TYPE_CAPABILITIES } from "../capabilities";
2
+ import { ROUTES } from "../../../../next/routing/route-map";
3
+ export const LISTING_TYPE = "stickers";
4
+ export const capability = LISTING_TYPE_CAPABILITIES.stickers;
5
+ export const config = {
6
+ listingType: LISTING_TYPE,
7
+ slugPrefix: "sticker-",
8
+ cartLine: "single-product",
9
+ detailRoute: (idOrSlug) => String(ROUTES.PUBLIC.PRODUCT_DETAIL(idOrSlug)),
10
+ badge: undefined,
11
+ priceLabel: "Price (₹)",
12
+ typeLabel: "Stickers",
13
+ showsStockQuantity: true,
14
+ };
@@ -0,0 +1 @@
1
+ export declare const ctas: readonly string[];
@@ -0,0 +1,3 @@
1
+ // Stickers listings reuse the standard "Add to Cart" / "Buy Now" CTAs — no
2
+ // bespoke CTA set needed (mirrors classified/digital-code/live placeholders).
3
+ export const ctas = [];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { ProductDocument } from "../../../../features/products/schemas/firestore";
2
+ export declare function isStickersProduct(doc: ProductDocument): boolean;
@@ -0,0 +1,3 @@
1
+ export function isStickersProduct(doc) {
2
+ return doc.listingType === "stickers";
3
+ }