@jsdev_ninja/core 0.12.6 → 0.12.8

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 (68) hide show
  1. package/dist/core.cjs.js +1 -1
  2. package/dist/core.cjs.js.map +1 -1
  3. package/dist/core.es.js +1001 -853
  4. package/dist/core.es.js.map +1 -1
  5. package/dist/core.umd.js +1 -1
  6. package/dist/core.umd.js.map +1 -1
  7. package/dist/entities/Discount/__tests__/engine.test.d.ts +2 -0
  8. package/dist/entities/Discount/__tests__/engine.test.d.ts.map +1 -0
  9. package/dist/entities/Discount/__tests__/engine.test.js +298 -0
  10. package/dist/entities/Discount/__tests__/factory.test.d.ts +2 -0
  11. package/dist/entities/Discount/__tests__/factory.test.d.ts.map +1 -0
  12. package/dist/entities/Discount/__tests__/factory.test.js +75 -0
  13. package/dist/entities/Discount/__tests__/integration.test.d.ts +2 -0
  14. package/dist/entities/Discount/__tests__/integration.test.d.ts.map +1 -0
  15. package/dist/entities/Discount/__tests__/integration.test.js +115 -0
  16. package/dist/entities/Discount/__tests__/simple.test.d.ts +2 -0
  17. package/dist/entities/Discount/__tests__/simple.test.d.ts.map +1 -0
  18. package/dist/entities/Discount/__tests__/simple.test.js +186 -0
  19. package/dist/entities/Discount/__tests__/utils.test.d.ts +2 -0
  20. package/dist/entities/Discount/__tests__/utils.test.d.ts.map +1 -0
  21. package/dist/entities/Discount/__tests__/utils.test.js +55 -0
  22. package/dist/entities/Discount/engine.d.ts +29 -0
  23. package/dist/entities/Discount/engine.d.ts.map +1 -0
  24. package/dist/entities/Discount/engine.js +80 -0
  25. package/dist/entities/Discount/factory.d.ts +10 -0
  26. package/dist/entities/Discount/factory.d.ts.map +1 -0
  27. package/dist/entities/Discount/factory.js +18 -0
  28. package/dist/entities/Discount/index.d.ts +9 -0
  29. package/dist/entities/Discount/index.d.ts.map +1 -0
  30. package/dist/entities/Discount/index.js +8 -0
  31. package/dist/entities/Discount/strategies/BundleStrategy.d.ts +12 -0
  32. package/dist/entities/Discount/strategies/BundleStrategy.d.ts.map +1 -0
  33. package/dist/entities/Discount/strategies/BundleStrategy.js +80 -0
  34. package/dist/entities/Discount/strategies/__tests__/BundleStrategy.test.d.ts +2 -0
  35. package/dist/entities/Discount/strategies/__tests__/BundleStrategy.test.d.ts.map +1 -0
  36. package/dist/entities/Discount/strategies/__tests__/BundleStrategy.test.js +265 -0
  37. package/dist/entities/Discount/strategy.d.ts +6 -0
  38. package/dist/entities/Discount/strategy.d.ts.map +1 -0
  39. package/dist/entities/Discount/strategy.js +1 -0
  40. package/dist/entities/Discount/types.d.ts +148 -0
  41. package/dist/entities/Discount/types.d.ts.map +1 -0
  42. package/dist/entities/Discount/types.js +27 -0
  43. package/dist/entities/Discount/utils.d.ts +29 -0
  44. package/dist/entities/Discount/utils.d.ts.map +1 -0
  45. package/dist/entities/Discount/utils.js +39 -0
  46. package/dist/tsconfig.app.tsbuildinfo +1 -1
  47. package/dist/utils/index.d.ts.map +1 -1
  48. package/dist/utils/index.js +16 -60
  49. package/lib/entities/Discount/__tests__/engine.test.ts +337 -0
  50. package/lib/entities/Discount/__tests__/factory.test.ts +91 -0
  51. package/lib/entities/Discount/__tests__/integration.test.ts +132 -0
  52. package/lib/entities/Discount/__tests__/simple.test.ts +215 -0
  53. package/lib/entities/Discount/__tests__/utils.test.ts +69 -0
  54. package/lib/entities/Discount/engine.ts +129 -0
  55. package/lib/entities/Discount/factory.ts +25 -0
  56. package/lib/entities/Discount/index.ts +10 -0
  57. package/lib/entities/Discount/strategies/BundleStrategy.ts +123 -0
  58. package/lib/entities/Discount/strategies/__tests__/BundleStrategy.test.ts +295 -0
  59. package/lib/entities/Discount/strategy.ts +6 -0
  60. package/lib/entities/Discount/types.ts +68 -0
  61. package/lib/entities/Discount/utils.ts +42 -0
  62. package/lib/utils/index.ts +19 -80
  63. package/package.json +10 -5
  64. package/vitest.config.ts +10 -0
  65. package/dist/entities/Discount.d.ts +0 -71
  66. package/dist/entities/Discount.d.ts.map +0 -1
  67. package/dist/entities/Discount.js +0 -20
  68. package/lib/entities/Discount.ts +0 -23
