@endora-commerce/mod-promotions 0.100.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 (183) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -0
  3. package/dist/admin/api/promotions-client.d.ts +98 -0
  4. package/dist/admin/api/promotions-client.d.ts.map +1 -0
  5. package/dist/admin/api/promotions-client.js +40 -0
  6. package/dist/admin/api/promotions-client.js.map +1 -0
  7. package/dist/admin/components/CouponGeneratorForm.d.ts +10 -0
  8. package/dist/admin/components/CouponGeneratorForm.d.ts.map +1 -0
  9. package/dist/admin/components/CouponGeneratorForm.js +56 -0
  10. package/dist/admin/components/CouponGeneratorForm.js.map +1 -0
  11. package/dist/admin/index.d.ts +43 -0
  12. package/dist/admin/index.d.ts.map +1 -0
  13. package/dist/admin/index.js +69 -0
  14. package/dist/admin/index.js.map +1 -0
  15. package/dist/admin/pages/PromotionEditPage.d.ts +9 -0
  16. package/dist/admin/pages/PromotionEditPage.d.ts.map +1 -0
  17. package/dist/admin/pages/PromotionEditPage.js +333 -0
  18. package/dist/admin/pages/PromotionEditPage.js.map +1 -0
  19. package/dist/admin/pages/PromotionRulesPage.d.ts +14 -0
  20. package/dist/admin/pages/PromotionRulesPage.d.ts.map +1 -0
  21. package/dist/admin/pages/PromotionRulesPage.js +86 -0
  22. package/dist/admin/pages/PromotionRulesPage.js.map +1 -0
  23. package/dist/admin/pages/PromotionStatsPage.d.ts +13 -0
  24. package/dist/admin/pages/PromotionStatsPage.d.ts.map +1 -0
  25. package/dist/admin/pages/PromotionStatsPage.js +44 -0
  26. package/dist/admin/pages/PromotionStatsPage.js.map +1 -0
  27. package/dist/admin/pages/PromotionsPage.d.ts +9 -0
  28. package/dist/admin/pages/PromotionsPage.d.ts.map +1 -0
  29. package/dist/admin/pages/PromotionsPage.js +79 -0
  30. package/dist/admin/pages/PromotionsPage.js.map +1 -0
  31. package/dist/backend/actions/amount-off-cart.d.ts +4 -0
  32. package/dist/backend/actions/amount-off-cart.d.ts.map +1 -0
  33. package/dist/backend/actions/amount-off-cart.js +16 -0
  34. package/dist/backend/actions/amount-off-cart.js.map +1 -0
  35. package/dist/backend/actions/buy-x-get-y-free.d.ts +8 -0
  36. package/dist/backend/actions/buy-x-get-y-free.d.ts.map +1 -0
  37. package/dist/backend/actions/buy-x-get-y-free.js +20 -0
  38. package/dist/backend/actions/buy-x-get-y-free.js.map +1 -0
  39. package/dist/backend/actions/buy-x-units-amount-off.d.ts +4 -0
  40. package/dist/backend/actions/buy-x-units-amount-off.d.ts.map +1 -0
  41. package/dist/backend/actions/buy-x-units-amount-off.js +19 -0
  42. package/dist/backend/actions/buy-x-units-amount-off.js.map +1 -0
  43. package/dist/backend/actions/buy-x-units-percent-off.d.ts +4 -0
  44. package/dist/backend/actions/buy-x-units-percent-off.d.ts.map +1 -0
  45. package/dist/backend/actions/buy-x-units-percent-off.js +15 -0
  46. package/dist/backend/actions/buy-x-units-percent-off.js.map +1 -0
  47. package/dist/backend/actions/buy-x-units-y-free.d.ts +7 -0
  48. package/dist/backend/actions/buy-x-units-y-free.d.ts.map +1 -0
  49. package/dist/backend/actions/buy-x-units-y-free.js +21 -0
  50. package/dist/backend/actions/buy-x-units-y-free.js.map +1 -0
  51. package/dist/backend/actions/every-nth-product-percent-off.d.ts +7 -0
  52. package/dist/backend/actions/every-nth-product-percent-off.d.ts.map +1 -0
  53. package/dist/backend/actions/every-nth-product-percent-off.js +17 -0
  54. package/dist/backend/actions/every-nth-product-percent-off.js.map +1 -0
  55. package/dist/backend/actions/free-delivery.d.ts +4 -0
  56. package/dist/backend/actions/free-delivery.d.ts.map +1 -0
  57. package/dist/backend/actions/free-delivery.js +11 -0
  58. package/dist/backend/actions/free-delivery.js.map +1 -0
  59. package/dist/backend/actions/percentage-off-cart.d.ts +4 -0
  60. package/dist/backend/actions/percentage-off-cart.d.ts.map +1 -0
  61. package/dist/backend/actions/percentage-off-cart.js +11 -0
  62. package/dist/backend/actions/percentage-off-cart.js.map +1 -0
  63. package/dist/backend/actions/spend-x-amount-off.d.ts +4 -0
  64. package/dist/backend/actions/spend-x-amount-off.d.ts.map +1 -0
  65. package/dist/backend/actions/spend-x-amount-off.js +17 -0
  66. package/dist/backend/actions/spend-x-amount-off.js.map +1 -0
  67. package/dist/backend/actions/spend-x-percent-off.d.ts +4 -0
  68. package/dist/backend/actions/spend-x-percent-off.d.ts.map +1 -0
  69. package/dist/backend/actions/spend-x-percent-off.js +18 -0
  70. package/dist/backend/actions/spend-x-percent-off.js.map +1 -0
  71. package/dist/backend/actions/types.d.ts +37 -0
  72. package/dist/backend/actions/types.d.ts.map +1 -0
  73. package/dist/backend/actions/types.js +2 -0
  74. package/dist/backend/actions/types.js.map +1 -0
  75. package/dist/backend/actions/util.d.ts +13 -0
  76. package/dist/backend/actions/util.d.ts.map +1 -0
  77. package/dist/backend/actions/util.js +18 -0
  78. package/dist/backend/actions/util.js.map +1 -0
  79. package/dist/backend/entities/coupon-batch.entity.d.ts +21 -0
  80. package/dist/backend/entities/coupon-batch.entity.d.ts.map +1 -0
  81. package/dist/backend/entities/coupon-batch.entity.js +78 -0
  82. package/dist/backend/entities/coupon-batch.entity.js.map +1 -0
  83. package/dist/backend/entities/promotion-coupon.entity.d.ts +17 -0
  84. package/dist/backend/entities/promotion-coupon.entity.d.ts.map +1 -0
  85. package/dist/backend/entities/promotion-coupon.entity.js +64 -0
  86. package/dist/backend/entities/promotion-coupon.entity.js.map +1 -0
  87. package/dist/backend/entities/promotion-rule.entity.d.ts +16 -0
  88. package/dist/backend/entities/promotion-rule.entity.d.ts.map +1 -0
  89. package/dist/backend/entities/promotion-rule.entity.js +57 -0
  90. package/dist/backend/entities/promotion-rule.entity.js.map +1 -0
  91. package/dist/backend/entities/promotion-usage-counter.entity.d.ts +15 -0
  92. package/dist/backend/entities/promotion-usage-counter.entity.d.ts.map +1 -0
  93. package/dist/backend/entities/promotion-usage-counter.entity.js +48 -0
  94. package/dist/backend/entities/promotion-usage-counter.entity.js.map +1 -0
  95. package/dist/backend/entities/promotion-usage.entity.d.ts +21 -0
  96. package/dist/backend/entities/promotion-usage.entity.d.ts.map +1 -0
  97. package/dist/backend/entities/promotion-usage.entity.js +89 -0
  98. package/dist/backend/entities/promotion-usage.entity.js.map +1 -0
  99. package/dist/backend/entities/promotion.entity.d.ts +63 -0
  100. package/dist/backend/entities/promotion.entity.d.ts.map +1 -0
  101. package/dist/backend/entities/promotion.entity.js +194 -0
  102. package/dist/backend/entities/promotion.entity.js.map +1 -0
  103. package/dist/backend/index.d.ts +124 -0
  104. package/dist/backend/index.d.ts.map +1 -0
  105. package/dist/backend/index.js +182 -0
  106. package/dist/backend/index.js.map +1 -0
  107. package/dist/backend/routes.d.ts +88 -0
  108. package/dist/backend/routes.d.ts.map +1 -0
  109. package/dist/backend/routes.js +256 -0
  110. package/dist/backend/routes.js.map +1 -0
  111. package/dist/backend/services/coupon-service.d.ts +40 -0
  112. package/dist/backend/services/coupon-service.d.ts.map +1 -0
  113. package/dist/backend/services/coupon-service.js +178 -0
  114. package/dist/backend/services/coupon-service.js.map +1 -0
  115. package/dist/backend/services/promotion-action-registry.d.ts +20 -0
  116. package/dist/backend/services/promotion-action-registry.d.ts.map +1 -0
  117. package/dist/backend/services/promotion-action-registry.js +57 -0
  118. package/dist/backend/services/promotion-action-registry.js.map +1 -0
  119. package/dist/backend/services/promotion-code-port.d.ts +24 -0
  120. package/dist/backend/services/promotion-code-port.d.ts.map +1 -0
  121. package/dist/backend/services/promotion-code-port.js +53 -0
  122. package/dist/backend/services/promotion-code-port.js.map +1 -0
  123. package/dist/backend/services/promotion-currency-reference.d.ts +13 -0
  124. package/dist/backend/services/promotion-currency-reference.d.ts.map +1 -0
  125. package/dist/backend/services/promotion-currency-reference.js +25 -0
  126. package/dist/backend/services/promotion-currency-reference.js.map +1 -0
  127. package/dist/backend/services/promotion-rule-evaluator.d.ts +32 -0
  128. package/dist/backend/services/promotion-rule-evaluator.d.ts.map +1 -0
  129. package/dist/backend/services/promotion-rule-evaluator.js +131 -0
  130. package/dist/backend/services/promotion-rule-evaluator.js.map +1 -0
  131. package/dist/backend/services/promotion-rule-service.d.ts +62 -0
  132. package/dist/backend/services/promotion-rule-service.d.ts.map +1 -0
  133. package/dist/backend/services/promotion-rule-service.js +95 -0
  134. package/dist/backend/services/promotion-rule-service.js.map +1 -0
  135. package/dist/backend/services/promotion-rule-store.d.ts +33 -0
  136. package/dist/backend/services/promotion-rule-store.d.ts.map +1 -0
  137. package/dist/backend/services/promotion-rule-store.js +88 -0
  138. package/dist/backend/services/promotion-rule-store.js.map +1 -0
  139. package/dist/backend/services/promotion-service.d.ts +312 -0
  140. package/dist/backend/services/promotion-service.d.ts.map +1 -0
  141. package/dist/backend/services/promotion-service.js +762 -0
  142. package/dist/backend/services/promotion-service.js.map +1 -0
  143. package/dist/backend/services/promotion-stats-service.d.ts +15 -0
  144. package/dist/backend/services/promotion-stats-service.d.ts.map +1 -0
  145. package/dist/backend/services/promotion-stats-service.js +66 -0
  146. package/dist/backend/services/promotion-stats-service.js.map +1 -0
  147. package/dist/backend/services/promotion-usage-service.d.ts +46 -0
  148. package/dist/backend/services/promotion-usage-service.d.ts.map +1 -0
  149. package/dist/backend/services/promotion-usage-service.js +168 -0
  150. package/dist/backend/services/promotion-usage-service.js.map +1 -0
  151. package/dist/manifest.d.ts +172 -0
  152. package/dist/manifest.d.ts.map +1 -0
  153. package/dist/manifest.js +140 -0
  154. package/dist/manifest.js.map +1 -0
  155. package/dist/migrations/20260505T074605_promotions_criteria.d.ts +19 -0
  156. package/dist/migrations/20260505T074605_promotions_criteria.d.ts.map +1 -0
  157. package/dist/migrations/20260505T074605_promotions_criteria.js +23 -0
  158. package/dist/migrations/20260505T074605_promotions_criteria.js.map +1 -0
  159. package/dist/migrations/20260618T100727_promotions_engine.d.ts +19 -0
  160. package/dist/migrations/20260618T100727_promotions_engine.d.ts.map +1 -0
  161. package/dist/migrations/20260618T100727_promotions_engine.js +148 -0
  162. package/dist/migrations/20260618T100727_promotions_engine.js.map +1 -0
  163. package/dist/migrations/20260818T081251_promotions_promotion_usage_order_fk.d.ts +42 -0
  164. package/dist/migrations/20260818T081251_promotions_promotion_usage_order_fk.d.ts.map +1 -0
  165. package/dist/migrations/20260818T081251_promotions_promotion_usage_order_fk.js +76 -0
  166. package/dist/migrations/20260818T081251_promotions_promotion_usage_order_fk.js.map +1 -0
  167. package/dist/migrations/20260912T094715_promotions_sales_channel_promotions.d.ts +27 -0
  168. package/dist/migrations/20260912T094715_promotions_sales_channel_promotions.d.ts.map +1 -0
  169. package/dist/migrations/20260912T094715_promotions_sales_channel_promotions.js +44 -0
  170. package/dist/migrations/20260912T094715_promotions_sales_channel_promotions.js.map +1 -0
  171. package/dist/migrations/index.d.ts +39 -0
  172. package/dist/migrations/index.d.ts.map +1 -0
  173. package/dist/migrations/index.js +44 -0
  174. package/dist/migrations/index.js.map +1 -0
  175. package/dist/ports/index.d.ts +106 -0
  176. package/dist/ports/index.d.ts.map +1 -0
  177. package/dist/ports/index.js +2 -0
  178. package/dist/ports/index.js.map +1 -0
  179. package/docs/promotions.md +96 -0
  180. package/i18n/en.json +34 -0
  181. package/i18n/pl.json +34 -0
  182. package/package.json +101 -0
  183. package/tailwind.css +14 -0
