@mohasinac/appkit 4.41.0 → 4.41.2

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 (169) hide show
  1. package/dist/features/seller/schemas/coupon-form.d.ts +37 -37
  2. package/dist/features/seller/schemas/coupon-form.js +36 -8
  3. package/dist/features/shell/SectionForm.js +44 -5
  4. package/dist/schemas/registry.d.ts +10 -10
  5. package/package.json +2 -2
  6. package/dist/_internal/server/features/classified/actions.d.ts +0 -12
  7. package/dist/_internal/server/features/classified/actions.js +0 -33
  8. package/dist/_internal/server/features/digital-code/actions.d.ts +0 -12
  9. package/dist/_internal/server/features/digital-code/actions.js +0 -33
  10. package/dist/_internal/server/features/homepage/data.d.ts +0 -18
  11. package/dist/_internal/server/features/homepage/data.js +0 -70
  12. package/dist/_internal/server/features/live/actions.d.ts +0 -6
  13. package/dist/_internal/server/features/live/actions.js +0 -27
  14. package/dist/_internal/server/features/messages/actions.d.ts +0 -6
  15. package/dist/_internal/server/features/messages/actions.js +0 -6
  16. package/dist/_internal/server/features/messages/data.d.ts +0 -10
  17. package/dist/_internal/server/features/messages/data.js +0 -24
  18. package/dist/_internal/server/features/messages/index.d.ts +0 -2
  19. package/dist/_internal/server/features/messages/index.js +0 -2
  20. package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +0 -12
  21. package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +0 -112
  22. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +0 -2
  23. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +0 -2
  24. package/dist/_internal/shared/features/homepage/section-gate.d.ts +0 -14
  25. package/dist/_internal/shared/features/homepage/section-gate.js +0 -51
  26. package/dist/_internal/shared/features/lottery/config-form.d.ts +0 -58
  27. package/dist/_internal/shared/features/lottery/config-form.js +0 -71
  28. package/dist/client/api/useFeatureFlags.d.ts +0 -22
  29. package/dist/client/api/useFeatureFlags.js +0 -27
  30. package/dist/features/account/address-validation.d.ts +0 -20
  31. package/dist/features/account/address-validation.js +0 -35
  32. package/dist/features/account/components/ChatList.d.ts +0 -14
  33. package/dist/features/account/components/ChatList.js +0 -9
  34. package/dist/features/account/components/ChatWindow.d.ts +0 -17
  35. package/dist/features/account/components/ChatWindow.js +0 -6
  36. package/dist/features/account/components/MessagesView.d.ts +0 -16
  37. package/dist/features/account/components/MessagesView.js +0 -5
  38. package/dist/features/account/components/UserOffersView.d.ts +0 -10
  39. package/dist/features/account/components/UserOffersView.js +0 -5
  40. package/dist/features/account/constants/addresses.d.ts +0 -13
  41. package/dist/features/account/constants/addresses.js +0 -43
  42. package/dist/features/account/hooks/useAddressForm.d.ts +0 -24
  43. package/dist/features/account/hooks/useAddressForm.js +0 -58
  44. package/dist/features/admin/actions/chat-actions.d.ts +0 -29
  45. package/dist/features/admin/actions/chat-actions.js +0 -101
  46. package/dist/features/admin/components/AdminFeatureFlagsView.d.ts +0 -9
  47. package/dist/features/admin/components/AdminFeatureFlagsView.js +0 -109
  48. package/dist/features/admin/components/AdminSiteView.d.ts +0 -10
  49. package/dist/features/admin/components/AdminSiteView.js +0 -52
  50. package/dist/features/admin/hooks/useChat.d.ts +0 -24
  51. package/dist/features/admin/hooks/useChat.js +0 -100
  52. package/dist/features/admin/permission-map.d.ts +0 -3
  53. package/dist/features/admin/permission-map.js +0 -26
  54. package/dist/features/admin/repository/chat.repository.d.ts +0 -50
  55. package/dist/features/admin/repository/chat.repository.js +0 -223
  56. package/dist/features/auth/actions/password-change-otp-actions.d.ts +0 -18
  57. package/dist/features/auth/actions/password-change-otp-actions.js +0 -88
  58. package/dist/features/auth/actions/realtime-token-actions.d.ts +0 -11
  59. package/dist/features/auth/actions/realtime-token-actions.js +0 -38
  60. package/dist/features/auth/password-change-otp.d.ts +0 -34
  61. package/dist/features/auth/password-change-otp.js +0 -56
  62. package/dist/features/classified/components/ClassifiedContactSellerPanel.d.ts +0 -12
  63. package/dist/features/classified/components/ClassifiedContactSellerPanel.js +0 -49
  64. package/dist/features/events/api/route.d.ts +0 -12
  65. package/dist/features/events/api/route.js +0 -90
  66. package/dist/features/faq/api/route.d.ts +0 -11
  67. package/dist/features/faq/api/route.js +0 -52
  68. package/dist/features/faq/hooks/useFAQs.d.ts +0 -22
  69. package/dist/features/faq/hooks/useFAQs.js +0 -41
  70. package/dist/features/media/upload/video-poster.test.d.ts +0 -1
  71. package/dist/features/media/upload/video-poster.test.js +0 -42
  72. package/dist/features/messages/actions/index.d.ts +0 -2
  73. package/dist/features/messages/actions/index.js +0 -2
  74. package/dist/features/messages/actions/messages-actions.d.ts +0 -15
  75. package/dist/features/messages/actions/messages-actions.js +0 -33
  76. package/dist/features/messages/actions/ping-rtdb.d.ts +0 -2
  77. package/dist/features/messages/actions/ping-rtdb.js +0 -26
  78. package/dist/features/messages/hooks/useConversation.d.ts +0 -22
  79. package/dist/features/messages/hooks/useConversation.js +0 -155
  80. package/dist/features/messages/hooks/useConversations.d.ts +0 -15
  81. package/dist/features/messages/hooks/useConversations.js +0 -104
  82. package/dist/features/messages/index.d.ts +0 -6
  83. package/dist/features/messages/index.js +0 -4
  84. package/dist/features/messages/realtime.d.ts +0 -32
  85. package/dist/features/messages/realtime.js +0 -39
  86. package/dist/features/messages/repository/conversations.repository.d.ts +0 -71
  87. package/dist/features/messages/repository/conversations.repository.js +0 -284
  88. package/dist/features/messages/schemas/firestore.d.ts +0 -34
  89. package/dist/features/messages/schemas/firestore.js +0 -16
  90. package/dist/features/messages/schemas/index.d.ts +0 -177
  91. package/dist/features/messages/schemas/index.js +0 -35
  92. package/dist/features/messages/server.d.ts +0 -6
  93. package/dist/features/messages/server.js +0 -6
  94. package/dist/features/products/components/MakeOfferForm.d.ts +0 -20
  95. package/dist/features/products/components/MakeOfferForm.js +0 -9
  96. package/dist/features/reviews/api/route.d.ts +0 -21
  97. package/dist/features/reviews/api/route.js +0 -174
  98. package/dist/features/seller/api/offers/route.d.ts +0 -17
  99. package/dist/features/seller/api/offers/route.js +0 -63
  100. package/dist/features/seller/components/SellerAuctionsView.d.ts +0 -9
  101. package/dist/features/seller/components/SellerAuctionsView.js +0 -113
  102. package/dist/features/seller/components/SellerOffersPanel.d.ts +0 -21
  103. package/dist/features/seller/components/SellerOffersPanel.js +0 -160
  104. package/dist/features/seller/components/SellerPreOrdersView.d.ts +0 -6
  105. package/dist/features/seller/components/SellerPreOrdersView.js +0 -148
  106. package/dist/features/seller/components/SellerPrizeDrawsView.d.ts +0 -6
  107. package/dist/features/seller/components/SellerPrizeDrawsView.js +0 -152
  108. package/dist/features/seller/permission-map.d.ts +0 -5
  109. package/dist/features/seller/permission-map.js +0 -17
  110. package/dist/features/shell/StepForm.d.ts +0 -80
  111. package/dist/features/shell/StepForm.js +0 -136
  112. package/dist/features/stores/api/route.d.ts +0 -12
  113. package/dist/features/stores/api/route.js +0 -110
  114. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.d.ts +0 -2
  115. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.js +0 -33
  116. package/dist/features/tester/seed-data/authored/account-auth__testing-program.d.ts +0 -2
  117. package/dist/features/tester/seed-data/authored/account-auth__testing-program.js +0 -138
  118. package/dist/features/tester/seed-data/bids-tester-seed-data.d.ts +0 -2
  119. package/dist/features/tester/seed-data/bids-tester-seed-data.js +0 -37
  120. package/dist/features/tester/seed-data/blog-tester-seed-data.d.ts +0 -2
  121. package/dist/features/tester/seed-data/blog-tester-seed-data.js +0 -40
  122. package/dist/features/tester/seed-data/carts-tester-seed-data.d.ts +0 -3
  123. package/dist/features/tester/seed-data/carts-tester-seed-data.js +0 -70
  124. package/dist/features/tester/seed-data/categories-tester-seed-data.d.ts +0 -2
  125. package/dist/features/tester/seed-data/categories-tester-seed-data.js +0 -218
  126. package/dist/features/tester/seed-data/coupons-tester-seed-data.d.ts +0 -2
  127. package/dist/features/tester/seed-data/coupons-tester-seed-data.js +0 -76
  128. package/dist/features/tester/seed-data/events-tester-seed-data.d.ts +0 -2
  129. package/dist/features/tester/seed-data/events-tester-seed-data.js +0 -193
  130. package/dist/features/tester/seed-data/offers-tester-seed-data.d.ts +0 -2
  131. package/dist/features/tester/seed-data/offers-tester-seed-data.js +0 -191
  132. package/dist/features/tester/seed-data/orders-tester-seed-data.d.ts +0 -2
  133. package/dist/features/tester/seed-data/orders-tester-seed-data.js +0 -329
  134. package/dist/features/tester/seed-data/products-tester-seed-data.d.ts +0 -2
  135. package/dist/features/tester/seed-data/products-tester-seed-data.js +0 -815
  136. package/dist/features/tester/seed-data/stores-tester-seed-data.d.ts +0 -2
  137. package/dist/features/tester/seed-data/stores-tester-seed-data.js +0 -79
  138. package/dist/features/wishlist/components/WishlistToggleButton.d.ts +0 -12
  139. package/dist/features/wishlist/components/WishlistToggleButton.js +0 -36
  140. package/dist/monitoring/analytics.d.ts +0 -80
  141. package/dist/monitoring/analytics.js +0 -176
  142. package/dist/next/middleware/pii-redactor.d.ts +0 -32
  143. package/dist/next/middleware/pii-redactor.js +0 -84
  144. package/dist/providers/db-firebase/realtime.d.ts +0 -42
  145. package/dist/providers/db-firebase/realtime.js +0 -138
  146. package/dist/security/rbac/Can.d.ts +0 -31
  147. package/dist/security/rbac/Can.js +0 -22
  148. package/dist/security/rbac/default-roles.d.ts +0 -2
  149. package/dist/security/rbac/default-roles.js +0 -83
  150. package/dist/security/rbac/hook.d.ts +0 -20
  151. package/dist/security/rbac/hook.js +0 -30
  152. package/dist/security/rbac/index.d.ts +0 -8
  153. package/dist/security/rbac/index.js +0 -6
  154. package/dist/security/rbac/middleware.d.ts +0 -51
  155. package/dist/security/rbac/middleware.js +0 -51
  156. package/dist/security/rbac/resolver.d.ts +0 -5
  157. package/dist/security/rbac/resolver.js +0 -38
  158. package/dist/security/rbac/server.d.ts +0 -24
  159. package/dist/security/rbac/server.js +0 -42
  160. package/dist/security/rbac/types.d.ts +0 -22
  161. package/dist/security/rbac/types.js +0 -2
  162. package/dist/seed/conversations-seed-data.d.ts +0 -2
  163. package/dist/seed/conversations-seed-data.js +0 -292
  164. package/dist/utils/filter.helper.d.ts +0 -18
  165. package/dist/utils/filter.helper.js +0 -21
  166. package/dist/utils/pagination.helper.d.ts +0 -23
  167. package/dist/utils/pagination.helper.js +0 -24
  168. package/dist/utils/search-tokens.d.ts +0 -2
  169. package/dist/utils/search-tokens.js +0 -21
