@inspirer-dev/crm-dashboard 1.0.80 → 1.0.82
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 +3 -3
- package/admin/src/components/CancelConditionsField/index.tsx +7 -6
- package/admin/src/components/RulesBuilder/index.tsx +9 -8
- package/admin/src/components/StepFlowBuilder/constants.ts +2 -0
- package/admin/src/components/StepFlowBuilder/index.tsx +1 -1
- package/admin/src/components/StepFlowBuilder/nodes/EventTriggerNode.tsx +29 -1
- package/admin/src/components/StepFlowBuilder/panels/EventTriggerConfig.tsx +97 -9
- package/admin/src/components/StepFlowBuilder/panels/NodeEditPanel.tsx +1 -1
- package/admin/src/components/StepFlowBuilder/panels/WaitConfig.tsx +1 -3
- package/admin/src/components/StepFlowBuilder/types.ts +2 -0
- package/admin/src/components/TriggerConfigField/index.tsx +11 -10
- package/admin/src/components/TriggerParamsField/constants.ts +109 -0
- package/admin/src/components/TriggerParamsField/index.tsx +292 -0
- package/admin/src/index.ts +26 -1
- package/admin/src/pages/HomePage/components/CampaignBuilder/index.tsx +4 -0
- package/admin/src/pages/HomePage/components/FlowBuilderTest.tsx +3 -3
- package/admin/src/pages/HomePage/components/SendTimeHeatMap.tsx +2 -2
- package/admin/src/pages/HomePage/components/StatsView.tsx +2 -2
- package/admin/src/translations/en.json +4 -1
- package/admin/src/translations/ru.json +4 -1
- package/admin/tsconfig.json +12 -1
- package/admin/tsconfig.tsbuildinfo +1 -1
- package/dist/_chunks/{en-DEUgX5uV.mjs → en-B5BgIROW.mjs} +3 -1
- package/dist/_chunks/{en-D2kTkBns.js → en-GKZo4lia.js} +3 -1
- package/dist/_chunks/{index-C-1xCfqJ.js → index-354YMebI.js} +152 -38
- package/dist/_chunks/{index-BydXrDhA.mjs → index-BKfFI_Jo.mjs} +2 -2
- package/dist/_chunks/{index-D1kMmlrA.js → index-BQcRoIJr.js} +5 -4
- package/dist/_chunks/{index-BJzk6xNb.mjs → index-BgwX1xYS.mjs} +7 -6
- package/dist/_chunks/{index-pJUyH-Qr.js → index-Cg0G_bTE.js} +2 -2
- package/dist/_chunks/index-CuMY0eo5.js +310 -0
- package/dist/_chunks/{index-unxa4Q_H.mjs → index-DKJtyGq7.mjs} +5 -4
- package/dist/_chunks/{index-BFRbyVHC.js → index-DRXMKPXI.js} +1 -1
- package/dist/_chunks/{index-Xa_4jez0.mjs → index-Dhj0KzCX.mjs} +5 -4
- package/dist/_chunks/{index-Dv1tGmDT.mjs → index-LXBoz7PC.mjs} +1 -1
- package/dist/_chunks/index-NvFKi6er.mjs +310 -0
- package/dist/_chunks/{index-BKrTVHBr.js → index-T7VXjklK.js} +5 -4
- package/dist/_chunks/{index-CWSibOAr.mjs → index-gR86Z3uh.mjs} +152 -38
- package/dist/_chunks/{index-CAwynvu7.js → index-xDSMnUMp.js} +7 -6
- package/dist/_chunks/{ru-BKzplvmu.js → ru-bj5iiIPr.js} +3 -1
- package/dist/_chunks/{ru-DOt1yfNm.mjs → ru-h22ZdPCS.mjs} +3 -1
- package/dist/admin/index.js +31 -7
- package/dist/admin/index.mjs +32 -8
- package/dist/server/index.js +5 -0
- package/dist/server/index.mjs +5 -0
- package/package.json +3 -3
- package/server/src/register.ts +6 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import React, { forwardRef, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Box,
|
|
4
|
+
Button,
|
|
5
|
+
Field,
|
|
6
|
+
Flex,
|
|
7
|
+
IconButton,
|
|
8
|
+
NumberInput,
|
|
9
|
+
Typography,
|
|
10
|
+
SingleSelect,
|
|
11
|
+
SingleSelectOption,
|
|
12
|
+
Card,
|
|
13
|
+
CardContent,
|
|
14
|
+
Tooltip,
|
|
15
|
+
} from '@strapi/design-system';
|
|
16
|
+
import { Plus, Trash } from '@strapi/icons';
|
|
17
|
+
import { useTheme } from 'styled-components';
|
|
18
|
+
import { TRIGGER_PARAMS, STAGE_TYPE_LABELS, type TriggerParamDef } from './constants';
|
|
19
|
+
|
|
20
|
+
type TriggerParamsValue = Record<string, number | undefined>;
|
|
21
|
+
|
|
22
|
+
interface TriggerParamsFieldProps {
|
|
23
|
+
name: string;
|
|
24
|
+
value?: string | TriggerParamsValue | null;
|
|
25
|
+
onChange: (event: { target: { name: string; value: string } }) => void;
|
|
26
|
+
intlLabel: {
|
|
27
|
+
id: string;
|
|
28
|
+
defaultMessage: string;
|
|
29
|
+
};
|
|
30
|
+
attribute?: unknown;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
error?: string;
|
|
33
|
+
required?: boolean;
|
|
34
|
+
hint?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const parseValue = (value: string | TriggerParamsValue | null | undefined): TriggerParamsValue => {
|
|
38
|
+
if (!value) return {};
|
|
39
|
+
if (typeof value === 'object' && !Array.isArray(value)) return value as TriggerParamsValue;
|
|
40
|
+
if (typeof value === 'string') {
|
|
41
|
+
try {
|
|
42
|
+
const parsed = JSON.parse(value);
|
|
43
|
+
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) return parsed;
|
|
44
|
+
} catch {}
|
|
45
|
+
}
|
|
46
|
+
return {};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const serialize = (params: TriggerParamsValue): string => {
|
|
50
|
+
const clean: Record<string, number> = {};
|
|
51
|
+
for (const [key, val] of Object.entries(params)) {
|
|
52
|
+
if (val !== undefined && val !== null) {
|
|
53
|
+
clean[key] = val;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return JSON.stringify(clean);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
interface StrapiTheme {
|
|
60
|
+
colors?: Record<string, string>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const useThemeColors = () => {
|
|
64
|
+
const theme = useTheme() as unknown as StrapiTheme;
|
|
65
|
+
const isDark = theme?.colors?.neutral0 === '#212134';
|
|
66
|
+
|
|
67
|
+
return useMemo(
|
|
68
|
+
() => ({
|
|
69
|
+
isDark,
|
|
70
|
+
emptyBorder: isDark ? '#32324d' : '#dcdce4',
|
|
71
|
+
cardBorder: isDark ? '#32324d' : '#eaeaef',
|
|
72
|
+
tagBg: isDark ? '#2d2d4a' : '#f0f0ff',
|
|
73
|
+
}),
|
|
74
|
+
[isDark]
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const TriggerParamsField = forwardRef<HTMLDivElement, TriggerParamsFieldProps>(
|
|
79
|
+
({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
|
|
80
|
+
const [params, setParams] = useState<TriggerParamsValue>(() => parseValue(value));
|
|
81
|
+
const colors = useThemeColors();
|
|
82
|
+
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
setParams(parseValue(value));
|
|
85
|
+
}, [value]);
|
|
86
|
+
|
|
87
|
+
const update = (next: TriggerParamsValue) => {
|
|
88
|
+
setParams(next);
|
|
89
|
+
onChange({ target: { name, value: serialize(next) } });
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const activeKeys = Object.keys(params).filter(
|
|
93
|
+
(k) => params[k] !== undefined && params[k] !== null
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const availableParams = TRIGGER_PARAMS.filter((p) => !activeKeys.includes(p.key));
|
|
97
|
+
|
|
98
|
+
const addParam = (key: string) => {
|
|
99
|
+
const def = TRIGGER_PARAMS.find((p) => p.key === key);
|
|
100
|
+
if (!def) return;
|
|
101
|
+
update({ ...params, [key]: undefined });
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const removeParam = (key: string) => {
|
|
105
|
+
const next = { ...params };
|
|
106
|
+
delete next[key];
|
|
107
|
+
update(next);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const setParamValue = (key: string, val: number | undefined) => {
|
|
111
|
+
update({ ...params, [key]: val });
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const getParamDef = (key: string): TriggerParamDef | undefined =>
|
|
115
|
+
TRIGGER_PARAMS.find((p) => p.key === key);
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<Field.Root name={name} error={error} required={required} hint={hint} ref={ref}>
|
|
119
|
+
<Flex direction="column" gap={3}>
|
|
120
|
+
<Flex justifyContent="space-between" alignItems="center">
|
|
121
|
+
<Box>
|
|
122
|
+
<Field.Label>{intlLabel?.defaultMessage || 'Trigger Params'}</Field.Label>
|
|
123
|
+
<Typography variant="pi" textColor="neutral500">
|
|
124
|
+
Настройте параметры срабатывания для этого этапа
|
|
125
|
+
</Typography>
|
|
126
|
+
</Box>
|
|
127
|
+
</Flex>
|
|
128
|
+
|
|
129
|
+
{activeKeys.length === 0 ? (
|
|
130
|
+
<Box
|
|
131
|
+
padding={5}
|
|
132
|
+
background="neutral100"
|
|
133
|
+
hasRadius
|
|
134
|
+
style={{
|
|
135
|
+
border: `2px dashed ${colors.emptyBorder}`,
|
|
136
|
+
textAlign: 'center',
|
|
137
|
+
}}
|
|
138
|
+
>
|
|
139
|
+
<Typography variant="omega" textColor="neutral500">
|
|
140
|
+
Параметры не настроены
|
|
141
|
+
</Typography>
|
|
142
|
+
<Typography
|
|
143
|
+
variant="pi"
|
|
144
|
+
textColor="neutral400"
|
|
145
|
+
style={{ display: 'block', marginTop: 4 }}
|
|
146
|
+
>
|
|
147
|
+
Добавьте параметры триггера, чтобы управлять условиями показа этапа
|
|
148
|
+
</Typography>
|
|
149
|
+
</Box>
|
|
150
|
+
) : (
|
|
151
|
+
<Flex direction="column" gap={2}>
|
|
152
|
+
{activeKeys.map((key) => {
|
|
153
|
+
const def = getParamDef(key);
|
|
154
|
+
if (!def) return null;
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<Card
|
|
158
|
+
key={key}
|
|
159
|
+
background="neutral0"
|
|
160
|
+
style={{
|
|
161
|
+
border: `1px solid ${colors.cardBorder}`,
|
|
162
|
+
}}
|
|
163
|
+
>
|
|
164
|
+
<CardContent>
|
|
165
|
+
<Flex gap={3} alignItems="center" padding={3}>
|
|
166
|
+
<Box style={{ flex: 1, minWidth: 0 }}>
|
|
167
|
+
<Flex gap={2} alignItems="center" marginBottom={1}>
|
|
168
|
+
<Typography variant="omega" fontWeight="semiBold">
|
|
169
|
+
{def.label}
|
|
170
|
+
</Typography>
|
|
171
|
+
{def.unit && (
|
|
172
|
+
<Typography variant="pi" textColor="neutral500">
|
|
173
|
+
({def.unit})
|
|
174
|
+
</Typography>
|
|
175
|
+
)}
|
|
176
|
+
</Flex>
|
|
177
|
+
<Typography variant="pi" textColor="neutral500">
|
|
178
|
+
{def.description}
|
|
179
|
+
</Typography>
|
|
180
|
+
<Flex gap={1} marginTop={1} wrap="wrap">
|
|
181
|
+
{def.stageTypes.map((st) => (
|
|
182
|
+
<Box
|
|
183
|
+
key={st}
|
|
184
|
+
style={{
|
|
185
|
+
padding: '1px 6px',
|
|
186
|
+
borderRadius: '4px',
|
|
187
|
+
backgroundColor: colors.tagBg,
|
|
188
|
+
fontSize: '11px',
|
|
189
|
+
}}
|
|
190
|
+
>
|
|
191
|
+
<Typography variant="pi" textColor="primary600">
|
|
192
|
+
{STAGE_TYPE_LABELS[st] || st}
|
|
193
|
+
</Typography>
|
|
194
|
+
</Box>
|
|
195
|
+
))}
|
|
196
|
+
</Flex>
|
|
197
|
+
</Box>
|
|
198
|
+
|
|
199
|
+
<Box style={{ width: 120, flexShrink: 0 }}>
|
|
200
|
+
<NumberInput
|
|
201
|
+
placeholder={def.placeholder}
|
|
202
|
+
value={params[key] ?? ''}
|
|
203
|
+
onValueChange={(val: number | undefined) => setParamValue(key, val)}
|
|
204
|
+
disabled={disabled}
|
|
205
|
+
size="S"
|
|
206
|
+
step={key === 'balanceThresholdMultiplier' ? 0.1 : 1}
|
|
207
|
+
/>
|
|
208
|
+
</Box>
|
|
209
|
+
|
|
210
|
+
<Tooltip label="Удалить параметр">
|
|
211
|
+
<IconButton
|
|
212
|
+
onClick={() => removeParam(key)}
|
|
213
|
+
label="Delete"
|
|
214
|
+
variant="ghost"
|
|
215
|
+
size="S"
|
|
216
|
+
disabled={disabled}
|
|
217
|
+
style={{ color: '#d02b20', flexShrink: 0 }}
|
|
218
|
+
>
|
|
219
|
+
<Trash width={16} height={16} />
|
|
220
|
+
</IconButton>
|
|
221
|
+
</Tooltip>
|
|
222
|
+
</Flex>
|
|
223
|
+
</CardContent>
|
|
224
|
+
</Card>
|
|
225
|
+
);
|
|
226
|
+
})}
|
|
227
|
+
</Flex>
|
|
228
|
+
)}
|
|
229
|
+
|
|
230
|
+
{availableParams.length > 0 && (
|
|
231
|
+
<AddParamSelect
|
|
232
|
+
available={availableParams}
|
|
233
|
+
onAdd={addParam}
|
|
234
|
+
disabled={disabled}
|
|
235
|
+
/>
|
|
236
|
+
)}
|
|
237
|
+
|
|
238
|
+
{error && <Field.Error />}
|
|
239
|
+
{hint && <Field.Hint />}
|
|
240
|
+
</Flex>
|
|
241
|
+
</Field.Root>
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
TriggerParamsField.displayName = 'TriggerParamsField';
|
|
247
|
+
|
|
248
|
+
interface AddParamSelectProps {
|
|
249
|
+
available: TriggerParamDef[];
|
|
250
|
+
onAdd: (key: string) => void;
|
|
251
|
+
disabled?: boolean;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const AddParamSelect: React.FC<AddParamSelectProps> = ({ available, onAdd, disabled }) => {
|
|
255
|
+
const [selected, setSelected] = useState<string | null>(null);
|
|
256
|
+
|
|
257
|
+
return (
|
|
258
|
+
<Flex gap={2} alignItems="flex-end">
|
|
259
|
+
<Box style={{ flex: 1 }}>
|
|
260
|
+
<SingleSelect
|
|
261
|
+
placeholder="Выберите параметр..."
|
|
262
|
+
value={selected}
|
|
263
|
+
onChange={(val: string) => setSelected(val)}
|
|
264
|
+
disabled={disabled}
|
|
265
|
+
size="S"
|
|
266
|
+
>
|
|
267
|
+
{available.map((p) => (
|
|
268
|
+
<SingleSelectOption key={p.key} value={p.key}>
|
|
269
|
+
{p.label} — {p.description}
|
|
270
|
+
</SingleSelectOption>
|
|
271
|
+
))}
|
|
272
|
+
</SingleSelect>
|
|
273
|
+
</Box>
|
|
274
|
+
<Button
|
|
275
|
+
startIcon={<Plus />}
|
|
276
|
+
onClick={() => {
|
|
277
|
+
if (selected) {
|
|
278
|
+
onAdd(selected);
|
|
279
|
+
setSelected(null);
|
|
280
|
+
}
|
|
281
|
+
}}
|
|
282
|
+
disabled={disabled || !selected}
|
|
283
|
+
variant="secondary"
|
|
284
|
+
size="S"
|
|
285
|
+
>
|
|
286
|
+
Добавить
|
|
287
|
+
</Button>
|
|
288
|
+
</Flex>
|
|
289
|
+
);
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
export default TriggerParamsField;
|
package/admin/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Message, Clock, Cross, Link, ArrowRight } from '@strapi/icons';
|
|
1
|
+
import { Message, Clock, Cross, Link, ArrowRight, Filter } from '@strapi/icons';
|
|
2
2
|
|
|
3
3
|
const PLUGIN_ID = 'crm-dashboard';
|
|
4
4
|
|
|
@@ -129,6 +129,31 @@ export default {
|
|
|
129
129
|
},
|
|
130
130
|
});
|
|
131
131
|
|
|
132
|
+
app.customFields.register({
|
|
133
|
+
name: 'trigger-params',
|
|
134
|
+
pluginId: PLUGIN_ID,
|
|
135
|
+
type: 'json',
|
|
136
|
+
intlLabel: {
|
|
137
|
+
id: `${PLUGIN_ID}.trigger-params.label`,
|
|
138
|
+
defaultMessage: 'Trigger Params',
|
|
139
|
+
},
|
|
140
|
+
intlDescription: {
|
|
141
|
+
id: `${PLUGIN_ID}.trigger-params.description`,
|
|
142
|
+
defaultMessage: 'Configure trigger parameters for popup flow stages',
|
|
143
|
+
},
|
|
144
|
+
icon: Filter,
|
|
145
|
+
components: {
|
|
146
|
+
Input: async () =>
|
|
147
|
+
import(
|
|
148
|
+
/* webpackChunkName: "crm-trigger-params" */ './components/TriggerParamsField/index'
|
|
149
|
+
),
|
|
150
|
+
},
|
|
151
|
+
options: {
|
|
152
|
+
base: [],
|
|
153
|
+
advanced: [],
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
|
|
132
157
|
app.addMenuLink({
|
|
133
158
|
to: `/plugins/${PLUGIN_ID}`,
|
|
134
159
|
icon: Message,
|
|
@@ -331,6 +331,8 @@ const CampaignBuilder: React.FC = () => {
|
|
|
331
331
|
<Field.Root>
|
|
332
332
|
<Flex gap={2} alignItems="center">
|
|
333
333
|
<Toggle
|
|
334
|
+
onLabel=""
|
|
335
|
+
offLabel=""
|
|
334
336
|
checked={editingCampaign.isActive}
|
|
335
337
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
336
338
|
handleFieldChange('isActive', e.target.checked)
|
|
@@ -342,6 +344,8 @@ const CampaignBuilder: React.FC = () => {
|
|
|
342
344
|
<Field.Root>
|
|
343
345
|
<Flex gap={2} alignItems="center">
|
|
344
346
|
<Toggle
|
|
347
|
+
onLabel=""
|
|
348
|
+
offLabel=""
|
|
345
349
|
checked={editingCampaign.ignoreQuietHours}
|
|
346
350
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
347
351
|
handleFieldChange('ignoreQuietHours', e.target.checked)
|
|
@@ -13,8 +13,8 @@ const SAMPLE_STEPS: FlowStep[] = [
|
|
|
13
13
|
order: 0,
|
|
14
14
|
channel: 'telegram',
|
|
15
15
|
variants: [
|
|
16
|
-
{ name: 'Variant A', template: { id: 1, name: 'Welcome Template' }, weight: 50 },
|
|
17
|
-
{ name: 'Variant B', template: { id: 2, name: 'Welcome V2' }, weight: 50 },
|
|
16
|
+
{ name: 'Variant A', template: { id: 1, documentId: '1', name: 'Welcome Template' }, weight: 50 },
|
|
17
|
+
{ name: 'Variant B', template: { id: 2, documentId: '2', name: 'Welcome V2' }, weight: 50 },
|
|
18
18
|
],
|
|
19
19
|
nextStep: 'step_wait',
|
|
20
20
|
},
|
|
@@ -32,7 +32,7 @@ const SAMPLE_STEPS: FlowStep[] = [
|
|
|
32
32
|
name: 'Check Activity',
|
|
33
33
|
stepType: 'branch',
|
|
34
34
|
order: 2,
|
|
35
|
-
branchSegment: { id: 1, name: 'Active Users' },
|
|
35
|
+
branchSegment: { id: 1, documentId: '1', name: 'Active Users' },
|
|
36
36
|
yesNextStep: 'step_active',
|
|
37
37
|
noNextStep: 'step_inactive',
|
|
38
38
|
},
|
|
@@ -20,8 +20,8 @@ const SendTimeHeatMap: React.FC<SendTimeHeatMapProps> = ({ filters }) => {
|
|
|
20
20
|
const { data, isLoading } = useSendTimeData(filters);
|
|
21
21
|
|
|
22
22
|
const gridMap = useMemo(() => {
|
|
23
|
-
if (!data?.grid) return new Map
|
|
24
|
-
const map = new Map<string, typeof data.grid[0]>();
|
|
23
|
+
if (!data?.grid) return new Map();
|
|
24
|
+
const map = new Map<string, (typeof data.grid)[0]>();
|
|
25
25
|
for (const cell of data.grid) {
|
|
26
26
|
map.set(`${cell.day}-${cell.hour}`, cell);
|
|
27
27
|
}
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
ActiveFilterChips,
|
|
18
18
|
FilterChip,
|
|
19
19
|
} from '../../../components/Filters';
|
|
20
|
-
import { useFilterOptions, useDashboardStats, StatsFilters, TimeGranularity } from '../../../hooks/api';
|
|
20
|
+
import { useFilterOptions, useDashboardStats, StatsFilters, TimeGranularity, DashboardTotals } from '../../../hooks/api';
|
|
21
21
|
import { SendChart, AntiSpamChart, ConversionFunnelChart, TopCampaignsChart } from './charts';
|
|
22
22
|
import { exportStats, ExportFormat } from '../../../utils/exportStats';
|
|
23
23
|
import TodayWidget from './TodayWidget';
|
|
@@ -422,7 +422,7 @@ const StatsView: React.FC = () => {
|
|
|
422
422
|
return chips;
|
|
423
423
|
}, [filters, campaigns, segments]);
|
|
424
424
|
|
|
425
|
-
const totals = stats?.totals || { sent: 0, clicks: 0, click_rate: 0, deposits_1h: 0, deposit_sum_1h: 0, deposit_rate: 0 };
|
|
425
|
+
const totals: DashboardTotals = stats?.totals || { sent: 0, clicks: 0, unique_clickers: 0, click_rate: 0, deposits_1h: 0, deposit_sum_1h: 0, deposit_rate: 0, unique_users_sent: 0 };
|
|
426
426
|
const previousTotals = stats?.previous_totals;
|
|
427
427
|
const funnel = stats?.funnel;
|
|
428
428
|
const timeSeries = stats?.time_series || [];
|
|
@@ -119,5 +119,8 @@
|
|
|
119
119
|
"crm-dashboard.template.title.description": "For email: subject line. For Telegram: optional internal title (not shown to user). For push: notification title.",
|
|
120
120
|
|
|
121
121
|
"crm-dashboard.template.body.label": "Message Body",
|
|
122
|
-
"crm-dashboard.template.body.description": "The message text. Variables: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *bold*, _italic_"
|
|
122
|
+
"crm-dashboard.template.body.description": "The message text. Variables: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *bold*, _italic_",
|
|
123
|
+
|
|
124
|
+
"crm-dashboard.trigger-params.label": "Trigger Params",
|
|
125
|
+
"crm-dashboard.trigger-params.description": "Configure trigger parameters for popup flow stages. Add only the parameters relevant to this stage type."
|
|
123
126
|
}
|
|
@@ -119,5 +119,8 @@
|
|
|
119
119
|
"crm-dashboard.template.title.description": "Для email: тема письма. Для Telegram: внутренний заголовок (не виден пользователю). Для push: заголовок уведомления.",
|
|
120
120
|
|
|
121
121
|
"crm-dashboard.template.body.label": "Текст сообщения",
|
|
122
|
-
"crm-dashboard.template.body.description": "Текст сообщения. Переменные: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *жирный*, _курсив_"
|
|
122
|
+
"crm-dashboard.template.body.description": "Текст сообщения. Переменные: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *жирный*, _курсив_",
|
|
123
|
+
|
|
124
|
+
"crm-dashboard.trigger-params.label": "Параметры триггера",
|
|
125
|
+
"crm-dashboard.trigger-params.description": "Настройте параметры срабатывания для этапов popup-флоу. Добавляйте только параметры, релевантные для данного типа этапа."
|
|
123
126
|
}
|
package/admin/tsconfig.json
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
{
|
|
2
|
-
"extends": "../../../../tsconfig.json",
|
|
3
2
|
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"types": ["react", "react-dom"],
|
|
4
15
|
"outDir": "dist",
|
|
5
16
|
"rootDir": "src"
|
|
6
17
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"
|
|
1
|
+
{"fileNames":[],"fileInfos":[],"root":[],"options":{"esModuleInterop":true,"module":1,"noEmitOnError":true,"noImplicitThis":true,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"strict":false,"target":6},"errors":true,"version":"5.8.3"}
|
|
@@ -79,7 +79,9 @@ const en = {
|
|
|
79
79
|
"crm-dashboard.template.title.label": "Title",
|
|
80
80
|
"crm-dashboard.template.title.description": "For email: subject line. For Telegram: optional internal title (not shown to user). For push: notification title.",
|
|
81
81
|
"crm-dashboard.template.body.label": "Message Body",
|
|
82
|
-
"crm-dashboard.template.body.description": "The message text. Variables: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *bold*, _italic_"
|
|
82
|
+
"crm-dashboard.template.body.description": "The message text. Variables: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *bold*, _italic_",
|
|
83
|
+
"crm-dashboard.trigger-params.label": "Trigger Params",
|
|
84
|
+
"crm-dashboard.trigger-params.description": "Configure trigger parameters for popup flow stages. Add only the parameters relevant to this stage type."
|
|
83
85
|
};
|
|
84
86
|
export {
|
|
85
87
|
en as default
|
|
@@ -81,6 +81,8 @@ const en = {
|
|
|
81
81
|
"crm-dashboard.template.title.label": "Title",
|
|
82
82
|
"crm-dashboard.template.title.description": "For email: subject line. For Telegram: optional internal title (not shown to user). For push: notification title.",
|
|
83
83
|
"crm-dashboard.template.body.label": "Message Body",
|
|
84
|
-
"crm-dashboard.template.body.description": "The message text. Variables: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *bold*, _italic_"
|
|
84
|
+
"crm-dashboard.template.body.description": "The message text. Variables: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *bold*, _italic_",
|
|
85
|
+
"crm-dashboard.trigger-params.label": "Trigger Params",
|
|
86
|
+
"crm-dashboard.trigger-params.description": "Configure trigger parameters for popup flow stages. Add only the parameters relevant to this stage type."
|
|
85
87
|
};
|
|
86
88
|
exports.default = en;
|