@inspirer-dev/crm-dashboard 1.0.81 → 1.0.83

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.
@@ -0,0 +1,109 @@
1
+ export interface TriggerParamDef {
2
+ key: string;
3
+ label: string;
4
+ description: string;
5
+ unit: string;
6
+ min: number;
7
+ placeholder: string;
8
+ stageTypes: string[];
9
+ }
10
+
11
+ export const TRIGGER_PARAMS: TriggerParamDef[] = [
12
+ {
13
+ key: 'delaySeconds',
14
+ label: 'Задержка',
15
+ description: 'Задержка перед показом после срабатывания триггера',
16
+ unit: 'сек',
17
+ min: 0,
18
+ placeholder: '7',
19
+ stageTypes: ['side_hint', 'modal', 'retry'],
20
+ },
21
+ {
22
+ key: 'timeOnSiteSeconds',
23
+ label: 'Время на сайте',
24
+ description: 'Мин. время на сайте для срабатывания',
25
+ unit: 'сек',
26
+ min: 0,
27
+ placeholder: '120',
28
+ stageTypes: ['exit_intent', 'side_hint', 'modal'],
29
+ },
30
+ {
31
+ key: 'scrollThresholdPx',
32
+ label: 'Порог скролла',
33
+ description: 'Скролл в пикселях для срабатывания',
34
+ unit: 'px',
35
+ min: 0,
36
+ placeholder: '200',
37
+ stageTypes: ['side_hint'],
38
+ },
39
+ {
40
+ key: 'idleSeconds',
41
+ label: 'Бездействие',
42
+ description: 'Время без кликов/скролла',
43
+ unit: 'сек',
44
+ min: 0,
45
+ placeholder: '15',
46
+ stageTypes: ['side_hint'],
47
+ },
48
+ {
49
+ key: 'caseViewSeconds',
50
+ label: 'Просмотр кейса',
51
+ description: 'Время на странице кейса',
52
+ unit: 'сек',
53
+ min: 0,
54
+ placeholder: '12',
55
+ stageTypes: ['modal', 'side_hint'],
56
+ },
57
+ {
58
+ key: 'activePlayMinutes',
59
+ label: 'Активная игра',
60
+ description: 'Время активной игры',
61
+ unit: 'мин',
62
+ min: 0,
63
+ placeholder: '10',
64
+ stageTypes: ['modal'],
65
+ },
66
+ {
67
+ key: 'actionCountThreshold',
68
+ label: 'Порог действий',
69
+ description: 'Кол-во значимых действий + низкий баланс',
70
+ unit: '',
71
+ min: 0,
72
+ placeholder: '2',
73
+ stageTypes: ['modal'],
74
+ },
75
+ {
76
+ key: 'balanceThresholdMultiplier',
77
+ label: 'Множитель баланса',
78
+ description: 'Множитель мин. цены кейса для "низкого баланса"',
79
+ unit: '×',
80
+ min: 0,
81
+ placeholder: '1.5',
82
+ stageTypes: ['modal', 'side_hint'],
83
+ },
84
+ {
85
+ key: 'abandonedTimeoutMinutes',
86
+ label: 'Таймаут заброшенного депозита',
87
+ description: 'Через сколько минут депозит считается заброшенным',
88
+ unit: 'мин',
89
+ min: 1,
90
+ placeholder: '10',
91
+ stageTypes: ['retry'],
92
+ },
93
+ {
94
+ key: 'minDepositAmount',
95
+ label: 'Мин. сумма депозита',
96
+ description: 'Подстановка в {{min_deposit}} в текстах',
97
+ unit: '₽',
98
+ min: 0,
99
+ placeholder: '250',
100
+ stageTypes: ['modal', 'side_hint', 'retry'],
101
+ },
102
+ ];
103
+
104
+ export const STAGE_TYPE_LABELS: Record<string, string> = {
105
+ side_hint: 'Side-hint',
106
+ modal: 'Modal',
107
+ exit_intent: 'Exit intent',
108
+ retry: 'Retry',
109
+ };
@@ -0,0 +1,290 @@
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);
93
+
94
+ const availableParams = TRIGGER_PARAMS.filter((p) => !activeKeys.includes(p.key));
95
+
96
+ const addParam = (key: string) => {
97
+ const def = TRIGGER_PARAMS.find((p) => p.key === key);
98
+ if (!def) return;
99
+ update({ ...params, [key]: undefined });
100
+ };
101
+
102
+ const removeParam = (key: string) => {
103
+ const next = { ...params };
104
+ delete next[key];
105
+ update(next);
106
+ };
107
+
108
+ const setParamValue = (key: string, val: number | undefined) => {
109
+ update({ ...params, [key]: val });
110
+ };
111
+
112
+ const getParamDef = (key: string): TriggerParamDef | undefined =>
113
+ TRIGGER_PARAMS.find((p) => p.key === key);
114
+
115
+ return (
116
+ <Field.Root name={name} error={error} required={required} hint={hint} ref={ref}>
117
+ <Flex direction="column" gap={3}>
118
+ <Flex justifyContent="space-between" alignItems="center">
119
+ <Box>
120
+ <Field.Label>{intlLabel?.defaultMessage || 'Trigger Params'}</Field.Label>
121
+ <Typography variant="pi" textColor="neutral500">
122
+ Настройте параметры срабатывания для этого этапа
123
+ </Typography>
124
+ </Box>
125
+ </Flex>
126
+
127
+ {activeKeys.length === 0 ? (
128
+ <Box
129
+ padding={5}
130
+ background="neutral100"
131
+ hasRadius
132
+ style={{
133
+ border: `2px dashed ${colors.emptyBorder}`,
134
+ textAlign: 'center',
135
+ }}
136
+ >
137
+ <Typography variant="omega" textColor="neutral500">
138
+ Параметры не настроены
139
+ </Typography>
140
+ <Typography
141
+ variant="pi"
142
+ textColor="neutral400"
143
+ style={{ display: 'block', marginTop: 4 }}
144
+ >
145
+ Добавьте параметры триггера, чтобы управлять условиями показа этапа
146
+ </Typography>
147
+ </Box>
148
+ ) : (
149
+ <Flex direction="column" gap={2}>
150
+ {activeKeys.map((key) => {
151
+ const def = getParamDef(key);
152
+ if (!def) return null;
153
+
154
+ return (
155
+ <Card
156
+ key={key}
157
+ background="neutral0"
158
+ style={{
159
+ border: `1px solid ${colors.cardBorder}`,
160
+ }}
161
+ >
162
+ <CardContent>
163
+ <Flex gap={3} alignItems="center" padding={3}>
164
+ <Box style={{ flex: 1, minWidth: 0 }}>
165
+ <Flex gap={2} alignItems="center" marginBottom={1}>
166
+ <Typography variant="omega" fontWeight="semiBold">
167
+ {def.label}
168
+ </Typography>
169
+ {def.unit && (
170
+ <Typography variant="pi" textColor="neutral500">
171
+ ({def.unit})
172
+ </Typography>
173
+ )}
174
+ </Flex>
175
+ <Typography variant="pi" textColor="neutral500">
176
+ {def.description}
177
+ </Typography>
178
+ <Flex gap={1} marginTop={1} wrap="wrap">
179
+ {def.stageTypes.map((st) => (
180
+ <Box
181
+ key={st}
182
+ style={{
183
+ padding: '1px 6px',
184
+ borderRadius: '4px',
185
+ backgroundColor: colors.tagBg,
186
+ fontSize: '11px',
187
+ }}
188
+ >
189
+ <Typography variant="pi" textColor="primary600">
190
+ {STAGE_TYPE_LABELS[st] || st}
191
+ </Typography>
192
+ </Box>
193
+ ))}
194
+ </Flex>
195
+ </Box>
196
+
197
+ <Box style={{ width: 120, flexShrink: 0 }}>
198
+ <NumberInput
199
+ placeholder={def.placeholder}
200
+ value={params[key] ?? ''}
201
+ onValueChange={(val: number | undefined) => setParamValue(key, val)}
202
+ disabled={disabled}
203
+ size="S"
204
+ step={key === 'balanceThresholdMultiplier' ? 0.1 : 1}
205
+ />
206
+ </Box>
207
+
208
+ <Tooltip label="Удалить параметр">
209
+ <IconButton
210
+ onClick={() => removeParam(key)}
211
+ label="Delete"
212
+ variant="ghost"
213
+ size="S"
214
+ disabled={disabled}
215
+ style={{ color: '#d02b20', flexShrink: 0 }}
216
+ >
217
+ <Trash width={16} height={16} />
218
+ </IconButton>
219
+ </Tooltip>
220
+ </Flex>
221
+ </CardContent>
222
+ </Card>
223
+ );
224
+ })}
225
+ </Flex>
226
+ )}
227
+
228
+ {availableParams.length > 0 && (
229
+ <AddParamSelect
230
+ available={availableParams}
231
+ onAdd={addParam}
232
+ disabled={disabled}
233
+ />
234
+ )}
235
+
236
+ {error && <Field.Error />}
237
+ {hint && <Field.Hint />}
238
+ </Flex>
239
+ </Field.Root>
240
+ );
241
+ }
242
+ );
243
+
244
+ TriggerParamsField.displayName = 'TriggerParamsField';
245
+
246
+ interface AddParamSelectProps {
247
+ available: TriggerParamDef[];
248
+ onAdd: (key: string) => void;
249
+ disabled?: boolean;
250
+ }
251
+
252
+ const AddParamSelect: React.FC<AddParamSelectProps> = ({ available, onAdd, disabled }) => {
253
+ const [selected, setSelected] = useState<string | null>(null);
254
+
255
+ return (
256
+ <Flex gap={2} alignItems="flex-end">
257
+ <Box style={{ flex: 1 }}>
258
+ <SingleSelect
259
+ placeholder="Выберите параметр..."
260
+ value={selected}
261
+ onChange={(val: string) => setSelected(val)}
262
+ disabled={disabled}
263
+ size="S"
264
+ >
265
+ {available.map((p) => (
266
+ <SingleSelectOption key={p.key} value={p.key}>
267
+ {p.label} — {p.description}
268
+ </SingleSelectOption>
269
+ ))}
270
+ </SingleSelect>
271
+ </Box>
272
+ <Button
273
+ startIcon={<Plus />}
274
+ onClick={() => {
275
+ if (selected) {
276
+ onAdd(selected);
277
+ setSelected(null);
278
+ }
279
+ }}
280
+ disabled={disabled || !selected}
281
+ variant="secondary"
282
+ size="S"
283
+ >
284
+ Добавить
285
+ </Button>
286
+ </Flex>
287
+ );
288
+ };
289
+
290
+ export default TriggerParamsField;
@@ -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,
@@ -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
  }