@@ -15,9 +15,9 @@ import { z } from "zod";
15
15
  export declare const couponFormBase: z.ZodObject<{
16
16
  code: z.ZodString;
17
17
  type: z.ZodEnum<["percentage", "fixed", "free_shipping"]>;
18
- value: z.ZodEffects<z.ZodString, string, string>;
18
+ value: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
19
19
  minPurchase: z.ZodEffects<z.ZodString, string, string>;
20
- maxDiscount: z.ZodEffects<z.ZodString, string, string>;
20
+ maxDiscount: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
21
21
  totalLimit: z.ZodEffects<z.ZodString, string, string>;
22
22
  perUserLimit: z.ZodEffects<z.ZodString, string, string>;
23
23
  startDate: z.ZodString;
@@ -26,31 +26,31 @@ export declare const couponFormBase: z.ZodObject<{
26
26
  applicableProducts: z.ZodArray<z.ZodString, "many">;
27
27
  applicableCategories: z.ZodArray<z.ZodString, "many">;
28
28
  }, "strip", z.ZodTypeAny, {
29
- value: string;
30
29
  code: string;
31
30
  type: "fixed" | "percentage" | "free_shipping";
32
31
  isActive: boolean;
33
32
  endDate: string;
34
- maxDiscount: string;
35
33
  minPurchase: string;
36
34
  applicableProducts: string[];
37
35
  applicableCategories: string[];
38
36
  totalLimit: string;
39
37
  perUserLimit: string;
40
38
  startDate: string;
39
+ value?: string | undefined;
40
+ maxDiscount?: string | undefined;
41
41
  }, {
42
- value: string;
43
42
  code: string;
44
43
  type: "fixed" | "percentage" | "free_shipping";
45
44
  isActive: boolean;
46
45
  endDate: string;
47
- maxDiscount: string;
48
46
  minPurchase: string;
49
47
  applicableProducts: string[];
50
48
  applicableCategories: string[];
51
49
  totalLimit: string;
52
50
  perUserLimit: string;
53
51
  startDate: string;
52
+ value?: string | undefined;
53
+ maxDiscount?: string | undefined;
54
54
  }>;
55
55
  /**
56
56
  * The cross-field rules both editors need. Shared for the same reason the
@@ -59,7 +59,7 @@ export declare const couponFormBase: z.ZodObject<{
59
59
  */
60
60
  export declare function refineCouponCommon(v: {
61
61
  type: string;
62
- value: string;
62
+ value?: string;
63
63
  startDate: string;
64
64
  endDate: string;
65
65
  totalLimit: string;
@@ -68,9 +68,9 @@ export declare function refineCouponCommon(v: {
68
68
  export declare const sellerCouponFormSchema: z.ZodEffects<z.ZodObject<{
69
69
  code: z.ZodString;
70
70
  type: z.ZodEnum<["percentage", "fixed", "free_shipping"]>;
71
- value: z.ZodEffects<z.ZodString, string, string>;
71
+ value: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
72
72
  minPurchase: z.ZodEffects<z.ZodString, string, string>;
73
- maxDiscount: z.ZodEffects<z.ZodString, string, string>;
73
+ maxDiscount: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
74
74
  totalLimit: z.ZodEffects<z.ZodString, string, string>;
75
75
  perUserLimit: z.ZodEffects<z.ZodString, string, string>;
76
76
  startDate: z.ZodString;
@@ -79,57 +79,57 @@ export declare const sellerCouponFormSchema: z.ZodEffects<z.ZodObject<{
79
79
  applicableProducts: z.ZodArray<z.ZodString, "many">;
80
80
  applicableCategories: z.ZodArray<z.ZodString, "many">;
81
81
  }, "strip", z.ZodTypeAny, {
82
- value: string;
83
82
  code: string;
84
83
  type: "fixed" | "percentage" | "free_shipping";
85
84
  isActive: boolean;
86
85
  endDate: string;
87
- maxDiscount: string;
88
86
  minPurchase: string;
89
87
  applicableProducts: string[];
90
88
  applicableCategories: string[];
91
89
  totalLimit: string;
92
90
  perUserLimit: string;
93
91
  startDate: string;
92
+ value?: string | undefined;
93
+ maxDiscount?: string | undefined;
94
94
  }, {
95
- value: string;
96
95
  code: string;
97
96
  type: "fixed" | "percentage" | "free_shipping";
98
97
  isActive: boolean;
99
98
  endDate: string;
100
- maxDiscount: string;
101
99
  minPurchase: string;
102
100
  applicableProducts: string[];
103
101
  applicableCategories: string[];
104
102
  totalLimit: string;
105
103
  perUserLimit: string;
106
104
  startDate: string;
105
+ value?: string | undefined;
106
+ maxDiscount?: string | undefined;
107
107
  }>, {
108
- value: string;
109
108
  code: string;
110
109
  type: "fixed" | "percentage" | "free_shipping";
111
110
  isActive: boolean;
112
111
  endDate: string;
113
- maxDiscount: string;
114
112
  minPurchase: string;
115
113
  applicableProducts: string[];
116
114
  applicableCategories: string[];
117
115
  totalLimit: string;
118
116
  perUserLimit: string;
119
117
  startDate: string;
118
+ value?: string | undefined;
119
+ maxDiscount?: string | undefined;
120
120
  }, {
121
- value: string;
122
121
  code: string;
123
122
  type: "fixed" | "percentage" | "free_shipping";
124
123
  isActive: boolean;
125
124
  endDate: string;
126
- maxDiscount: string;
127
125
  minPurchase: string;
128
126
  applicableProducts: string[];
129
127
  applicableCategories: string[];
130
128
  totalLimit: string;
131
129
  perUserLimit: string;
132
130
  startDate: string;
131
+ value?: string | undefined;
132
+ maxDiscount?: string | undefined;
133
133
  }>;
134
134
  export type SellerCouponFormValues = z.infer<typeof sellerCouponFormSchema>;
135
135
  /**
@@ -183,9 +183,9 @@ export declare function couponDraftToPayload(draft: SellerCouponFormValues): Sel
183
183
  */
184
184
  export declare const adminCouponFormSchema: z.ZodEffects<z.ZodObject<{
185
185
  code: z.ZodString;
186
- value: z.ZodEffects<z.ZodString, string, string>;
186
+ value: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
187
187
  minPurchase: z.ZodEffects<z.ZodString, string, string>;
188
- maxDiscount: z.ZodEffects<z.ZodString, string, string>;
188
+ maxDiscount: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
189
189
  totalLimit: z.ZodEffects<z.ZodString, string, string>;
190
190
  perUserLimit: z.ZodEffects<z.ZodString, string, string>;
191
191
  startDate: z.ZodString;
@@ -197,90 +197,90 @@ export declare const adminCouponFormSchema: z.ZodEffects<z.ZodObject<{
197
197
  type: z.ZodEnum<["percentage", "fixed", "free_shipping", "buy_x_get_y"]>;
198
198
  name: z.ZodString;
199
199
  description: z.ZodUnion<[z.ZodOptional<z.ZodString>, z.ZodLiteral<"">]>;
200
- buyQuantity: z.ZodEffects<z.ZodString, string, string>;
201
- getQuantity: z.ZodEffects<z.ZodString, string, string>;
200
+ buyQuantity: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
201
+ getQuantity: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
202
202
  currentUsage: z.ZodOptional<z.ZodNumber>;
203
203
  firstTimeUserOnly: z.ZodBoolean;
204
204
  appliesToAuctions: z.ZodBoolean;
205
205
  }, "strip", z.ZodTypeAny, {
206
- value: string;
207
206
  code: string;
208
207
  type: "fixed" | "percentage" | "free_shipping" | "buy_x_get_y";
209
208
  name: string;
210
209
  isActive: boolean;
211
210
  endDate: string;
212
211
  firstTimeUserOnly: boolean;
213
- maxDiscount: string;
214
212
  minPurchase: string;
215
- buyQuantity: string;
216
- getQuantity: string;
217
213
  applicableProducts: string[];
218
214
  applicableCategories: string[];
219
215
  totalLimit: string;
220
216
  perUserLimit: string;
221
217
  startDate: string;
222
218
  appliesToAuctions: boolean;
219
+ value?: string | undefined;
223
220
  description?: string | undefined;
224
221
  currentUsage?: number | undefined;
222
+ maxDiscount?: string | undefined;
223
+ buyQuantity?: string | undefined;
224
+ getQuantity?: string | undefined;
225
225
  }, {
226
- value: string;
227
226
  code: string;
228
227
  type: "fixed" | "percentage" | "free_shipping" | "buy_x_get_y";
229
228
  name: string;
230
229
  isActive: boolean;
231
230
  endDate: string;
232
231
  firstTimeUserOnly: boolean;
233
- maxDiscount: string;
234
232
  minPurchase: string;
235
- buyQuantity: string;
236
- getQuantity: string;
237
233
  applicableProducts: string[];
238
234
  applicableCategories: string[];
239
235
  totalLimit: string;
240
236
  perUserLimit: string;
241
237
  startDate: string;
242
238
  appliesToAuctions: boolean;
239
+ value?: string | undefined;
243
240
  description?: string | undefined;
244
241
  currentUsage?: number | undefined;
242
+ maxDiscount?: string | undefined;
243
+ buyQuantity?: string | undefined;
244
+ getQuantity?: string | undefined;
245
245
  }>, {
246
- value: string;
247
246
  code: string;
248
247
  type: "fixed" | "percentage" | "free_shipping" | "buy_x_get_y";
249
248
  name: string;
250
249
  isActive: boolean;
251
250
  endDate: string;
252
251
  firstTimeUserOnly: boolean;
253
- maxDiscount: string;
254
252
  minPurchase: string;
255
- buyQuantity: string;
256
- getQuantity: string;
257
253
  applicableProducts: string[];
258
254
  applicableCategories: string[];
259
255
  totalLimit: string;
260
256
  perUserLimit: string;
261
257
  startDate: string;
262
258
  appliesToAuctions: boolean;
259
+ value?: string | undefined;
263
260
  description?: string | undefined;
264
261
  currentUsage?: number | undefined;
262
+ maxDiscount?: string | undefined;
263
+ buyQuantity?: string | undefined;
264
+ getQuantity?: string | undefined;
265
265
  }, {
266
- value: string;
267
266
  code: string;
268
267
  type: "fixed" | "percentage" | "free_shipping" | "buy_x_get_y";
269
268
  name: string;
270
269
  isActive: boolean;
271
270
  endDate: string;
272
271
  firstTimeUserOnly: boolean;
273
- maxDiscount: string;
274
272
  minPurchase: string;
275
- buyQuantity: string;
276
- getQuantity: string;
277
273
  applicableProducts: string[];
278
274
  applicableCategories: string[];
279
275
  totalLimit: string;
280
276
  perUserLimit: string;
281
277
  startDate: string;
282
278
  appliesToAuctions: boolean;
279
+ value?: string | undefined;
283
280
  description?: string | undefined;
284
281
  currentUsage?: number | undefined;
282
+ maxDiscount?: string | undefined;
283
+ buyQuantity?: string | undefined;
284
+ getQuantity?: string | undefined;
285
285
  }>;
286
286
  export type AdminCouponFormValues = z.infer<typeof adminCouponFormSchema>;
@@ -70,7 +70,10 @@ export const couponFormBase = z
70
70
  * `when` carries what the editor held as JSX conditionals, so a field the
71
71
  * form hides is one the payload cannot carry — see `couponDraftToPayload`.
72
72
  */
73
- value: annotate(numericString("The discount value"), {
73
+ // Optional for the same reason as buyQuantity/getQuantity below: this field
74
+ // is `when`-gated, so visibleValues() strips it on a free-shipping coupon.
75
+ // refineCouponCommon still requires it for every other type.
76
+ value: annotate(numericString("The discount value").optional(), {
74
77
  section: "basics", quick: true, order: 3, row: "pair",
75
78
  when: (v) => v.type !== "free_shipping",
76
79
  }),
@@ -83,7 +86,9 @@ export const couponFormBase = z
83
86
  * cap typed while the type was "percentage" persisted after switching to
84
87
  * free shipping, invisibly.
85
88
  */
86
- maxDiscount: annotate(numericString("Maximum discount"), {
89
+ // `when`-gated to percentage only, so it is stripped for fixed and
90
+ // free-shipping coupons — optional, or those two types cannot be saved.
91
+ maxDiscount: annotate(numericString("Maximum discount").optional(), {
87
92
  section: "limits", order: 2, row: "pair",
88
93
  when: (v) => v.type === "percentage",
89
94
  }),
@@ -121,8 +126,9 @@ export function refineCouponCommon(v, ctx) {
121
126
  // a percentage above 100 is not a discount — it is the store paying the
122
127
  // customer. Nothing bounded this before.
123
128
  if (v.type !== "free_shipping") {
124
- const amount = Number(v.value);
125
- if (v.value.trim() === "")
129
+ const rawValue = v.value ?? "";
130
+ const amount = Number(rawValue);
131
+ if (rawValue.trim() === "")
126
132
  issue("value", "A discount value is required.");
127
133
  else if (amount <= 0)
128
134
  issue("value", "The discount must be greater than zero.");
@@ -205,11 +211,28 @@ export const adminCouponFormSchema = couponFormBase
205
211
  description: annotate(z.string().max(500).optional().or(z.literal("")), {
206
212
  section: "basics", order: 5, row: "full", kind: "textarea",
207
213
  }),
208
- buyQuantity: annotate(numericString("Buy quantity"), {
214
+ /*
215
+ * 🛑 A `when`-gated field MUST be optional, or the form cannot be submitted
216
+ * at all while the condition is false.
217
+ *
218
+ * `visibleValues()` strips every field whose `when` is false before the
219
+ * submit path parses the draft — that is its whole job, so a hidden input
220
+ * cannot smuggle a stale value into the payload. But a stripped key is
221
+ * `undefined` to Zod, and these were required strings, so editing any
222
+ * ordinary percentage coupon produced exactly two "This field is required"
223
+ * issues for the two buy-x-get-y inputs that are not on screen. The summary
224
+ * rendered them as "Coupon: This field is required" twice, naming the
225
+ * section rather than any field, and no PATCH was ever issued.
226
+ *
227
+ * Optional here is not a loosening: the superRefine below still demands a
228
+ * whole number of one or more whenever the type IS buy_x_get_y, which is
229
+ * the only time either field is real.
230
+ */
231
+ buyQuantity: annotate(numericString("Buy quantity").optional(), {
209
232
  section: "basics", order: 6, row: "pair", kind: "number",
210
233
  when: (v) => v.type === "buy_x_get_y",
211
234
  }),
212
- getQuantity: annotate(numericString("Get quantity"), {
235
+ getQuantity: annotate(numericString("Get quantity").optional(), {
213
236
  section: "basics", order: 7, row: "pair", kind: "number",
214
237
  when: (v) => v.type === "buy_x_get_y",
215
238
  }),
@@ -235,8 +258,13 @@ export const adminCouponFormSchema = couponFormBase
235
258
  // A buy-x-get-y with a zero on either side is not an offer.
236
259
  if (v.type === "buy_x_get_y") {
237
260
  for (const key of ["buyQuantity", "getQuantity"]) {
238
- const n = Number(v[key]);
239
- if (v[key].trim() === "" || !Number.isFinite(n) || n < 1) {
261
+ // `?? ""` because the field is optional now — see the note on its
262
+ // declaration. When the type IS buy_x_get_y the input is on screen, so
263
+ // an absent value here means the admin left it blank, which this
264
+ // rejects exactly as it did before.
265
+ const raw = v[key] ?? "";
266
+ const n = Number(raw);
267
+ if (raw.trim() === "" || !Number.isFinite(n) || n < 1) {
240
268
  ctx.addIssue({
241
269
  code: z.ZodIssueCode.custom,
242
270
  path: [key],
@@ -158,6 +158,20 @@ export function SectionForm({ sections, values, onChange, onSubmit, submitLabel
158
158
  // validator on every render and re-fire the effect below in a loop.
159
159
  const onValidationChangeRef = useRef(onValidationChange);
160
160
  onValidationChangeRef.current = onValidationChange;
161
+ /**
162
+ * Are two field-error maps the same set of messages?
163
+ *
164
+ * Flat string maps, so a key sweep is exact — no deep compare needed. This is
165
+ * what lets the validation effect depend on `values` (a new object every
166
+ * render) without looping: an unchanged result returns the previous object
167
+ * and React bails out of the update.
168
+ */
169
+ const sameErrors = (a, b) => {
170
+ const ak = Object.keys(a);
171
+ if (ak.length !== Object.keys(b).length)
172
+ return false;
173
+ return ak.every((k) => a[k] === b[k]);
174
+ };
161
175
  /** Section ids holding at least one error, in render order. */
162
176
  const erroringSectionIds = useCallback((errs) => {
163
177
  const keys = Object.keys(errs);
@@ -176,8 +190,8 @@ export function SectionForm({ sections, values, onChange, onSubmit, submitLabel
176
190
  // applyZodIssues' incremental setFieldError-per-issue cannot do.
177
191
  const parsed = activeSchema.safeParse(nextValues);
178
192
  if (parsed.success) {
179
- setFieldErrors({});
180
- setForceOpenIds([]);
193
+ setFieldErrors((prev) => (Object.keys(prev).length === 0 ? prev : {}));
194
+ setForceOpenIds((prev) => (prev.length === 0 ? prev : []));
181
195
  onValidationChangeRef.current?.({}, fieldToSectionIndex);
182
196
  return;
183
197
  }
@@ -187,7 +201,12 @@ export function SectionForm({ sections, values, onChange, onSubmit, submitLabel
187
201
  continue;
188
202
  next[issue.path.map(String).join(".")] = issue.message;
189
203
  }
190
- setFieldErrors(next);
204
+ /*
205
+ * Return the PREVIOUS object when nothing actually changed. `values` is a
206
+ * fresh object on every render, so the effect below re-validates on every
207
+ * render; handing back an equal-but-new errors map would setState in a loop.
208
+ */
209
+ setFieldErrors((prev) => (sameErrors(prev, next) ? prev : next));
191
210
  // Release a force-opened section as soon as ITS OWN errors clear, rather
192
211
  // than waiting for the whole form to become valid — otherwise fixing
193
212
  // section 1 leaves it pinned open while the user works through section 5.
@@ -198,10 +217,30 @@ export function SectionForm({ sections, values, onChange, onSubmit, submitLabel
198
217
  });
199
218
  onValidationChangeRef.current?.(next, fieldToSectionIndex);
200
219
  }, [schema, inheritedSchema, fieldToSectionIndex, erroringSectionIds]);
220
+ /*
221
+ * 🛑 `values` MUST be a dependency, and leaving it out cost the entire admin
222
+ * coupon editor.
223
+ *
224
+ * This effect used to run once on mount with an eslint-disable, so it
225
+ * validated the INITIAL draft. On an edit form that draft is the empty
226
+ * defaults: the record arrives asynchronously (useQuery → useEffect →
227
+ * patch()), and `patch` is not `handleFieldChange`, so the only other caller
228
+ * of runValidation never fired. The mount-time errors therefore outlived the
229
+ * data that fixed them.
230
+ *
231
+ * Measured on production 2026-09-15: opening ARENA25 showed "3 issues" with
232
+ * "A discount value is required." under a field containing 25 and "Give the
233
+ * campaign a name." under a populated name — the three fields that are empty
234
+ * BEFORE the load. Save then refused with "Coupon: This field is required"
235
+ * and issued no PATCH at all, so no coupon could be edited through the UI.
236
+ *
237
+ * Re-validating per render is safe because runValidation returns the previous
238
+ * errors object when nothing changed (see `sameErrors`); without that this
239
+ * would setState in a loop, which is presumably why the dep was dropped.
240
+ */
201
241
  useEffect(() => {
202
242
  runValidation(values);
203
- // eslint-disable-next-line react-hooks/exhaustive-deps
204
- }, [schema, inheritedSchema, fieldToSectionIndex]);
243
+ }, [runValidation, values]);
205
244
  const handleFieldChange = useCallback((partial) => {
206
245
  onChange(partial);
207
246
  runValidation({ ...values, ...partial });
@@ -4755,9 +4755,9 @@ export declare const SCHEMAS: {
4755
4755
  readonly sellerCoupon: import("zod").ZodEffects<import("zod").ZodObject<{
4756
4756
  code: import("zod").ZodString;
4757
4757
  type: import("zod").ZodEnum<["percentage", "fixed", "free_shipping"]>;
4758
- value: import("zod").ZodEffects<import("zod").ZodString, string, string>;
4758
+ value: import("zod").ZodOptional<import("zod").ZodEffects<import("zod").ZodString, string, string>>;
4759
4759
  minPurchase: import("zod").ZodEffects<import("zod").ZodString, string, string>;
4760
- maxDiscount: import("zod").ZodEffects<import("zod").ZodString, string, string>;
4760
+ maxDiscount: import("zod").ZodOptional<import("zod").ZodEffects<import("zod").ZodString, string, string>>;
4761
4761
  totalLimit: import("zod").ZodEffects<import("zod").ZodString, string, string>;
4762
4762
  perUserLimit: import("zod").ZodEffects<import("zod").ZodString, string, string>;
4763
4763
  startDate: import("zod").ZodString;
@@ -4766,57 +4766,57 @@ export declare const SCHEMAS: {
4766
4766
  applicableProducts: import("zod").ZodArray<import("zod").ZodString, "many">;
4767
4767
  applicableCategories: import("zod").ZodArray<import("zod").ZodString, "many">;
4768
4768
  }, "strip", import("zod").ZodTypeAny, {
4769
- value: string;
4770
4769
  code: string;
4771
4770
  type: "fixed" | "percentage" | "free_shipping";
4772
4771
  isActive: boolean;
4773
4772
  endDate: string;
4774
- maxDiscount: string;
4775
4773
  minPurchase: string;
4776
4774
  applicableProducts: string[];
4777
4775
  applicableCategories: string[];
4778
4776
  totalLimit: string;
4779
4777
  perUserLimit: string;
4780
4778
  startDate: string;
4779
+ value?: string | undefined;
4780
+ maxDiscount?: string | undefined;
4781
4781
  }, {
4782
- value: string;
4783
4782
  code: string;
4784
4783
  type: "fixed" | "percentage" | "free_shipping";
4785
4784
  isActive: boolean;
4786
4785
  endDate: string;
4787
- maxDiscount: string;
4788
4786
  minPurchase: string;
4789
4787
  applicableProducts: string[];
4790
4788
  applicableCategories: string[];
4791
4789
  totalLimit: string;
4792
4790
  perUserLimit: string;
4793
4791
  startDate: string;
4792
+ value?: string | undefined;
4793
+ maxDiscount?: string | undefined;
4794
4794
  }>, {
4795
- value: string;
4796
4795
  code: string;
4797
4796
  type: "fixed" | "percentage" | "free_shipping";
4798
4797
  isActive: boolean;
4799
4798
  endDate: string;
4800
- maxDiscount: string;
4801
4799
  minPurchase: string;
4802
4800
  applicableProducts: string[];
4803
4801
  applicableCategories: string[];
4804
4802
  totalLimit: string;
4805
4803
  perUserLimit: string;
4806
4804
  startDate: string;
4805
+ value?: string | undefined;
4806
+ maxDiscount?: string | undefined;
4807
4807
  }, {
4808
- value: string;
4809
4808
  code: string;
4810
4809
  type: "fixed" | "percentage" | "free_shipping";
4811
4810
  isActive: boolean;
4812
4811
  endDate: string;
4813
- maxDiscount: string;
4814
4812
  minPurchase: string;
4815
4813
  applicableProducts: string[];
4816
4814
  applicableCategories: string[];
4817
4815
  totalLimit: string;
4818
4816
  perUserLimit: string;
4819
4817
  startDate: string;
4818
+ value?: string | undefined;
4819
+ maxDiscount?: string | undefined;
4820
4820
  }>;
4821
4821
  readonly customRole: import("zod").ZodObject<{
4822
4822
  name: import("zod").ZodString;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mohasinac/appkit",
3
- "version": "4.41.0",
3
+ "version": "4.41.2",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -151,7 +151,7 @@
151
151
  },
152
152
  "scripts": {
153
153
  "postinstall": "node scripts/dedupe-peer-deps.mjs",
154
- "build": "node scripts/dedupe-peer-deps.mjs && node -e \"const fs=require('fs');try{fs.rmSync('tsconfig.build.tsbuildinfo')}catch(e){}\" && tsc -p tsconfig.build.json && node scripts/copy-assets.mjs && tailwindcss -i src/tailwind-input.css -o dist/tailwind-utilities.css --minify && node scripts/bundle-css.mjs && node scripts/verify-css-build.mjs",
154
+ "build": "node scripts/dedupe-peer-deps.mjs && node -e \"const fs=require('fs');for(const t of ['tsconfig.build.tsbuildinfo','dist']){try{fs.rmSync(t,{recursive:true})}catch(e){}}\" && tsc -p tsconfig.build.json && node scripts/copy-assets.mjs && tailwindcss -i src/tailwind-input.css -o dist/tailwind-utilities.css --minify && node scripts/bundle-css.mjs && node scripts/verify-css-build.mjs",
155
155
  "prepublishOnly": "npm run build",
156
156
  "watch": "concurrently --kill-others --restart-tries 0 --names \"ts,css\" \"tsc -p tsconfig.build.json --watch\" \"npm run watch:css\"",
157
157
  "watch:css": "tailwindcss -i src/tailwind-input.css -o dist/tailwind-utilities.css --watch",
@@ -1,12 +0,0 @@
1
- import { type ActionResult } from "@mohasinac/appkit/server";
2
- import type { ConversationDocument } from "../../../../features/messages/schemas/firestore";
3
- export interface StartConversationInput {
4
- productId: string;
5
- }
6
- /**
7
- * Open (or resume) a buyer↔seller conversation for a classified listing.
8
- * Called when the buyer clicks "Contact Seller" on the classified PDP.
9
- * Idempotent — returns the existing conversation if one already exists for
10
- * this buyer × store × product tuple.
11
- */
12
- export declare function startClassifiedConversationAction(input: StartConversationInput): Promise<ActionResult<ConversationDocument>>;
@@ -1,33 +0,0 @@
1
- "use server";
2
- import { wrapAction } from "@mohasinac/appkit/server";
3
- import { conversationsRepository } from "../../../../features/messages/repository/conversations.repository";
4
- import { requireRoleUser } from "../../../../providers/auth-firebase/helpers";
5
- import { storeRepository, productRepository } from "../../../../repositories";
6
- /**
7
- * Open (or resume) a buyer↔seller conversation for a classified listing.
8
- * Called when the buyer clicks "Contact Seller" on the classified PDP.
9
- * Idempotent — returns the existing conversation if one already exists for
10
- * this buyer × store × product tuple.
11
- */
12
- export async function startClassifiedConversationAction(input) {
13
- return wrapAction(async () => {
14
- const user = await requireRoleUser(["user", "buyer", "seller", "admin"]);
15
- const product = await productRepository.findByIdOrSlug(input.productId);
16
- if (!product || product.listingType !== "classified") {
17
- throw new Error("Product not found or not a classified listing");
18
- }
19
- const store = await storeRepository.findById(product.storeId);
20
- if (!store) {
21
- throw new Error("Store not found");
22
- }
23
- return conversationsRepository.findOrCreateByContext({
24
- buyerId: user.uid,
25
- buyerDisplayName: user.name ?? user.email ?? user.uid,
26
- storeId: product.storeId,
27
- storeName: store.storeName,
28
- sellerDisplayName: store.storeName,
29
- productId: product.id,
30
- productTitle: product.title,
31
- });
32
- });
33
- }
@@ -1,12 +0,0 @@
1
- import { type ActionResult } from "@mohasinac/appkit/server";
2
- import type { ConversationDocument } from "../../../../features/messages/schemas/firestore";
3
- export interface StartDigitalCodeConversationInput {
4
- productId: string;
5
- }
6
- /**
7
- * Open a buyer↔seller conversation for a digital-code listing (questions
8
- * about platform/region/edition before purchase). Post-purchase code reveal
9
- * is handled by the existing `/api/orders/[id]/code` endpoint, not a server
10
- * action — the code reveal panel lives in the order detail view.
11
- */
12
- export declare function startDigitalCodeConversationAction(input: StartDigitalCodeConversationInput): Promise<ActionResult<ConversationDocument>>;
@@ -1,33 +0,0 @@
1
- "use server";
2
- import { wrapAction } from "@mohasinac/appkit/server";
3
- import { conversationsRepository } from "../../../../features/messages/repository/conversations.repository";
4
- import { requireRoleUser } from "../../../../providers/auth-firebase/helpers";
5
- import { storeRepository, productRepository } from "../../../../repositories";
6
- /**
7
- * Open a buyer↔seller conversation for a digital-code listing (questions
8
- * about platform/region/edition before purchase). Post-purchase code reveal
9
- * is handled by the existing `/api/orders/[id]/code` endpoint, not a server
10
- * action — the code reveal panel lives in the order detail view.
11
- */
12
- export async function startDigitalCodeConversationAction(input) {
13
- return wrapAction(async () => {
14
- const user = await requireRoleUser(["user", "buyer", "seller", "admin"]);
15
- const product = await productRepository.findByIdOrSlug(input.productId);
16
- if (!product || product.listingType !== "digital-code") {
17
- throw new Error("Product not found or not a digital-code listing");
18
- }
19
- const store = await storeRepository.findById(product.storeId);
20
- if (!store) {
21
- throw new Error("Store not found");
22
- }
23
- return conversationsRepository.findOrCreateByContext({
24
- buyerId: user.uid,
25
- buyerDisplayName: user.name ?? user.email ?? user.uid,
26
- storeId: product.storeId,
27
- storeName: store.storeName,
28
- sellerDisplayName: store.storeName,
29
- productId: product.id,
30
- productTitle: product.title,
31
- });
32
- });
33
- }
@@ -1,18 +0,0 @@
1
- export declare const getHomepageSections: () => Promise<import("../../../..").HomepageSectionDocument[]>;
2
- export declare const getHeroCarouselSlides: () => Promise<never[] | import("../../../..").CarouselSlideDocument[]>;
3
- /**
4
- * One parallel fetch returning every piece of data the homepage sections need.
5
- * Page components call this once; React.cache() deduplicates per request.
6
- */
7
- export declare const getHomepageInitial: () => Promise<{
8
- sections: import("../../../..").HomepageSectionDocument[];
9
- carouselSlides: never[] | import("../../../..").CarouselSlideDocument[];
10
- featuredProducts: never[] | import("../../../..").ProductDocument[];
11
- activeAuctions: never[] | import("../../../..").ProductDocument[];
12
- activePreOrders: never[] | import("../../../..").ProductDocument[];
13
- activeBrands: never[] | import("../../../..").CategoryDocument[];
14
- featuredReviews: never[] | import("../../../..").ReviewDocument[];
15
- recentBlogPosts: never[] | import("../../../..").BlogPostDocument[];
16
- activeEvents: never[] | import("../../../..").EventDocument[];
17
- featuredCategories: never[] | import("../../../..").CategoryDocument[];
18
- }>;