@inspirer-dev/crm-dashboard 1.0.37 → 1.0.39
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 +4 -4
- package/admin/src/components/CancelConditionsField/index.tsx +6 -6
- package/admin/src/components/RulesBuilder/index.tsx +4 -4
- package/admin/src/components/StepFlowBuilder/flow-canvas/FlowCanvas.tsx +11 -2
- package/admin/src/components/StepFlowBuilder/panels/BranchConfig.tsx +5 -5
- package/admin/src/components/StepFlowBuilder/panels/EntryConfig.tsx +17 -17
- package/admin/src/components/StepFlowBuilder/panels/MessageConfig.tsx +9 -9
- package/admin/src/components/StepFlowBuilder/panels/WaitConfig.tsx +4 -4
- package/admin/src/components/TriggerConfigField/index.tsx +25 -15
- package/dist/_chunks/{FlowCanvas-B24xSTsy.mjs → FlowCanvas-Dosn1PWx.mjs} +48 -43
- package/dist/_chunks/{FlowCanvas-CyPjsEVc.js → FlowCanvas-O8LZmpU9.js} +47 -42
- package/dist/_chunks/{index-CLv1Ce0a.js → index--0PypLko.js} +4 -4
- package/dist/_chunks/{index-DphnHWJg.js → index-BAEkCRvB.js} +1 -1
- package/dist/_chunks/{index-D4D9naFd.mjs → index-Bxnf94Nw.mjs} +307 -258
- package/dist/_chunks/{index-Cj7L2FNg.js → index-C-Vbihve.js} +1 -1
- package/dist/_chunks/{index-DdgfQNw_.mjs → index-C-eKNjo5.mjs} +6 -6
- package/dist/_chunks/{index-DkY191XW.mjs → index-CR4G6zrn.mjs} +1 -1
- package/dist/_chunks/{index-JOsIDBgU.mjs → index-CuPT2Zxf.mjs} +4 -4
- package/dist/_chunks/{index-jwDYIfnW.js → index-CvoXAIng.js} +6 -6
- package/dist/_chunks/{index-DGIbwLd4.js → index-CwfIGC3K.js} +23 -15
- package/dist/_chunks/{index-CrIUBH7C.mjs → index-D4m1lj0p.mjs} +23 -15
- package/dist/_chunks/{index-CipW7YLs.js → index-DDmUtV_B.js} +4 -4
- package/dist/_chunks/{index-BTVDaym0.mjs → index-DlqzYMRV.mjs} +4 -4
- package/dist/admin/index.js +6 -6
- package/dist/admin/index.mjs +6 -6
- package/package.json +1 -1
|
@@ -188,7 +188,7 @@ const ButtonsBuilder = forwardRef<HTMLDivElement, ButtonsBuilderProps>(
|
|
|
188
188
|
<Box>
|
|
189
189
|
<Field.Label>{intlLabel?.defaultMessage || 'Buttons'}</Field.Label>
|
|
190
190
|
<Typography variant="pi" textColor="neutral500">
|
|
191
|
-
|
|
191
|
+
Inline-кнопки для Telegram
|
|
192
192
|
</Typography>
|
|
193
193
|
</Box>
|
|
194
194
|
<Button
|
|
@@ -213,10 +213,10 @@ const ButtonsBuilder = forwardRef<HTMLDivElement, ButtonsBuilderProps>(
|
|
|
213
213
|
}}
|
|
214
214
|
>
|
|
215
215
|
<Typography variant="omega" textColor="neutral500">
|
|
216
|
-
|
|
216
|
+
Кнопок пока нет
|
|
217
217
|
</Typography>
|
|
218
218
|
<Typography variant="pi" textColor="neutral400" style={{ display: 'block', marginTop: 4 }}>
|
|
219
|
-
|
|
219
|
+
Добавьте кнопку для создания inline-клавиатуры в Telegram-сообщении
|
|
220
220
|
</Typography>
|
|
221
221
|
</Box>
|
|
222
222
|
) : (
|
|
@@ -329,7 +329,7 @@ const ButtonsBuilder = forwardRef<HTMLDivElement, ButtonsBuilderProps>(
|
|
|
329
329
|
{!urlOk && (
|
|
330
330
|
<Box paddingLeft={3} paddingBottom={2}>
|
|
331
331
|
<Typography variant="pi" textColor="danger600">
|
|
332
|
-
|
|
332
|
+
Введите корректный http/https URL
|
|
333
333
|
</Typography>
|
|
334
334
|
</Box>
|
|
335
335
|
)}
|
|
@@ -325,7 +325,7 @@ const CancelConditionsField = forwardRef<HTMLDivElement, CancelConditionsFieldPr
|
|
|
325
325
|
<Flex direction="column" gap={3}>
|
|
326
326
|
<Field.Label>{intlLabel?.defaultMessage || 'Cancel Conditions'}</Field.Label>
|
|
327
327
|
<Typography variant="pi" textColor="neutral600">
|
|
328
|
-
|
|
328
|
+
Пропустить отправку, если любое из условий истинно (проверяется перед отправкой)
|
|
329
329
|
</Typography>
|
|
330
330
|
|
|
331
331
|
<Card background="neutral100">
|
|
@@ -343,9 +343,9 @@ const CancelConditionsField = forwardRef<HTMLDivElement, CancelConditionsFieldPr
|
|
|
343
343
|
{config.logic === '$or' ? 'OR' : 'AND'}
|
|
344
344
|
</Button>
|
|
345
345
|
<Typography variant="omega" textColor="neutral600">
|
|
346
|
-
{config.logic === '$or'
|
|
347
|
-
? '
|
|
348
|
-
: '
|
|
346
|
+
{config.logic === '$or'
|
|
347
|
+
? 'Отменить, если ЛЮБОЕ условие истинно'
|
|
348
|
+
: 'Отменить, если ВСЕ условия истинны'}
|
|
349
349
|
</Typography>
|
|
350
350
|
</Flex>
|
|
351
351
|
</Flex>
|
|
@@ -365,7 +365,7 @@ const CancelConditionsField = forwardRef<HTMLDivElement, CancelConditionsFieldPr
|
|
|
365
365
|
{!hasRules && (
|
|
366
366
|
<Box padding={4} background="neutral0" hasRadius style={{ textAlign: 'center' }}>
|
|
367
367
|
<Typography variant="omega" textColor="neutral500">
|
|
368
|
-
|
|
368
|
+
Условия отмены не заданы. Сообщение будет отправлено, если правила сегмента совпадают.
|
|
369
369
|
</Typography>
|
|
370
370
|
</Box>
|
|
371
371
|
)}
|
|
@@ -379,7 +379,7 @@ const CancelConditionsField = forwardRef<HTMLDivElement, CancelConditionsFieldPr
|
|
|
379
379
|
disabled={disabled}
|
|
380
380
|
size="S"
|
|
381
381
|
>
|
|
382
|
-
|
|
382
|
+
Добавить условие отмены
|
|
383
383
|
</Button>
|
|
384
384
|
</Box>
|
|
385
385
|
</Box>
|
|
@@ -380,7 +380,7 @@ const RuleGroupComponent: React.FC<RuleGroupComponentProps> = ({
|
|
|
380
380
|
{group.logic === '$and' ? 'AND' : 'OR'}
|
|
381
381
|
</Button>
|
|
382
382
|
<Typography variant="pi" textColor="neutral600">
|
|
383
|
-
{group.logic === '$and' ? '
|
|
383
|
+
{group.logic === '$and' ? 'Все условия должны совпадать' : 'Любое условие может совпадать'}
|
|
384
384
|
</Typography>
|
|
385
385
|
</Flex>
|
|
386
386
|
{depth > 0 && onDelete && (
|
|
@@ -426,7 +426,7 @@ const RuleGroupComponent: React.FC<RuleGroupComponentProps> = ({
|
|
|
426
426
|
onClick={handleAddRule}
|
|
427
427
|
disabled={disabled}
|
|
428
428
|
>
|
|
429
|
-
|
|
429
|
+
Добавить условие
|
|
430
430
|
</Button>
|
|
431
431
|
{depth < 2 && (
|
|
432
432
|
<Button
|
|
@@ -436,7 +436,7 @@ const RuleGroupComponent: React.FC<RuleGroupComponentProps> = ({
|
|
|
436
436
|
onClick={handleAddGroup}
|
|
437
437
|
disabled={disabled}
|
|
438
438
|
>
|
|
439
|
-
|
|
439
|
+
Добавить {group.logic === '$and' ? 'ИЛИ' : 'И'} группу
|
|
440
440
|
</Button>
|
|
441
441
|
)}
|
|
442
442
|
</Flex>
|
|
@@ -483,7 +483,7 @@ const RulesBuilder = forwardRef<HTMLDivElement, RulesBuilderProps>(
|
|
|
483
483
|
</Badge>
|
|
484
484
|
{rulesCount > 0 && (
|
|
485
485
|
<Button variant="ghost" size="S" onClick={handleClear} disabled={disabled}>
|
|
486
|
-
|
|
486
|
+
Очистить всё
|
|
487
487
|
</Button>
|
|
488
488
|
)}
|
|
489
489
|
</Flex>
|
|
@@ -5,6 +5,7 @@ import ReactFlow, {
|
|
|
5
5
|
MiniMap,
|
|
6
6
|
useNodesState,
|
|
7
7
|
useEdgesState,
|
|
8
|
+
useReactFlow,
|
|
8
9
|
addEdge,
|
|
9
10
|
type Connection,
|
|
10
11
|
type OnNodesChange,
|
|
@@ -44,6 +45,7 @@ const FlowCanvas: React.FC<FlowCanvasProps> = ({ steps, onStepsChange, disabled,
|
|
|
44
45
|
const isInitialMount = useRef(true);
|
|
45
46
|
const syncTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
46
47
|
const lastStepsRef = useRef<string>('');
|
|
48
|
+
const { fitView } = useReactFlow();
|
|
47
49
|
|
|
48
50
|
useEffect(() => {
|
|
49
51
|
const stepsJson = JSON.stringify(steps);
|
|
@@ -60,9 +62,13 @@ const FlowCanvas: React.FC<FlowCanvasProps> = ({ steps, onStepsChange, disabled,
|
|
|
60
62
|
const layoutedNodes = applyAutoLayout(n, e);
|
|
61
63
|
setNodes(layoutedNodes);
|
|
62
64
|
setEdges(e);
|
|
65
|
+
|
|
66
|
+
setTimeout(() => {
|
|
67
|
+
fitView({ padding: 0.2, duration: 200 });
|
|
68
|
+
}, 50);
|
|
63
69
|
}
|
|
64
70
|
isInitialMount.current = false;
|
|
65
|
-
}, [steps, setNodes, setEdges]);
|
|
71
|
+
}, [steps, setNodes, setEdges, fitView]);
|
|
66
72
|
|
|
67
73
|
const syncToParent = useCallback(() => {
|
|
68
74
|
if (isInitialMount.current) return;
|
|
@@ -168,7 +174,10 @@ const FlowCanvas: React.FC<FlowCanvasProps> = ({ steps, onStepsChange, disabled,
|
|
|
168
174
|
const handleAutoLayout = useCallback(() => {
|
|
169
175
|
const layoutedNodes = applyAutoLayout(nodes, edges);
|
|
170
176
|
setNodes(layoutedNodes);
|
|
171
|
-
|
|
177
|
+
setTimeout(() => {
|
|
178
|
+
fitView({ padding: 0.2, duration: 200 });
|
|
179
|
+
}, 50);
|
|
180
|
+
}, [nodes, edges, setNodes, fitView]);
|
|
172
181
|
|
|
173
182
|
const handleNodeUpdate = useCallback(
|
|
174
183
|
(nodeId: string, data: Partial<FlowNodeData>) => {
|
|
@@ -94,7 +94,7 @@ const BranchConfig: React.FC<BranchConfigProps> = ({ data, onUpdate, disabled })
|
|
|
94
94
|
color: theme.textMuted,
|
|
95
95
|
}}
|
|
96
96
|
>
|
|
97
|
-
|
|
97
|
+
СЕГМЕНТ УСЛОВИЯ
|
|
98
98
|
</Typography>
|
|
99
99
|
<div style={{ width: '100%' }}>
|
|
100
100
|
{fetchError ? (
|
|
@@ -106,7 +106,7 @@ const BranchConfig: React.FC<BranchConfigProps> = ({ data, onUpdate, disabled })
|
|
|
106
106
|
placeholder="Enter segment ID..."
|
|
107
107
|
/>
|
|
108
108
|
<Typography variant="pi" style={{ color: theme.textSubtle, fontSize: 11, marginTop: 6 }}>
|
|
109
|
-
|
|
109
|
+
Введите ID сегмента вручную (API недоступен в тестовом режиме)
|
|
110
110
|
</Typography>
|
|
111
111
|
</>
|
|
112
112
|
) : (
|
|
@@ -174,7 +174,7 @@ const BranchConfig: React.FC<BranchConfigProps> = ({ data, onUpdate, disabled })
|
|
|
174
174
|
variant="pi"
|
|
175
175
|
style={{ color: theme.textMuted, fontWeight: 600, marginBottom: 10, display: 'block' }}
|
|
176
176
|
>
|
|
177
|
-
|
|
177
|
+
Как это работает
|
|
178
178
|
</Typography>
|
|
179
179
|
<Flex direction="column" gap={2}>
|
|
180
180
|
<Flex alignItems="center" gap={2}>
|
|
@@ -195,7 +195,7 @@ const BranchConfig: React.FC<BranchConfigProps> = ({ data, onUpdate, disabled })
|
|
|
195
195
|
</svg>
|
|
196
196
|
</span>
|
|
197
197
|
<Typography variant="pi" style={{ color: theme.textMuted }}>
|
|
198
|
-
|
|
198
|
+
Соответствует сегменту → путь <strong style={{ color: '#10b981' }}>Да</strong>
|
|
199
199
|
</Typography>
|
|
200
200
|
</Flex>
|
|
201
201
|
<Flex alignItems="center" gap={2}>
|
|
@@ -216,7 +216,7 @@ const BranchConfig: React.FC<BranchConfigProps> = ({ data, onUpdate, disabled })
|
|
|
216
216
|
</svg>
|
|
217
217
|
</span>
|
|
218
218
|
<Typography variant="pi" style={{ color: theme.textMuted }}>
|
|
219
|
-
|
|
219
|
+
Не соответствует → путь <strong style={{ color: '#ef4444' }}>Нет</strong>
|
|
220
220
|
</Typography>
|
|
221
221
|
</Flex>
|
|
222
222
|
</Flex>
|
|
@@ -103,7 +103,7 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
103
103
|
}}
|
|
104
104
|
>
|
|
105
105
|
<Typography variant="pi" style={{ color: theme.textSubtle }}>
|
|
106
|
-
|
|
106
|
+
Триггер не настроен
|
|
107
107
|
</Typography>
|
|
108
108
|
</div>
|
|
109
109
|
);
|
|
@@ -119,7 +119,7 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
119
119
|
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" fill="#8b5cf6" />
|
|
120
120
|
</svg>
|
|
121
121
|
}
|
|
122
|
-
title="
|
|
122
|
+
title="Триггер по событию"
|
|
123
123
|
gradient={
|
|
124
124
|
theme.isDark
|
|
125
125
|
? 'linear-gradient(135deg, #4c1d95 0%, #5b21b6 100%)'
|
|
@@ -131,13 +131,13 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
131
131
|
<Flex direction="column" gap={2}>
|
|
132
132
|
<Flex alignItems="center" gap={2}>
|
|
133
133
|
<Typography variant="pi" style={{ color: theme.textMuted }}>
|
|
134
|
-
|
|
134
|
+
Событие:
|
|
135
135
|
</Typography>
|
|
136
136
|
<Badge
|
|
137
137
|
background={theme.isDark ? '#7c3aed' : '#ddd6fe'}
|
|
138
138
|
color={theme.isDark ? '#f5f3ff' : '#6d28d9'}
|
|
139
139
|
>
|
|
140
|
-
{config.eventName || '
|
|
140
|
+
{config.eventName || 'Не задано'}
|
|
141
141
|
</Badge>
|
|
142
142
|
</Flex>
|
|
143
143
|
{config.delayValue && config.delayValue > 0 && (
|
|
@@ -152,7 +152,7 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
152
152
|
/>
|
|
153
153
|
</svg>
|
|
154
154
|
<Typography variant="pi" style={{ color: theme.textMuted }}>
|
|
155
|
-
|
|
155
|
+
Задержка: {config.delayValue} {config.delayUnit || 'minutes'}
|
|
156
156
|
</Typography>
|
|
157
157
|
</Flex>
|
|
158
158
|
)}
|
|
@@ -174,7 +174,7 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
174
174
|
/>
|
|
175
175
|
</svg>
|
|
176
176
|
}
|
|
177
|
-
title="
|
|
177
|
+
title="Триггер по расписанию"
|
|
178
178
|
gradient={
|
|
179
179
|
theme.isDark
|
|
180
180
|
? 'linear-gradient(135deg, #78350f 0%, #92400e 100%)'
|
|
@@ -186,7 +186,7 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
186
186
|
<Flex direction="column" gap={2}>
|
|
187
187
|
<Flex alignItems="center" gap={2}>
|
|
188
188
|
<Typography variant="pi" style={{ color: theme.textMuted }}>
|
|
189
|
-
|
|
189
|
+
Тип:
|
|
190
190
|
</Typography>
|
|
191
191
|
<Badge
|
|
192
192
|
background={theme.isDark ? '#d97706' : '#fde68a'}
|
|
@@ -197,13 +197,13 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
197
197
|
</Flex>
|
|
198
198
|
{config.scheduleType === 'interval' && (
|
|
199
199
|
<Typography variant="pi" style={{ color: theme.textMuted }}>
|
|
200
|
-
|
|
200
|
+
Каждые {config.scheduleEveryMinutes || 5} минут
|
|
201
201
|
</Typography>
|
|
202
202
|
)}
|
|
203
203
|
{(config.scheduleType === 'daily' || config.scheduleType === 'weekly') &&
|
|
204
204
|
config.scheduleTime && (
|
|
205
205
|
<Typography variant="pi" style={{ color: theme.textMuted }}>
|
|
206
|
-
|
|
206
|
+
В {config.scheduleTime} UTC
|
|
207
207
|
</Typography>
|
|
208
208
|
)}
|
|
209
209
|
{config.scheduleType === 'weekly' && config.scheduleDays && (
|
|
@@ -248,7 +248,7 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
248
248
|
}}
|
|
249
249
|
>
|
|
250
250
|
<Typography variant="pi" style={{ color: theme.textSubtle }}>
|
|
251
|
-
|
|
251
|
+
Сегмент не задан (все пользователи могут войти)
|
|
252
252
|
</Typography>
|
|
253
253
|
</div>
|
|
254
254
|
);
|
|
@@ -268,7 +268,7 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
268
268
|
<path d="M19 8v6M16 11h6" stroke="#0ea5e9" strokeWidth="2" strokeLinecap="round" />
|
|
269
269
|
</svg>
|
|
270
270
|
}
|
|
271
|
-
title="
|
|
271
|
+
title="Сегмент входа"
|
|
272
272
|
gradient={
|
|
273
273
|
theme.isDark
|
|
274
274
|
? 'linear-gradient(135deg, #0c4a6e 0%, #075985 100%)'
|
|
@@ -280,7 +280,7 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
280
280
|
<Flex direction="column" gap={2}>
|
|
281
281
|
<Flex alignItems="center" gap={2}>
|
|
282
282
|
<Typography variant="pi" style={{ color: theme.textMuted }}>
|
|
283
|
-
|
|
283
|
+
Сегмент:
|
|
284
284
|
</Typography>
|
|
285
285
|
<Badge
|
|
286
286
|
background={theme.isDark ? '#0284c7' : '#bae6fd'}
|
|
@@ -290,7 +290,7 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
290
290
|
</Badge>
|
|
291
291
|
</Flex>
|
|
292
292
|
<Typography variant="pi" style={{ color: theme.textSubtle, fontSize: 11 }}>
|
|
293
|
-
|
|
293
|
+
Только подходящие пользователи могут войти
|
|
294
294
|
</Typography>
|
|
295
295
|
</Flex>
|
|
296
296
|
</InfoCard>
|
|
@@ -310,7 +310,7 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
310
310
|
color: theme.textMuted,
|
|
311
311
|
}}
|
|
312
312
|
>
|
|
313
|
-
|
|
313
|
+
ТРИГГЕР
|
|
314
314
|
</Typography>
|
|
315
315
|
{renderTriggerInfo()}
|
|
316
316
|
</Box>
|
|
@@ -326,7 +326,7 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
326
326
|
color: theme.textMuted,
|
|
327
327
|
}}
|
|
328
328
|
>
|
|
329
|
-
|
|
329
|
+
УСЛОВИЯ ВХОДА
|
|
330
330
|
</Typography>
|
|
331
331
|
{renderSegmentInfo()}
|
|
332
332
|
</Box>
|
|
@@ -368,7 +368,7 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
368
368
|
marginBottom: 4,
|
|
369
369
|
}}
|
|
370
370
|
>
|
|
371
|
-
|
|
371
|
+
Точка входа в кампанию
|
|
372
372
|
</Typography>
|
|
373
373
|
<Typography
|
|
374
374
|
variant="pi"
|
|
@@ -378,7 +378,7 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
378
378
|
lineHeight: 1.5,
|
|
379
379
|
}}
|
|
380
380
|
>
|
|
381
|
-
|
|
381
|
+
Настройте триггер и сегмент входа в основных полях кампании выше.
|
|
382
382
|
</Typography>
|
|
383
383
|
</div>
|
|
384
384
|
</Flex>
|
|
@@ -160,7 +160,7 @@ const MessageConfig: React.FC<MessageConfigProps> = ({ data, onUpdate, disabled
|
|
|
160
160
|
color: theme.textMuted,
|
|
161
161
|
}}
|
|
162
162
|
>
|
|
163
|
-
|
|
163
|
+
КАНАЛ
|
|
164
164
|
</Typography>
|
|
165
165
|
<div style={{ width: '100%' }}>
|
|
166
166
|
<SingleSelect value={channel} onChange={handleChannelChange} disabled={disabled}>
|
|
@@ -179,7 +179,7 @@ const MessageConfig: React.FC<MessageConfigProps> = ({ data, onUpdate, disabled
|
|
|
179
179
|
variant="sigma"
|
|
180
180
|
style={{ fontSize: 11, letterSpacing: '0.05em', color: theme.textMuted }}
|
|
181
181
|
>
|
|
182
|
-
|
|
182
|
+
ВАРИАНТЫ (A/B ТЕСТИРОВАНИЕ)
|
|
183
183
|
</Typography>
|
|
184
184
|
<button
|
|
185
185
|
type="button"
|
|
@@ -217,7 +217,7 @@ const MessageConfig: React.FC<MessageConfigProps> = ({ data, onUpdate, disabled
|
|
|
217
217
|
}}
|
|
218
218
|
>
|
|
219
219
|
<Typography variant="pi" style={{ color: theme.textSubtle }}>
|
|
220
|
-
|
|
220
|
+
Вариантов пока нет. Добавьте вариант для A/B тестирования.
|
|
221
221
|
</Typography>
|
|
222
222
|
</div>
|
|
223
223
|
) : (
|
|
@@ -243,7 +243,7 @@ const MessageConfig: React.FC<MessageConfigProps> = ({ data, onUpdate, disabled
|
|
|
243
243
|
variant="pi"
|
|
244
244
|
style={{ color: theme.textMuted, fontSize: 10, fontWeight: 600 }}
|
|
245
245
|
>
|
|
246
|
-
|
|
246
|
+
Вариант {index + 1}
|
|
247
247
|
</Typography>
|
|
248
248
|
<button
|
|
249
249
|
type="button"
|
|
@@ -276,7 +276,7 @@ const MessageConfig: React.FC<MessageConfigProps> = ({ data, onUpdate, disabled
|
|
|
276
276
|
display: 'block',
|
|
277
277
|
}}
|
|
278
278
|
>
|
|
279
|
-
|
|
279
|
+
Название
|
|
280
280
|
</Typography>
|
|
281
281
|
<TextInput
|
|
282
282
|
value={variant.name}
|
|
@@ -297,7 +297,7 @@ const MessageConfig: React.FC<MessageConfigProps> = ({ data, onUpdate, disabled
|
|
|
297
297
|
display: 'block',
|
|
298
298
|
}}
|
|
299
299
|
>
|
|
300
|
-
|
|
300
|
+
Вес
|
|
301
301
|
</Typography>
|
|
302
302
|
<NumberInput
|
|
303
303
|
value={variant.weight}
|
|
@@ -318,7 +318,7 @@ const MessageConfig: React.FC<MessageConfigProps> = ({ data, onUpdate, disabled
|
|
|
318
318
|
display: 'block',
|
|
319
319
|
}}
|
|
320
320
|
>
|
|
321
|
-
|
|
321
|
+
Шаблон
|
|
322
322
|
</Typography>
|
|
323
323
|
{loadingTemplates ? (
|
|
324
324
|
<Flex padding={2}>
|
|
@@ -337,7 +337,7 @@ const MessageConfig: React.FC<MessageConfigProps> = ({ data, onUpdate, disabled
|
|
|
337
337
|
variant="pi"
|
|
338
338
|
style={{ color: theme.textSubtle, fontSize: 10, marginTop: 4 }}
|
|
339
339
|
>
|
|
340
|
-
|
|
340
|
+
Введите ID шаблона вручную
|
|
341
341
|
</Typography>
|
|
342
342
|
</>
|
|
343
343
|
) : (
|
|
@@ -369,7 +369,7 @@ const MessageConfig: React.FC<MessageConfigProps> = ({ data, onUpdate, disabled
|
|
|
369
369
|
variant="pi"
|
|
370
370
|
style={{ color: theme.isDark ? '#fcd34d' : '#b45309', fontSize: 11 }}
|
|
371
371
|
>
|
|
372
|
-
|
|
372
|
+
Нет шаблонов для {channel}
|
|
373
373
|
</Typography>
|
|
374
374
|
</div>
|
|
375
375
|
)}
|
|
@@ -53,7 +53,7 @@ const WaitConfig: React.FC<WaitConfigProps> = ({ data, onUpdate, disabled }) =>
|
|
|
53
53
|
color: theme.textMuted,
|
|
54
54
|
}}
|
|
55
55
|
>
|
|
56
|
-
|
|
56
|
+
ДЛИТЕЛЬНОСТЬ
|
|
57
57
|
</Typography>
|
|
58
58
|
<div style={{ width: '100%' }}>
|
|
59
59
|
<NumberInput
|
|
@@ -76,7 +76,7 @@ const WaitConfig: React.FC<WaitConfigProps> = ({ data, onUpdate, disabled }) =>
|
|
|
76
76
|
color: theme.textMuted,
|
|
77
77
|
}}
|
|
78
78
|
>
|
|
79
|
-
|
|
79
|
+
ЕДИНИЦА
|
|
80
80
|
</Typography>
|
|
81
81
|
<div style={{ width: '100%' }}>
|
|
82
82
|
<SingleSelect
|
|
@@ -112,11 +112,11 @@ const WaitConfig: React.FC<WaitConfigProps> = ({ data, onUpdate, disabled }) =>
|
|
|
112
112
|
lineHeight: 1.5,
|
|
113
113
|
}}
|
|
114
114
|
>
|
|
115
|
-
|
|
115
|
+
Пользователи будут ждать{' '}
|
|
116
116
|
<strong>
|
|
117
117
|
{duration} {durationUnit.toLowerCase()}
|
|
118
118
|
</strong>{' '}
|
|
119
|
-
|
|
119
|
+
перед продолжением.
|
|
120
120
|
</Typography>
|
|
121
121
|
</div>
|
|
122
122
|
</Flex>
|
|
@@ -150,6 +150,15 @@ const WEEKDAYS = [
|
|
|
150
150
|
{ value: 6, label: 'S', full: 'Saturday' },
|
|
151
151
|
];
|
|
152
152
|
|
|
153
|
+
const ALL_EVENTS = Object.entries(ANALYTICS_EVENTS).flatMap(([category, events]) =>
|
|
154
|
+
events.map((event) => ({ ...event, category }))
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const getEventLabel = (eventValue: string): string => {
|
|
158
|
+
const event = ALL_EVENTS.find((e) => e.value === eventValue);
|
|
159
|
+
return event ? `${event.label} (${event.value})` : eventValue;
|
|
160
|
+
};
|
|
161
|
+
|
|
153
162
|
const parseConfig = (value: string | TriggerConfig | null | undefined): TriggerConfig => {
|
|
154
163
|
if (!value) return DEFAULT_CONFIG;
|
|
155
164
|
const normalize = (parsed: Partial<TriggerConfig>): TriggerConfig => ({
|
|
@@ -399,8 +408,8 @@ const TriggerConfigField = forwardRef<HTMLDivElement, TriggerConfigFieldProps>(
|
|
|
399
408
|
onClick={() => handleUpdate({ type: 'event_based' })}
|
|
400
409
|
disabled={disabled}
|
|
401
410
|
icon={<Magic width={24} height={24} />}
|
|
402
|
-
title="
|
|
403
|
-
description="
|
|
411
|
+
title="По событию"
|
|
412
|
+
description="Срабатывает при действии пользователя"
|
|
404
413
|
color={colors.event.color}
|
|
405
414
|
gradientActive={colors.event.gradientActive}
|
|
406
415
|
gradientInactive={colors.card.inactive}
|
|
@@ -413,8 +422,8 @@ const TriggerConfigField = forwardRef<HTMLDivElement, TriggerConfigFieldProps>(
|
|
|
413
422
|
onClick={() => handleUpdate({ type: 'db_based' })}
|
|
414
423
|
disabled={disabled}
|
|
415
424
|
icon={<Calendar width={24} height={24} />}
|
|
416
|
-
title="
|
|
417
|
-
description="
|
|
425
|
+
title="По расписанию"
|
|
426
|
+
description="Запускается по расписанию"
|
|
418
427
|
color={colors.schedule.color}
|
|
419
428
|
gradientActive={colors.schedule.gradientActive}
|
|
420
429
|
gradientInactive={colors.card.inactive}
|
|
@@ -436,7 +445,7 @@ const TriggerConfigField = forwardRef<HTMLDivElement, TriggerConfigFieldProps>(
|
|
|
436
445
|
>
|
|
437
446
|
<SectionHeader
|
|
438
447
|
icon={<Magic width={18} height={18} />}
|
|
439
|
-
title="
|
|
448
|
+
title="Настройка события"
|
|
440
449
|
color={colors.event.color}
|
|
441
450
|
/>
|
|
442
451
|
|
|
@@ -448,11 +457,12 @@ const TriggerConfigField = forwardRef<HTMLDivElement, TriggerConfigFieldProps>(
|
|
|
448
457
|
textColor="neutral700"
|
|
449
458
|
style={{ marginBottom: 8, display: 'block' }}
|
|
450
459
|
>
|
|
451
|
-
|
|
460
|
+
Событие-триггер
|
|
452
461
|
</Typography>
|
|
453
462
|
<Combobox
|
|
454
463
|
placeholder="Search events..."
|
|
455
464
|
value={config.eventName || ''}
|
|
465
|
+
textValue={config.eventName ? getEventLabel(config.eventName) : ''}
|
|
456
466
|
onChange={(val: string) => handleUpdate({ eventName: val })}
|
|
457
467
|
onClear={() => handleUpdate({ eventName: '' })}
|
|
458
468
|
disabled={disabled}
|
|
@@ -481,7 +491,7 @@ const TriggerConfigField = forwardRef<HTMLDivElement, TriggerConfigFieldProps>(
|
|
|
481
491
|
textColor="neutral500"
|
|
482
492
|
style={{ marginTop: 6, display: 'block' }}
|
|
483
493
|
>
|
|
484
|
-
|
|
494
|
+
Выберите из списка или введите своё название события
|
|
485
495
|
</Typography>
|
|
486
496
|
</Box>
|
|
487
497
|
|
|
@@ -516,10 +526,10 @@ const TriggerConfigField = forwardRef<HTMLDivElement, TriggerConfigFieldProps>(
|
|
|
516
526
|
textColor="neutral700"
|
|
517
527
|
style={{ marginBottom: 4, display: 'block' }}
|
|
518
528
|
>
|
|
519
|
-
|
|
529
|
+
Задержка перед отправкой
|
|
520
530
|
</Typography>
|
|
521
531
|
<Typography variant="pi" textColor="neutral500">
|
|
522
|
-
|
|
532
|
+
Ожидание после события перед проверкой правил
|
|
523
533
|
</Typography>
|
|
524
534
|
</Box>
|
|
525
535
|
<Flex gap={2} alignItems="center">
|
|
@@ -567,7 +577,7 @@ const TriggerConfigField = forwardRef<HTMLDivElement, TriggerConfigFieldProps>(
|
|
|
567
577
|
>
|
|
568
578
|
<SectionHeader
|
|
569
579
|
icon={<Calendar width={18} height={18} />}
|
|
570
|
-
title="
|
|
580
|
+
title="Настройка расписания"
|
|
571
581
|
color={colors.schedule.color}
|
|
572
582
|
/>
|
|
573
583
|
|
|
@@ -658,7 +668,7 @@ const TriggerConfigField = forwardRef<HTMLDivElement, TriggerConfigFieldProps>(
|
|
|
658
668
|
{config.scheduleType === 'interval' && (
|
|
659
669
|
<Flex alignItems="center" gap={2} style={{ flex: 1 }}>
|
|
660
670
|
<Typography variant="omega" textColor="neutral700">
|
|
661
|
-
|
|
671
|
+
Запускать каждые
|
|
662
672
|
</Typography>
|
|
663
673
|
<Box style={{ width: 160 }}>
|
|
664
674
|
<SingleSelect
|
|
@@ -682,7 +692,7 @@ const TriggerConfigField = forwardRef<HTMLDivElement, TriggerConfigFieldProps>(
|
|
|
682
692
|
{config.scheduleType === 'daily' && (
|
|
683
693
|
<Flex alignItems="center" gap={2} style={{ flex: 1 }}>
|
|
684
694
|
<Typography variant="omega" textColor="neutral700">
|
|
685
|
-
|
|
695
|
+
Каждый день в
|
|
686
696
|
</Typography>
|
|
687
697
|
<Box style={{ width: 120 }}>
|
|
688
698
|
<TextInput
|
|
@@ -704,7 +714,7 @@ const TriggerConfigField = forwardRef<HTMLDivElement, TriggerConfigFieldProps>(
|
|
|
704
714
|
{config.scheduleType === 'weekly' && (
|
|
705
715
|
<Flex alignItems="center" gap={2} style={{ flex: 1 }}>
|
|
706
716
|
<Typography variant="omega" textColor="neutral700">
|
|
707
|
-
|
|
717
|
+
Каждую неделю в
|
|
708
718
|
</Typography>
|
|
709
719
|
<Box style={{ width: 120 }}>
|
|
710
720
|
<TextInput
|
|
@@ -750,7 +760,7 @@ const TriggerConfigField = forwardRef<HTMLDivElement, TriggerConfigFieldProps>(
|
|
|
750
760
|
textColor="neutral600"
|
|
751
761
|
style={{ marginBottom: 8, display: 'block' }}
|
|
752
762
|
>
|
|
753
|
-
|
|
763
|
+
Выберите дни
|
|
754
764
|
</Typography>
|
|
755
765
|
<Flex gap={2}>
|
|
756
766
|
{WEEKDAYS.map((day) => {
|
|
@@ -805,7 +815,7 @@ const TriggerConfigField = forwardRef<HTMLDivElement, TriggerConfigFieldProps>(
|
|
|
805
815
|
textColor="neutral500"
|
|
806
816
|
style={{ marginTop: 8, display: 'block' }}
|
|
807
817
|
>
|
|
808
|
-
|
|
818
|
+
Формат: минута час день месяц день_недели (напр., "0 12 * * *" = ежедневно в 12:00
|
|
809
819
|
UTC)
|
|
810
820
|
</Typography>
|
|
811
821
|
)}
|