@inspirer-dev/crm-dashboard 1.0.84 → 1.0.86
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/admin/src/components/ButtonsBuilder/index.tsx +97 -58
- package/admin/src/components/TriggerParamsField/index.tsx +331 -109
- package/admin/src/types/crm.ts +3 -1
- package/dist/_chunks/index-BqcFfrh8.js +478 -0
- package/dist/_chunks/index-CKr1VvX0.mjs +476 -0
- package/dist/_chunks/{index-Cg0G_bTE.js → index-CapXG1AZ.js} +73 -48
- package/dist/_chunks/{index-BKfFI_Jo.mjs → index-ClbsgJmF.mjs} +75 -50
- package/dist/admin/index.js +2 -2
- package/dist/admin/index.mjs +2 -2
- package/package.json +1 -1
- package/dist/_chunks/index-Bot_XlI2.mjs +0 -304
- package/dist/_chunks/index-Cmo9If32.js +0 -304
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { forwardRef, useRef, useState, useMemo } from "react";
|
|
3
|
+
import { Field, Flex, Box, Typography, Button, Tooltip, IconButton, SingleSelect, SingleSelectOption, Card, CardContent, NumberInput } from "@strapi/design-system";
|
|
4
|
+
import { Plus, Trash } from "@strapi/icons";
|
|
5
|
+
import { useTheme } from "styled-components";
|
|
6
|
+
const TRIGGER_PARAMS = [
|
|
7
|
+
{
|
|
8
|
+
key: "delaySeconds",
|
|
9
|
+
label: "Задержка",
|
|
10
|
+
description: "Задержка перед показом после срабатывания триггера",
|
|
11
|
+
unit: "сек",
|
|
12
|
+
min: 0,
|
|
13
|
+
placeholder: "7",
|
|
14
|
+
stageTypes: ["side_hint", "modal", "retry"]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
key: "timeOnSiteSeconds",
|
|
18
|
+
label: "Время на сайте",
|
|
19
|
+
description: "Мин. время на сайте для срабатывания",
|
|
20
|
+
unit: "сек",
|
|
21
|
+
min: 0,
|
|
22
|
+
placeholder: "120",
|
|
23
|
+
stageTypes: ["exit_intent", "side_hint", "modal"]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
key: "scrollThresholdPx",
|
|
27
|
+
label: "Порог скролла",
|
|
28
|
+
description: "Скролл в пикселях для срабатывания",
|
|
29
|
+
unit: "px",
|
|
30
|
+
min: 0,
|
|
31
|
+
placeholder: "200",
|
|
32
|
+
stageTypes: ["side_hint"]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
key: "idleSeconds",
|
|
36
|
+
label: "Бездействие",
|
|
37
|
+
description: "Время без кликов/скролла",
|
|
38
|
+
unit: "сек",
|
|
39
|
+
min: 0,
|
|
40
|
+
placeholder: "15",
|
|
41
|
+
stageTypes: ["side_hint"]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
key: "caseViewSeconds",
|
|
45
|
+
label: "Просмотр кейса",
|
|
46
|
+
description: "Время на странице кейса",
|
|
47
|
+
unit: "сек",
|
|
48
|
+
min: 0,
|
|
49
|
+
placeholder: "12",
|
|
50
|
+
stageTypes: ["modal", "side_hint"]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
key: "activePlayMinutes",
|
|
54
|
+
label: "Активная игра",
|
|
55
|
+
description: "Время активной игры",
|
|
56
|
+
unit: "мин",
|
|
57
|
+
min: 0,
|
|
58
|
+
placeholder: "10",
|
|
59
|
+
stageTypes: ["modal"]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
key: "actionCountThreshold",
|
|
63
|
+
label: "Порог действий",
|
|
64
|
+
description: "Кол-во значимых действий + низкий баланс",
|
|
65
|
+
unit: "",
|
|
66
|
+
min: 0,
|
|
67
|
+
placeholder: "2",
|
|
68
|
+
stageTypes: ["modal"]
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
key: "balanceThresholdMultiplier",
|
|
72
|
+
label: "Множитель баланса",
|
|
73
|
+
description: 'Множитель мин. цены кейса для "низкого баланса"',
|
|
74
|
+
unit: "×",
|
|
75
|
+
min: 0,
|
|
76
|
+
placeholder: "1.5",
|
|
77
|
+
stageTypes: ["modal", "side_hint"]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
key: "abandonedTimeoutMinutes",
|
|
81
|
+
label: "Таймаут заброшенного депозита",
|
|
82
|
+
description: "Через сколько минут депозит считается заброшенным",
|
|
83
|
+
unit: "мин",
|
|
84
|
+
min: 1,
|
|
85
|
+
placeholder: "10",
|
|
86
|
+
stageTypes: ["retry"]
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
key: "minDepositAmount",
|
|
90
|
+
label: "Мин. сумма депозита",
|
|
91
|
+
description: "Подстановка в {{min_deposit}} в текстах",
|
|
92
|
+
unit: "₽",
|
|
93
|
+
min: 0,
|
|
94
|
+
placeholder: "250",
|
|
95
|
+
stageTypes: ["modal", "side_hint", "retry"]
|
|
96
|
+
}
|
|
97
|
+
];
|
|
98
|
+
const STAGE_TYPE_LABELS = {
|
|
99
|
+
side_hint: "Side-hint",
|
|
100
|
+
modal: "Modal",
|
|
101
|
+
exit_intent: "Exit intent",
|
|
102
|
+
retry: "Retry"
|
|
103
|
+
};
|
|
104
|
+
const parseValue = (value) => {
|
|
105
|
+
if (!value) return [{}];
|
|
106
|
+
if (typeof value === "string") {
|
|
107
|
+
try {
|
|
108
|
+
const parsed = JSON.parse(value);
|
|
109
|
+
if (Array.isArray(parsed)) return parsed.length > 0 ? parsed : [{}];
|
|
110
|
+
if (typeof parsed === "object" && parsed !== null) return [parsed];
|
|
111
|
+
} catch {
|
|
112
|
+
}
|
|
113
|
+
return [{}];
|
|
114
|
+
}
|
|
115
|
+
if (Array.isArray(value)) return value.length > 0 ? value : [{}];
|
|
116
|
+
if (typeof value === "object") return [value];
|
|
117
|
+
return [{}];
|
|
118
|
+
};
|
|
119
|
+
const serialize = (groups) => {
|
|
120
|
+
const cleaned = groups.map((group) => {
|
|
121
|
+
const out = {};
|
|
122
|
+
for (const [key, val] of Object.entries(group)) {
|
|
123
|
+
if (typeof val === "number") out[key] = val;
|
|
124
|
+
}
|
|
125
|
+
return out;
|
|
126
|
+
}).filter((group) => Object.keys(group).length > 0);
|
|
127
|
+
return JSON.stringify(cleaned.length > 0 ? cleaned : []);
|
|
128
|
+
};
|
|
129
|
+
const DEPTH_BORDERS = ["#7b79ff", "#ee5e52", "#0c75af", "#328048"];
|
|
130
|
+
const useThemeColors = () => {
|
|
131
|
+
const theme = useTheme();
|
|
132
|
+
const isDark = theme?.colors?.neutral0 === "#212134";
|
|
133
|
+
return useMemo(
|
|
134
|
+
() => ({
|
|
135
|
+
isDark,
|
|
136
|
+
emptyBorder: isDark ? "#32324d" : "#dcdce4",
|
|
137
|
+
cardBorder: isDark ? "#32324d" : "#eaeaef",
|
|
138
|
+
tagBg: isDark ? "#2d2d4a" : "#f0f0ff",
|
|
139
|
+
groupBg: isDark ? "#1a1a2e" : "#f6f6f9",
|
|
140
|
+
orDividerLine: isDark ? "#32324d" : "#dcdce4",
|
|
141
|
+
andLabelColor: isDark ? "#a5a5ba" : "#666687",
|
|
142
|
+
depthBorders: DEPTH_BORDERS
|
|
143
|
+
}),
|
|
144
|
+
[isDark]
|
|
145
|
+
);
|
|
146
|
+
};
|
|
147
|
+
const getParamDef = (key) => TRIGGER_PARAMS.find((p) => p.key === key);
|
|
148
|
+
const ParamCard = ({
|
|
149
|
+
paramKey,
|
|
150
|
+
value,
|
|
151
|
+
onValueChange,
|
|
152
|
+
onRemove,
|
|
153
|
+
disabled,
|
|
154
|
+
colors
|
|
155
|
+
}) => {
|
|
156
|
+
const def = getParamDef(paramKey);
|
|
157
|
+
if (!def) return null;
|
|
158
|
+
return /* @__PURE__ */ jsx(Card, { background: "neutral0", style: { border: `1px solid ${colors.cardBorder}` }, children: /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "center", padding: 3, children: [
|
|
159
|
+
/* @__PURE__ */ jsxs(Box, { style: { flex: 1, minWidth: 0 }, children: [
|
|
160
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", marginBottom: 1, children: [
|
|
161
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", children: def.label }),
|
|
162
|
+
def.unit && /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral500", children: [
|
|
163
|
+
"(",
|
|
164
|
+
def.unit,
|
|
165
|
+
")"
|
|
166
|
+
] })
|
|
167
|
+
] }),
|
|
168
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: def.description }),
|
|
169
|
+
/* @__PURE__ */ jsx(Flex, { gap: 1, marginTop: 1, wrap: "wrap", children: def.stageTypes.map((st) => /* @__PURE__ */ jsx(
|
|
170
|
+
Box,
|
|
171
|
+
{
|
|
172
|
+
style: {
|
|
173
|
+
padding: "1px 6px",
|
|
174
|
+
borderRadius: "4px",
|
|
175
|
+
backgroundColor: colors.tagBg,
|
|
176
|
+
fontSize: "11px"
|
|
177
|
+
},
|
|
178
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "primary600", children: STAGE_TYPE_LABELS[st] || st })
|
|
179
|
+
},
|
|
180
|
+
st
|
|
181
|
+
)) })
|
|
182
|
+
] }),
|
|
183
|
+
/* @__PURE__ */ jsx(Box, { style: { width: 120, flexShrink: 0 }, children: /* @__PURE__ */ jsx(
|
|
184
|
+
NumberInput,
|
|
185
|
+
{
|
|
186
|
+
placeholder: def.placeholder,
|
|
187
|
+
value: value ?? "",
|
|
188
|
+
onValueChange,
|
|
189
|
+
disabled,
|
|
190
|
+
size: "S",
|
|
191
|
+
step: paramKey === "balanceThresholdMultiplier" ? 0.1 : 1
|
|
192
|
+
}
|
|
193
|
+
) }),
|
|
194
|
+
/* @__PURE__ */ jsx(Tooltip, { label: "Удалить параметр", children: /* @__PURE__ */ jsx(
|
|
195
|
+
IconButton,
|
|
196
|
+
{
|
|
197
|
+
onClick: onRemove,
|
|
198
|
+
label: "Delete",
|
|
199
|
+
variant: "ghost",
|
|
200
|
+
size: "S",
|
|
201
|
+
disabled,
|
|
202
|
+
style: { color: "#d02b20", flexShrink: 0 },
|
|
203
|
+
children: /* @__PURE__ */ jsx(Trash, { width: 16, height: 16 })
|
|
204
|
+
}
|
|
205
|
+
) })
|
|
206
|
+
] }) }) });
|
|
207
|
+
};
|
|
208
|
+
const AndLabel = ({ colors }) => /* @__PURE__ */ jsx(Flex, { justifyContent: "center", paddingTop: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(
|
|
209
|
+
Typography,
|
|
210
|
+
{
|
|
211
|
+
variant: "sigma",
|
|
212
|
+
textColor: "neutral600",
|
|
213
|
+
style: {
|
|
214
|
+
fontSize: "11px",
|
|
215
|
+
fontWeight: 700,
|
|
216
|
+
letterSpacing: "0.5px",
|
|
217
|
+
color: colors.andLabelColor,
|
|
218
|
+
textTransform: "uppercase"
|
|
219
|
+
},
|
|
220
|
+
children: "И"
|
|
221
|
+
}
|
|
222
|
+
) });
|
|
223
|
+
const OrDivider = ({ colors }) => /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 3, paddingTop: 2, paddingBottom: 2, children: [
|
|
224
|
+
/* @__PURE__ */ jsx(Box, { style: { flex: 1, height: "1px", backgroundColor: colors.orDividerLine } }),
|
|
225
|
+
/* @__PURE__ */ jsx(
|
|
226
|
+
Box,
|
|
227
|
+
{
|
|
228
|
+
style: {
|
|
229
|
+
padding: "2px 12px",
|
|
230
|
+
borderRadius: "12px",
|
|
231
|
+
border: `1px solid ${colors.orDividerLine}`,
|
|
232
|
+
backgroundColor: colors.isDark ? "#212134" : "#ffffff"
|
|
233
|
+
},
|
|
234
|
+
children: /* @__PURE__ */ jsx(
|
|
235
|
+
Typography,
|
|
236
|
+
{
|
|
237
|
+
variant: "sigma",
|
|
238
|
+
style: {
|
|
239
|
+
fontSize: "11px",
|
|
240
|
+
fontWeight: 700,
|
|
241
|
+
letterSpacing: "0.5px",
|
|
242
|
+
color: colors.andLabelColor,
|
|
243
|
+
textTransform: "uppercase"
|
|
244
|
+
},
|
|
245
|
+
children: "ИЛИ"
|
|
246
|
+
}
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
),
|
|
250
|
+
/* @__PURE__ */ jsx(Box, { style: { flex: 1, height: "1px", backgroundColor: colors.orDividerLine } })
|
|
251
|
+
] });
|
|
252
|
+
const ParamGroupCard = ({
|
|
253
|
+
group,
|
|
254
|
+
groupIndex,
|
|
255
|
+
totalGroups,
|
|
256
|
+
onAddParam,
|
|
257
|
+
onRemoveParam,
|
|
258
|
+
onSetValue,
|
|
259
|
+
onRemoveGroup,
|
|
260
|
+
disabled,
|
|
261
|
+
colors
|
|
262
|
+
}) => {
|
|
263
|
+
const activeKeys = Object.keys(group);
|
|
264
|
+
const availableParams = TRIGGER_PARAMS.filter((p) => !activeKeys.includes(p.key));
|
|
265
|
+
const borderColor = colors.depthBorders[groupIndex % colors.depthBorders.length];
|
|
266
|
+
return /* @__PURE__ */ jsx(
|
|
267
|
+
Box,
|
|
268
|
+
{
|
|
269
|
+
padding: 4,
|
|
270
|
+
hasRadius: true,
|
|
271
|
+
style: {
|
|
272
|
+
backgroundColor: colors.groupBg,
|
|
273
|
+
borderLeft: `3px solid ${borderColor}`,
|
|
274
|
+
border: `1px solid ${colors.cardBorder}`,
|
|
275
|
+
borderLeftWidth: "3px",
|
|
276
|
+
borderLeftColor: borderColor
|
|
277
|
+
},
|
|
278
|
+
children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
|
279
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
|
|
280
|
+
/* @__PURE__ */ jsxs(
|
|
281
|
+
Typography,
|
|
282
|
+
{
|
|
283
|
+
variant: "sigma",
|
|
284
|
+
textColor: "neutral700",
|
|
285
|
+
style: { textTransform: "uppercase", fontSize: "11px", letterSpacing: "0.5px" },
|
|
286
|
+
children: [
|
|
287
|
+
"Группа ",
|
|
288
|
+
groupIndex + 1
|
|
289
|
+
]
|
|
290
|
+
}
|
|
291
|
+
),
|
|
292
|
+
totalGroups > 1 && /* @__PURE__ */ jsx(Tooltip, { label: "Удалить группу", children: /* @__PURE__ */ jsx(
|
|
293
|
+
IconButton,
|
|
294
|
+
{
|
|
295
|
+
onClick: onRemoveGroup,
|
|
296
|
+
label: "Удалить группу",
|
|
297
|
+
variant: "ghost",
|
|
298
|
+
size: "S",
|
|
299
|
+
disabled,
|
|
300
|
+
style: { color: "#d02b20" },
|
|
301
|
+
children: /* @__PURE__ */ jsx(Trash, { width: 14, height: 14 })
|
|
302
|
+
}
|
|
303
|
+
) })
|
|
304
|
+
] }),
|
|
305
|
+
activeKeys.length === 0 ? /* @__PURE__ */ jsx(
|
|
306
|
+
Box,
|
|
307
|
+
{
|
|
308
|
+
padding: 3,
|
|
309
|
+
hasRadius: true,
|
|
310
|
+
style: {
|
|
311
|
+
border: `1px dashed ${colors.emptyBorder}`,
|
|
312
|
+
textAlign: "center"
|
|
313
|
+
},
|
|
314
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: "Добавьте параметры в группу" })
|
|
315
|
+
}
|
|
316
|
+
) : activeKeys.map((key, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
317
|
+
i > 0 && /* @__PURE__ */ jsx(AndLabel, { colors }),
|
|
318
|
+
/* @__PURE__ */ jsx(
|
|
319
|
+
ParamCard,
|
|
320
|
+
{
|
|
321
|
+
paramKey: key,
|
|
322
|
+
value: group[key],
|
|
323
|
+
onValueChange: (val) => onSetValue(key, val),
|
|
324
|
+
onRemove: () => onRemoveParam(key),
|
|
325
|
+
disabled,
|
|
326
|
+
colors
|
|
327
|
+
}
|
|
328
|
+
)
|
|
329
|
+
] }, key)),
|
|
330
|
+
availableParams.length > 0 && /* @__PURE__ */ jsx(Box, { paddingTop: 1, children: /* @__PURE__ */ jsx(AddParamSelect, { available: availableParams, onAdd: onAddParam, disabled }) })
|
|
331
|
+
] })
|
|
332
|
+
}
|
|
333
|
+
);
|
|
334
|
+
};
|
|
335
|
+
const TriggerParamsField = forwardRef(
|
|
336
|
+
({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
|
|
337
|
+
const initialRef = useRef(value);
|
|
338
|
+
const [groups, setGroups] = useState(() => parseValue(initialRef.current));
|
|
339
|
+
const colors = useThemeColors();
|
|
340
|
+
const update = (next) => {
|
|
341
|
+
setGroups(next);
|
|
342
|
+
onChange({ target: { name, value: serialize(next) } });
|
|
343
|
+
};
|
|
344
|
+
const addGroup = () => {
|
|
345
|
+
update([...groups, {}]);
|
|
346
|
+
};
|
|
347
|
+
const removeGroup = (idx) => {
|
|
348
|
+
const next = groups.filter((_, i) => i !== idx);
|
|
349
|
+
update(next.length > 0 ? next : [{}]);
|
|
350
|
+
};
|
|
351
|
+
const addParamToGroup = (idx, key) => {
|
|
352
|
+
const next = groups.map((g, i) => i === idx ? { ...g, [key]: null } : g);
|
|
353
|
+
update(next);
|
|
354
|
+
};
|
|
355
|
+
const removeParamFromGroup = (idx, key) => {
|
|
356
|
+
const next = groups.map((g, i) => {
|
|
357
|
+
if (i !== idx) return g;
|
|
358
|
+
const copy = { ...g };
|
|
359
|
+
delete copy[key];
|
|
360
|
+
return copy;
|
|
361
|
+
});
|
|
362
|
+
update(next);
|
|
363
|
+
};
|
|
364
|
+
const setParamValue = (idx, key, val) => {
|
|
365
|
+
const next = groups.map((g, i) => i === idx ? { ...g, [key]: val ?? null } : g);
|
|
366
|
+
update(next);
|
|
367
|
+
};
|
|
368
|
+
const allEmpty = groups.every((g) => Object.keys(g).length === 0);
|
|
369
|
+
return /* @__PURE__ */ jsx(Field.Root, { name, error, required, hint, ref, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, children: [
|
|
370
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", alignItems: "center", children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
371
|
+
/* @__PURE__ */ jsx(Field.Label, { children: intlLabel?.defaultMessage || "Trigger Params" }),
|
|
372
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: "Настройте параметры срабатывания для этого этапа" })
|
|
373
|
+
] }) }),
|
|
374
|
+
groups.length === 1 && allEmpty ? /* @__PURE__ */ jsxs(
|
|
375
|
+
Box,
|
|
376
|
+
{
|
|
377
|
+
padding: 5,
|
|
378
|
+
background: "neutral100",
|
|
379
|
+
hasRadius: true,
|
|
380
|
+
style: {
|
|
381
|
+
border: `2px dashed ${colors.emptyBorder}`,
|
|
382
|
+
textAlign: "center"
|
|
383
|
+
},
|
|
384
|
+
children: [
|
|
385
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral500", children: "Параметры не настроены" }),
|
|
386
|
+
/* @__PURE__ */ jsx(
|
|
387
|
+
Typography,
|
|
388
|
+
{
|
|
389
|
+
variant: "pi",
|
|
390
|
+
textColor: "neutral400",
|
|
391
|
+
style: { display: "block", marginTop: 4 },
|
|
392
|
+
children: "Добавьте параметры триггера, чтобы управлять условиями показа этапа"
|
|
393
|
+
}
|
|
394
|
+
)
|
|
395
|
+
]
|
|
396
|
+
}
|
|
397
|
+
) : /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 0, children: groups.map((group, idx) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
398
|
+
idx > 0 && /* @__PURE__ */ jsx(OrDivider, { colors }),
|
|
399
|
+
/* @__PURE__ */ jsx(
|
|
400
|
+
ParamGroupCard,
|
|
401
|
+
{
|
|
402
|
+
group,
|
|
403
|
+
groupIndex: idx,
|
|
404
|
+
totalGroups: groups.length,
|
|
405
|
+
onAddParam: (key) => addParamToGroup(idx, key),
|
|
406
|
+
onRemoveParam: (key) => removeParamFromGroup(idx, key),
|
|
407
|
+
onSetValue: (key, val) => setParamValue(idx, key, val),
|
|
408
|
+
onRemoveGroup: () => removeGroup(idx),
|
|
409
|
+
disabled,
|
|
410
|
+
colors
|
|
411
|
+
}
|
|
412
|
+
)
|
|
413
|
+
] }, idx)) }),
|
|
414
|
+
groups.length === 1 && allEmpty ? /* @__PURE__ */ jsx(
|
|
415
|
+
AddParamSelect,
|
|
416
|
+
{
|
|
417
|
+
available: TRIGGER_PARAMS,
|
|
418
|
+
onAdd: (key) => addParamToGroup(0, key),
|
|
419
|
+
disabled
|
|
420
|
+
}
|
|
421
|
+
) : /* @__PURE__ */ jsx(
|
|
422
|
+
Button,
|
|
423
|
+
{
|
|
424
|
+
startIcon: /* @__PURE__ */ jsx(Plus, {}),
|
|
425
|
+
onClick: addGroup,
|
|
426
|
+
disabled,
|
|
427
|
+
variant: "tertiary",
|
|
428
|
+
size: "S",
|
|
429
|
+
children: "Добавить OR группу"
|
|
430
|
+
}
|
|
431
|
+
),
|
|
432
|
+
error && /* @__PURE__ */ jsx(Field.Error, {}),
|
|
433
|
+
hint && /* @__PURE__ */ jsx(Field.Hint, {})
|
|
434
|
+
] }) });
|
|
435
|
+
}
|
|
436
|
+
);
|
|
437
|
+
TriggerParamsField.displayName = "TriggerParamsField";
|
|
438
|
+
const AddParamSelect = ({ available, onAdd, disabled }) => {
|
|
439
|
+
const [selected, setSelected] = useState(null);
|
|
440
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "flex-end", children: [
|
|
441
|
+
/* @__PURE__ */ jsx(Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(
|
|
442
|
+
SingleSelect,
|
|
443
|
+
{
|
|
444
|
+
placeholder: "Выберите параметр...",
|
|
445
|
+
value: selected,
|
|
446
|
+
onChange: (val) => setSelected(val),
|
|
447
|
+
disabled,
|
|
448
|
+
size: "S",
|
|
449
|
+
children: available.map((p) => /* @__PURE__ */ jsxs(SingleSelectOption, { value: p.key, children: [
|
|
450
|
+
p.label,
|
|
451
|
+
" — ",
|
|
452
|
+
p.description
|
|
453
|
+
] }, p.key))
|
|
454
|
+
}
|
|
455
|
+
) }),
|
|
456
|
+
/* @__PURE__ */ jsx(
|
|
457
|
+
Button,
|
|
458
|
+
{
|
|
459
|
+
startIcon: /* @__PURE__ */ jsx(Plus, {}),
|
|
460
|
+
onClick: () => {
|
|
461
|
+
if (selected) {
|
|
462
|
+
onAdd(selected);
|
|
463
|
+
setSelected(null);
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
disabled: disabled || !selected,
|
|
467
|
+
variant: "secondary",
|
|
468
|
+
size: "S",
|
|
469
|
+
children: "Добавить"
|
|
470
|
+
}
|
|
471
|
+
)
|
|
472
|
+
] });
|
|
473
|
+
};
|
|
474
|
+
export {
|
|
475
|
+
TriggerParamsField as default
|
|
476
|
+
};
|
|
@@ -6,26 +6,24 @@ const designSystem = require("@strapi/design-system");
|
|
|
6
6
|
const icons = require("@strapi/icons");
|
|
7
7
|
const styledComponents = require("styled-components");
|
|
8
8
|
const utils = require("./utils-CAs_GSGv.js");
|
|
9
|
+
const mapRawButton = (b) => ({
|
|
10
|
+
id: typeof b?.id === "string" ? b.id : utils.generateId(),
|
|
11
|
+
text: typeof b?.text === "string" ? b.text : "",
|
|
12
|
+
url: typeof b?.url === "string" ? b.url : "",
|
|
13
|
+
row: typeof b?.row === "number" ? b.row : 0,
|
|
14
|
+
type: b?.type === "screen" ? "screen" : "url",
|
|
15
|
+
screenSlug: typeof b?.screenSlug === "string" ? b.screenSlug : ""
|
|
16
|
+
});
|
|
9
17
|
const parseButtons = (value) => {
|
|
10
18
|
if (!value) return [];
|
|
11
19
|
if (Array.isArray(value)) {
|
|
12
|
-
return value.map(
|
|
13
|
-
id: typeof b?.id === "string" ? b.id : utils.generateId(),
|
|
14
|
-
text: typeof b?.text === "string" ? b.text : "",
|
|
15
|
-
url: typeof b?.url === "string" ? b.url : "",
|
|
16
|
-
row: typeof b?.row === "number" ? b.row : 0
|
|
17
|
-
}));
|
|
20
|
+
return value.map(mapRawButton);
|
|
18
21
|
}
|
|
19
22
|
if (typeof value === "string") {
|
|
20
23
|
try {
|
|
21
24
|
const parsed = JSON.parse(value);
|
|
22
25
|
if (!Array.isArray(parsed)) return [];
|
|
23
|
-
return parsed.map(
|
|
24
|
-
id: typeof b?.id === "string" ? b.id : utils.generateId(),
|
|
25
|
-
text: typeof b?.text === "string" ? b.text : "",
|
|
26
|
-
url: typeof b?.url === "string" ? b.url : "",
|
|
27
|
-
row: typeof b?.row === "number" ? b.row : 0
|
|
28
|
-
}));
|
|
26
|
+
return parsed.map(mapRawButton);
|
|
29
27
|
} catch {
|
|
30
28
|
return [];
|
|
31
29
|
}
|
|
@@ -61,37 +59,38 @@ const useThemeColors = () => {
|
|
|
61
59
|
}
|
|
62
60
|
}), [isDark]);
|
|
63
61
|
};
|
|
64
|
-
const TelegramButtonPreview = ({ text,
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
);
|
|
62
|
+
const TelegramButtonPreview = ({ text, btnType }) => {
|
|
63
|
+
const isScreen = btnType === "screen";
|
|
64
|
+
const bgColor = isScreen ? "#7c3aed" : "#3390ec";
|
|
65
|
+
const bgHover = isScreen ? "#6d28d9" : "#2b7ed8";
|
|
66
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
67
|
+
"span",
|
|
68
|
+
{
|
|
69
|
+
style: {
|
|
70
|
+
display: "inline-flex",
|
|
71
|
+
alignItems: "center",
|
|
72
|
+
justifyContent: "center",
|
|
73
|
+
gap: "6px",
|
|
74
|
+
padding: "8px 16px",
|
|
75
|
+
backgroundColor: bgColor,
|
|
76
|
+
color: "#ffffff",
|
|
77
|
+
borderRadius: "8px",
|
|
78
|
+
textDecoration: "none",
|
|
79
|
+
fontSize: "14px",
|
|
80
|
+
fontWeight: 500,
|
|
81
|
+
cursor: "default",
|
|
82
|
+
transition: "background-color 0.15s ease",
|
|
83
|
+
minWidth: "80px"
|
|
84
|
+
},
|
|
85
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = bgHover,
|
|
86
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = bgColor,
|
|
87
|
+
children: [
|
|
88
|
+
isScreen ? /* @__PURE__ */ jsxRuntime.jsx(icons.Layout, { width: 14, height: 14, style: { opacity: 0.9 } }) : /* @__PURE__ */ jsxRuntime.jsx(icons.Link, { width: 14, height: 14, style: { opacity: 0.9 } }),
|
|
89
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: text || "(empty)" })
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
};
|
|
95
94
|
const ButtonsBuilder = React.forwardRef(
|
|
96
95
|
({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
|
|
97
96
|
const [buttons, setButtons] = React.useState(() => parseButtons(value));
|
|
@@ -106,7 +105,7 @@ const ButtonsBuilder = React.forwardRef(
|
|
|
106
105
|
const addButton = () => {
|
|
107
106
|
update([
|
|
108
107
|
...buttons,
|
|
109
|
-
{ id: utils.generateId(), text: "Button", url: "https://cases.gg", row: 0 }
|
|
108
|
+
{ id: utils.generateId(), text: "Button", url: "https://cases.gg", row: 0, type: "url", screenSlug: "" }
|
|
110
109
|
]);
|
|
111
110
|
};
|
|
112
111
|
const updateButton = (id, patch) => {
|
|
@@ -164,7 +163,8 @@ const ButtonsBuilder = React.forwardRef(
|
|
|
164
163
|
]
|
|
165
164
|
}
|
|
166
165
|
) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 2, children: buttons.map((btn, idx) => {
|
|
167
|
-
const
|
|
166
|
+
const isScreen = btn.type === "screen";
|
|
167
|
+
const urlOk = isScreen || (btn.url ?? "").length === 0 || isValidUrl(btn.url ?? "");
|
|
168
168
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
169
169
|
designSystem.Card,
|
|
170
170
|
{
|
|
@@ -191,6 +191,22 @@ const ButtonsBuilder = React.forwardRef(
|
|
|
191
191
|
children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "primary600", children: idx + 1 })
|
|
192
192
|
}
|
|
193
193
|
),
|
|
194
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: 100, flexShrink: 0 }, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
195
|
+
designSystem.SingleSelect,
|
|
196
|
+
{
|
|
197
|
+
value: btn.type || "url",
|
|
198
|
+
onChange: (val) => updateButton(btn.id, {
|
|
199
|
+
type: val,
|
|
200
|
+
...val === "url" ? { screenSlug: "" } : { url: "" }
|
|
201
|
+
}),
|
|
202
|
+
disabled,
|
|
203
|
+
size: "S",
|
|
204
|
+
children: [
|
|
205
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "url", children: "URL" }),
|
|
206
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "screen", children: "Screen" })
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
) }),
|
|
194
210
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1, minWidth: 120 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
195
211
|
designSystem.TextInput,
|
|
196
212
|
{
|
|
@@ -201,11 +217,20 @@ const ButtonsBuilder = React.forwardRef(
|
|
|
201
217
|
size: "S"
|
|
202
218
|
}
|
|
203
219
|
) }),
|
|
204
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 2, minWidth: 180 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
220
|
+
isScreen ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 2, minWidth: 180 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
221
|
+
designSystem.TextInput,
|
|
222
|
+
{
|
|
223
|
+
placeholder: "screen-slug",
|
|
224
|
+
value: btn.screenSlug ?? "",
|
|
225
|
+
onChange: (e) => updateButton(btn.id, { screenSlug: e.target.value }),
|
|
226
|
+
disabled,
|
|
227
|
+
size: "S"
|
|
228
|
+
}
|
|
229
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 2, minWidth: 180 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
205
230
|
designSystem.TextInput,
|
|
206
231
|
{
|
|
207
232
|
placeholder: "https://...",
|
|
208
|
-
value: btn.url,
|
|
233
|
+
value: btn.url ?? "",
|
|
209
234
|
onChange: (e) => updateButton(btn.id, { url: e.target.value }),
|
|
210
235
|
disabled,
|
|
211
236
|
size: "S",
|
|
@@ -284,7 +309,7 @@ const ButtonsBuilder = React.forwardRef(
|
|
|
284
309
|
children: "PREVIEW"
|
|
285
310
|
}
|
|
286
311
|
),
|
|
287
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 2, alignItems: "center", children: previewRows.map((row) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, wrap: "wrap", justifyContent: "center", children: row.items.map((b) => /* @__PURE__ */ jsxRuntime.jsx(TelegramButtonPreview, { text: b.text,
|
|
312
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 2, alignItems: "center", children: previewRows.map((row) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, wrap: "wrap", justifyContent: "center", children: row.items.map((b) => /* @__PURE__ */ jsxRuntime.jsx(TelegramButtonPreview, { text: b.text, btnType: b.type }, b.id)) }, row.row)) })
|
|
288
313
|
]
|
|
289
314
|
}
|
|
290
315
|
),
|