@@ -0,0 +1,333 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import { useNavigate, useParams } from 'react-router-dom';
4
+ import { Check, Copy } from 'lucide-react';
5
+ import { ApiError, usePageSizePreference } from '@endora-commerce/admin-kit/lib';
6
+ import { Alert, AlertDescription, Badge, Button, Card, CardContent, CardHeader, CardTitle, Checkbox, Input, Label, PageHeader, Select, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@endora-commerce/admin-kit/ui';
7
+ import { PaginationFooter, RuleBuilder } from '@endora-commerce/admin-kit/components';
8
+ import { useTranslation } from '@endora-commerce/admin-kit/i18n';
9
+ import { promotionsClient, promotionRulesClient } from '../api/promotions-client.js';
10
+ import { CouponGeneratorForm } from '../components/CouponGeneratorForm.js';
11
+ const ACTION_TYPES = [
12
+ 'free_delivery',
13
+ 'percentage_off_cart',
14
+ 'amount_off_cart',
15
+ 'buy_x_get_y_free',
16
+ 'spend_x_percent_off',
17
+ 'spend_x_amount_off',
18
+ 'every_nth_product_percent_off',
19
+ 'buy_x_units_y_free',
20
+ 'buy_x_units_percent_off',
21
+ 'buy_x_units_amount_off',
22
+ ];
23
+ /** Deep-copy a rule definition so the promotion owns an independent snapshot. */
24
+ function cloneRule(rule) {
25
+ return JSON.parse(JSON.stringify(rule));
26
+ }
27
+ function defaultAction(type) {
28
+ switch (type) {
29
+ case 'free_delivery':
30
+ return { type };
31
+ case 'percentage_off_cart':
32
+ return { type, percent: 10 };
33
+ case 'amount_off_cart':
34
+ return { type, amount: 10, currency: 'PLN' };
35
+ case 'buy_x_get_y_free':
36
+ return { type, buyQuantity: 2, freeQuantity: 1, target: 'cheapest' };
37
+ case 'spend_x_percent_off':
38
+ return { type, spendStep: 100, percent: 5, currency: 'PLN' };
39
+ case 'spend_x_amount_off':
40
+ return { type, spendStep: 100, amount: 5, currency: 'PLN' };
41
+ case 'every_nth_product_percent_off':
42
+ return { type, nth: 3, percent: 50 };
43
+ case 'buy_x_units_y_free':
44
+ return { type, productId: '', buyUnits: 2, freeUnits: 1 };
45
+ case 'buy_x_units_percent_off':
46
+ return { type, productId: '', buyUnits: 3, percent: 10 };
47
+ case 'buy_x_units_amount_off':
48
+ return { type, productId: '', buyUnits: 3, amount: 10, currency: 'PLN' };
49
+ }
50
+ }
51
+ export const PromotionEditPage = () => {
52
+ const t = useTranslation('core');
53
+ const navigate = useNavigate();
54
+ const { id } = useParams();
55
+ const isNew = !id;
56
+ const [name, setName] = useState('');
57
+ const [description, setDescription] = useState('');
58
+ const [code, setCode] = useState('');
59
+ const [isActive, setIsActive] = useState(true);
60
+ const [priority, setPriority] = useState(0);
61
+ const [stopFurther, setStopFurther] = useState(false);
62
+ const [action, setAction] = useState(defaultAction('percentage_off_cart'));
63
+ const [rule, setRule] = useState({ kind: 'all' });
64
+ const [savedRules, setSavedRules] = useState([]);
65
+ // Legacy promotions that linked a saved rule by id: resolved into an
66
+ // independent snapshot once `savedRules` has loaded.
67
+ const [pendingRuleId, setPendingRuleId] = useState(null);
68
+ const [usageGlobal, setUsageGlobal] = useState('');
69
+ const [usagePerOrg, setUsagePerOrg] = useState('');
70
+ const [usagePerCustomer, setUsagePerCustomer] = useState('');
71
+ const [attributeFields, setAttributeFields] = useState([]);
72
+ const [fieldOptions, setFieldOptions] = useState({});
73
+ const [error, setError] = useState(null);
74
+ const [loading, setLoading] = useState(!isNew);
75
+ const [saving, setSaving] = useState(false);
76
+ useEffect(() => {
77
+ void promotionsClient
78
+ .ruleAttributes()
79
+ .then((items) => setAttributeFields(items.map((a) => ({ attributeKey: a.key, label: a.labelDefault || a.key }))))
80
+ .catch(() => setAttributeFields([]));
81
+ void promotionRulesClient.list().then(setSavedRules).catch(() => setSavedRules([]));
82
+ void (async () => {
83
+ try {
84
+ const [groups, orgs, cats, pays, ships] = await Promise.all([
85
+ promotionsClient.ruleTarget('customer-groups'),
86
+ promotionsClient.ruleTarget('organizations'),
87
+ promotionsClient.ruleTarget('categories'),
88
+ promotionsClient.ruleTarget('payment-methods'),
89
+ promotionsClient.ruleTarget('delivery-methods'),
90
+ ]);
91
+ setFieldOptions({
92
+ customerGroup: groups.map((g) => ({ value: g.id, label: g.name || g.code || g.id })),
93
+ organization: orgs.map((o) => ({ value: o.id, label: o.name || o.id })),
94
+ category: cats.map((c) => ({ value: c.id, label: c.name || c.slug || c.id })),
95
+ paymentMethod: pays.map((p) => ({ value: p.code ?? p.id, label: p.name || p.code || p.id })),
96
+ deliveryMethod: ships.map((s) => ({ value: s.code ?? s.id, label: s.name || s.code || s.id })),
97
+ });
98
+ }
99
+ catch {
100
+ setFieldOptions({});
101
+ }
102
+ })();
103
+ }, []);
104
+ useEffect(() => {
105
+ if (isNew)
106
+ return;
107
+ setLoading(true);
108
+ void promotionsClient
109
+ .get(id)
110
+ .then((p) => {
111
+ setName(p.name);
112
+ setDescription(p.description ?? '');
113
+ setCode(p.code ?? '');
114
+ setIsActive(p.isActive);
115
+ setPriority(p.priority);
116
+ setStopFurther(p.stopFurther);
117
+ if (p.action)
118
+ setAction(p.action);
119
+ if (p.rule) {
120
+ setRule(p.rule);
121
+ }
122
+ else if (p.ruleId) {
123
+ setPendingRuleId(p.ruleId);
124
+ }
125
+ else {
126
+ setRule({ kind: 'all' });
127
+ }
128
+ setUsageGlobal(p.usageLimitGlobal != null ? String(p.usageLimitGlobal) : '');
129
+ setUsagePerOrg(p.usageLimitPerOrganization != null ? String(p.usageLimitPerOrganization) : '');
130
+ setUsagePerCustomer(p.usageLimitPerCustomer != null ? String(p.usageLimitPerCustomer) : '');
131
+ })
132
+ .catch((err) => setError(err instanceof ApiError ? err.envelope.error.message : t('promotions.error.load')))
133
+ .finally(() => setLoading(false));
134
+ }, [id, isNew, t]);
135
+ // Resolve a legacy linked rule into an independent snapshot once the saved
136
+ // rule list is available.
137
+ useEffect(() => {
138
+ if (!pendingRuleId)
139
+ return;
140
+ const found = savedRules.find((r) => r.id === pendingRuleId);
141
+ if (found) {
142
+ setRule(cloneRule(found.definition));
143
+ setPendingRuleId(null);
144
+ }
145
+ }, [pendingRuleId, savedRules]);
146
+ const intOrNull = (s) => {
147
+ const n = Number(s);
148
+ return s.trim() === '' || !Number.isFinite(n) ? null : Math.trunc(n);
149
+ };
150
+ const onSubmit = useCallback(async (e) => {
151
+ e.preventDefault();
152
+ setError(null);
153
+ setSaving(true);
154
+ try {
155
+ const payload = {
156
+ name,
157
+ description: description.trim() === '' ? null : description,
158
+ isActive,
159
+ priority,
160
+ stopFurther,
161
+ action,
162
+ rule,
163
+ code: code.trim() === '' ? null : code,
164
+ usageLimitGlobal: intOrNull(usageGlobal),
165
+ usageLimitPerOrganization: intOrNull(usagePerOrg),
166
+ usageLimitPerCustomer: intOrNull(usagePerCustomer),
167
+ };
168
+ if (isNew)
169
+ await promotionsClient.create(payload);
170
+ else
171
+ await promotionsClient.update(id, payload);
172
+ navigate('/promotions');
173
+ }
174
+ catch (err) {
175
+ setError(err instanceof ApiError ? err.envelope.error.message : t('promotions.error.save'));
176
+ }
177
+ finally {
178
+ setSaving(false);
179
+ }
180
+ }, [
181
+ name, description, isActive, priority, stopFurther, action, rule, code,
182
+ usageGlobal, usagePerOrg, usagePerCustomer, isNew, id, navigate, t,
183
+ ]);
184
+ if (loading)
185
+ return _jsx("p", { className: "p-4 text-sm text-muted-foreground", children: t('promotions.loading') });
186
+ return (_jsxs(_Fragment, { children: [_jsx(PageHeader, { title: isNew ? t('promotions.edit.titleNew') : t('promotions.edit.titleEdit'), description: t('promotions.edit.description') }), error ? (_jsx(Alert, { variant: "destructive", className: "mb-4", children: _jsx(AlertDescription, { children: error }) })) : null, _jsxs("form", { onSubmit: onSubmit, className: "flex flex-col gap-4", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('promotions.edit.general') }) }), _jsxs(CardContent, { className: "grid gap-4 md:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "name", children: t('promotions.field.name') }), _jsx(Input, { id: "name", value: name, onChange: (e) => setName(e.target.value), required: true })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "code", children: t('promotions.field.code') }), _jsx(Input, { id: "code", value: code, onChange: (e) => setCode(e.target.value) })] }), _jsxs("div", { className: "flex flex-col gap-1 md:col-span-2", children: [_jsx(Label, { htmlFor: "description", children: t('promotions.field.description') }), _jsx(Input, { id: "description", value: description, onChange: (e) => setDescription(e.target.value) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "priority", children: t('promotions.field.priority') }), _jsx(Input, { id: "priority", type: "number", value: priority, onChange: (e) => setPriority(Math.trunc(Number(e.target.value) || 0)) })] }), _jsxs("div", { className: "flex items-center gap-4 pt-6", children: [_jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { checked: isActive, onChange: (e) => setIsActive(e.target.checked) }), t('promotions.field.active')] }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { checked: stopFurther, onChange: (e) => setStopFurther(e.target.checked) }), t('promotions.field.stopFurther')] })] })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('promotions.edit.action') }) }), _jsxs(CardContent, { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { children: t('promotions.edit.actionType') }), _jsx(Select, { className: "w-72", value: action.type, onChange: (e) => setAction(defaultAction(e.target.value)), children: ACTION_TYPES.map((tpe) => (_jsx("option", { value: tpe, children: t(`action.${tpe}`) }, tpe))) })] }), _jsx(ActionConfigEditor, { action: action, onChange: setAction })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('promotions.edit.rule') }) }), _jsxs(CardContent, { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "ruleCopyFrom", children: t('promotions.edit.ruleCopyFrom') }), _jsxs(Select, { id: "ruleCopyFrom", className: "w-72", value: "", disabled: savedRules.length === 0, onChange: (e) => {
187
+ const found = savedRules.find((r) => r.id === e.target.value);
188
+ if (found)
189
+ setRule(cloneRule(found.definition));
190
+ }, children: [_jsx("option", { value: "", children: "\u2014" }), savedRules.map((r) => (_jsx("option", { value: r.id, children: r.name }, r.id)))] }), _jsx("p", { className: "text-xs text-muted-foreground", children: t('promotions.edit.ruleCopyHint') })] }), _jsx(RuleBuilder, { value: rule, onChange: setRule, attributeFields: attributeFields, fieldOptions: fieldOptions,
191
+ // This screen has option sets too (payment and delivery methods),
192
+ // so it gets the same value picker — and its copy translated
193
+ // rather than the component's English fallback.
194
+ labels: {
195
+ valuesPlaceholder: t('ruleBuilder.values.placeholder'),
196
+ valuesLabel: t('ruleBuilder.values.label'),
197
+ valuesSearchPlaceholder: t('ruleBuilder.values.search'),
198
+ } })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('promotions.edit.limits') }) }), _jsxs(CardContent, { className: "grid gap-4 md:grid-cols-3", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "ug", children: t('limits.global') }), _jsx(Input, { id: "ug", type: "number", value: usageGlobal, onChange: (e) => setUsageGlobal(e.target.value) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "uo", children: t('limits.perOrganization') }), _jsx(Input, { id: "uo", type: "number", value: usagePerOrg, onChange: (e) => setUsagePerOrg(e.target.value) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "uc", children: t('limits.perCustomer') }), _jsx(Input, { id: "uc", type: "number", value: usagePerCustomer, onChange: (e) => setUsagePerCustomer(e.target.value) })] })] })] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { type: "submit", disabled: saving, children: saving ? t('promotions.loading') : t('promotions.edit.save') }), _jsx(Button, { type: "button", variant: "outline", onClick: () => navigate('/promotions'), children: t('promotions.edit.cancel') })] })] }), !isNew && id ? (_jsx(CouponsSection, { promotionId: id })) : (_jsxs(Card, { className: "mt-4", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('promotions.coupons.title') }) }), _jsx(CardContent, { children: _jsx("p", { className: "text-sm text-muted-foreground", children: t('promotions.coupons.saveFirst') }) })] }))] }));
199
+ };
200
+ // Renders a coupon code with a hover-revealed copy affordance. Clicking the
201
+ // code text or the copy icon writes the code to the clipboard; the icon briefly
202
+ // switches to a check mark to confirm.
203
+ function CouponCodeCell({ code }) {
204
+ const t = useTranslation('core');
205
+ const [copied, setCopied] = useState(false);
206
+ const copy = useCallback(async () => {
207
+ try {
208
+ await navigator.clipboard.writeText(code);
209
+ setCopied(true);
210
+ window.setTimeout(() => setCopied(false), 1500);
211
+ }
212
+ catch {
213
+ // Clipboard API unavailable (e.g. insecure context) — silently ignore.
214
+ }
215
+ }, [code]);
216
+ return (_jsxs("button", { type: "button", onClick: () => void copy(), title: copied ? t('promotions.coupons.copied') : t('promotions.coupons.copyCode'), "aria-label": t('promotions.coupons.copyCode'), className: "group inline-flex items-center gap-1.5 font-mono hover:opacity-80", children: [code, copied ? (_jsx(Check, { className: "size-3.5 text-green-600", "aria-hidden": true })) : (_jsx(Copy, { className: "size-3.5 opacity-0 transition-opacity group-hover:opacity-60", "aria-hidden": true }))] }));
217
+ }
218
+ function CouponsSection({ promotionId }) {
219
+ const t = useTranslation('core');
220
+ const [coupons, setCoupons] = useState([]);
221
+ const [selected, setSelected] = useState(new Set());
222
+ const [code, setCode] = useState('');
223
+ const [busy, setBusy] = useState(false);
224
+ const [err, setErr] = useState(null);
225
+ const [page, setPage] = useState(0);
226
+ const { pageSize, setPageSize } = usePageSizePreference('promotion-coupons');
227
+ const reload = useCallback(() => {
228
+ void promotionsClient
229
+ .listCoupons(promotionId)
230
+ .then((rows) => {
231
+ setCoupons(rows);
232
+ // Drop any selection that no longer exists.
233
+ setSelected((prev) => new Set(rows.filter((c) => prev.has(c.id)).map((c) => c.id)));
234
+ })
235
+ .catch(() => setCoupons([]));
236
+ }, [promotionId]);
237
+ useEffect(() => reload(), [reload]);
238
+ // Keep the current page within bounds as the list or page size changes.
239
+ const pageCount = Math.max(1, Math.ceil(coupons.length / pageSize));
240
+ useEffect(() => {
241
+ setPage((p) => Math.min(p, pageCount - 1));
242
+ }, [pageCount]);
243
+ const visibleCoupons = coupons.slice(page * pageSize, page * pageSize + pageSize);
244
+ const add = async () => {
245
+ setErr(null);
246
+ try {
247
+ await promotionsClient.createCoupon(promotionId, code.trim());
248
+ setCode('');
249
+ reload();
250
+ }
251
+ catch (e) {
252
+ setErr(e instanceof ApiError ? e.envelope.error.message : t('promotions.error.save'));
253
+ }
254
+ };
255
+ const toggle = (id) => {
256
+ setSelected((prev) => {
257
+ const next = new Set(prev);
258
+ if (next.has(id))
259
+ next.delete(id);
260
+ else
261
+ next.add(id);
262
+ return next;
263
+ });
264
+ };
265
+ const allSelected = coupons.length > 0 && selected.size === coupons.length;
266
+ const toggleAll = () => {
267
+ setSelected(allSelected ? new Set() : new Set(coupons.map((c) => c.id)));
268
+ };
269
+ const bulkSetActive = async (isActive) => {
270
+ if (selected.size === 0)
271
+ return;
272
+ setErr(null);
273
+ setBusy(true);
274
+ try {
275
+ await promotionsClient.bulkSetCouponActive(promotionId, [...selected], isActive);
276
+ reload();
277
+ }
278
+ catch (e) {
279
+ setErr(e instanceof ApiError ? e.envelope.error.message : t('promotions.error.save'));
280
+ }
281
+ finally {
282
+ setBusy(false);
283
+ }
284
+ };
285
+ return (_jsxs(Card, { className: "mt-4", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('promotions.coupons.title') }) }), _jsxs(CardContent, { className: "flex flex-col gap-3", children: [err ? (_jsx(Alert, { variant: "destructive", children: _jsx(AlertDescription, { children: err }) })) : null, _jsxs("div", { className: "flex items-end gap-2", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "couponCode", children: t('promotions.coupons.code') }), _jsx(Input, { id: "couponCode", value: code, onChange: (e) => setCode(e.target.value), className: "w-64" })] }), _jsx(Button, { type: "button", disabled: code.trim() === '', onClick: () => void add(), children: t('promotions.coupons.add') })] }), _jsx(CouponGeneratorForm, { promotionId: promotionId, onGenerated: reload }), coupons.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('promotions.coupons.empty') })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { type: "button", variant: "outline", size: "sm", disabled: busy || selected.size === 0, onClick: () => void bulkSetActive(true), children: t('promotions.coupons.activate') }), _jsx(Button, { type: "button", variant: "outline", size: "sm", disabled: busy || selected.size === 0, onClick: () => void bulkSetActive(false), children: t('promotions.coupons.deactivate') }), selected.size > 0 ? (_jsx("span", { className: "text-sm text-muted-foreground", children: t('promotions.coupons.selectedCount', { count: selected.size }) })) : null] }), _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { className: "w-8", children: _jsx(Checkbox, { checked: allSelected, onChange: toggleAll, "aria-label": t('promotions.coupons.colCode') }) }), _jsx(TableHead, { children: t('promotions.coupons.colCode') }), _jsx(TableHead, { children: t('promotions.coupons.colScope') }), _jsx(TableHead, { children: t('promotions.coupons.colStatus') })] }) }), _jsx(TableBody, { children: visibleCoupons.map((c) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(Checkbox, { checked: selected.has(c.id), onChange: () => toggle(c.id), "aria-label": c.code }) }), _jsx(TableCell, { children: _jsx(CouponCodeCell, { code: c.code }) }), _jsx(TableCell, { className: "text-muted-foreground", children: c.limitScope }), _jsx(TableCell, { children: _jsx(Badge, { variant: c.isActive ? 'success' : 'secondary', children: c.isActive
286
+ ? t('promotions.coupons.active')
287
+ : t('promotions.coupons.inactive') }) })] }, c.id))) })] }), _jsx(PaginationFooter, { page: page, pageSize: pageSize, total: coupons.length, onPageSizeChange: (next) => {
288
+ setPageSize(next);
289
+ setPage(0);
290
+ }, onPrev: () => setPage((p) => Math.max(0, p - 1)), onNext: () => setPage((p) => Math.min(pageCount - 1, p + 1)) })] }))] })] }));
291
+ }
292
+ function NumberField({ label, value, onChange, }) {
293
+ return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { children: label }), _jsx(Input, { type: "number", value: value, onChange: (e) => onChange(Number(e.target.value) || 0) })] }));
294
+ }
295
+ function ActionConfigEditor({ action, onChange, }) {
296
+ const t = useTranslation('core');
297
+ const grid = 'grid gap-3 md:grid-cols-3';
298
+ switch (action.type) {
299
+ case 'free_delivery':
300
+ return _jsx("p", { className: "text-sm text-muted-foreground", children: t('promotions.edit.noConfig') });
301
+ case 'percentage_off_cart':
302
+ return (_jsx("div", { className: grid, children: _jsx(NumberField, { label: "percent", value: action.percent, onChange: (percent) => onChange({ ...action, percent }) }) }));
303
+ case 'amount_off_cart':
304
+ return (_jsxs("div", { className: grid, children: [_jsx(NumberField, { label: "amount", value: action.amount, onChange: (amount) => onChange({ ...action, amount }) }), _jsx(CurrencyField, { value: action.currency, onChange: (currency) => onChange({ ...action, currency }) })] }));
305
+ case 'buy_x_get_y_free':
306
+ return (_jsxs("div", { className: grid, children: [_jsx(NumberField, { label: "buyQuantity", value: action.buyQuantity, onChange: (buyQuantity) => onChange({ ...action, buyQuantity }) }), _jsx(NumberField, { label: "freeQuantity", value: action.freeQuantity, onChange: (freeQuantity) => onChange({ ...action, freeQuantity }) }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { children: "target" }), _jsxs(Select, { value: action.target, onChange: (e) => onChange({ ...action, target: e.target.value }), children: [_jsx("option", { value: "cheapest", children: "cheapest" }), _jsx("option", { value: "most_expensive", children: "most_expensive" })] })] })] }));
307
+ case 'spend_x_percent_off':
308
+ return (_jsxs("div", { className: grid, children: [_jsx(NumberField, { label: "spendStep", value: action.spendStep, onChange: (spendStep) => onChange({ ...action, spendStep }) }), _jsx(NumberField, { label: "percent", value: action.percent, onChange: (percent) => onChange({ ...action, percent }) }), _jsx(CurrencyField, { value: action.currency, onChange: (currency) => onChange({ ...action, currency }) })] }));
309
+ case 'spend_x_amount_off':
310
+ return (_jsxs("div", { className: grid, children: [_jsx(NumberField, { label: "spendStep", value: action.spendStep, onChange: (spendStep) => onChange({ ...action, spendStep }) }), _jsx(NumberField, { label: "amount", value: action.amount, onChange: (amount) => onChange({ ...action, amount }) }), _jsx(CurrencyField, { value: action.currency, onChange: (currency) => onChange({ ...action, currency }) })] }));
311
+ case 'every_nth_product_percent_off':
312
+ return (_jsxs("div", { className: grid, children: [_jsx(NumberField, { label: "nth", value: action.nth, onChange: (nth) => onChange({ ...action, nth }) }), _jsx(NumberField, { label: "percent", value: action.percent, onChange: (percent) => onChange({ ...action, percent }) })] }));
313
+ case 'buy_x_units_y_free':
314
+ return (_jsxs("div", { className: grid, children: [_jsx(ProductIdField, { value: action.productId, onChange: (productId) => onChange({ ...action, productId }) }), _jsx(NumberField, { label: "buyUnits", value: action.buyUnits, onChange: (buyUnits) => onChange({ ...action, buyUnits }) }), _jsx(NumberField, { label: "freeUnits", value: action.freeUnits, onChange: (freeUnits) => onChange({ ...action, freeUnits }) })] }));
315
+ case 'buy_x_units_percent_off':
316
+ return (_jsxs("div", { className: grid, children: [_jsx(ProductIdField, { value: action.productId, onChange: (productId) => onChange({ ...action, productId }) }), _jsx(NumberField, { label: "buyUnits", value: action.buyUnits, onChange: (buyUnits) => onChange({ ...action, buyUnits }) }), _jsx(NumberField, { label: "percent", value: action.percent, onChange: (percent) => onChange({ ...action, percent }) })] }));
317
+ case 'buy_x_units_amount_off':
318
+ return (_jsxs("div", { className: grid, children: [_jsx(ProductIdField, { value: action.productId, onChange: (productId) => onChange({ ...action, productId }) }), _jsx(NumberField, { label: "buyUnits", value: action.buyUnits, onChange: (buyUnits) => onChange({ ...action, buyUnits }) }), _jsx(NumberField, { label: "amount", value: action.amount, onChange: (amount) => onChange({ ...action, amount }) }), _jsx(CurrencyField, { value: action.currency, onChange: (currency) => onChange({ ...action, currency }) })] }));
319
+ }
320
+ }
321
+ function CurrencyField({ value, onChange }) {
322
+ return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { children: "currency" }), _jsx(Input, { value: value, maxLength: 3, onChange: (e) => onChange(e.target.value.toUpperCase()) })] }));
323
+ }
324
+ function ProductIdField({ value, onChange }) {
325
+ return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { children: "productId" }), _jsx(Input, { value: value, onChange: (e) => onChange(e.target.value), placeholder: "product UUID" })] }));
326
+ }
327
+ /**
328
+ * The default export the route declaration's dynamic-import factory takes
329
+ * (`contracts/admin-contribution.md` R6). The named export is kept because the
330
+ * screen is also the subject of this module's own admin tests.
331
+ */
332
+ export default PromotionEditPage;
333
+ //# sourceMappingURL=PromotionEditPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromotionEditPage.js","sourceRoot":"","sources":["../../../src/admin/pages/PromotionEditPage.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { type ReactNode } from 'react';
2
+ /**
3
+ * Feature 045 (US6) — standalone named-rule library. Build a rule with the
4
+ * shared RuleBuilder, save it by name, and reuse it across promotions. Existing
5
+ * rules can be loaded back into the builder to edit and re-save in place.
6
+ */
7
+ export declare const PromotionRulesPage: () => ReactNode;
8
+ /**
9
+ * The default export the route declaration's dynamic-import factory takes
10
+ * (`contracts/admin-contribution.md` R6). The named export is kept because the
11
+ * screen is also the subject of this module's own admin tests.
12
+ */
13
+ export default PromotionRulesPage;
14
+ //# sourceMappingURL=PromotionRulesPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromotionRulesPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/PromotionRulesPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AASzE;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAO,SA8HrC,CAAC;AAEF;;;;GAIG;AACH,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,86 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import { Pencil, Trash2, X } from 'lucide-react';
4
+ import { ApiError } from '@endora-commerce/admin-kit/lib';
5
+ import { Alert, AlertDescription, Button, Card, CardContent, CardHeader, CardTitle, Input, Label, PageHeader } from '@endora-commerce/admin-kit/ui';
6
+ import { RuleBuilder } from '@endora-commerce/admin-kit/components';
7
+ import { useTranslation } from '@endora-commerce/admin-kit/i18n';
8
+ import { promotionRulesClient, promotionsClient } from '../api/promotions-client.js';
9
+ /**
10
+ * Feature 045 (US6) — standalone named-rule library. Build a rule with the
11
+ * shared RuleBuilder, save it by name, and reuse it across promotions. Existing
12
+ * rules can be loaded back into the builder to edit and re-save in place.
13
+ */
14
+ export const PromotionRulesPage = () => {
15
+ const t = useTranslation('core');
16
+ const [rows, setRows] = useState([]);
17
+ const [name, setName] = useState('');
18
+ const [rule, setRule] = useState({ kind: 'all' });
19
+ const [editingId, setEditingId] = useState(null);
20
+ const [description, setDescription] = useState(null);
21
+ const [attributeFields, setAttributeFields] = useState([]);
22
+ const [error, setError] = useState(null);
23
+ const refresh = useCallback(() => {
24
+ void promotionRulesClient.list().then(setRows).catch(() => setRows([]));
25
+ }, []);
26
+ useEffect(() => refresh(), [refresh]);
27
+ // Promo-rule-flagged catalog attributes power the RuleBuilder's attribute
28
+ // conditions (feature: attributes promoRule toggle). Best-effort: a failure
29
+ // leaves the attribute list empty rather than breaking the builder.
30
+ useEffect(() => {
31
+ void promotionsClient
32
+ .ruleAttributes()
33
+ .then((items) => setAttributeFields(items.map((a) => ({ attributeKey: a.key, label: a.labelDefault || a.key }))))
34
+ .catch(() => setAttributeFields([]));
35
+ }, []);
36
+ const resetForm = () => {
37
+ setEditingId(null);
38
+ setName('');
39
+ setRule({ kind: 'all' });
40
+ setDescription(null);
41
+ };
42
+ const startEdit = (r) => {
43
+ setEditingId(r.id);
44
+ setName(r.name);
45
+ setRule(r.definition);
46
+ setDescription(r.description);
47
+ setError(null);
48
+ };
49
+ const save = async () => {
50
+ setError(null);
51
+ try {
52
+ const payload = { name: name.trim(), description, definition: rule };
53
+ if (editingId) {
54
+ await promotionRulesClient.update(editingId, payload);
55
+ }
56
+ else {
57
+ await promotionRulesClient.create(payload);
58
+ }
59
+ resetForm();
60
+ refresh();
61
+ }
62
+ catch (e) {
63
+ setError(e instanceof ApiError ? e.envelope.error.message : t('promotions.error.save'));
64
+ }
65
+ };
66
+ const remove = async (id) => {
67
+ setError(null);
68
+ try {
69
+ await promotionRulesClient.remove(id);
70
+ if (editingId === id)
71
+ resetForm();
72
+ refresh();
73
+ }
74
+ catch (e) {
75
+ setError(e instanceof ApiError ? e.envelope.error.message : t('promotions.error.delete'));
76
+ }
77
+ };
78
+ return (_jsxs(_Fragment, { children: [_jsx(PageHeader, { title: t('promotionRules.page.title'), description: t('promotionRules.page.description') }), error ? (_jsx(Alert, { variant: "destructive", className: "mb-4", children: _jsx(AlertDescription, { children: error }) })) : null, _jsxs(Card, { className: "mb-4", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: editingId ? t('common.action.edit') : t('promotionRules.create.title') }) }), _jsxs(CardContent, { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "ruleName", children: t('promotionRules.field.name') }), _jsx(Input, { id: "ruleName", value: name, onChange: (e) => setName(e.target.value), className: "w-72" })] }), _jsx(RuleBuilder, { value: rule, onChange: setRule, attributeFields: attributeFields }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { type: "button", disabled: name.trim() === '', onClick: () => void save(), children: editingId ? t('common.action.save') : t('promotionRules.create.save') }), editingId ? (_jsxs(Button, { type: "button", variant: "outline", onClick: resetForm, children: [_jsx(X, {}), " ", t('common.action.cancel')] })) : null] })] })] }), _jsx(Card, { children: _jsx(CardContent, { className: "pt-6", children: rows.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('promotionRules.empty') })) : (_jsx("ul", { className: "flex flex-col gap-2", children: rows.map((r) => (_jsxs("li", { className: "flex items-center justify-between border-b border-line pb-2", children: [_jsx("span", { className: "font-medium", children: r.name }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => startEdit(r), children: [_jsx(Pencil, {}), " ", t('common.action.edit')] }), _jsxs(Button, { type: "button", variant: "destructive", size: "sm", onClick: () => void remove(r.id), children: [_jsx(Trash2, {}), " ", t('promotions.action.delete')] })] })] }, r.id))) })) }) })] }));
79
+ };
80
+ /**
81
+ * The default export the route declaration's dynamic-import factory takes
82
+ * (`contracts/admin-contribution.md` R6). The named export is kept because the
83
+ * screen is also the subject of this module's own admin tests.
84
+ */
85
+ export default PromotionRulesPage;
86
+ //# sourceMappingURL=PromotionRulesPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromotionRulesPage.js","sourceRoot":"","sources":["../../../src/admin/pages/PromotionRulesPage.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type ReactNode } from 'react';
2
+ /**
3
+ * Feature 045 (US7) — promotion usage statistics: totals + a breakdown chart
4
+ * by the chosen dimension, rendered with the shared ECharts wrapper.
5
+ */
6
+ export declare const PromotionStatsPage: () => ReactNode;
7
+ /**
8
+ * The default export the route declaration's dynamic-import factory takes
9
+ * (`contracts/admin-contribution.md` R6). The named export is kept because the
10
+ * screen is also the subject of this module's own admin tests.
11
+ */
12
+ export default PromotionStatsPage;
13
+ //# sourceMappingURL=PromotionStatsPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromotionStatsPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/PromotionStatsPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAS5D;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,SAoErC,CAAC;AAEF;;;;GAIG;AACH,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { useParams } from 'react-router-dom';
4
+ import { Card, CardContent, CardHeader, CardTitle, Label, PageHeader, Select } from '@endora-commerce/admin-kit/ui';
5
+ import { EChart } from '@endora-commerce/admin-kit/components';
6
+ import { useTranslation } from '@endora-commerce/admin-kit/i18n';
7
+ import { formatMoney } from '@endora-commerce/admin-kit/lib';
8
+ import { promotionsClient } from '../api/promotions-client.js';
9
+ /**
10
+ * Feature 045 (US7) — promotion usage statistics: totals + a breakdown chart
11
+ * by the chosen dimension, rendered with the shared ECharts wrapper.
12
+ */
13
+ export const PromotionStatsPage = () => {
14
+ const t = useTranslation('core');
15
+ const { id } = useParams();
16
+ const [groupBy, setGroupBy] = useState('organization');
17
+ const [data, setData] = useState(null);
18
+ useEffect(() => {
19
+ if (!id)
20
+ return;
21
+ void promotionsClient.stats(id, groupBy).then(setData).catch(() => setData(null));
22
+ }, [id, groupBy]);
23
+ const option = {
24
+ tooltip: {},
25
+ grid: { left: 40, right: 16, top: 16, bottom: 40 },
26
+ xAxis: { type: 'category', data: (data?.breakdown ?? []).map((b) => b.key ?? '—') },
27
+ yAxis: { type: 'value' },
28
+ series: [
29
+ {
30
+ type: 'bar',
31
+ name: t('promotionStats.discount'),
32
+ data: (data?.breakdown ?? []).map((b) => b.discount),
33
+ },
34
+ ],
35
+ };
36
+ return (_jsxs(_Fragment, { children: [_jsx(PageHeader, { title: t('promotionStats.title'), description: t('promotionStats.description') }), _jsxs("div", { className: "mb-4 grid gap-4 md:grid-cols-2", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('promotionStats.totalUses') }) }), _jsx(CardContent, { className: "text-2xl font-semibold tabular-nums", children: data?.totalUses ?? 0 })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('promotionStats.totalDiscount') }) }), _jsx(CardContent, { className: "text-2xl font-semibold tabular-nums", children: formatMoney(data?.totalDiscount ?? 0, data?.currency ?? 'PLN') })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('promotionStats.breakdown') }) }), _jsxs(CardContent, { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { children: t('promotionStats.groupBy') }), _jsxs(Select, { className: "w-56", value: groupBy, onChange: (e) => setGroupBy(e.target.value), children: [_jsx("option", { value: "customer", children: "customer" }), _jsx("option", { value: "customerGroup", children: "customer group" }), _jsx("option", { value: "organization", children: "organization" }), _jsx("option", { value: "salesChannel", children: "sales channel" })] })] }), _jsx(EChart, { option: option, className: "h-80 w-full" })] })] })] }));
37
+ };
38
+ /**
39
+ * The default export the route declaration's dynamic-import factory takes
40
+ * (`contracts/admin-contribution.md` R6). The named export is kept because the
41
+ * screen is also the subject of this module's own admin tests.
42
+ */
43
+ export default PromotionStatsPage;
44
+ //# sourceMappingURL=PromotionStatsPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromotionStatsPage.js","sourceRoot":"","sources":["../../../src/admin/pages/PromotionStatsPage.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACpH,OAAO,EAAE,MAAM,EAAE,MAAM,uCAAuC,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAE7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAE/D;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAc,EAAE;IAChD,MAAM,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,EAAE,EAAE,EAAE,GAAG,SAAS,EAAkB,CAAC;IAC3C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAwB,cAAc,CAAC,CAAC;IAC9E,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAA6B,IAAI,CAAC,CAAC;IAEnE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,KAAK,gBAAgB,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACpF,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IAElB,MAAM,MAAM,GAAG;QACb,OAAO,EAAE,EAAE;QACX,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QAClD,KAAK,EAAE,EAAE,IAAI,EAAE,UAAmB,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE;QAC5F,KAAK,EAAE,EAAE,IAAI,EAAE,OAAgB,EAAE;QACjC,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,KAAc;gBACpB,IAAI,EAAE,CAAC,CAAC,yBAAyB,CAAC;gBAClC,IAAI,EAAE,CAAC,IAAI,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;aACrD;SACF;KACF,CAAC;IAEF,OAAO,CACL,8BACE,KAAC,UAAU,IAAC,KAAK,EAAE,CAAC,CAAC,sBAAsB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,4BAA4B,CAAC,GAAI,EAC9F,eAAK,SAAS,EAAC,gCAAgC,aAC7C,MAAC,IAAI,eACH,KAAC,UAAU,cACT,KAAC,SAAS,cAAE,CAAC,CAAC,0BAA0B,CAAC,GAAa,GAC3C,EACb,KAAC,WAAW,IAAC,SAAS,EAAC,qCAAqC,YAAE,IAAI,EAAE,SAAS,IAAI,CAAC,GAAe,IAC5F,EACP,MAAC,IAAI,eACH,KAAC,UAAU,cACT,KAAC,SAAS,cAAE,CAAC,CAAC,8BAA8B,CAAC,GAAa,GAC/C,EACb,KAAC,WAAW,IAAC,SAAS,EAAC,qCAAqC,YACzD,WAAW,CAAC,IAAI,EAAE,aAAa,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,IAAI,KAAK,CAAC,GACnD,IACT,IACH,EAEN,MAAC,IAAI,eACH,KAAC,UAAU,cACT,KAAC,SAAS,cAAE,CAAC,CAAC,0BAA0B,CAAC,GAAa,GAC3C,EACb,MAAC,WAAW,IAAC,SAAS,EAAC,qBAAqB,aAC1C,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,cAAE,CAAC,CAAC,wBAAwB,CAAC,GAAS,EAC5C,MAAC,MAAM,IACL,SAAS,EAAC,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAA8B,CAAC,aAEpE,iBAAQ,KAAK,EAAC,UAAU,yBAAkB,EAC1C,iBAAQ,KAAK,EAAC,eAAe,+BAAwB,EACrD,iBAAQ,KAAK,EAAC,cAAc,6BAAsB,EAClD,iBAAQ,KAAK,EAAC,cAAc,8BAAuB,IAC5C,IACL,EACN,KAAC,MAAM,IAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAC,aAAa,GAAG,IACtC,IACT,IACN,CACJ,CAAC;AACJ,CAAC,CAAC;AAEF;;;;GAIG;AACH,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { type ReactNode } from 'react';
2
+ export declare const PromotionsPage: () => ReactNode;
3
+ /**
4
+ * The default export the route declaration's dynamic-import factory takes
5
+ * (`contracts/admin-contribution.md` R6). The named export is kept because the
6
+ * screen is also the subject of this module's own admin tests.
7
+ */
8
+ export default PromotionsPage;
9
+ //# sourceMappingURL=PromotionsPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromotionsPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/PromotionsPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AA2DzE,eAAO,MAAM,cAAc,QAAO,SAqKjC,CAAC;AAEF;;;;GAIG;AACH,eAAe,cAAc,CAAC"}