@inspirer-dev/crm-dashboard 1.0.10 → 1.0.11

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,339 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import React__default, { forwardRef, useState, useCallback } from "react";
3
+ import { Field, Flex, Typography, Card, CardContent, Box, Button, SingleSelect, SingleSelectOption, Tooltip, IconButton, Switch, TextInput } from "@strapi/design-system";
4
+ import { Plus, Trash } from "@strapi/icons";
5
+ import { useTheme } from "styled-components";
6
+ const booleanOperators = ["$eq", "$ne"];
7
+ const numberOperators = ["$eq", "$ne", "$gt", "$lt", "$gte", "$lte"];
8
+ const timeAgoOperators = ["$gt", "$lt", "$gte", "$lte"];
9
+ const CANCEL_METRICS = [
10
+ {
11
+ key: "has_deposit_since_trigger",
12
+ label: "Made Deposit",
13
+ valueType: "boolean",
14
+ description: "User made a successful deposit after the trigger event",
15
+ operators: booleanOperators
16
+ },
17
+ {
18
+ key: "has_activity_since_trigger",
19
+ label: "Had Activity",
20
+ valueType: "boolean",
21
+ description: "User had any activity (case open, upgrade, battle, etc.) after trigger",
22
+ operators: booleanOperators
23
+ },
24
+ {
25
+ key: "has_session_since_trigger",
26
+ label: "Returned to Site",
27
+ valueType: "boolean",
28
+ description: "User had a new session/visit after the trigger event",
29
+ operators: booleanOperators
30
+ },
31
+ {
32
+ key: "balance_sufficient",
33
+ label: "Balance Sufficient",
34
+ valueType: "boolean",
35
+ description: "User balance is now sufficient for the intended action",
36
+ operators: booleanOperators
37
+ },
38
+ {
39
+ key: "is_authenticated",
40
+ label: "Is Authenticated",
41
+ valueType: "boolean",
42
+ description: "User has logged in / authenticated",
43
+ operators: booleanOperators
44
+ },
45
+ {
46
+ key: "battle_completed",
47
+ label: "Battle Completed",
48
+ valueType: "boolean",
49
+ description: "The battle was completed or continued",
50
+ operators: booleanOperators
51
+ },
52
+ {
53
+ key: "upgrade_completed",
54
+ label: "Upgrade Completed",
55
+ valueType: "boolean",
56
+ description: "The upgrade was completed or retried",
57
+ operators: booleanOperators
58
+ },
59
+ {
60
+ key: "contract_completed",
61
+ label: "Contract Completed",
62
+ valueType: "boolean",
63
+ description: "The contract was completed",
64
+ operators: booleanOperators
65
+ },
66
+ {
67
+ key: "deposit_count",
68
+ label: "Deposit Count",
69
+ valueType: "number",
70
+ description: "Total number of deposits (e.g., for checking if 2nd deposit exists)",
71
+ operators: numberOperators
72
+ },
73
+ {
74
+ key: "case_open_count_since_trigger",
75
+ label: "Cases Opened Since Trigger",
76
+ valueType: "number",
77
+ description: "Number of cases opened after the trigger event",
78
+ operators: numberOperators
79
+ },
80
+ {
81
+ key: "time_since_trigger",
82
+ label: "Time Since Trigger",
83
+ valueType: "time_ago",
84
+ description: "How long since the trigger event fired",
85
+ operators: timeAgoOperators
86
+ }
87
+ ];
88
+ const CANCEL_TIME_UNITS = [
89
+ { value: "minutes_ago", label: "minutes" },
90
+ { value: "hours_ago", label: "hours" }
91
+ ];
92
+ const generateId = () => Math.random().toString(36).substring(2, 11);
93
+ const DEFAULT_CONFIG = {
94
+ logic: "$or",
95
+ rules: []
96
+ };
97
+ const parseConfig = (value) => {
98
+ if (!value) return DEFAULT_CONFIG;
99
+ try {
100
+ const parsed = JSON.parse(value);
101
+ if (parsed.logic && Array.isArray(parsed.rules)) {
102
+ return parsed;
103
+ }
104
+ return DEFAULT_CONFIG;
105
+ } catch {
106
+ return DEFAULT_CONFIG;
107
+ }
108
+ };
109
+ const serializeConfig = (config) => {
110
+ return JSON.stringify(config);
111
+ };
112
+ const getMetric = (key) => {
113
+ return CANCEL_METRICS.find((m) => m.key === key);
114
+ };
115
+ const OPERATORS = [
116
+ { value: "$eq", label: "=" },
117
+ { value: "$ne", label: "≠" },
118
+ { value: "$gt", label: ">" },
119
+ { value: "$lt", label: "<" },
120
+ { value: "$gte", label: "≥" },
121
+ { value: "$lte", label: "≤" }
122
+ ];
123
+ const ValueInput = ({ metric, value, operator, onChange, disabled }) => {
124
+ if (metric.valueType === "boolean") {
125
+ const boolVal = value === true || value === "true";
126
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
127
+ /* @__PURE__ */ jsx(
128
+ Switch,
129
+ {
130
+ label: "",
131
+ checked: boolVal,
132
+ onChange: () => onChange(!boolVal),
133
+ disabled
134
+ }
135
+ ),
136
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", children: boolVal ? "true" : "false" })
137
+ ] });
138
+ }
139
+ if (metric.valueType === "number") {
140
+ return /* @__PURE__ */ jsx(
141
+ TextInput,
142
+ {
143
+ type: "number",
144
+ value: String(value ?? 0),
145
+ onChange: (e) => onChange(parseInt(e.target.value, 10) || 0),
146
+ disabled,
147
+ "aria-label": "Value"
148
+ }
149
+ );
150
+ }
151
+ if (metric.valueType === "time_ago") {
152
+ const timeValue = value || { minutes_ago: 10 };
153
+ const unit = Object.keys(timeValue)[0] || "minutes_ago";
154
+ const numValue = timeValue[unit] || 10;
155
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
156
+ /* @__PURE__ */ jsx(Box, { style: { width: "80px" }, children: /* @__PURE__ */ jsx(
157
+ TextInput,
158
+ {
159
+ type: "number",
160
+ value: String(numValue),
161
+ onChange: (e) => onChange({ [unit]: parseInt(e.target.value, 10) || 0 }),
162
+ disabled,
163
+ "aria-label": "Time value"
164
+ }
165
+ ) }),
166
+ /* @__PURE__ */ jsx(Box, { style: { width: "120px" }, children: /* @__PURE__ */ jsx(
167
+ SingleSelect,
168
+ {
169
+ value: unit,
170
+ onChange: (newUnit) => onChange({ [newUnit]: numValue }),
171
+ disabled,
172
+ children: CANCEL_TIME_UNITS.map((u) => /* @__PURE__ */ jsx(SingleSelectOption, { value: u.value, children: u.label }, u.value))
173
+ }
174
+ ) })
175
+ ] });
176
+ }
177
+ return null;
178
+ };
179
+ const RuleRow = ({ rule, onUpdate, onDelete, disabled }) => {
180
+ const theme = useTheme();
181
+ const colors = theme?.colors;
182
+ const metric = getMetric(rule.field);
183
+ const availableOperators = metric?.operators || ["$eq"];
184
+ const handleFieldChange = (fieldKey) => {
185
+ const newMetric = getMetric(fieldKey);
186
+ let newValue = true;
187
+ if (newMetric?.valueType === "number") {
188
+ newValue = 0;
189
+ } else if (newMetric?.valueType === "time_ago") {
190
+ newValue = { minutes_ago: 10 };
191
+ }
192
+ const newOp = newMetric?.operators[0] || "$eq";
193
+ onUpdate({ ...rule, field: fieldKey, operator: newOp, value: newValue });
194
+ };
195
+ return /* @__PURE__ */ jsxs(
196
+ Flex,
197
+ {
198
+ gap: 2,
199
+ alignItems: "center",
200
+ padding: 2,
201
+ background: "neutral0",
202
+ hasRadius: true,
203
+ style: { border: `1px solid ${colors?.neutral200 || "#dcdce4"}` },
204
+ children: [
205
+ /* @__PURE__ */ jsx(Box, { style: { flex: "1 1 200px", minWidth: "180px" }, children: /* @__PURE__ */ jsx(
206
+ SingleSelect,
207
+ {
208
+ value: rule.field,
209
+ onChange: (val) => handleFieldChange(val),
210
+ disabled,
211
+ size: "S",
212
+ children: CANCEL_METRICS.map((m) => /* @__PURE__ */ jsx(SingleSelectOption, { value: m.key, children: m.label }, m.key))
213
+ }
214
+ ) }),
215
+ /* @__PURE__ */ jsx(Box, { style: { width: "80px" }, children: /* @__PURE__ */ jsx(
216
+ SingleSelect,
217
+ {
218
+ value: rule.operator,
219
+ onChange: (val) => onUpdate({ ...rule, operator: val }),
220
+ disabled,
221
+ size: "S",
222
+ children: OPERATORS.filter((op) => availableOperators.includes(op.value)).map((op) => /* @__PURE__ */ jsx(SingleSelectOption, { value: op.value, children: op.label }, op.value))
223
+ }
224
+ ) }),
225
+ /* @__PURE__ */ jsx(Box, { style: { flex: "1 1 150px", minWidth: "120px" }, children: metric && /* @__PURE__ */ jsx(
226
+ ValueInput,
227
+ {
228
+ metric,
229
+ value: rule.value,
230
+ operator: rule.operator,
231
+ onChange: (val) => onUpdate({ ...rule, value: val }),
232
+ disabled
233
+ }
234
+ ) }),
235
+ /* @__PURE__ */ jsx(Tooltip, { label: "Delete condition", children: /* @__PURE__ */ jsx(IconButton, { onClick: onDelete, label: "Delete condition", variant: "ghost", disabled, children: /* @__PURE__ */ jsx(Trash, {}) }) })
236
+ ]
237
+ }
238
+ );
239
+ };
240
+ const CancelConditionsField = forwardRef(
241
+ ({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
242
+ const [config, setConfig] = useState(() => parseConfig(value));
243
+ const theme = useTheme();
244
+ theme?.colors;
245
+ React__default.useEffect(() => {
246
+ const parsed = parseConfig(value);
247
+ setConfig(parsed);
248
+ }, [value]);
249
+ const handleUpdate = useCallback((newConfig) => {
250
+ setConfig(newConfig);
251
+ onChange({
252
+ target: {
253
+ name,
254
+ value: serializeConfig(newConfig)
255
+ }
256
+ });
257
+ }, [name, onChange]);
258
+ const handleAddRule = () => {
259
+ const newRule = {
260
+ id: generateId(),
261
+ field: "has_deposit_since_trigger",
262
+ operator: "$eq",
263
+ value: true
264
+ };
265
+ handleUpdate({
266
+ ...config,
267
+ rules: [...config.rules, newRule]
268
+ });
269
+ };
270
+ const handleUpdateRule = (ruleId, updatedRule) => {
271
+ handleUpdate({
272
+ ...config,
273
+ rules: config.rules.map((r) => r.id === ruleId ? updatedRule : r)
274
+ });
275
+ };
276
+ const handleDeleteRule = (ruleId) => {
277
+ handleUpdate({
278
+ ...config,
279
+ rules: config.rules.filter((r) => r.id !== ruleId)
280
+ });
281
+ };
282
+ const handleLogicToggle = () => {
283
+ handleUpdate({
284
+ ...config,
285
+ logic: config.logic === "$or" ? "$and" : "$or"
286
+ });
287
+ };
288
+ const hasRules = config.rules.length > 0;
289
+ return /* @__PURE__ */ jsx(Field.Root, { name, error, required, hint, ref, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, children: [
290
+ /* @__PURE__ */ jsx(Field.Label, { children: intlLabel?.defaultMessage || "Cancel Conditions" }),
291
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Skip sending if any of these conditions are true (checked right before send)" }),
292
+ /* @__PURE__ */ jsx(Card, { background: "neutral100", children: /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(Box, { padding: 4, children: [
293
+ hasRules && /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 3, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
294
+ /* @__PURE__ */ jsx(
295
+ Button,
296
+ {
297
+ variant: config.logic === "$or" ? "default" : "secondary",
298
+ size: "S",
299
+ onClick: handleLogicToggle,
300
+ disabled,
301
+ children: config.logic === "$or" ? "OR" : "AND"
302
+ }
303
+ ),
304
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", children: config.logic === "$or" ? "Cancel if ANY condition is true" : "Cancel if ALL conditions are true" })
305
+ ] }) }),
306
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
307
+ config.rules.map((rule) => /* @__PURE__ */ jsx(
308
+ RuleRow,
309
+ {
310
+ rule,
311
+ onUpdate: (updated) => handleUpdateRule(rule.id, updated),
312
+ onDelete: () => handleDeleteRule(rule.id),
313
+ disabled
314
+ },
315
+ rule.id
316
+ )),
317
+ !hasRules && /* @__PURE__ */ jsx(Box, { padding: 4, background: "neutral0", hasRadius: true, style: { textAlign: "center" }, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral500", children: "No cancel conditions defined. Message will be sent if segment rules match." }) })
318
+ ] }),
319
+ /* @__PURE__ */ jsx(Box, { marginTop: 3, children: /* @__PURE__ */ jsx(
320
+ Button,
321
+ {
322
+ variant: "secondary",
323
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
324
+ onClick: handleAddRule,
325
+ disabled,
326
+ size: "S",
327
+ children: "Add Cancel Condition"
328
+ }
329
+ ) })
330
+ ] }) }) }),
331
+ error && /* @__PURE__ */ jsx(Field.Error, { children: error }),
332
+ hint && /* @__PURE__ */ jsx(Field.Hint, { children: hint })
333
+ ] }) });
334
+ }
335
+ );
336
+ CancelConditionsField.displayName = "CancelConditionsField";
337
+ export {
338
+ CancelConditionsField as default
339
+ };
@@ -0,0 +1,341 @@
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 styled = require("styled-components");
8
+ const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
9
+ const React__default = /* @__PURE__ */ _interopDefault(React);
10
+ const booleanOperators = ["$eq", "$ne"];
11
+ const numberOperators = ["$eq", "$ne", "$gt", "$lt", "$gte", "$lte"];
12
+ const timeAgoOperators = ["$gt", "$lt", "$gte", "$lte"];
13
+ const CANCEL_METRICS = [
14
+ {
15
+ key: "has_deposit_since_trigger",
16
+ label: "Made Deposit",
17
+ valueType: "boolean",
18
+ description: "User made a successful deposit after the trigger event",
19
+ operators: booleanOperators
20
+ },
21
+ {
22
+ key: "has_activity_since_trigger",
23
+ label: "Had Activity",
24
+ valueType: "boolean",
25
+ description: "User had any activity (case open, upgrade, battle, etc.) after trigger",
26
+ operators: booleanOperators
27
+ },
28
+ {
29
+ key: "has_session_since_trigger",
30
+ label: "Returned to Site",
31
+ valueType: "boolean",
32
+ description: "User had a new session/visit after the trigger event",
33
+ operators: booleanOperators
34
+ },
35
+ {
36
+ key: "balance_sufficient",
37
+ label: "Balance Sufficient",
38
+ valueType: "boolean",
39
+ description: "User balance is now sufficient for the intended action",
40
+ operators: booleanOperators
41
+ },
42
+ {
43
+ key: "is_authenticated",
44
+ label: "Is Authenticated",
45
+ valueType: "boolean",
46
+ description: "User has logged in / authenticated",
47
+ operators: booleanOperators
48
+ },
49
+ {
50
+ key: "battle_completed",
51
+ label: "Battle Completed",
52
+ valueType: "boolean",
53
+ description: "The battle was completed or continued",
54
+ operators: booleanOperators
55
+ },
56
+ {
57
+ key: "upgrade_completed",
58
+ label: "Upgrade Completed",
59
+ valueType: "boolean",
60
+ description: "The upgrade was completed or retried",
61
+ operators: booleanOperators
62
+ },
63
+ {
64
+ key: "contract_completed",
65
+ label: "Contract Completed",
66
+ valueType: "boolean",
67
+ description: "The contract was completed",
68
+ operators: booleanOperators
69
+ },
70
+ {
71
+ key: "deposit_count",
72
+ label: "Deposit Count",
73
+ valueType: "number",
74
+ description: "Total number of deposits (e.g., for checking if 2nd deposit exists)",
75
+ operators: numberOperators
76
+ },
77
+ {
78
+ key: "case_open_count_since_trigger",
79
+ label: "Cases Opened Since Trigger",
80
+ valueType: "number",
81
+ description: "Number of cases opened after the trigger event",
82
+ operators: numberOperators
83
+ },
84
+ {
85
+ key: "time_since_trigger",
86
+ label: "Time Since Trigger",
87
+ valueType: "time_ago",
88
+ description: "How long since the trigger event fired",
89
+ operators: timeAgoOperators
90
+ }
91
+ ];
92
+ const CANCEL_TIME_UNITS = [
93
+ { value: "minutes_ago", label: "minutes" },
94
+ { value: "hours_ago", label: "hours" }
95
+ ];
96
+ const generateId = () => Math.random().toString(36).substring(2, 11);
97
+ const DEFAULT_CONFIG = {
98
+ logic: "$or",
99
+ rules: []
100
+ };
101
+ const parseConfig = (value) => {
102
+ if (!value) return DEFAULT_CONFIG;
103
+ try {
104
+ const parsed = JSON.parse(value);
105
+ if (parsed.logic && Array.isArray(parsed.rules)) {
106
+ return parsed;
107
+ }
108
+ return DEFAULT_CONFIG;
109
+ } catch {
110
+ return DEFAULT_CONFIG;
111
+ }
112
+ };
113
+ const serializeConfig = (config) => {
114
+ return JSON.stringify(config);
115
+ };
116
+ const getMetric = (key) => {
117
+ return CANCEL_METRICS.find((m) => m.key === key);
118
+ };
119
+ const OPERATORS = [
120
+ { value: "$eq", label: "=" },
121
+ { value: "$ne", label: "≠" },
122
+ { value: "$gt", label: ">" },
123
+ { value: "$lt", label: "<" },
124
+ { value: "$gte", label: "≥" },
125
+ { value: "$lte", label: "≤" }
126
+ ];
127
+ const ValueInput = ({ metric, value, operator, onChange, disabled }) => {
128
+ if (metric.valueType === "boolean") {
129
+ const boolVal = value === true || value === "true";
130
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
131
+ /* @__PURE__ */ jsxRuntime.jsx(
132
+ designSystem.Switch,
133
+ {
134
+ label: "",
135
+ checked: boolVal,
136
+ onChange: () => onChange(!boolVal),
137
+ disabled
138
+ }
139
+ ),
140
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: boolVal ? "true" : "false" })
141
+ ] });
142
+ }
143
+ if (metric.valueType === "number") {
144
+ return /* @__PURE__ */ jsxRuntime.jsx(
145
+ designSystem.TextInput,
146
+ {
147
+ type: "number",
148
+ value: String(value ?? 0),
149
+ onChange: (e) => onChange(parseInt(e.target.value, 10) || 0),
150
+ disabled,
151
+ "aria-label": "Value"
152
+ }
153
+ );
154
+ }
155
+ if (metric.valueType === "time_ago") {
156
+ const timeValue = value || { minutes_ago: 10 };
157
+ const unit = Object.keys(timeValue)[0] || "minutes_ago";
158
+ const numValue = timeValue[unit] || 10;
159
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
160
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "80px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
161
+ designSystem.TextInput,
162
+ {
163
+ type: "number",
164
+ value: String(numValue),
165
+ onChange: (e) => onChange({ [unit]: parseInt(e.target.value, 10) || 0 }),
166
+ disabled,
167
+ "aria-label": "Time value"
168
+ }
169
+ ) }),
170
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "120px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
171
+ designSystem.SingleSelect,
172
+ {
173
+ value: unit,
174
+ onChange: (newUnit) => onChange({ [newUnit]: numValue }),
175
+ disabled,
176
+ children: CANCEL_TIME_UNITS.map((u) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: u.value, children: u.label }, u.value))
177
+ }
178
+ ) })
179
+ ] });
180
+ }
181
+ return null;
182
+ };
183
+ const RuleRow = ({ rule, onUpdate, onDelete, disabled }) => {
184
+ const theme = styled.useTheme();
185
+ const colors = theme?.colors;
186
+ const metric = getMetric(rule.field);
187
+ const availableOperators = metric?.operators || ["$eq"];
188
+ const handleFieldChange = (fieldKey) => {
189
+ const newMetric = getMetric(fieldKey);
190
+ let newValue = true;
191
+ if (newMetric?.valueType === "number") {
192
+ newValue = 0;
193
+ } else if (newMetric?.valueType === "time_ago") {
194
+ newValue = { minutes_ago: 10 };
195
+ }
196
+ const newOp = newMetric?.operators[0] || "$eq";
197
+ onUpdate({ ...rule, field: fieldKey, operator: newOp, value: newValue });
198
+ };
199
+ return /* @__PURE__ */ jsxRuntime.jsxs(
200
+ designSystem.Flex,
201
+ {
202
+ gap: 2,
203
+ alignItems: "center",
204
+ padding: 2,
205
+ background: "neutral0",
206
+ hasRadius: true,
207
+ style: { border: `1px solid ${colors?.neutral200 || "#dcdce4"}` },
208
+ children: [
209
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: "1 1 200px", minWidth: "180px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
210
+ designSystem.SingleSelect,
211
+ {
212
+ value: rule.field,
213
+ onChange: (val) => handleFieldChange(val),
214
+ disabled,
215
+ size: "S",
216
+ children: CANCEL_METRICS.map((m) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: m.key, children: m.label }, m.key))
217
+ }
218
+ ) }),
219
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "80px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
220
+ designSystem.SingleSelect,
221
+ {
222
+ value: rule.operator,
223
+ onChange: (val) => onUpdate({ ...rule, operator: val }),
224
+ disabled,
225
+ size: "S",
226
+ children: OPERATORS.filter((op) => availableOperators.includes(op.value)).map((op) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: op.value, children: op.label }, op.value))
227
+ }
228
+ ) }),
229
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: "1 1 150px", minWidth: "120px" }, children: metric && /* @__PURE__ */ jsxRuntime.jsx(
230
+ ValueInput,
231
+ {
232
+ metric,
233
+ value: rule.value,
234
+ operator: rule.operator,
235
+ onChange: (val) => onUpdate({ ...rule, value: val }),
236
+ disabled
237
+ }
238
+ ) }),
239
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label: "Delete condition", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.IconButton, { onClick: onDelete, label: "Delete condition", variant: "ghost", disabled, children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {}) }) })
240
+ ]
241
+ }
242
+ );
243
+ };
244
+ const CancelConditionsField = React.forwardRef(
245
+ ({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
246
+ const [config, setConfig] = React.useState(() => parseConfig(value));
247
+ const theme = styled.useTheme();
248
+ theme?.colors;
249
+ React__default.default.useEffect(() => {
250
+ const parsed = parseConfig(value);
251
+ setConfig(parsed);
252
+ }, [value]);
253
+ const handleUpdate = React.useCallback((newConfig) => {
254
+ setConfig(newConfig);
255
+ onChange({
256
+ target: {
257
+ name,
258
+ value: serializeConfig(newConfig)
259
+ }
260
+ });
261
+ }, [name, onChange]);
262
+ const handleAddRule = () => {
263
+ const newRule = {
264
+ id: generateId(),
265
+ field: "has_deposit_since_trigger",
266
+ operator: "$eq",
267
+ value: true
268
+ };
269
+ handleUpdate({
270
+ ...config,
271
+ rules: [...config.rules, newRule]
272
+ });
273
+ };
274
+ const handleUpdateRule = (ruleId, updatedRule) => {
275
+ handleUpdate({
276
+ ...config,
277
+ rules: config.rules.map((r) => r.id === ruleId ? updatedRule : r)
278
+ });
279
+ };
280
+ const handleDeleteRule = (ruleId) => {
281
+ handleUpdate({
282
+ ...config,
283
+ rules: config.rules.filter((r) => r.id !== ruleId)
284
+ });
285
+ };
286
+ const handleLogicToggle = () => {
287
+ handleUpdate({
288
+ ...config,
289
+ logic: config.logic === "$or" ? "$and" : "$or"
290
+ });
291
+ };
292
+ const hasRules = config.rules.length > 0;
293
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Root, { name, error, required, hint, ref, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, children: [
294
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: intlLabel?.defaultMessage || "Cancel Conditions" }),
295
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: "Skip sending if any of these conditions are true (checked right before send)" }),
296
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Card, { background: "neutral100", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.CardContent, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 4, children: [
297
+ hasRules && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 3, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
298
+ /* @__PURE__ */ jsxRuntime.jsx(
299
+ designSystem.Button,
300
+ {
301
+ variant: config.logic === "$or" ? "default" : "secondary",
302
+ size: "S",
303
+ onClick: handleLogicToggle,
304
+ disabled,
305
+ children: config.logic === "$or" ? "OR" : "AND"
306
+ }
307
+ ),
308
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: config.logic === "$or" ? "Cancel if ANY condition is true" : "Cancel if ALL conditions are true" })
309
+ ] }) }),
310
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
311
+ config.rules.map((rule) => /* @__PURE__ */ jsxRuntime.jsx(
312
+ RuleRow,
313
+ {
314
+ rule,
315
+ onUpdate: (updated) => handleUpdateRule(rule.id, updated),
316
+ onDelete: () => handleDeleteRule(rule.id),
317
+ disabled
318
+ },
319
+ rule.id
320
+ )),
321
+ !hasRules && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, background: "neutral0", hasRadius: true, style: { textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral500", children: "No cancel conditions defined. Message will be sent if segment rules match." }) })
322
+ ] }),
323
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 3, children: /* @__PURE__ */ jsxRuntime.jsx(
324
+ designSystem.Button,
325
+ {
326
+ variant: "secondary",
327
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
328
+ onClick: handleAddRule,
329
+ disabled,
330
+ size: "S",
331
+ children: "Add Cancel Condition"
332
+ }
333
+ ) })
334
+ ] }) }) }),
335
+ error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, { children: error }),
336
+ hint && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, { children: hint })
337
+ ] }) });
338
+ }
339
+ );
340
+ CancelConditionsField.displayName = "CancelConditionsField";
341
+ exports.default = CancelConditionsField;