@@ -0,0 +1,295 @@
1
+ import { describe, it, expect, beforeEach } from "vitest";
2
+ import { BundleDiscountStrategy } from "../BundleStrategy";
3
+ import { TDiscount, DiscountContext } from "../../types";
4
+
5
+ describe("BundleDiscountStrategy", () => {
6
+ let strategy: BundleDiscountStrategy;
7
+ let mockContext: DiscountContext;
8
+
9
+ beforeEach(() => {
10
+ strategy = new BundleDiscountStrategy();
11
+
12
+ mockContext = {
13
+ cart: [
14
+ {
15
+ amount: 2,
16
+ product: {
17
+ id: "product1",
18
+ price: 10,
19
+ },
20
+ },
21
+ {
22
+ amount: 1,
23
+ product: {
24
+ id: "product2",
25
+ price: 15,
26
+ },
27
+ },
28
+ ],
29
+ user: undefined,
30
+ appliedDiscounts: [],
31
+ };
32
+ });
33
+
34
+ describe("canApply", () => {
35
+ it("should return true for valid bundle discount", () => {
36
+ const discount: TDiscount = {
37
+ type: "Discount",
38
+ storeId: "store1",
39
+ companyId: "company1",
40
+ id: "bundle1",
41
+ name: [{ lang: "he", value: "Buy 3 for $25" }],
42
+ active: true,
43
+ startDate: Date.now() - 1000,
44
+ endDate: Date.now() + 1000,
45
+ variant: {
46
+ variantType: "bundle",
47
+ productsId: ["product1", "product2"],
48
+ requiredQuantity: 3,
49
+ bundlePrice: 25,
50
+ },
51
+ conditions: {
52
+ stackable: false,
53
+ },
54
+ };
55
+
56
+ expect(strategy.canApply(discount, mockContext)).toBe(true);
57
+ });
58
+
59
+ it("should return true for bundle variant type", () => {
60
+ const discount = {
61
+ ...mockDiscount,
62
+ variant: {
63
+ variantType: "bundle" as const,
64
+ productsId: ["product1", "product2"],
65
+ requiredQuantity: 3,
66
+ bundlePrice: 25,
67
+ },
68
+ };
69
+
70
+ // This should work since it's a bundle type and we have 3 items total
71
+ expect(strategy.canApply(discount, mockContext)).toBe(true);
72
+ });
73
+
74
+ it("should return false when not enough items", () => {
75
+ const discount: TDiscount = {
76
+ type: "Discount",
77
+ storeId: "store1",
78
+ companyId: "company1",
79
+ id: "bundle1",
80
+ name: [{ lang: "he", value: "Buy 5 for $40" }],
81
+ active: true,
82
+ startDate: Date.now() - 1000,
83
+ endDate: Date.now() + 1000,
84
+ variant: {
85
+ variantType: "bundle",
86
+ productsId: ["product1", "product2"],
87
+ requiredQuantity: 5, // Need 5, but cart only has 3
88
+ bundlePrice: 40,
89
+ },
90
+ conditions: {
91
+ stackable: false,
92
+ },
93
+ };
94
+
95
+ expect(strategy.canApply(discount, mockContext)).toBe(false);
96
+ });
97
+
98
+ it("should return false when discount is inactive", () => {
99
+ const discount: TDiscount = {
100
+ type: "Discount",
101
+ storeId: "store1",
102
+ companyId: "company1",
103
+ id: "bundle1",
104
+ name: [{ lang: "he", value: "Buy 3 for $25" }],
105
+ active: false, // Inactive
106
+ startDate: Date.now() - 1000,
107
+ endDate: Date.now() + 1000,
108
+ variant: {
109
+ variantType: "bundle",
110
+ productsId: ["product1", "product2"],
111
+ requiredQuantity: 3,
112
+ bundlePrice: 25,
113
+ },
114
+ conditions: {
115
+ stackable: false,
116
+ },
117
+ };
118
+
119
+ expect(strategy.canApply(discount, mockContext)).toBe(false);
120
+ });
121
+
122
+ it("should return false when discount is expired", () => {
123
+ const discount: TDiscount = {
124
+ type: "Discount",
125
+ storeId: "store1",
126
+ companyId: "company1",
127
+ id: "bundle1",
128
+ name: [{ lang: "he", value: "Buy 3 for $25" }],
129
+ active: true,
130
+ startDate: Date.now() - 2000,
131
+ endDate: Date.now() - 1000, // Expired
132
+ variant: {
133
+ variantType: "bundle",
134
+ productsId: ["product1", "product2"],
135
+ requiredQuantity: 3,
136
+ bundlePrice: 25,
137
+ },
138
+ conditions: {
139
+ stackable: false,
140
+ },
141
+ };
142
+
143
+ expect(strategy.canApply(discount, mockContext)).toBe(false);
144
+ });
145
+ });
146
+
147
+ describe("calculate", () => {
148
+ it("should calculate bundle discount correctly", () => {
149
+ const discount: TDiscount = {
150
+ type: "Discount",
151
+ storeId: "store1",
152
+ companyId: "company1",
153
+ id: "bundle1",
154
+ name: [{ lang: "he", value: "Buy 3 for $25" }],
155
+ active: true,
156
+ startDate: Date.now() - 1000,
157
+ endDate: Date.now() + 1000,
158
+ variant: {
159
+ variantType: "bundle",
160
+ productsId: ["product1", "product2"],
161
+ requiredQuantity: 3,
162
+ bundlePrice: 25,
163
+ },
164
+ conditions: {
165
+ stackable: false,
166
+ },
167
+ };
168
+
169
+ const result = strategy.calculate(discount, mockContext);
170
+
171
+ expect(result.applicable).toBe(true);
172
+ expect(result.discountAmount).toBe(10); // (2×10 + 1×15) - 25 = 35 - 25 = 10
173
+ expect(result.affectedItems).toHaveLength(2);
174
+
175
+ // Check product1 discount
176
+ const product1Item = result.affectedItems.find(item => item.productId === "product1");
177
+ expect(product1Item).toBeDefined();
178
+ expect(product1Item!.discountAmount).toBeCloseTo(5.71, 2); // Proportional to 20/35
179
+
180
+ // Check product2 discount
181
+ const product2Item = result.affectedItems.find(item => item.productId === "product2");
182
+ expect(product2Item).toBeDefined();
183
+ expect(product2Item!.discountAmount).toBeCloseTo(4.29, 2); // Proportional to 15/35
184
+ });
185
+
186
+ it("should handle multiple bundles", () => {
187
+ const contextWithMoreItems: DiscountContext = {
188
+ cart: [
189
+ {
190
+ amount: 6, // 6 items
191
+ product: {
192
+ id: "product1",
193
+ price: 10,
194
+ },
195
+ },
196
+ ],
197
+ user: undefined,
198
+ appliedDiscounts: [],
199
+ };
200
+
201
+ const discount: TDiscount = {
202
+ type: "Discount",
203
+ storeId: "store1",
204
+ companyId: "company1",
205
+ id: "bundle1",
206
+ name: [{ lang: "he", value: "Buy 3 for $25" }],
207
+ active: true,
208
+ startDate: Date.now() - 1000,
209
+ endDate: Date.now() + 1000,
210
+ variant: {
211
+ variantType: "bundle",
212
+ productsId: ["product1"],
213
+ requiredQuantity: 3,
214
+ bundlePrice: 25,
215
+ },
216
+ conditions: {
217
+ stackable: false,
218
+ },
219
+ };
220
+
221
+ const result = strategy.calculate(discount, contextWithMoreItems);
222
+
223
+ expect(result.applicable).toBe(true);
224
+ expect(result.discountAmount).toBe(10); // (6×10) - (2×25) = 60 - 50 = 10
225
+ expect(result.affectedItems).toHaveLength(1);
226
+ expect(result.affectedItems[0].discountAmount).toBe(10);
227
+ });
228
+
229
+ it("should return not applicable for invalid bundle", () => {
230
+ const discount = {
231
+ ...mockDiscount,
232
+ variant: {
233
+ variantType: "bundle" as const,
234
+ productsId: ["product1"],
235
+ requiredQuantity: 10, // Too many required
236
+ bundlePrice: 25,
237
+ },
238
+ };
239
+
240
+ const result = strategy.calculate(discount, mockContext);
241
+
242
+ expect(result.applicable).toBe(false);
243
+ expect(result.discountAmount).toBe(0);
244
+ expect(result.affectedItems).toHaveLength(0);
245
+ });
246
+
247
+ it("should return not applicable when not enough items", () => {
248
+ const discount: TDiscount = {
249
+ type: "Discount",
250
+ storeId: "store1",
251
+ companyId: "company1",
252
+ id: "bundle1",
253
+ name: [{ lang: "he", value: "Buy 5 for $40" }],
254
+ active: true,
255
+ startDate: Date.now() - 1000,
256
+ endDate: Date.now() + 1000,
257
+ variant: {
258
+ variantType: "bundle",
259
+ productsId: ["product1", "product2"],
260
+ requiredQuantity: 5,
261
+ bundlePrice: 40,
262
+ },
263
+ conditions: {
264
+ stackable: false,
265
+ },
266
+ };
267
+
268
+ const result = strategy.calculate(discount, mockContext);
269
+
270
+ expect(result.applicable).toBe(false);
271
+ expect(result.discountAmount).toBe(0);
272
+ expect(result.affectedItems).toHaveLength(0);
273
+ });
274
+ });
275
+ });
276
+
277
+ const mockDiscount: TDiscount = {
278
+ type: "Discount",
279
+ storeId: "store1",
280
+ companyId: "company1",
281
+ id: "bundle1",
282
+ name: [{ lang: "he", value: "Buy 3 for $25" }],
283
+ active: true,
284
+ startDate: Date.now() - 1000,
285
+ endDate: Date.now() + 1000,
286
+ variant: {
287
+ variantType: "bundle",
288
+ productsId: ["product1", "product2"],
289
+ requiredQuantity: 3,
290
+ bundlePrice: 25,
291
+ },
292
+ conditions: {
293
+ stackable: false,
294
+ },
295
+ };
@@ -0,0 +1,6 @@
1
+ import { TDiscount, DiscountResult, DiscountContext } from "./types";
2
+
3
+ export interface DiscountStrategy {
4
+ canApply(discount: TDiscount, context: DiscountContext): boolean;
5
+ calculate(discount: TDiscount, context: DiscountContext): DiscountResult;
6
+ }
@@ -0,0 +1,68 @@
1
+ import { z } from "zod";
2
+
3
+ // Simple discount conditions
4
+ export const DiscountConditionsSchema = z.object({
5
+ minSpend: z.number().positive().optional(),
6
+ stackable: z.boolean().default(false),
7
+ }).optional();
8
+
9
+ // Bundle discount - buy X items for Y price
10
+ export const DiscountVariantSchema = z.discriminatedUnion("variantType", [
11
+ z.object({
12
+ variantType: z.literal("bundle"),
13
+ productsId: z.array(z.string()).min(1), // Which products are included
14
+ requiredQuantity: z.number().positive(), // How many items needed (e.g., 3)
15
+ bundlePrice: z.number().positive(), // Total price for the bundle (e.g., $25)
16
+ }),
17
+ ]);
18
+
19
+ export const DiscountSchema = z.object({
20
+ type: z.literal("Discount"),
21
+ storeId: z.string().min(1),
22
+ companyId: z.string().min(1),
23
+ id: z.string().min(1),
24
+ name: z.array(z.object({ lang: z.enum(["he"]), value: z.string() })),
25
+ active: z.boolean(),
26
+ startDate: z.number(),
27
+ endDate: z.number(),
28
+ variant: DiscountVariantSchema,
29
+ conditions: DiscountConditionsSchema,
30
+ });
31
+
32
+ export type TDiscount = z.infer<typeof DiscountSchema>;
33
+ export type DiscountVariant = z.infer<typeof DiscountVariantSchema>;
34
+ export type DiscountConditions = z.infer<typeof DiscountConditionsSchema>;
35
+
36
+ // Simple result types
37
+ export interface DiscountResult {
38
+ applicable: boolean;
39
+ discountAmount: number;
40
+ affectedItems: Array<{
41
+ productId: string;
42
+ quantity: number;
43
+ originalPrice: number;
44
+ discountedPrice: number;
45
+ discountAmount: number;
46
+ }>;
47
+ }
48
+
49
+ export interface AppliedDiscount {
50
+ discountId: string;
51
+ discountName: string;
52
+ discountAmount: number;
53
+ affectedItems: DiscountResult["affectedItems"];
54
+ }
55
+
56
+ export interface DiscountContext {
57
+ cart: Array<{
58
+ amount: number;
59
+ product: {
60
+ id: string;
61
+ price: number;
62
+ };
63
+ }>;
64
+ user?: Record<string, unknown>;
65
+ appliedDiscounts: AppliedDiscount[];
66
+ }
67
+
68
+
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Utility functions for discount calculations
3
+ */
4
+
5
+ /**
6
+ * Formats a number to 2 decimal places and returns as a number
7
+ * @param value - The number to format
8
+ * @returns The formatted number with 2 decimal places
9
+ */
10
+ export function formatCurrency(value: number): number {
11
+ return Number(value.toFixed(2));
12
+ }
13
+
14
+ /**
15
+ * Formats a number to 2 decimal places and returns as a string
16
+ * @param value - The number to format
17
+ * @returns The formatted string with 2 decimal places
18
+ */
19
+ export function formatCurrencyString(value: number): string {
20
+ return value.toFixed(2);
21
+ }
22
+
23
+ /**
24
+ * Ensures a monetary value is never negative
25
+ * @param value - The value to check
26
+ * @returns The value, or 0 if negative
27
+ */
28
+ export function ensureNonNegative(value: number): number {
29
+ return Math.max(0, formatCurrency(value));
30
+ }
31
+
32
+ /**
33
+ * Calculates the percentage discount
34
+ * @param originalPrice - The original price
35
+ * @param discountedPrice - The discounted price
36
+ * @returns The percentage discount (0-100)
37
+ */
38
+ export function calculatePercentageDiscount(originalPrice: number, discountedPrice: number): number {
39
+ if (originalPrice <= 0) return 0;
40
+ const discount = originalPrice - discountedPrice;
41
+ return formatCurrency((discount / originalPrice) * 100);
42
+ }
@@ -1,4 +1,5 @@
1
1
  import { TCart, TDiscount, TProduct, TStore } from "../entities";
