@inspirer-dev/crm-dashboard 1.0.21 → 1.0.22

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.
Files changed (33) hide show
  1. package/admin/src/components/StepFlowBuilder/constants.ts +91 -0
  2. package/admin/src/components/StepFlowBuilder/edges/LabeledEdge.tsx +77 -0
  3. package/admin/src/components/StepFlowBuilder/edges/index.ts +8 -0
  4. package/admin/src/components/StepFlowBuilder/index.tsx +320 -0
  5. package/admin/src/components/StepFlowBuilder/nodes/BranchNode.tsx +90 -0
  6. package/admin/src/components/StepFlowBuilder/nodes/EntryNode.tsx +47 -0
  7. package/admin/src/components/StepFlowBuilder/nodes/ExitNode.tsx +47 -0
  8. package/admin/src/components/StepFlowBuilder/nodes/MessageNode.tsx +78 -0
  9. package/admin/src/components/StepFlowBuilder/nodes/WaitNode.tsx +71 -0
  10. package/admin/src/components/StepFlowBuilder/nodes/index.ts +16 -0
  11. package/admin/src/components/StepFlowBuilder/panels/BranchConfig.tsx +112 -0
  12. package/admin/src/components/StepFlowBuilder/panels/MessageConfig.tsx +188 -0
  13. package/admin/src/components/StepFlowBuilder/panels/NodeEditPanel.tsx +158 -0
  14. package/admin/src/components/StepFlowBuilder/panels/WaitConfig.tsx +87 -0
  15. package/admin/src/components/StepFlowBuilder/panels/index.ts +4 -0
  16. package/admin/src/components/StepFlowBuilder/toolbar/FlowToolbar.tsx +86 -0
  17. package/admin/src/components/StepFlowBuilder/toolbar/index.ts +1 -0
  18. package/admin/src/components/StepFlowBuilder/types.ts +77 -0
  19. package/admin/src/components/StepFlowBuilder/utils.ts +217 -0
  20. package/admin/src/index.ts +8 -8
  21. package/dist/_chunks/index-BK8649hk.mjs +1405 -0
  22. package/dist/_chunks/{index-CWnuAWMG.mjs → index-BeiHTAlq.mjs} +91 -112
  23. package/dist/_chunks/{index-Bw1mkNpv.js → index-T7-DTUJN.js} +262 -227
  24. package/dist/_chunks/index-aSjgyfVX.js +1408 -0
  25. package/dist/admin/index.js +9 -9
  26. package/dist/admin/index.mjs +10 -10
  27. package/dist/server/index.js +1 -1
  28. package/dist/server/index.mjs +1 -1
  29. package/package.json +3 -1
  30. package/server/src/register.ts +1 -1
  31. package/admin/src/components/JourneyConfigField/index.tsx +0 -744
  32. package/dist/_chunks/index-BhNY5vYI.js +0 -591
  33. package/dist/_chunks/index-D0XEcc24.mjs +0 -591
