@inspirer-dev/crm-dashboard 1.0.21 → 1.0.23

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