@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.
- package/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/admin/api/promotions-client.d.ts +98 -0
- package/dist/admin/api/promotions-client.d.ts.map +1 -0
- package/dist/admin/api/promotions-client.js +40 -0
- package/dist/admin/api/promotions-client.js.map +1 -0
- package/dist/admin/components/CouponGeneratorForm.d.ts +10 -0
- package/dist/admin/components/CouponGeneratorForm.d.ts.map +1 -0
- package/dist/admin/components/CouponGeneratorForm.js +56 -0
- package/dist/admin/components/CouponGeneratorForm.js.map +1 -0
- package/dist/admin/index.d.ts +43 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +69 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/PromotionEditPage.d.ts +9 -0
- package/dist/admin/pages/PromotionEditPage.d.ts.map +1 -0
- package/dist/admin/pages/PromotionEditPage.js +333 -0
- package/dist/admin/pages/PromotionEditPage.js.map +1 -0
- package/dist/admin/pages/PromotionRulesPage.d.ts +14 -0
- package/dist/admin/pages/PromotionRulesPage.d.ts.map +1 -0
- package/dist/admin/pages/PromotionRulesPage.js +86 -0
- package/dist/admin/pages/PromotionRulesPage.js.map +1 -0
- package/dist/admin/pages/PromotionStatsPage.d.ts +13 -0
- package/dist/admin/pages/PromotionStatsPage.d.ts.map +1 -0
- package/dist/admin/pages/PromotionStatsPage.js +44 -0
- package/dist/admin/pages/PromotionStatsPage.js.map +1 -0
- package/dist/admin/pages/PromotionsPage.d.ts +9 -0
- package/dist/admin/pages/PromotionsPage.d.ts.map +1 -0
- package/dist/admin/pages/PromotionsPage.js +79 -0
- package/dist/admin/pages/PromotionsPage.js.map +1 -0
- package/dist/backend/actions/amount-off-cart.d.ts +4 -0
- package/dist/backend/actions/amount-off-cart.d.ts.map +1 -0
- package/dist/backend/actions/amount-off-cart.js +16 -0
- package/dist/backend/actions/amount-off-cart.js.map +1 -0
- package/dist/backend/actions/buy-x-get-y-free.d.ts +8 -0
- package/dist/backend/actions/buy-x-get-y-free.d.ts.map +1 -0
- package/dist/backend/actions/buy-x-get-y-free.js +20 -0
- package/dist/backend/actions/buy-x-get-y-free.js.map +1 -0
- package/dist/backend/actions/buy-x-units-amount-off.d.ts +4 -0
- package/dist/backend/actions/buy-x-units-amount-off.d.ts.map +1 -0
- package/dist/backend/actions/buy-x-units-amount-off.js +19 -0
- package/dist/backend/actions/buy-x-units-amount-off.js.map +1 -0
- package/dist/backend/actions/buy-x-units-percent-off.d.ts +4 -0
- package/dist/backend/actions/buy-x-units-percent-off.d.ts.map +1 -0
- package/dist/backend/actions/buy-x-units-percent-off.js +15 -0
- package/dist/backend/actions/buy-x-units-percent-off.js.map +1 -0
- package/dist/backend/actions/buy-x-units-y-free.d.ts +7 -0
- package/dist/backend/actions/buy-x-units-y-free.d.ts.map +1 -0
- package/dist/backend/actions/buy-x-units-y-free.js +21 -0
- package/dist/backend/actions/buy-x-units-y-free.js.map +1 -0
- package/dist/backend/actions/every-nth-product-percent-off.d.ts +7 -0
- package/dist/backend/actions/every-nth-product-percent-off.d.ts.map +1 -0
- package/dist/backend/actions/every-nth-product-percent-off.js +17 -0
- package/dist/backend/actions/every-nth-product-percent-off.js.map +1 -0
- package/dist/backend/actions/free-delivery.d.ts +4 -0
- package/dist/backend/actions/free-delivery.d.ts.map +1 -0
- package/dist/backend/actions/free-delivery.js +11 -0
- package/dist/backend/actions/free-delivery.js.map +1 -0
- package/dist/backend/actions/percentage-off-cart.d.ts +4 -0
- package/dist/backend/actions/percentage-off-cart.d.ts.map +1 -0
- package/dist/backend/actions/percentage-off-cart.js +11 -0
- package/dist/backend/actions/percentage-off-cart.js.map +1 -0
- package/dist/backend/actions/spend-x-amount-off.d.ts +4 -0
- package/dist/backend/actions/spend-x-amount-off.d.ts.map +1 -0
- package/dist/backend/actions/spend-x-amount-off.js +17 -0
- package/dist/backend/actions/spend-x-amount-off.js.map +1 -0
- package/dist/backend/actions/spend-x-percent-off.d.ts +4 -0
- package/dist/backend/actions/spend-x-percent-off.d.ts.map +1 -0
- package/dist/backend/actions/spend-x-percent-off.js +18 -0
- package/dist/backend/actions/spend-x-percent-off.js.map +1 -0
- package/dist/backend/actions/types.d.ts +37 -0
- package/dist/backend/actions/types.d.ts.map +1 -0
- package/dist/backend/actions/types.js +2 -0
- package/dist/backend/actions/types.js.map +1 -0
- package/dist/backend/actions/util.d.ts +13 -0
- package/dist/backend/actions/util.d.ts.map +1 -0
- package/dist/backend/actions/util.js +18 -0
- package/dist/backend/actions/util.js.map +1 -0
- package/dist/backend/entities/coupon-batch.entity.d.ts +21 -0
- package/dist/backend/entities/coupon-batch.entity.d.ts.map +1 -0
- package/dist/backend/entities/coupon-batch.entity.js +78 -0
- package/dist/backend/entities/coupon-batch.entity.js.map +1 -0
- package/dist/backend/entities/promotion-coupon.entity.d.ts +17 -0
- package/dist/backend/entities/promotion-coupon.entity.d.ts.map +1 -0
- package/dist/backend/entities/promotion-coupon.entity.js +64 -0
- package/dist/backend/entities/promotion-coupon.entity.js.map +1 -0
- package/dist/backend/entities/promotion-rule.entity.d.ts +16 -0
- package/dist/backend/entities/promotion-rule.entity.d.ts.map +1 -0
- package/dist/backend/entities/promotion-rule.entity.js +57 -0
- package/dist/backend/entities/promotion-rule.entity.js.map +1 -0
- package/dist/backend/entities/promotion-usage-counter.entity.d.ts +15 -0
- package/dist/backend/entities/promotion-usage-counter.entity.d.ts.map +1 -0
- package/dist/backend/entities/promotion-usage-counter.entity.js +48 -0
- package/dist/backend/entities/promotion-usage-counter.entity.js.map +1 -0
- package/dist/backend/entities/promotion-usage.entity.d.ts +21 -0
- package/dist/backend/entities/promotion-usage.entity.d.ts.map +1 -0
- package/dist/backend/entities/promotion-usage.entity.js +89 -0
- package/dist/backend/entities/promotion-usage.entity.js.map +1 -0
- package/dist/backend/entities/promotion.entity.d.ts +63 -0
- package/dist/backend/entities/promotion.entity.d.ts.map +1 -0
- package/dist/backend/entities/promotion.entity.js +194 -0
- package/dist/backend/entities/promotion.entity.js.map +1 -0
- package/dist/backend/index.d.ts +124 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +182 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/routes.d.ts +88 -0
- package/dist/backend/routes.d.ts.map +1 -0
- package/dist/backend/routes.js +256 -0
- package/dist/backend/routes.js.map +1 -0
- package/dist/backend/services/coupon-service.d.ts +40 -0
- package/dist/backend/services/coupon-service.d.ts.map +1 -0
- package/dist/backend/services/coupon-service.js +178 -0
- package/dist/backend/services/coupon-service.js.map +1 -0
- package/dist/backend/services/promotion-action-registry.d.ts +20 -0
- package/dist/backend/services/promotion-action-registry.d.ts.map +1 -0
- package/dist/backend/services/promotion-action-registry.js +57 -0
- package/dist/backend/services/promotion-action-registry.js.map +1 -0
- package/dist/backend/services/promotion-code-port.d.ts +24 -0
- package/dist/backend/services/promotion-code-port.d.ts.map +1 -0
- package/dist/backend/services/promotion-code-port.js +53 -0
- package/dist/backend/services/promotion-code-port.js.map +1 -0
- package/dist/backend/services/promotion-currency-reference.d.ts +13 -0
- package/dist/backend/services/promotion-currency-reference.d.ts.map +1 -0
- package/dist/backend/services/promotion-currency-reference.js +25 -0
- package/dist/backend/services/promotion-currency-reference.js.map +1 -0
- package/dist/backend/services/promotion-rule-evaluator.d.ts +32 -0
- package/dist/backend/services/promotion-rule-evaluator.d.ts.map +1 -0
- package/dist/backend/services/promotion-rule-evaluator.js +131 -0
- package/dist/backend/services/promotion-rule-evaluator.js.map +1 -0
- package/dist/backend/services/promotion-rule-service.d.ts +62 -0
- package/dist/backend/services/promotion-rule-service.d.ts.map +1 -0
- package/dist/backend/services/promotion-rule-service.js +95 -0
- package/dist/backend/services/promotion-rule-service.js.map +1 -0
- package/dist/backend/services/promotion-rule-store.d.ts +33 -0
- package/dist/backend/services/promotion-rule-store.d.ts.map +1 -0
- package/dist/backend/services/promotion-rule-store.js +88 -0
- package/dist/backend/services/promotion-rule-store.js.map +1 -0
- package/dist/backend/services/promotion-service.d.ts +312 -0
- package/dist/backend/services/promotion-service.d.ts.map +1 -0
- package/dist/backend/services/promotion-service.js +762 -0
- package/dist/backend/services/promotion-service.js.map +1 -0
- package/dist/backend/services/promotion-stats-service.d.ts +15 -0
- package/dist/backend/services/promotion-stats-service.d.ts.map +1 -0
- package/dist/backend/services/promotion-stats-service.js +66 -0
- package/dist/backend/services/promotion-stats-service.js.map +1 -0
- package/dist/backend/services/promotion-usage-service.d.ts +46 -0
- package/dist/backend/services/promotion-usage-service.d.ts.map +1 -0
- package/dist/backend/services/promotion-usage-service.js +168 -0
- package/dist/backend/services/promotion-usage-service.js.map +1 -0
- package/dist/manifest.d.ts +172 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +140 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260505T074605_promotions_criteria.d.ts +19 -0
- package/dist/migrations/20260505T074605_promotions_criteria.d.ts.map +1 -0
- package/dist/migrations/20260505T074605_promotions_criteria.js +23 -0
- package/dist/migrations/20260505T074605_promotions_criteria.js.map +1 -0
- package/dist/migrations/20260618T100727_promotions_engine.d.ts +19 -0
- package/dist/migrations/20260618T100727_promotions_engine.d.ts.map +1 -0
- package/dist/migrations/20260618T100727_promotions_engine.js +148 -0
- package/dist/migrations/20260618T100727_promotions_engine.js.map +1 -0
- package/dist/migrations/20260818T081251_promotions_promotion_usage_order_fk.d.ts +42 -0
- package/dist/migrations/20260818T081251_promotions_promotion_usage_order_fk.d.ts.map +1 -0
- package/dist/migrations/20260818T081251_promotions_promotion_usage_order_fk.js +76 -0
- package/dist/migrations/20260818T081251_promotions_promotion_usage_order_fk.js.map +1 -0
- package/dist/migrations/20260912T094715_promotions_sales_channel_promotions.d.ts +27 -0
- package/dist/migrations/20260912T094715_promotions_sales_channel_promotions.d.ts.map +1 -0
- package/dist/migrations/20260912T094715_promotions_sales_channel_promotions.js +44 -0
- package/dist/migrations/20260912T094715_promotions_sales_channel_promotions.js.map +1 -0
- package/dist/migrations/index.d.ts +39 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +44 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/ports/index.d.ts +106 -0
- package/dist/ports/index.d.ts.map +1 -0
- package/dist/ports/index.js +2 -0
- package/dist/ports/index.js.map +1 -0
- package/docs/promotions.md +96 -0
- package/i18n/en.json +34 -0
- package/i18n/pl.json +34 -0
- package/package.json +101 -0
- 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":";AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAkC,MAAM,OAAO,CAAC;AACzF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACjF,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC5O,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAkD,MAAM,uCAAuC,CAAC;AACtI,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAe,MAAM,6BAA6B,CAAC;AAClG,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAG3E,MAAM,YAAY,GAA0B;IAC1C,eAAe;IACf,qBAAqB;IACrB,iBAAiB;IACjB,kBAAkB;IAClB,qBAAqB;IACrB,oBAAoB;IACpB,+BAA+B;IAC/B,oBAAoB;IACpB,yBAAyB;IACzB,wBAAwB;CACzB,CAAC;AAEF,iFAAiF;AACjF,SAAS,SAAS,CAAC,IAAmB;IACpC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAkB,CAAC;AAC3D,CAAC;AAED,SAAS,aAAa,CAAC,IAAyB;IAC9C,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,eAAe;YAClB,OAAO,EAAE,IAAI,EAAE,CAAC;QAClB,KAAK,qBAAqB;YACxB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QAC/B,KAAK,iBAAiB;YACpB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC/C,KAAK,kBAAkB;YACrB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QACvE,KAAK,qBAAqB;YACxB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC/D,KAAK,oBAAoB;YACvB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC9D,KAAK,+BAA+B;YAClC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACvC,KAAK,oBAAoB;YACvB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;QAC5D,KAAK,yBAAyB;YAC5B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QAC3D,KAAK,wBAAwB;YAC3B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7E,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAc,EAAE;IAC/C,MAAM,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAC/B,MAAM,EAAE,EAAE,EAAE,GAAG,SAAS,EAAkB,CAAC;IAC3C,MAAM,KAAK,GAAG,CAAC,EAAE,CAAC;IAElB,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACrC,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACnD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACrC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAkB,aAAa,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAC5F,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAgB,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACjE,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAwB,EAAE,CAAC,CAAC;IACxE,qEAAqE;IACrE,qDAAqD;IACrD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACnD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACnD,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7D,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAuB,EAAE,CAAC,CAAC;IACjF,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAmB,EAAE,CAAC,CAAC;IACvE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE5C,SAAS,CAAC,GAAG,EAAE;QACb,KAAK,gBAAgB;aAClB,cAAc,EAAE;aAChB,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACd,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAChG;aACA,KAAK,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC;QACvC,KAAK,oBAAoB,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC;QACpF,KAAK,CAAC,KAAK,IAAmB,EAAE;YAC9B,IAAI,CAAC;gBACH,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;oBAC1D,gBAAgB,CAAC,UAAU,CAAC,iBAAiB,CAAC;oBAC9C,gBAAgB,CAAC,UAAU,CAAC,eAAe,CAAC;oBAC5C,gBAAgB,CAAC,UAAU,CAAC,YAAY,CAAC;oBACzC,gBAAgB,CAAC,UAAU,CAAC,iBAAiB,CAAC;oBAC9C,gBAAgB,CAAC,UAAU,CAAC,kBAAkB,CAAC;iBAChD,CAAC,CAAC;gBACH,eAAe,CAAC;oBACd,aAAa,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACpF,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACvE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAC7E,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAC5F,cAAc,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;iBAC/F,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,eAAe,CAAC,EAAE,CAAC,CAAC;YACtB,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;IACP,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK;YAAE,OAAO;QAClB,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,KAAK,gBAAgB;aAClB,GAAG,CAAC,EAAE,CAAC;aACP,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;YACV,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChB,cAAc,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;YACpC,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YACtB,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YACxB,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YACxB,cAAc,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;YAC9B,IAAI,CAAC,CAAC,MAAM;gBAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;gBACX,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;iBAAM,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;gBACpB,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAC7B,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAC3B,CAAC;YACD,cAAc,CAAC,CAAC,CAAC,gBAAgB,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC7E,cAAc,CAAC,CAAC,CAAC,yBAAyB,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC/F,mBAAmB,CAAC,CAAC,CAAC,qBAAqB,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9F,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CACb,QAAQ,CAAC,GAAG,YAAY,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAC5F;aACA,OAAO,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IACtC,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IAEnB,2EAA2E;IAC3E,0BAA0B;IAC1B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,aAAa;YAAE,OAAO;QAC3B,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,aAAa,CAAC,CAAC;QAC7D,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;YACrC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;IACH,CAAC,EAAE,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC;IAEhC,MAAM,SAAS,GAAG,CAAC,CAAS,EAAiB,EAAE;QAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACpB,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,WAAW,CAC1B,KAAK,EAAE,CAAY,EAAiB,EAAE;QACpC,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,SAAS,CAAC,IAAI,CAAC,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG;gBACd,IAAI;gBACJ,WAAW,EAAE,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW;gBAC3D,QAAQ;gBACR,QAAQ;gBACR,WAAW;gBACX,MAAM;gBACN,IAAI;gBACJ,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;gBACtC,gBAAgB,EAAE,SAAS,CAAC,WAAW,CAAC;gBACxC,yBAAyB,EAAE,SAAS,CAAC,WAAW,CAAC;gBACjD,qBAAqB,EAAE,SAAS,CAAC,gBAAgB,CAAC;aACnD,CAAC;YACF,IAAI,KAAK;gBAAE,MAAM,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;;gBAC7C,MAAM,gBAAgB,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAChD,QAAQ,CAAC,aAAa,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,GAAG,YAAY,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC;QAC9F,CAAC;gBAAS,CAAC;YACT,SAAS,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,EACD;QACE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI;QACtE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;KACnE,CACF,CAAC;IAEF,IAAI,OAAO;QAAE,OAAO,YAAG,SAAS,EAAC,mCAAmC,YAAE,CAAC,CAAC,oBAAoB,CAAC,GAAK,CAAC;IAEnG,OAAO,CACL,8BACE,KAAC,UAAU,IACT,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,2BAA2B,CAAC,EAC7E,WAAW,EAAE,CAAC,CAAC,6BAA6B,CAAC,GAC7C,EACD,KAAK,CAAC,CAAC,CAAC,CACP,KAAC,KAAK,IAAC,OAAO,EAAC,aAAa,EAAC,SAAS,EAAC,MAAM,YAC3C,KAAC,gBAAgB,cAAE,KAAK,GAAoB,GACtC,CACT,CAAC,CAAC,CAAC,IAAI,EACR,gBAAM,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAC,qBAAqB,aACvD,MAAC,IAAI,eACH,KAAC,UAAU,cACT,KAAC,SAAS,cAAE,CAAC,CAAC,yBAAyB,CAAC,GAAa,GAC1C,EACb,MAAC,WAAW,IAAC,SAAS,EAAC,2BAA2B,aAChD,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,IAAC,OAAO,EAAC,MAAM,YAAE,CAAC,CAAC,uBAAuB,CAAC,GAAS,EAC1D,KAAC,KAAK,IAAC,EAAE,EAAC,MAAM,EAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,SAAG,IAC/E,EACN,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,IAAC,OAAO,EAAC,MAAM,YAAE,CAAC,CAAC,uBAAuB,CAAC,GAAS,EAC1D,KAAC,KAAK,IAAC,EAAE,EAAC,MAAM,EAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAI,IACtE,EACN,eAAK,SAAS,EAAC,mCAAmC,aAChD,KAAC,KAAK,IAAC,OAAO,EAAC,aAAa,YAAE,CAAC,CAAC,8BAA8B,CAAC,GAAS,EACxE,KAAC,KAAK,IAAC,EAAE,EAAC,aAAa,EAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAI,IAC3F,EACN,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,IAAC,OAAO,EAAC,UAAU,YAAE,CAAC,CAAC,2BAA2B,CAAC,GAAS,EAClE,KAAC,KAAK,IACJ,EAAE,EAAC,UAAU,EACb,IAAI,EAAC,QAAQ,EACb,KAAK,EAAE,QAAQ,EACf,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GACrE,IACE,EACN,eAAK,SAAS,EAAC,8BAA8B,aAC3C,iBAAO,SAAS,EAAC,iCAAiC,aAChD,KAAC,QAAQ,IAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAI,EAC9E,CAAC,CAAC,yBAAyB,CAAC,IACvB,EACR,iBAAO,SAAS,EAAC,iCAAiC,aAChD,KAAC,QAAQ,IAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAI,EACpF,CAAC,CAAC,8BAA8B,CAAC,IAC5B,IACJ,IACM,IACT,EAEP,MAAC,IAAI,eACH,KAAC,UAAU,cACT,KAAC,SAAS,cAAE,CAAC,CAAC,wBAAwB,CAAC,GAAa,GACzC,EACb,MAAC,WAAW,IAAC,SAAS,EAAC,qBAAqB,aAC1C,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,cAAE,CAAC,CAAC,4BAA4B,CAAC,GAAS,EAChD,KAAC,MAAM,IACL,SAAS,EAAC,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,IAAI,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,KAA4B,CAAC,CAAC,YAE/E,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACzB,iBAAkB,KAAK,EAAE,GAAG,YACzB,CAAC,CAAC,UAAU,GAAG,EAAE,CAAC,IADR,GAAG,CAEP,CACV,CAAC,GACK,IACL,EACN,KAAC,kBAAkB,IAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,GAAI,IAC/C,IACT,EAEP,MAAC,IAAI,eACH,KAAC,UAAU,cACT,KAAC,SAAS,cAAE,CAAC,CAAC,sBAAsB,CAAC,GAAa,GACvC,EACb,MAAC,WAAW,IAAC,SAAS,EAAC,qBAAqB,aAC1C,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,IAAC,OAAO,EAAC,cAAc,YAAE,CAAC,CAAC,8BAA8B,CAAC,GAAS,EACzE,MAAC,MAAM,IACL,EAAE,EAAC,cAAc,EACjB,SAAS,EAAC,MAAM,EAChB,KAAK,EAAC,EAAE,EACR,QAAQ,EAAE,UAAU,CAAC,MAAM,KAAK,CAAC,EACjC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;oDACd,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oDAC9D,IAAI,KAAK;wDAAE,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;gDAClD,CAAC,aAED,iBAAQ,KAAK,EAAC,EAAE,uBAAW,EAC1B,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACrB,iBAAmB,KAAK,EAAE,CAAC,CAAC,EAAE,YAC3B,CAAC,CAAC,IAAI,IADI,CAAC,CAAC,EAAE,CAER,CACV,CAAC,IACK,EACT,YAAG,SAAS,EAAC,+BAA+B,YAAE,CAAC,CAAC,8BAA8B,CAAC,GAAK,IAChF,EACN,KAAC,WAAW,IACV,KAAK,EAAE,IAAI,EACX,QAAQ,EAAE,OAAO,EACjB,eAAe,EAAE,eAAe,EAChC,YAAY,EAAE,YAAY;wCAC1B,kEAAkE;wCAClE,6DAA6D;wCAC7D,gDAAgD;wCAChD,MAAM,EAAE;4CACN,iBAAiB,EAAE,CAAC,CAAC,gCAAgC,CAAC;4CACtD,WAAW,EAAE,CAAC,CAAC,0BAA0B,CAAC;4CAC1C,uBAAuB,EAAE,CAAC,CAAC,2BAA2B,CAAC;yCACxD,GACD,IACU,IACT,EAEP,MAAC,IAAI,eACH,KAAC,UAAU,cACT,KAAC,SAAS,cAAE,CAAC,CAAC,wBAAwB,CAAC,GAAa,GACzC,EACb,MAAC,WAAW,IAAC,SAAS,EAAC,2BAA2B,aAChD,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,IAAC,OAAO,EAAC,IAAI,YAAE,CAAC,CAAC,eAAe,CAAC,GAAS,EAChD,KAAC,KAAK,IAAC,EAAE,EAAC,IAAI,EAAC,IAAI,EAAC,QAAQ,EAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAI,IAChG,EACN,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,IAAC,OAAO,EAAC,IAAI,YAAE,CAAC,CAAC,wBAAwB,CAAC,GAAS,EACzD,KAAC,KAAK,IAAC,EAAE,EAAC,IAAI,EAAC,IAAI,EAAC,QAAQ,EAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAI,IAChG,EACN,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,IAAC,OAAO,EAAC,IAAI,YAAE,CAAC,CAAC,oBAAoB,CAAC,GAAS,EACrD,KAAC,KAAK,IAAC,EAAE,EAAC,IAAI,EAAC,IAAI,EAAC,QAAQ,EAAC,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAI,IAC1G,IACM,IACT,EAEP,eAAK,SAAS,EAAC,YAAY,aACzB,KAAC,MAAM,IAAC,IAAI,EAAC,QAAQ,EAAC,QAAQ,EAAE,MAAM,YACnC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,GACtD,EACT,KAAC,MAAM,IAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,YAC3E,CAAC,CAAC,wBAAwB,CAAC,GACrB,IACL,IACD,EAEN,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CACd,KAAC,cAAc,IAAC,WAAW,EAAE,EAAE,GAAI,CACpC,CAAC,CAAC,CAAC,CACF,MAAC,IAAI,IAAC,SAAS,EAAC,MAAM,aACpB,KAAC,UAAU,cACT,KAAC,SAAS,cAAE,CAAC,CAAC,0BAA0B,CAAC,GAAa,GAC3C,EACb,KAAC,WAAW,cACV,YAAG,SAAS,EAAC,+BAA+B,YAAE,CAAC,CAAC,8BAA8B,CAAC,GAAK,GACxE,IACT,CACR,IACA,CACJ,CAAC;AACJ,CAAC,CAAC;AAEF,4EAA4E;AAC5E,gFAAgF;AAChF,uCAAuC;AACvC,SAAS,cAAc,CAAC,EAAE,IAAI,EAAoB;IAChD,MAAM,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE5C,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,IAAmB,EAAE;QACjD,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAC1C,SAAS,CAAC,IAAI,CAAC,CAAC;YAChB,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACP,uEAAuE;QACzE,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,OAAO,CACL,kBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,IAAI,EAAE,EAC1B,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,6BAA6B,CAAC,gBACrE,CAAC,CAAC,6BAA6B,CAAC,EAC5C,SAAS,EAAC,mEAAmE,aAE5E,IAAI,EACJ,MAAM,CAAC,CAAC,CAAC,CACR,KAAC,KAAK,IAAC,SAAS,EAAC,yBAAyB,wBAAe,CAC1D,CAAC,CAAC,CAAC,CACF,KAAC,IAAI,IACH,SAAS,EAAC,8DAA8D,wBAExE,CACH,IACM,CACV,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,EAAE,WAAW,EAA2B;IAC9D,MAAM,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAW,EAAE,CAAC,CAAC;IACrD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAc,IAAI,GAAG,EAAE,CAAC,CAAC;IACjE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACrC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACpD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,qBAAqB,CAAC,mBAAmB,CAAC,CAAC;IAE7E,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;QAC9B,KAAK,gBAAgB;aAClB,WAAW,CAAC,WAAW,CAAC;aACxB,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACb,UAAU,CAAC,IAAI,CAAC,CAAC;YACjB,4CAA4C;YAC5C,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACtF,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;IACjC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAClB,SAAS,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEpC,wEAAwE;IACxE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;IACpE,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAChB,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG,QAAQ,EAAE,IAAI,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;IAElF,MAAM,GAAG,GAAG,KAAK,IAAmB,EAAE;QACpC,MAAM,CAAC,IAAI,CAAC,CAAC;QACb,IAAI,CAAC;YACH,MAAM,gBAAgB,CAAC,YAAY,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,EAAE,CAAC,CAAC;YACZ,MAAM,EAAE,CAAC;QACX,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,CAAC,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC;QACxF,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,CAAC,EAAU,EAAQ,EAAE;QAClC,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE;YACnB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;YAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;;gBAC7B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClB,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC;IAC3E,MAAM,SAAS,GAAG,GAAS,EAAE;QAC3B,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,KAAK,EAAE,QAAiB,EAAiB,EAAE;QAC/D,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO;QAChC,MAAM,CAAC,IAAI,CAAC,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,CAAC;QACd,IAAI,CAAC;YACH,MAAM,gBAAgB,CAAC,mBAAmB,CAAC,WAAW,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;YACjF,MAAM,EAAE,CAAC;QACX,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,CAAC,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC;QACxF,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CACL,MAAC,IAAI,IAAC,SAAS,EAAC,MAAM,aACpB,KAAC,UAAU,cACT,KAAC,SAAS,cAAE,CAAC,CAAC,0BAA0B,CAAC,GAAa,GAC3C,EACb,MAAC,WAAW,IAAC,SAAS,EAAC,qBAAqB,aACzC,GAAG,CAAC,CAAC,CAAC,CACL,KAAC,KAAK,IAAC,OAAO,EAAC,aAAa,YAC1B,KAAC,gBAAgB,cAAE,GAAG,GAAoB,GACpC,CACT,CAAC,CAAC,CAAC,IAAI,EACR,eAAK,SAAS,EAAC,sBAAsB,aACnC,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,IAAC,OAAO,EAAC,YAAY,YAAE,CAAC,CAAC,yBAAyB,CAAC,GAAS,EAClE,KAAC,KAAK,IAAC,EAAE,EAAC,YAAY,EAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,EAAC,MAAM,GAAG,IAC7F,EACN,KAAC,MAAM,IAAC,IAAI,EAAC,QAAQ,EAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,GAAG,EAAE,YAC1E,CAAC,CAAC,wBAAwB,CAAC,GACrB,IACL,EACN,KAAC,mBAAmB,IAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,GAAI,EACrE,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACtB,YAAG,SAAS,EAAC,+BAA+B,YAAE,CAAC,CAAC,0BAA0B,CAAC,GAAK,CACjF,CAAC,CAAC,CAAC,CACF,8BACE,eAAK,SAAS,EAAC,yBAAyB,aACtC,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,IAAI,EACT,QAAQ,EAAE,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EACrC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,aAAa,CAAC,IAAI,CAAC,YAEtC,CAAC,CAAC,6BAA6B,CAAC,GAC1B,EACT,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,IAAI,EACT,QAAQ,EAAE,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EACrC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,aAAa,CAAC,KAAK,CAAC,YAEvC,CAAC,CAAC,+BAA+B,CAAC,GAC5B,EACR,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CACnB,eAAM,SAAS,EAAC,+BAA+B,YAC5C,CAAC,CAAC,kCAAkC,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,GAC3D,CACR,CAAC,CAAC,CAAC,IAAI,IACJ,EACN,MAAC,KAAK,eACJ,KAAC,WAAW,cACV,MAAC,QAAQ,eACP,KAAC,SAAS,IAAC,SAAS,EAAC,KAAK,YACxB,KAAC,QAAQ,IACP,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,SAAS,gBACP,CAAC,CAAC,4BAA4B,CAAC,GAC3C,GACQ,EACZ,KAAC,SAAS,cAAE,CAAC,CAAC,4BAA4B,CAAC,GAAa,EACxD,KAAC,SAAS,cAAE,CAAC,CAAC,6BAA6B,CAAC,GAAa,EACzD,KAAC,SAAS,cAAE,CAAC,CAAC,8BAA8B,CAAC,GAAa,IACjD,GACC,EACd,KAAC,SAAS,cACP,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACzB,MAAC,QAAQ,eACP,KAAC,SAAS,cACR,KAAC,QAAQ,IACP,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAC3B,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,gBAChB,CAAC,CAAC,IAAI,GAClB,GACQ,EACZ,KAAC,SAAS,cACR,KAAC,cAAc,IAAC,IAAI,EAAE,CAAC,CAAC,IAAI,GAAI,GACtB,EACZ,KAAC,SAAS,IAAC,SAAS,EAAC,uBAAuB,YAAE,CAAC,CAAC,UAAU,GAAa,EACvE,KAAC,SAAS,cACR,KAAC,KAAK,IAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,YACjD,CAAC,CAAC,QAAQ;4DACT,CAAC,CAAC,CAAC,CAAC,2BAA2B,CAAC;4DAChC,CAAC,CAAC,CAAC,CAAC,6BAA6B,CAAC,GAC9B,GACE,KAlBC,CAAC,CAAC,EAAE,CAmBR,CACZ,CAAC,GACQ,IACN,EACR,KAAC,gBAAgB,IACf,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,OAAO,CAAC,MAAM,EACrB,gBAAgB,EAAE,CAAC,IAAI,EAAE,EAAE;oCACzB,WAAW,CAAC,IAAI,CAAC,CAAC;oCAClB,OAAO,CAAC,CAAC,CAAC,CAAC;gCACb,CAAC,EACD,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAChD,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAC5D,IACD,CACJ,IACW,IACT,CACR,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,EACnB,KAAK,EACL,KAAK,EACL,QAAQ,GAKT;IACC,OAAO,CACL,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,cAAE,KAAK,GAAS,EACtB,KAAC,KAAK,IAAC,IAAI,EAAC,QAAQ,EAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAI,IACzF,CACP,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,EAC1B,MAAM,EACN,QAAQ,GAIT;IACC,MAAM,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,2BAA2B,CAAC;IACzC,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,eAAe;YAClB,OAAO,YAAG,SAAS,EAAC,+BAA+B,YAAE,CAAC,CAAC,0BAA0B,CAAC,GAAK,CAAC;QAC1F,KAAK,qBAAqB;YACxB,OAAO,CACL,cAAK,SAAS,EAAE,IAAI,YAClB,KAAC,WAAW,IAAC,KAAK,EAAC,SAAS,EAAC,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,CAAC,GAAI,GAC3G,CACP,CAAC;QACJ,KAAK,iBAAiB;YACpB,OAAO,CACL,eAAK,SAAS,EAAE,IAAI,aAClB,KAAC,WAAW,IAAC,KAAK,EAAC,QAAQ,EAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,CAAC,GAAI,EAC3G,KAAC,aAAa,IAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAI,IAChG,CACP,CAAC;QACJ,KAAK,kBAAkB;YACrB,OAAO,CACL,eAAK,SAAS,EAAE,IAAI,aAClB,KAAC,WAAW,IAAC,KAAK,EAAC,aAAa,EAAC,KAAK,EAAE,MAAM,CAAC,WAAW,EAAE,QAAQ,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,WAAW,EAAE,CAAC,GAAI,EAC/H,KAAC,WAAW,IAAC,KAAK,EAAC,cAAc,EAAC,KAAK,EAAE,MAAM,CAAC,YAAY,EAAE,QAAQ,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,YAAY,EAAE,CAAC,GAAI,EACnI,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,yBAAe,EACrB,MAAC,MAAM,IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,KAAsC,EAAE,CAAC,aAC7H,iBAAQ,KAAK,EAAC,UAAU,yBAAkB,EAC1C,iBAAQ,KAAK,EAAC,gBAAgB,+BAAwB,IAC/C,IACL,IACF,CACP,CAAC;QACJ,KAAK,qBAAqB;YACxB,OAAO,CACL,eAAK,SAAS,EAAE,IAAI,aAClB,KAAC,WAAW,IAAC,KAAK,EAAC,WAAW,EAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,CAAC,GAAI,EACvH,KAAC,WAAW,IAAC,KAAK,EAAC,SAAS,EAAC,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,CAAC,GAAI,EAC/G,KAAC,aAAa,IAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAI,IAChG,CACP,CAAC;QACJ,KAAK,oBAAoB;YACvB,OAAO,CACL,eAAK,SAAS,EAAE,IAAI,aAClB,KAAC,WAAW,IAAC,KAAK,EAAC,WAAW,EAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,CAAC,GAAI,EACvH,KAAC,WAAW,IAAC,KAAK,EAAC,QAAQ,EAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,CAAC,GAAI,EAC3G,KAAC,aAAa,IAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAI,IAChG,CACP,CAAC;QACJ,KAAK,+BAA+B;YAClC,OAAO,CACL,eAAK,SAAS,EAAE,IAAI,aAClB,KAAC,WAAW,IAAC,KAAK,EAAC,KAAK,EAAC,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,CAAC,GAAI,EAC/F,KAAC,WAAW,IAAC,KAAK,EAAC,SAAS,EAAC,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,CAAC,GAAI,IAC3G,CACP,CAAC;QACJ,KAAK,oBAAoB;YACvB,OAAO,CACL,eAAK,SAAS,EAAE,IAAI,aAClB,KAAC,cAAc,IAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,CAAC,GAAI,EACxG,KAAC,WAAW,IAAC,KAAK,EAAC,UAAU,EAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAI,EACnH,KAAC,WAAW,IAAC,KAAK,EAAC,WAAW,EAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,CAAC,GAAI,IACnH,CACP,CAAC;QACJ,KAAK,yBAAyB;YAC5B,OAAO,CACL,eAAK,SAAS,EAAE,IAAI,aAClB,KAAC,cAAc,IAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,CAAC,GAAI,EACxG,KAAC,WAAW,IAAC,KAAK,EAAC,UAAU,EAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAI,EACnH,KAAC,WAAW,IAAC,KAAK,EAAC,SAAS,EAAC,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,CAAC,GAAI,IAC3G,CACP,CAAC;QACJ,KAAK,wBAAwB;YAC3B,OAAO,CACL,eAAK,SAAS,EAAE,IAAI,aAClB,KAAC,cAAc,IAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,CAAC,GAAI,EACxG,KAAC,WAAW,IAAC,KAAK,EAAC,UAAU,EAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAI,EACnH,KAAC,WAAW,IAAC,KAAK,EAAC,QAAQ,EAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,CAAC,GAAI,EAC3G,KAAC,aAAa,IAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAI,IAChG,CACP,CAAC;IACN,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAoD;IAC1F,OAAO,CACL,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,2BAAiB,EACvB,KAAC,KAAK,IAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,GAAI,IAC1F,CACP,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAoD;IAC3F,OAAO,CACL,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,KAAK,4BAAkB,EACxB,KAAC,KAAK,IAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,WAAW,EAAC,cAAc,GAAG,IACzF,CACP,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,eAAe,iBAAiB,CAAC"}
|
|
@@ -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":"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"}
|
|
@@ -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"}
|