@@ -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;
@@ -0,0 +1,308 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const React = require("react");
5
+ const designSystem = require("@strapi/design-system");
6
+ const icons = require("@strapi/icons");
7
+ const styledComponents = require("styled-components");
8
+ const TRIGGER_PARAMS = [
9
+ {
10
+ key: "delaySeconds",
11
+ label: "Задержка",
12
+ description: "Задержка перед показом после срабатывания триггера",
13
+ unit: "сек",
14
+ min: 0,
15
+ placeholder: "7",
16
+ stageTypes: ["side_hint", "modal", "retry"]
17
+ },
18
+ {
19
+ key: "timeOnSiteSeconds",
20
+ label: "Время на сайте",
21
+ description: "Мин. время на сайте для срабатывания",
22
+ unit: "сек",
23
+ min: 0,
24
+ placeholder: "120",
25
+ stageTypes: ["exit_intent", "side_hint", "modal"]
26
+ },
27
+ {
28
+ key: "scrollThresholdPx",
29
+ label: "Порог скролла",
30
+ description: "Скролл в пикселях для срабатывания",
31
+ unit: "px",
32
+ min: 0,
33
+ placeholder: "200",
34
+ stageTypes: ["side_hint"]
35
+ },
36
+ {
37
+ key: "idleSeconds",
38
+ label: "Бездействие",
39
+ description: "Время без кликов/скролла",
40
+ unit: "сек",
41
+ min: 0,
42
+ placeholder: "15",
43
+ stageTypes: ["side_hint"]
44
+ },
45
+ {
46
+ key: "caseViewSeconds",
47
+ label: "Просмотр кейса",
48
+ description: "Время на странице кейса",
49
+ unit: "сек",
50
+ min: 0,
51
+ placeholder: "12",
52
+ stageTypes: ["modal", "side_hint"]
53
+ },
54
+ {
55
+ key: "activePlayMinutes",
56
+ label: "Активная игра",
57
+ description: "Время активной игры",
58
+ unit: "мин",
59
+ min: 0,
60
+ placeholder: "10",
61
+ stageTypes: ["modal"]
62
+ },
63
+ {
64
+ key: "actionCountThreshold",
65
+ label: "Порог действий",
66
+ description: "Кол-во значимых действий + низкий баланс",
67
+ unit: "",
68
+ min: 0,
69
+ placeholder: "2",
70
+ stageTypes: ["modal"]
71
+ },
72
+ {
73
+ key: "balanceThresholdMultiplier",
74
+ label: "Множитель баланса",
75
+ description: 'Множитель мин. цены кейса для "низкого баланса"',
76
+ unit: "×",
77
+ min: 0,
78
+ placeholder: "1.5",
79
+ stageTypes: ["modal", "side_hint"]
80
+ },
81
+ {
82
+ key: "abandonedTimeoutMinutes",
83
+ label: "Таймаут заброшенного депозита",
84
+ description: "Через сколько минут депозит считается заброшенным",
85
+ unit: "мин",
86
+ min: 1,
87
+ placeholder: "10",
88
+ stageTypes: ["retry"]
89
+ },
90
+ {
91
+ key: "minDepositAmount",
92
+ label: "Мин. сумма депозита",
93
+ description: "Подстановка в {{min_deposit}} в текстах",
94
+ unit: "₽",
95
+ min: 0,
96
+ placeholder: "250",
97
+ stageTypes: ["modal", "side_hint", "retry"]
98
+ }
99
+ ];
100
+ const STAGE_TYPE_LABELS = {
101
+ side_hint: "Side-hint",
102
+ modal: "Modal",
103
+ exit_intent: "Exit intent",
104
+ retry: "Retry"
105
+ };
106
+ const parseValue = (value) => {
107
+ if (!value) return {};
108
+ if (typeof value === "object" && !Array.isArray(value)) return value;
109
+ if (typeof value === "string") {
110
+ try {
111
+ const parsed = JSON.parse(value);
112
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
113
+ } catch {
114
+ }
115
+ }
116
+ return {};
117
+ };
118
+ const serialize = (params) => {
119
+ const clean = {};
120
+ for (const [key, val] of Object.entries(params)) {
121
+ if (val !== void 0 && val !== null) {
122
+ clean[key] = val;
123
+ }
124
+ }
125
+ return JSON.stringify(clean);
126
+ };
127
+ const useThemeColors = () => {
128
+ const theme = styledComponents.useTheme();
129
+ const isDark = theme?.colors?.neutral0 === "#212134";
130
+ return React.useMemo(
131
+ () => ({
132
+ isDark,
133
+ emptyBorder: isDark ? "#32324d" : "#dcdce4",
134
+ cardBorder: isDark ? "#32324d" : "#eaeaef",
135
+ tagBg: isDark ? "#2d2d4a" : "#f0f0ff"
136
+ }),
137
+ [isDark]
138
+ );
139
+ };
140
+ const TriggerParamsField = React.forwardRef(
141
+ ({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
142
+ const [params, setParams] = React.useState(() => parseValue(value));
143
+ const colors = useThemeColors();
144
+ React.useEffect(() => {
145
+ setParams(parseValue(value));
146
+ }, [value]);
147
+ const update = (next) => {
148
+ setParams(next);
149
+ onChange({ target: { name, value: serialize(next) } });
150
+ };
151
+ const activeKeys = Object.keys(params);
152
+ const availableParams = TRIGGER_PARAMS.filter((p) => !activeKeys.includes(p.key));
153
+ const addParam = (key) => {
154
+ const def = TRIGGER_PARAMS.find((p) => p.key === key);
155
+ if (!def) return;
156
+ update({ ...params, [key]: void 0 });
157
+ };
158
+ const removeParam = (key) => {
159
+ const next = { ...params };
160
+ delete next[key];
161
+ update(next);
162
+ };
163
+ const setParamValue = (key, val) => {
164
+ update({ ...params, [key]: val });
165
+ };
166
+ const getParamDef = (key) => TRIGGER_PARAMS.find((p) => p.key === key);
167
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Root, { name, error, required, hint, ref, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, children: [
168
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
169
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: intlLabel?.defaultMessage || "Trigger Params" }),
170
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", children: "Настройте параметры срабатывания для этого этапа" })
171
+ ] }) }),
172
+ activeKeys.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
173
+ designSystem.Box,
174
+ {
175
+ padding: 5,
176
+ background: "neutral100",
177
+ hasRadius: true,
178
+ style: {
179
+ border: `2px dashed ${colors.emptyBorder}`,
180
+ textAlign: "center"
181
+ },
182
+ children: [
183
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral500", children: "Параметры не настроены" }),
184
+ /* @__PURE__ */ jsxRuntime.jsx(
185
+ designSystem.Typography,
186
+ {
187
+ variant: "pi",
188
+ textColor: "neutral400",
189
+ style: { display: "block", marginTop: 4 },
190
+ children: "Добавьте параметры триггера, чтобы управлять условиями показа этапа"
191
+ }
192
+ )
193
+ ]
194
+ }
195
+ ) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 2, children: activeKeys.map((key) => {
196
+ const def = getParamDef(key);
197
+ if (!def) return null;
198
+ return /* @__PURE__ */ jsxRuntime.jsx(
199
+ designSystem.Card,
200
+ {
201
+ background: "neutral0",
202
+ style: {
203
+ border: `1px solid ${colors.cardBorder}`
204
+ },
205
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.CardContent, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 3, alignItems: "center", padding: 3, children: [
206
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { flex: 1, minWidth: 0 }, children: [
207
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", marginBottom: 1, children: [
208
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", children: def.label }),
209
+ def.unit && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", textColor: "neutral500", children: [
210
+ "(",
211
+ def.unit,
212
+ ")"
213
+ ] })
214
+ ] }),
215
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", children: def.description }),
216
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, marginTop: 1, wrap: "wrap", children: def.stageTypes.map((st) => /* @__PURE__ */ jsxRuntime.jsx(
217
+ designSystem.Box,
218
+ {
219
+ style: {
220
+ padding: "1px 6px",
221
+ borderRadius: "4px",
222
+ backgroundColor: colors.tagBg,
223
+ fontSize: "11px"
224
+ },
225
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "primary600", children: STAGE_TYPE_LABELS[st] || st })
226
+ },
227
+ st
228
+ )) })
229
+ ] }),
230
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: 120, flexShrink: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(
231
+ designSystem.NumberInput,
232
+ {
233
+ placeholder: def.placeholder,
234
+ value: params[key] ?? "",
235
+ onValueChange: (val) => setParamValue(key, val),
236
+ disabled,
237
+ size: "S",
238
+ step: key === "balanceThresholdMultiplier" ? 0.1 : 1
239
+ }
240
+ ) }),
241
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label: "Удалить параметр", children: /* @__PURE__ */ jsxRuntime.jsx(
242
+ designSystem.IconButton,
243
+ {
244
+ onClick: () => removeParam(key),
245
+ label: "Delete",
246
+ variant: "ghost",
247
+ size: "S",
248
+ disabled,
249
+ style: { color: "#d02b20", flexShrink: 0 },
250
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { width: 16, height: 16 })
251
+ }
252
+ ) })
253
+ ] }) })
254
+ },
255
+ key
256
+ );
257
+ }) }),
258
+ availableParams.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
259
+ AddParamSelect,
260
+ {
261
+ available: availableParams,
262
+ onAdd: addParam,
263
+ disabled
264
+ }
265
+ ),
266
+ error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {}),
267
+ hint && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
268
+ ] }) });
269
+ }
270
+ );
271
+ TriggerParamsField.displayName = "TriggerParamsField";
272
+ const AddParamSelect = ({ available, onAdd, disabled }) => {
273
+ const [selected, setSelected] = React.useState(null);
274
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "flex-end", children: [
275
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(
276
+ designSystem.SingleSelect,
277
+ {
278
+ placeholder: "Выберите параметр...",
279
+ value: selected,
280
+ onChange: (val) => setSelected(val),
281
+ disabled,
282
+ size: "S",
283
+ children: available.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.SingleSelectOption, { value: p.key, children: [
284
+ p.label,
285
+ " — ",
286
+ p.description
287
+ ] }, p.key))
288
+ }
289
+ ) }),
290
+ /* @__PURE__ */ jsxRuntime.jsx(
291
+ designSystem.Button,
292
+ {
293
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
294
+ onClick: () => {
295
+ if (selected) {
296
+ onAdd(selected);
297
+ setSelected(null);
298
+ }
299
+ },
300
+ disabled: disabled || !selected,
301
+ variant: "secondary",
302
+ size: "S",
303
+ children: "Добавить"
304
+ }
305
+ )
306
+ ] });
307
+ };
308
+ exports.default = TriggerParamsField;
@@ -0,0 +1,308 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useState, useEffect, useMemo } from "react";
3
+ import { Field, Flex, Box, Typography, Card, CardContent, NumberInput, Tooltip, IconButton, SingleSelect, SingleSelectOption, Button } from "@strapi/design-system";
4
+ import { Trash, Plus } 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 === "object" && !Array.isArray(value)) return value;
107
+ if (typeof value === "string") {
108
+ try {
109
+ const parsed = JSON.parse(value);
110
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
111
+ } catch {
112
+ }
113
+ }
114
+ return {};
115
+ };
116
+ const serialize = (params) => {
117
+ const clean = {};
118
+ for (const [key, val] of Object.entries(params)) {
119
+ if (val !== void 0 && val !== null) {
120
+ clean[key] = val;
121
+ }
122
+ }
123
+ return JSON.stringify(clean);
124
+ };
125
+ const useThemeColors = () => {
126
+ const theme = useTheme();
127
+ const isDark = theme?.colors?.neutral0 === "#212134";
128
+ return useMemo(
129
+ () => ({
130
+ isDark,
131
+ emptyBorder: isDark ? "#32324d" : "#dcdce4",
132
+ cardBorder: isDark ? "#32324d" : "#eaeaef",
133
+ tagBg: isDark ? "#2d2d4a" : "#f0f0ff"
134
+ }),
135
+ [isDark]
136
+ );
137
+ };
138
+ const TriggerParamsField = forwardRef(
139
+ ({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
140
+ const [params, setParams] = useState(() => parseValue(value));
141
+ const colors = useThemeColors();
142
+ useEffect(() => {
143
+ setParams(parseValue(value));
144
+ }, [value]);
145
+ const update = (next) => {
146
+ setParams(next);
147
+ onChange({ target: { name, value: serialize(next) } });
148
+ };
149
+ const activeKeys = Object.keys(params);
150
+ const availableParams = TRIGGER_PARAMS.filter((p) => !activeKeys.includes(p.key));
151
+ const addParam = (key) => {
152
+ const def = TRIGGER_PARAMS.find((p) => p.key === key);
153
+ if (!def) return;
154
+ update({ ...params, [key]: void 0 });
155
+ };
156
+ const removeParam = (key) => {
157
+ const next = { ...params };
158
+ delete next[key];
159
+ update(next);
160
+ };
161
+ const setParamValue = (key, val) => {
162
+ update({ ...params, [key]: val });
163
+ };
164
+ const getParamDef = (key) => TRIGGER_PARAMS.find((p) => p.key === key);
165
+ return /* @__PURE__ */ jsx(Field.Root, { name, error, required, hint, ref, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, children: [
166
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", alignItems: "center", children: /* @__PURE__ */ jsxs(Box, { children: [
167
+ /* @__PURE__ */ jsx(Field.Label, { children: intlLabel?.defaultMessage || "Trigger Params" }),
168
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: "Настройте параметры срабатывания для этого этапа" })
169
+ ] }) }),
170
+ activeKeys.length === 0 ? /* @__PURE__ */ jsxs(
171
+ Box,
172
+ {
173
+ padding: 5,
174
+ background: "neutral100",
175
+ hasRadius: true,
176
+ style: {
177
+ border: `2px dashed ${colors.emptyBorder}`,
178
+ textAlign: "center"
179
+ },
180
+ children: [
181
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral500", children: "Параметры не настроены" }),
182
+ /* @__PURE__ */ jsx(
183
+ Typography,
184
+ {
185
+ variant: "pi",
186
+ textColor: "neutral400",
187
+ style: { display: "block", marginTop: 4 },
188
+ children: "Добавьте параметры триггера, чтобы управлять условиями показа этапа"
189
+ }
190
+ )
191
+ ]
192
+ }
193
+ ) : /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 2, children: activeKeys.map((key) => {
194
+ const def = getParamDef(key);
195
+ if (!def) return null;
196
+ return /* @__PURE__ */ jsx(
197
+ Card,
198
+ {
199
+ background: "neutral0",
200
+ style: {
201
+ border: `1px solid ${colors.cardBorder}`
202
+ },
203
+ children: /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "center", padding: 3, children: [
204
+ /* @__PURE__ */ jsxs(Box, { style: { flex: 1, minWidth: 0 }, children: [
205
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", marginBottom: 1, children: [
206
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", children: def.label }),
207
+ def.unit && /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral500", children: [
208
+ "(",
209
+ def.unit,
210
+ ")"
211
+ ] })
212
+ ] }),
213
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: def.description }),
214
+ /* @__PURE__ */ jsx(Flex, { gap: 1, marginTop: 1, wrap: "wrap", children: def.stageTypes.map((st) => /* @__PURE__ */ jsx(
215
+ Box,
216
+ {
217
+ style: {
218
+ padding: "1px 6px",
219
+ borderRadius: "4px",
220
+ backgroundColor: colors.tagBg,
221
+ fontSize: "11px"
222
+ },
223
+ children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "primary600", children: STAGE_TYPE_LABELS[st] || st })
224
+ },
225
+ st
226
+ )) })
227
+ ] }),
228
+ /* @__PURE__ */ jsx(Box, { style: { width: 120, flexShrink: 0 }, children: /* @__PURE__ */ jsx(
229
+ NumberInput,
230
+ {
231
+ placeholder: def.placeholder,
232
+ value: params[key] ?? "",
233
+ onValueChange: (val) => setParamValue(key, val),
234
+ disabled,
235
+ size: "S",
236
+ step: key === "balanceThresholdMultiplier" ? 0.1 : 1
237
+ }
238
+ ) }),
239
+ /* @__PURE__ */ jsx(Tooltip, { label: "Удалить параметр", children: /* @__PURE__ */ jsx(
240
+ IconButton,
241
+ {
242
+ onClick: () => removeParam(key),
243
+ label: "Delete",
244
+ variant: "ghost",
245
+ size: "S",
246
+ disabled,
247
+ style: { color: "#d02b20", flexShrink: 0 },
248
+ children: /* @__PURE__ */ jsx(Trash, { width: 16, height: 16 })
249
+ }
250
+ ) })
251
+ ] }) })
252
+ },
253
+ key
254
+ );
255
+ }) }),
256
+ availableParams.length > 0 && /* @__PURE__ */ jsx(
257
+ AddParamSelect,
258
+ {
259
+ available: availableParams,
260
+ onAdd: addParam,
261
+ disabled
262
+ }
263
+ ),
264
+ error && /* @__PURE__ */ jsx(Field.Error, {}),
265
+ hint && /* @__PURE__ */ jsx(Field.Hint, {})
266
+ ] }) });
267
+ }
268
+ );
269
+ TriggerParamsField.displayName = "TriggerParamsField";
270
+ const AddParamSelect = ({ available, onAdd, disabled }) => {
271
+ const [selected, setSelected] = useState(null);
272
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "flex-end", children: [
273
+ /* @__PURE__ */ jsx(Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(
274
+ SingleSelect,
275
+ {
276
+ placeholder: "Выберите параметр...",
277
+ value: selected,
278
+ onChange: (val) => setSelected(val),
279
+ disabled,
280
+ size: "S",
281
+ children: available.map((p) => /* @__PURE__ */ jsxs(SingleSelectOption, { value: p.key, children: [
282
+ p.label,
283
+ " — ",
284
+ p.description
285
+ ] }, p.key))
286
+ }
287
+ ) }),
288
+ /* @__PURE__ */ jsx(
289
+ Button,
290
+ {
291
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
292
+ onClick: () => {
293
+ if (selected) {
294
+ onAdd(selected);
295
+ setSelected(null);
296
+ }
297
+ },
298
+ disabled: disabled || !selected,
299
+ variant: "secondary",
300
+ size: "S",
301
+ children: "Добавить"
302
+ }
303
+ )
304
+ ] });
305
+ };
306
+ export {
307
+ TriggerParamsField as default
308
+ };
@@ -81,6 +81,8 @@ const ru = {
81
81
  "crm-dashboard.template.title.label": "Заголовок",
82
82
  "crm-dashboard.template.title.description": "Для email: тема письма. Для Telegram: внутренний заголовок (не виден пользователю). Для push: заголовок уведомления.",
83
83
  "crm-dashboard.template.body.label": "Текст сообщения",
84
- "crm-dashboard.template.body.description": "Текст сообщения. Переменные: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *жирный*, _курсив_"
84
+ "crm-dashboard.template.body.description": "Текст сообщения. Переменные: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *жирный*, _курсив_",
85
+ "crm-dashboard.trigger-params.label": "Параметры триггера",
86
+ "crm-dashboard.trigger-params.description": "Настройте параметры срабатывания для этапов popup-флоу. Добавляйте только параметры, релевантные для данного типа этапа."
85
87
  };