2
+ import { DiscountEngine } from "../entities/Discount/engine";
2
3
 
3
4
  const CONFIG = {
4
5
  VAT: 18,
@@ -26,10 +27,6 @@ function getPriceAfterDiscount(product: TProduct) {
26
27
  return product.price;
27
28
  }
28
29
 
29
- // mark product that used in discount
30
- // get final price for product and discount id
31
- // filter better discount
32
-
33
30
  // main
34
31
  export function getCartCost({
35
32
  cart,
@@ -41,89 +38,31 @@ export function getCartCost({
41
38
  store: TStore;
42
39
  }) {
43
40
  const { isVatIncludedInPrice } = store;
44
- let result = cart.map((item) => {
41
+
42
+ // Convert cart items to the format expected by the discount engine
43
+ const cartForEngine = cart.map(item => ({
44
+ amount: item.amount,
45
+ product: {
46
+ id: item.product.id,
47
+ price: item.product.price,
48
+ },
49
+ }));
50
+
51
+ // Apply discounts using the new discount engine
52
+ const discountResult = DiscountEngine.calculateDiscounts(cartForEngine, discounts);
53
+
54
+ // Map the results back to the original format with additional product info
55
+ const result = cart.map((item, index) => {
56
+ const engineItem = discountResult.items[index];
45
57
  return {
46
58
  amount: item.amount,
47
59
  product: { ...item.product },
48
60
  originalPrice: item.product.price,
49
- finalPrice: getPriceAfterDiscount(item.product),
50
- finalDiscount: calculateDiscount(item.product),
61
+ finalPrice: engineItem ? engineItem.finalPrice : getPriceAfterDiscount(item.product),
62
+ finalDiscount: engineItem ? engineItem.finalDiscount : calculateDiscount(item.product),
51
63
  };
52
64
  });
53
65
 
54
- // calculate delivery price before
55
- // check if cart cost is greater than free delivery price
56
-
57
- const activeDiscounts = discounts.filter((discount) => {
58
- if (discount.variant.variantType === "bundle") {
59
- const productsTotal =
60
- cart?.reduce((total, item) => {
61
- if (discount.variant.productsId.includes(item.product.id)) {
62
- total += item.amount;
63
- return total;
64
- }
65
- return total;
66
- }, 0) ?? 0;
67
- if (productsTotal >= discount.variant.requiredQuantity) {
68
- // const times = Math.floor(productsTotal / discount.variant.requiredQuantity);
69
- // console.log("yes", times, discount.variant.discountPrice);
70
- return true;
71
- }
72
- }
73
- return false;
74
- });
75
- console.log("activeDiscounts", activeDiscounts);
76
-
77
- activeDiscounts.forEach((discount) => {
78
- if (discount.variant.variantType === "bundle") {
79
- // get all products in cart
80
- const products = cart.filter((item) =>
81
- discount.variant.productsId.includes(item.product.id)
82
- );
83
- const productsTotal =
84
- products?.reduce((total, item) => {
85
- if (discount.variant.productsId.includes(item.product.id)) {
86
- total += item.amount;
87
- return total;
88
- }
89
- return total;
90
- }, 0) ?? 0;
91
-
92
- const times = Math.floor(productsTotal / discount.variant.requiredQuantity);
93
- const price = getPriceAfterDiscount(products[0]?.product);
94
- const _discount = calculateDiscount(products[0]?.product);
95
- console.log("price", price, _discount);
96
- const discountPrice =
97
- Number(
98
- (discount.variant.discountPrice / discount.variant.requiredQuantity).toFixed(2)
99
- ) * 1;
100
-
101
- console.log("discountPrice", discountPrice);
102
- const totalDiscount =
103
- (price * discount.variant.requiredQuantity - discount.variant.discountPrice) * times;
104
-
105
- const originalPrice = productsTotal * price;
106
- const discountPriceFinal = originalPrice - totalDiscount;
107
-
108
- const averagePrice = Number((discountPriceFinal / productsTotal).toFixed(2));
109
-
110
- result = result.map((item) => {
111
- if (discount.variant.productsId.includes(item.product.id)) {
112
- return {
113
- ...item,
114
- finalPrice: averagePrice,
115
- originalPrice: item.product.price,
116
- discountPrice: price,
117
- finalDiscount: item.finalDiscount + (item.product.price - averagePrice),
118
- };
119
- }
120
- return item;
121
- });
122
-
123
- // find average price
124
- }
125
- });
126
-
127
66
  const cartDetails = result.reduce(
128
67
  (acc, item) => {
129
68
  const { product, amount, finalPrice, finalDiscount } = item;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsdev_ninja/core",
3
- "version": "0.12.6",
3
+ "version": "0.12.8",
4
4
  "main": "dist/core.cjs.js",
5
5
  "module": "dist/core.es.js",
6
6
  "types": "dist/index.d.ts",
@@ -12,15 +12,16 @@
12
12
  "build": "vite build && tsc -b",
13
13
  "lint": "eslint .",
14
14
  "preview": "vite preview",
15
- "publish_core": "yarn publish --non-interactive"
15
+ "publish_core": "yarn publish --non-interactive",
16
+ "test": "vitest",
17
+ "test:run": "vitest run"
16
18
  },
17
19
  "dependencies": {
18
20
  "zod": "^3.23.8"
19
21
  },
20
22
  "devDependencies": {
21
- "react": "^18.3.1",
22
- "react-dom": "^18.3.1",
23
23
  "@eslint/js": "^9.9.0",
24
+ "@types/node": "^24.0.15",
24
25
  "@types/react": "^18.3.3",
25
26
  "@types/react-dom": "^18.3.0",
26
27
  "@vitejs/plugin-react-swc": "^3.5.0",
@@ -28,8 +29,12 @@
28
29
  "eslint-plugin-react-hooks": "^5.1.0-rc.0",
29
30
  "eslint-plugin-react-refresh": "^0.4.9",
30
31
  "globals": "^15.9.0",
32
+ "react": "^18.3.1",
33
+ "react-dom": "^18.3.1",
34
+ "ts-node": "^10.9.2",
31
35
  "typescript": "^5.5.3",
32
36
  "typescript-eslint": "^8.0.1",
33
- "vite": "^5.4.1"
37
+ "vite": "^5.4.1",
38
+ "vitest": "^3.2.4"
34
39
  }
35
40
  }
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: 'node',
7
+ include: ['**/__tests__/**/*.test.ts', '**/*.test.ts'],
8
+ exclude: ['node_modules', 'dist'],
9
+ },
10
+ });
@@ -1,71 +0,0 @@
1
- import { z } from "zod";
2
- export declare const DiscountSchema: z.ZodObject<{
3
- type: z.ZodLiteral<"Discount">;
4
- storeId: z.ZodString;
5
- companyId: z.ZodString;
6
- id: z.ZodString;
7
- name: z.ZodArray<z.ZodObject<{
8
- lang: z.ZodEnum<["he"]>;
9
- value: z.ZodString;
10
- }, "strip", z.ZodTypeAny, {
11
- value: string;
12
- lang: "he";
13
- }, {
14
- value: string;
15
- lang: "he";
16
- }>, "many">;
17
- active: z.ZodBoolean;
18
- variant: z.ZodDiscriminatedUnion<"variantType", [z.ZodObject<{
19
- variantType: z.ZodLiteral<"bundle">;
20
- productsId: z.ZodArray<z.ZodString, "many">;
21
- requiredQuantity: z.ZodNumber;
22
- discountPrice: z.ZodNumber;
23
- }, "strip", z.ZodTypeAny, {
24
- variantType: "bundle";
25
- productsId: string[];
26
- requiredQuantity: number;
27
- discountPrice: number;
28
- }, {
29
- variantType: "bundle";
30
- productsId: string[];
31
- requiredQuantity: number;
32
- discountPrice: number;
33
- }>]>;
34
- images: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
35
- }, "strip", z.ZodTypeAny, {
36
- type: "Discount";
37
- id: string;
38
- companyId: string;
39
- storeId: string;
40
- name: {
41
- value: string;
42
- lang: "he";
43
- }[];
44
- active: boolean;
45
- variant: {
46
- variantType: "bundle";
47
- productsId: string[];
48
- requiredQuantity: number;
49
- discountPrice: number;
50
- };
51
- images?: string[] | undefined;
52
- }, {
53
- type: "Discount";
54
- id: string;
55
- companyId: string;
56
- storeId: string;
57
- name: {
58
- value: string;
59
- lang: "he";
60
- }[];
61
- active: boolean;
62
- variant: {
63
- variantType: "bundle";
64
- productsId: string[];
65
- requiredQuantity: number;
66
- discountPrice: number;
67
- };
68
- images?: string[] | undefined;
69
- }>;
70
- export type TDiscount = z.infer<typeof DiscountSchema>;
71
- //# sourceMappingURL=Discount.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Discount.d.ts","sourceRoot":"","sources":["../../lib/entities/Discount.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgBzB,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC"}
@@ -1,20 +0,0 @@
1
- import { z } from "zod";
2
- import { LocaleSchema } from "./Locale";
3
- const text = z.string().min(1);
4
- export const DiscountSchema = z.object({
5
- type: z.literal("Discount"),
6
- storeId: text,
7
- companyId: text,
8
- id: text,
9
- name: z.array(LocaleSchema),
10
- active: z.boolean(),
11
- variant: z.discriminatedUnion("variantType", [
12
- z.object({
13
- variantType: z.literal("bundle"),
14
- productsId: z.array(z.string()).min(1),
15
- requiredQuantity: z.number().positive(),
16
- discountPrice: z.number().positive(),
17
- }),
18
- ]),
19
- images: z.array(z.string().nonempty()).optional(),
20
- });