@@ -1,591 +0,0 @@
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 utils = require("./utils-CmonL0io.js");
8
- const NODE_TYPES = [
9
- { value: "message", label: "Send Message", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Mail, {}), description: "Send a message to user" },
10
- { value: "wait", label: "Wait", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}), description: "Wait for a period of time" },
11
- { value: "branch", label: "Branch", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowRight, {}), description: "Split flow based on segment" },
12
- { value: "exit", label: "Exit", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {}), description: "End the journey" }
13
- ];
14
- const CHANNELS = [
15
- { value: "telegram", label: "Telegram" },
16
- { value: "email", label: "Email" },
17
- { value: "push", label: "Push Notification" },
18
- { value: "sms", label: "SMS" }
19
- ];
20
- const WAIT_UNITS = [
21
- { value: "minutes", label: "Minutes" },
22
- { value: "hours", label: "Hours" },
23
- { value: "days", label: "Days" }
24
- ];
25
- const DEFAULT_CONFIG = {
26
- steps: [
27
- { id: utils.generateId(), stepKey: "entrance", name: "Entry Point", nodeType: "entrance" }
28
- ],
29
- transitions: [],
30
- entryOncePerUser: true,
31
- reEntryDelayDays: 30
32
- };
33
- const parseConfig = (value) => {
34
- if (!value) return { ...DEFAULT_CONFIG, steps: [{ ...DEFAULT_CONFIG.steps[0], id: utils.generateId() }] };
35
- if (typeof value === "string") {
36
- try {
37
- const parsed = JSON.parse(value);
38
- if (parsed.steps && Array.isArray(parsed.steps)) {
39
- return parsed;
40
- }
41
- } catch {
42
- return { ...DEFAULT_CONFIG, steps: [{ ...DEFAULT_CONFIG.steps[0], id: utils.generateId() }] };
43
- }
44
- }
45
- if (typeof value === "object" && value.steps) {
46
- return value;
47
- }
48
- return { ...DEFAULT_CONFIG, steps: [{ ...DEFAULT_CONFIG.steps[0], id: utils.generateId() }] };
49
- };
50
- const serializeConfig = (config) => JSON.stringify(config);
51
- const getStepIcon = (nodeType) => {
52
- switch (nodeType) {
53
- case "entrance":
54
- return /* @__PURE__ */ jsxRuntime.jsx(icons.Play, {});
55
- case "message":
56
- return /* @__PURE__ */ jsxRuntime.jsx(icons.Mail, {});
57
- case "wait":
58
- return /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {});
59
- case "branch":
60
- return /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowRight, {});
61
- case "exit":
62
- return /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {});
63
- default:
64
- return null;
65
- }
66
- };
67
- const getStepColor = (nodeType) => {
68
- switch (nodeType) {
69
- case "entrance":
70
- return { bg: "success100", border: "#328048", text: "success600" };
71
- case "message":
72
- return { bg: "primary100", border: "#4945ff", text: "primary600" };
73
- case "wait":
74
- return { bg: "warning100", border: "#d9822f", text: "warning600" };
75
- case "branch":
76
- return { bg: "secondary100", border: "#8e44ad", text: "secondary600" };
77
- case "exit":
78
- return { bg: "neutral200", border: "#666687", text: "neutral600" };
79
- default:
80
- return { bg: "neutral100", border: "#dcdce4", text: "neutral600" };
81
- }
82
- };
83
- const StepCard = ({ step, index, totalSteps, disabled, expanded, onToggleExpand, onUpdate, onDelete, onMove, transitions, allSteps, onUpdateTransition }) => {
84
- const colors = getStepColor(step.nodeType);
85
- const isEntrance = step.nodeType === "entrance";
86
- const availableTargets = allSteps.filter((s) => s.stepKey !== step.stepKey && s.nodeType !== "entrance");
87
- const getNextStep = (branchType) => {
88
- const t = transitions.find((tr) => tr.sourceStepKey === step.stepKey && tr.branchType === branchType);
89
- return t?.targetStepKey || "";
90
- };
91
- const updateMessageConfig = (updates) => {
92
- onUpdate({
93
- messageConfig: {
94
- channel: step.messageConfig?.channel || "telegram",
95
- variants: step.messageConfig?.variants || [],
96
- ...step.messageConfig,
97
- ...updates
98
- }
99
- });
100
- };
101
- const updateWaitConfig = (updates) => {
102
- onUpdate({
103
- waitConfig: {
104
- durationValue: step.waitConfig?.durationValue || 30,
105
- durationUnit: step.waitConfig?.durationUnit || "minutes",
106
- ...step.waitConfig,
107
- ...updates
108
- }
109
- });
110
- };
111
- const updateBranchConfig = (updates) => {
112
- onUpdate({
113
- branchConfig: {
114
- segmentId: step.branchConfig?.segmentId || "",
115
- useStepSegment: step.branchConfig?.useStepSegment || false,
116
- ...step.branchConfig,
117
- ...updates
118
- }
119
- });
120
- };
121
- const addVariant = () => {
122
- const variants = step.messageConfig?.variants || [];
123
- updateMessageConfig({
124
- variants: [
125
- ...variants,
126
- { id: utils.generateId(), name: `Variant ${variants.length + 1}`, templateId: "", weight: 100 }
127
- ]
128
- });
129
- };
130
- const updateVariant = (variantId, updates) => {
131
- const variants = step.messageConfig?.variants || [];
132
- updateMessageConfig({
133
- variants: variants.map((v) => v.id === variantId ? { ...v, ...updates } : v)
134
- });
135
- };
136
- const deleteVariant = (variantId) => {
137
- const variants = step.messageConfig?.variants || [];
138
- updateMessageConfig({
139
- variants: variants.filter((v) => v.id !== variantId)
140
- });
141
- };
142
- return /* @__PURE__ */ jsxRuntime.jsx(
143
- designSystem.Card,
144
- {
145
- background: colors.bg,
146
- style: { border: `2px solid ${colors.border}` },
147
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.CardContent, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, padding: 3, children: [
148
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", children: [
149
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
150
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { color: colors.border }, children: getStepIcon(step.nodeType) }),
151
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: colors.bg, textColor: colors.text, children: step.nodeType.toUpperCase() }),
152
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", children: step.name })
153
- ] }),
154
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, children: [
155
- !isEntrance && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
156
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label: "Move up", children: /* @__PURE__ */ jsxRuntime.jsx(
157
- designSystem.IconButton,
158
- {
159
- onClick: () => onMove("up"),
160
- label: "Move up",
161
- variant: "ghost",
162
- disabled: disabled || index <= 1,
163
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUp, {})
164
- }
165
- ) }),
166
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label: "Move down", children: /* @__PURE__ */ jsxRuntime.jsx(
167
- designSystem.IconButton,
168
- {
169
- onClick: () => onMove("down"),
170
- label: "Move down",
171
- variant: "ghost",
172
- disabled: disabled || index >= totalSteps - 1,
173
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDown, {})
174
- }
175
- ) }),
176
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label: "Delete step", children: /* @__PURE__ */ jsxRuntime.jsx(
177
- designSystem.IconButton,
178
- {
179
- onClick: onDelete,
180
- label: "Delete",
181
- variant: "ghost",
182
- disabled,
183
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {})
184
- }
185
- ) })
186
- ] }),
187
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "ghost", onClick: onToggleExpand, size: "S", children: expanded ? "Collapse" : "Expand" })
188
- ] })
189
- ] }),
190
- expanded && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { paddingTop: 2, children: [
191
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, {}),
192
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 3, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, children: [
193
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
194
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Step Name" }),
195
- /* @__PURE__ */ jsxRuntime.jsx(
196
- designSystem.TextInput,
197
- {
198
- value: step.name,
199
- onChange: (e) => onUpdate({ name: e.target.value }),
200
- disabled: disabled || isEntrance
201
- }
202
- )
203
- ] }),
204
- !isEntrance && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
205
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Step Key (unique identifier)" }),
206
- /* @__PURE__ */ jsxRuntime.jsx(
207
- designSystem.TextInput,
208
- {
209
- value: step.stepKey,
210
- onChange: (e) => onUpdate({ stepKey: e.target.value.toLowerCase().replace(/\s+/g, "_") }),
211
- disabled,
212
- placeholder: "e.g., welcome_message"
213
- }
214
- )
215
- ] }),
216
- step.nodeType === "message" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
217
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
218
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Channel" }),
219
- /* @__PURE__ */ jsxRuntime.jsx(
220
- designSystem.SingleSelect,
221
- {
222
- value: step.messageConfig?.channel || "telegram",
223
- onChange: (val) => updateMessageConfig({ channel: val }),
224
- disabled,
225
- children: CHANNELS.map((ch) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: ch.value, children: ch.label }, ch.value))
226
- }
227
- )
228
- ] }),
229
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
230
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: 8, display: "block" }, children: "Message Variants (A/B Testing)" }),
231
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
232
- (step.messageConfig?.variants || []).map((variant, vIdx) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "flex-end", background: "neutral0", padding: 2, hasRadius: true, children: [
233
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
234
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Name" }),
235
- /* @__PURE__ */ jsxRuntime.jsx(
236
- designSystem.TextInput,
237
- {
238
- value: variant.name,
239
- onChange: (e) => updateVariant(variant.id, { name: e.target.value }),
240
- disabled
241
- }
242
- )
243
- ] }) }),
244
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
245
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Template ID" }),
246
- /* @__PURE__ */ jsxRuntime.jsx(
247
- designSystem.TextInput,
248
- {
249
- value: variant.templateId,
250
- onChange: (e) => updateVariant(variant.id, { templateId: e.target.value }),
251
- disabled,
252
- placeholder: "Enter template documentId"
253
- }
254
- )
255
- ] }) }),
256
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: 80 }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
257
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Weight %" }),
258
- /* @__PURE__ */ jsxRuntime.jsx(
259
- designSystem.TextInput,
260
- {
261
- type: "number",
262
- value: String(variant.weight),
263
- onChange: (e) => updateVariant(variant.id, { weight: parseInt(e.target.value, 10) || 0 }),
264
- disabled
265
- }
266
- )
267
- ] }) }),
268
- /* @__PURE__ */ jsxRuntime.jsx(
269
- designSystem.IconButton,
270
- {
271
- onClick: () => deleteVariant(variant.id),
272
- label: "Delete variant",
273
- variant: "ghost",
274
- disabled,
275
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {})
276
- }
277
- )
278
- ] }, variant.id)),
279
- /* @__PURE__ */ jsxRuntime.jsx(
280
- designSystem.Button,
281
- {
282
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
283
- onClick: addVariant,
284
- variant: "secondary",
285
- size: "S",
286
- disabled,
287
- children: "Add Variant"
288
- }
289
- )
290
- ] })
291
- ] })
292
- ] }),
293
- step.nodeType === "wait" && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
294
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: 120 }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
295
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Duration" }),
296
- /* @__PURE__ */ jsxRuntime.jsx(
297
- designSystem.TextInput,
298
- {
299
- type: "number",
300
- value: String(step.waitConfig?.durationValue || 30),
301
- onChange: (e) => updateWaitConfig({ durationValue: parseInt(e.target.value, 10) || 0 }),
302
- disabled
303
- }
304
- )
305
- ] }) }),
306
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: 150 }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
307
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Unit" }),
308
- /* @__PURE__ */ jsxRuntime.jsx(
309
- designSystem.SingleSelect,
310
- {
311
- value: step.waitConfig?.durationUnit || "minutes",
312
- onChange: (val) => updateWaitConfig({ durationUnit: val }),
313
- disabled,
314
- children: WAIT_UNITS.map((u) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: u.value, children: u.label }, u.value))
315
- }
316
- )
317
- ] }) })
318
- ] }),
319
- step.nodeType === "branch" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
320
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
321
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Segment ID (optional)" }),
322
- /* @__PURE__ */ jsxRuntime.jsx(
323
- designSystem.TextInput,
324
- {
325
- value: step.branchConfig?.segmentId || "",
326
- onChange: (e) => updateBranchConfig({ segmentId: e.target.value }),
327
- disabled,
328
- placeholder: "Leave empty to use campaign's segment"
329
- }
330
- ),
331
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, { children: "If empty, uses campaign's segment for evaluation" })
332
- ] }),
333
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { background: "neutral0", padding: 3, hasRadius: true, children: [
334
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: 12, display: "block" }, children: "Branch Paths" }),
335
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
336
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
337
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "success100", textColor: "success600", children: "YES" }),
338
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsxs(
339
- designSystem.SingleSelect,
340
- {
341
- value: getNextStep("yes"),
342
- onChange: (val) => onUpdateTransition(step.stepKey, "yes", val),
343
- disabled,
344
- placeholder: "Select next step...",
345
- children: [
346
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "", children: "-- None --" }),
347
- availableTargets.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.SingleSelectOption, { value: s.stepKey, children: [
348
- s.name,
349
- " (",
350
- s.nodeType,
351
- ")"
352
- ] }, s.stepKey))
353
- ]
354
- }
355
- ) })
356
- ] }),
357
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
358
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "danger100", textColor: "danger600", children: "NO" }),
359
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsxs(
360
- designSystem.SingleSelect,
361
- {
362
- value: getNextStep("no"),
363
- onChange: (val) => onUpdateTransition(step.stepKey, "no", val),
364
- disabled,
365
- placeholder: "Select next step...",
366
- children: [
367
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "", children: "-- None --" }),
368
- availableTargets.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.SingleSelectOption, { value: s.stepKey, children: [
369
- s.name,
370
- " (",
371
- s.nodeType,
372
- ")"
373
- ] }, s.stepKey))
374
- ]
375
- }
376
- ) })
377
- ] })
378
- ] })
379
- ] })
380
- ] }),
381
- step.nodeType !== "branch" && step.nodeType !== "exit" && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
382
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Next Step" }),
383
- /* @__PURE__ */ jsxRuntime.jsxs(
384
- designSystem.SingleSelect,
385
- {
386
- value: getNextStep("default"),
387
- onChange: (val) => onUpdateTransition(step.stepKey, "default", val),
388
- disabled,
389
- placeholder: "Select next step...",
390
- children: [
391
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "", children: "-- None (end) --" }),
392
- availableTargets.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.SingleSelectOption, { value: s.stepKey, children: [
393
- s.name,
394
- " (",
395
- s.nodeType,
396
- ")"
397
- ] }, s.stepKey))
398
- ]
399
- }
400
- )
401
- ] })
402
- ] }) })
403
- ] })
404
- ] }) })
405
- }
406
- );
407
- };
408
- const JourneyConfigField = React.forwardRef(
409
- ({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
410
- const [config, setConfig] = React.useState(() => parseConfig(value));
411
- const [expandedSteps, setExpandedSteps] = React.useState(/* @__PURE__ */ new Set());
412
- const [showAddStep, setShowAddStep] = React.useState(false);
413
- React.useEffect(() => {
414
- setConfig(parseConfig(value));
415
- }, [value]);
416
- const update = (newConfig) => {
417
- setConfig(newConfig);
418
- onChange({ target: { name, value: serializeConfig(newConfig) } });
419
- };
420
- const toggleExpand = (stepId) => {
421
- setExpandedSteps((prev) => {
422
- const next = new Set(prev);
423
- if (next.has(stepId)) {
424
- next.delete(stepId);
425
- } else {
426
- next.add(stepId);
427
- }
428
- return next;
429
- });
430
- };
431
- const addStep = (nodeType) => {
432
- const newStep = {
433
- id: utils.generateId(),
434
- stepKey: `${nodeType}_${Date.now()}`,
435
- name: NODE_TYPES.find((n) => n.value === nodeType)?.label || nodeType,
436
- nodeType,
437
- ...nodeType === "message" && {
438
- messageConfig: { channel: "telegram", variants: [] }
439
- },
440
- ...nodeType === "wait" && {
441
- waitConfig: { durationValue: 30, durationUnit: "minutes" }
442
- },
443
- ...nodeType === "branch" && {
444
- branchConfig: { segmentId: "", useStepSegment: false }
445
- }
446
- };
447
- update({ ...config, steps: [...config.steps, newStep] });
448
- setExpandedSteps((prev) => new Set(prev).add(newStep.id));
449
- setShowAddStep(false);
450
- };
451
- const updateStep = (stepId, updates) => {
452
- update({
453
- ...config,
454
- steps: config.steps.map((s) => s.id === stepId ? { ...s, ...updates } : s)
455
- });
456
- };
457
- const deleteStep = (stepId) => {
458
- const step = config.steps.find((s) => s.id === stepId);
459
- if (!step) return;
460
- update({
461
- ...config,
462
- steps: config.steps.filter((s) => s.id !== stepId),
463
- transitions: config.transitions.filter(
464
- (t) => t.sourceStepKey !== step.stepKey && t.targetStepKey !== step.stepKey
465
- )
466
- });
467
- };
468
- const moveStep = (stepId, direction) => {
469
- const idx = config.steps.findIndex((s) => s.id === stepId);
470
- if (idx <= 0 && direction === "up") return;
471
- if (idx >= config.steps.length - 1 && direction === "down") return;
472
- const newSteps = [...config.steps];
473
- const targetIdx = direction === "up" ? idx - 1 : idx + 1;
474
- if (targetIdx === 0) return;
475
- [newSteps[idx], newSteps[targetIdx]] = [newSteps[targetIdx], newSteps[idx]];
476
- update({ ...config, steps: newSteps });
477
- };
478
- const updateTransition = (sourceStepKey, branchType, targetStepKey) => {
479
- let transitions = config.transitions.filter(
480
- (t) => !(t.sourceStepKey === sourceStepKey && t.branchType === branchType)
481
- );
482
- if (targetStepKey) {
483
- transitions.push({
484
- id: utils.generateId(),
485
- sourceStepKey,
486
- targetStepKey,
487
- branchType
488
- });
489
- }
490
- update({ ...config, transitions });
491
- };
492
- const updateGlobalConfig = (updates) => {
493
- update({ ...config, ...updates });
494
- };
495
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Root, { name, error, required, hint, ref, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 4, children: [
496
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: intlLabel?.defaultMessage || "Journey Configuration" }),
497
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Card, { background: "neutral100", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.CardContent, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, padding: 3, children: [
498
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", children: "Journey Settings" }),
499
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, children: [
500
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
501
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Entry once per user" }),
502
- /* @__PURE__ */ jsxRuntime.jsxs(
503
- designSystem.SingleSelect,
504
- {
505
- value: config.entryOncePerUser ? "yes" : "no",
506
- onChange: (val) => updateGlobalConfig({ entryOncePerUser: val === "yes" }),
507
- disabled,
508
- children: [
509
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "yes", children: "Yes" }),
510
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "no", children: "No (allow re-entry)" })
511
- ]
512
- }
513
- )
514
- ] }),
515
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
516
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Re-entry delay (days)" }),
517
- /* @__PURE__ */ jsxRuntime.jsx(
518
- designSystem.TextInput,
519
- {
520
- type: "number",
521
- value: String(config.reEntryDelayDays || 30),
522
- onChange: (e) => updateGlobalConfig({ reEntryDelayDays: parseInt(e.target.value, 10) || 0 }),
523
- disabled
524
- }
525
- )
526
- ] })
527
- ] })
528
- ] }) }) }),
529
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
530
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", style: { marginBottom: 12 }, children: [
531
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "delta", children: [
532
- "Steps (",
533
- config.steps.length,
534
- ")"
535
- ] }),
536
- /* @__PURE__ */ jsxRuntime.jsx(
537
- designSystem.Button,
538
- {
539
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
540
- onClick: () => setShowAddStep(!showAddStep),
541
- variant: "secondary",
542
- disabled,
543
- children: "Add Step"
544
- }
545
- )
546
- ] }),
547
- showAddStep && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Card, { background: "primary100", style: { marginBottom: 16, border: "2px dashed #4945ff" }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.CardContent, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, padding: 3, children: [
548
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", children: "Select step type:" }),
549
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, wrap: "wrap", children: NODE_TYPES.map((nt) => /* @__PURE__ */ jsxRuntime.jsx(
550
- designSystem.Box,
551
- {
552
- padding: 3,
553
- background: "neutral0",
554
- hasRadius: true,
555
- style: { cursor: "pointer", border: "1px solid #dcdce4", minWidth: 140 },
556
- onClick: () => addStep(nt.value),
557
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", gap: 1, children: [
558
- nt.icon,
559
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", children: nt.label }),
560
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", style: { textAlign: "center" }, children: nt.description })
561
- ] })
562
- },
563
- nt.value
564
- )) })
565
- ] }) }) }),
566
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 2, children: config.steps.map((step, idx) => /* @__PURE__ */ jsxRuntime.jsx(
567
- StepCard,
568
- {
569
- step,
570
- index: idx,
571
- totalSteps: config.steps.length,
572
- disabled,
573
- expanded: expandedSteps.has(step.id),
574
- onToggleExpand: () => toggleExpand(step.id),
575
- onUpdate: (updates) => updateStep(step.id, updates),
576
- onDelete: () => deleteStep(step.id),
577
- onMove: (dir) => moveStep(step.id, dir),
578
- transitions: config.transitions,
579
- allSteps: config.steps,
580
- onUpdateTransition: updateTransition
581
- },
582
- step.id
583
- )) })
584
- ] }),
585
- error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, { children: error }),
586
- hint && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, { children: hint })
587
- ] }) });
588
- }
589
- );
590
- JourneyConfigField.displayName = "JourneyConfigField";
591
- exports.default = JourneyConfigField;