86
88
  exports.default = ru;
@@ -79,7 +79,9 @@ const ru = {
79
79
  "crm-dashboard.template.title.label": "Заголовок",
80
80
  "crm-dashboard.template.title.description": "Для email: тема письма. Для Telegram: внутренний заголовок (не виден пользователю). Для push: заголовок уведомления.",
81
81
  "crm-dashboard.template.body.label": "Текст сообщения",
82
- "crm-dashboard.template.body.description": "Текст сообщения. Переменные: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *жирный*, _курсив_"
82
+ "crm-dashboard.template.body.description": "Текст сообщения. Переменные: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *жирный*, _курсив_",
83
+ "crm-dashboard.trigger-params.label": "Параметры триггера",
84
+ "crm-dashboard.trigger-params.description": "Настройте параметры срабатывания для этапов popup-флоу. Добавляйте только параметры, релевантные для данного типа этапа."
83
85
  };
84
86
  export {
85
87
  ru as default
@@ -139,6 +139,30 @@ const index = {
139
139
  advanced: []
140
140
  }
141
141
  });
142
+ app.customFields.register({
143
+ name: "trigger-params",
144
+ pluginId: PLUGIN_ID,
145
+ type: "json",
146
+ intlLabel: {
147
+ id: `${PLUGIN_ID}.trigger-params.label`,
148
+ defaultMessage: "Trigger Params"
149
+ },
150
+ intlDescription: {
151
+ id: `${PLUGIN_ID}.trigger-params.description`,
152
+ defaultMessage: "Configure trigger parameters for popup flow stages"
153
+ },
154
+ icon: icons.Filter,
155
+ components: {
156
+ Input: async () => Promise.resolve().then(() => require(
157
+ /* webpackChunkName: "crm-trigger-params" */
158
+ "../_chunks/index-2rErXqfH.js"
159
+ ))
160
+ },
161
+ options: {
162
+ base: [],
163
+ advanced: []
164
+ }
165
+ });
142
166
  app.addMenuLink({
143
167
  to: `/plugins/${PLUGIN_ID}`,
144
168
  icon: icons.Message,
@@ -168,7 +192,7 @@ const index = {
168
192
  return Promise.all(
169
193
  locales.map(async (locale) => {
170
194
  try {
171
- const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("../_chunks/en-D2kTkBns.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("../_chunks/ru-BKzplvmu.js")) }), `./translations/${locale}.json`, 3);
195
+ const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("../_chunks/en-GKZo4lia.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("../_chunks/ru-bj5iiIPr.js")) }), `./translations/${locale}.json`, 3);
172
196
  return { data, locale };
173
197
  } catch {
174
198
  return { data: {}, locale };
@@ -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
  const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
3
3
  const v = glob[path];
4
4
  if (v) {
@@ -138,6 +138,30 @@ const index = {
138
138
  advanced: []
139
139
  }
140
140
  });
141
+ app.customFields.register({
142
+ name: "trigger-params",
143
+ pluginId: PLUGIN_ID,
144
+ type: "json",
145
+ intlLabel: {
146
+ id: `${PLUGIN_ID}.trigger-params.label`,
147
+ defaultMessage: "Trigger Params"
148
+ },
149
+ intlDescription: {
150
+ id: `${PLUGIN_ID}.trigger-params.description`,
151
+ defaultMessage: "Configure trigger parameters for popup flow stages"
152
+ },
153
+ icon: Filter,
154
+ components: {
155
+ Input: async () => import(
156
+ /* webpackChunkName: "crm-trigger-params" */
157
+ "../_chunks/index-BMvCnlEy.mjs"
158
+ )
159
+ },
160
+ options: {
161
+ base: [],
162
+ advanced: []
163
+ }
164
+ });
141
165
  app.addMenuLink({
142
166
  to: `/plugins/${PLUGIN_ID}`,
143
167
  icon: Message,
@@ -167,7 +191,7 @@ const index = {
167
191
  return Promise.all(
168
192
  locales.map(async (locale) => {
169
193
  try {
170
- const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("../_chunks/en-DEUgX5uV.mjs"), "./translations/ru.json": () => import("../_chunks/ru-DOt1yfNm.mjs") }), `./translations/${locale}.json`, 3);
194
+ const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("../_chunks/en-B5BgIROW.mjs"), "./translations/ru.json": () => import("../_chunks/ru-h22ZdPCS.mjs") }), `./translations/${locale}.json`, 3);
171
195
  return { data, locale };
172
196
  } catch {
173
197
  return { data: {}, locale };
@@ -32,6 +32,11 @@ const register = ({ strapi }) => {
32
32
  plugin: "crm-dashboard",
33
33
  type: "json"
34
34
  });
35
+ strapi.customFields.register({
36
+ name: "trigger-params",
37
+ plugin: "crm-dashboard",
38
+ type: "json"
39
+ });
35
40
  };
36
41
  const bootstrap = ({ strapi }) => {
37
42
  };
@@ -31,6 +31,11 @@ const register = ({ strapi }) => {
31
31
  plugin: "crm-dashboard",
32
32
  type: "json"
33
33
  });
34
+ strapi.customFields.register({
35
+ name: "trigger-params",
36
+ plugin: "crm-dashboard",
37
+ type: "json"
38
+ });
34
39
  };
35
40
  const bootstrap = ({ strapi }) => {
36
41
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inspirer-dev/crm-dashboard",
3
- "version": "1.0.81",
3
+ "version": "1.0.83",
4
4
  "description": "CRM Dashboard and Tools",
5
5
  "strapi": {
6
6
  "name": "crm-dashboard",
@@ -38,6 +38,12 @@ const register = ({ strapi }: { strapi: Core.Strapi }) => {
38
38
  plugin: 'crm-dashboard',
39
39
  type: 'json',
40
40
  });
41
+
42
+ strapi.customFields.register({
43
+ name: 'trigger-params',
44
+ plugin: 'crm-dashboard',
45
+ type: 'json',
46
+ });
41
47
  };
42
48
 
43
49
  export default register;