@inspirer-dev/crm-dashboard 1.0.80 → 1.0.82

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/admin/src/components/ButtonsBuilder/index.tsx +3 -3
  2. package/admin/src/components/CancelConditionsField/index.tsx +7 -6
  3. package/admin/src/components/RulesBuilder/index.tsx +9 -8
  4. package/admin/src/components/StepFlowBuilder/constants.ts +2 -0
  5. package/admin/src/components/StepFlowBuilder/index.tsx +1 -1
  6. package/admin/src/components/StepFlowBuilder/nodes/EventTriggerNode.tsx +29 -1
  7. package/admin/src/components/StepFlowBuilder/panels/EventTriggerConfig.tsx +97 -9
  8. package/admin/src/components/StepFlowBuilder/panels/NodeEditPanel.tsx +1 -1
  9. package/admin/src/components/StepFlowBuilder/panels/WaitConfig.tsx +1 -3
  10. package/admin/src/components/StepFlowBuilder/types.ts +2 -0
  11. package/admin/src/components/TriggerConfigField/index.tsx +11 -10
  12. package/admin/src/components/TriggerParamsField/constants.ts +109 -0
  13. package/admin/src/components/TriggerParamsField/index.tsx +292 -0
  14. package/admin/src/index.ts +26 -1
  15. package/admin/src/pages/HomePage/components/CampaignBuilder/index.tsx +4 -0
  16. package/admin/src/pages/HomePage/components/FlowBuilderTest.tsx +3 -3
  17. package/admin/src/pages/HomePage/components/SendTimeHeatMap.tsx +2 -2
  18. package/admin/src/pages/HomePage/components/StatsView.tsx +2 -2
  19. package/admin/src/translations/en.json +4 -1
  20. package/admin/src/translations/ru.json +4 -1
  21. package/admin/tsconfig.json +12 -1
  22. package/admin/tsconfig.tsbuildinfo +1 -1
  23. package/dist/_chunks/{en-DEUgX5uV.mjs → en-B5BgIROW.mjs} +3 -1
  24. package/dist/_chunks/{en-D2kTkBns.js → en-GKZo4lia.js} +3 -1
  25. package/dist/_chunks/{index-C-1xCfqJ.js → index-354YMebI.js} +152 -38
  26. package/dist/_chunks/{index-BydXrDhA.mjs → index-BKfFI_Jo.mjs} +2 -2
  27. package/dist/_chunks/{index-D1kMmlrA.js → index-BQcRoIJr.js} +5 -4
  28. package/dist/_chunks/{index-BJzk6xNb.mjs → index-BgwX1xYS.mjs} +7 -6
  29. package/dist/_chunks/{index-pJUyH-Qr.js → index-Cg0G_bTE.js} +2 -2
  30. package/dist/_chunks/index-CuMY0eo5.js +310 -0
  31. package/dist/_chunks/{index-unxa4Q_H.mjs → index-DKJtyGq7.mjs} +5 -4
  32. package/dist/_chunks/{index-BFRbyVHC.js → index-DRXMKPXI.js} +1 -1
  33. package/dist/_chunks/{index-Xa_4jez0.mjs → index-Dhj0KzCX.mjs} +5 -4
  34. package/dist/_chunks/{index-Dv1tGmDT.mjs → index-LXBoz7PC.mjs} +1 -1
  35. package/dist/_chunks/index-NvFKi6er.mjs +310 -0
  36. package/dist/_chunks/{index-BKrTVHBr.js → index-T7VXjklK.js} +5 -4
  37. package/dist/_chunks/{index-CWSibOAr.mjs → index-gR86Z3uh.mjs} +152 -38
  38. package/dist/_chunks/{index-CAwynvu7.js → index-xDSMnUMp.js} +7 -6
  39. package/dist/_chunks/{ru-BKzplvmu.js → ru-bj5iiIPr.js} +3 -1
  40. package/dist/_chunks/{ru-DOt1yfNm.mjs → ru-h22ZdPCS.mjs} +3 -1
  41. package/dist/admin/index.js +31 -7
  42. package/dist/admin/index.mjs +32 -8
  43. package/dist/server/index.js +5 -0
  44. package/dist/server/index.mjs +5 -0
  45. package/package.json +3 -3
  46. package/server/src/register.ts +6 -0
@@ -144,7 +144,9 @@ const DEFAULT_NODE_DATA = {
144
144
  config: {
145
145
  eventTrigger: {
146
146
  events: [],
147
- logic: "or"
147
+ logic: "or",
148
+ timeout: 0,
149
+ timeoutUnit: "minutes"
148
150
  }
149
151
  }
150
152
  }
@@ -1092,12 +1094,24 @@ const EventTriggerNode = ({ id, data, selected }) => {
1092
1094
  const eventTrigger = data.config.eventTrigger;
1093
1095
  const events = eventTrigger?.events || [];
1094
1096
  const logic = eventTrigger?.logic || "or";
1097
+ const timeout = eventTrigger?.timeout || 0;
1098
+ const timeoutUnit = eventTrigger?.timeoutUnit || "minutes";
1095
1099
  const { hasError, hasWarning } = useNodeValidation(id);
1096
1100
  const getEventLabel2 = () => {
1097
1101
  if (events.length === 0) return "No events";
1098
1102
  if (events.length === 1) return events[0];
1099
1103
  return `${events.length} events (${logic.toUpperCase()})`;
1100
1104
  };
1105
+ const getTimeoutLabel = () => {
1106
+ if (timeout <= 0) return null;
1107
+ const unitShort = {
1108
+ seconds: "s",
1109
+ minutes: "m",
1110
+ hours: "h",
1111
+ days: "d"
1112
+ };
1113
+ return `${timeout}${unitShort[timeoutUnit] || timeoutUnit}`;
1114
+ };
1101
1115
  return /* @__PURE__ */ jsxRuntime.jsxs(
1102
1116
  "div",
1103
1117
  {
@@ -1179,7 +1193,7 @@ const EventTriggerNode = ({ id, data, selected }) => {
1179
1193
  children: data.name
1180
1194
  }
1181
1195
  ),
1182
- /* @__PURE__ */ jsxRuntime.jsx(
1196
+ /* @__PURE__ */ jsxRuntime.jsxs(
1183
1197
  "div",
1184
1198
  {
1185
1199
  style: {
@@ -1187,24 +1201,44 @@ const EventTriggerNode = ({ id, data, selected }) => {
1187
1201
  gap: 6,
1188
1202
  marginTop: 6
1189
1203
  },
1190
- children: /* @__PURE__ */ jsxRuntime.jsx(
1191
- "span",
1192
- {
1193
- style: {
1194
- fontSize: 10,
1195
- fontWeight: 600,
1196
- color: colors.border,
1197
- background: "rgba(255, 255, 255, 0.9)",
1198
- padding: "2px 10px",
1199
- borderRadius: 4,
1200
- maxWidth: 160,
1201
- overflow: "hidden",
1202
- textOverflow: "ellipsis",
1203
- whiteSpace: "nowrap"
1204
- },
1205
- children: getEventLabel2()
1206
- }
1207
- )
1204
+ children: [
1205
+ /* @__PURE__ */ jsxRuntime.jsx(
1206
+ "span",
1207
+ {
1208
+ style: {
1209
+ fontSize: 10,
1210
+ fontWeight: 600,
1211
+ color: colors.border,
1212
+ background: "rgba(255, 255, 255, 0.9)",
1213
+ padding: "2px 10px",
1214
+ borderRadius: 4,
1215
+ maxWidth: getTimeoutLabel() ? 120 : 160,
1216
+ overflow: "hidden",
1217
+ textOverflow: "ellipsis",
1218
+ whiteSpace: "nowrap"
1219
+ },
1220
+ children: getEventLabel2()
1221
+ }
1222
+ ),
1223
+ getTimeoutLabel() && /* @__PURE__ */ jsxRuntime.jsxs(
1224
+ "span",
1225
+ {
1226
+ style: {
1227
+ fontSize: 10,
1228
+ fontWeight: 600,
1229
+ color: "#d97706",
1230
+ background: "rgba(255, 255, 255, 0.9)",
1231
+ padding: "2px 8px",
1232
+ borderRadius: 4,
1233
+ whiteSpace: "nowrap"
1234
+ },
1235
+ children: [
1236
+ "⏱ ",
1237
+ getTimeoutLabel()
1238
+ ]
1239
+ }
1240
+ )
1241
+ ]
1208
1242
  }
1209
1243
  )
1210
1244
  ] }),
@@ -1716,8 +1750,7 @@ const WaitConfig = ({ data, onUpdate, disabled }) => {
1716
1750
  value: duration,
1717
1751
  onValueChange: handleDurationChange,
1718
1752
  disabled,
1719
- step: 1,
1720
- label: ""
1753
+ step: 1
1721
1754
  }
1722
1755
  ) })
1723
1756
  ] }),
@@ -1740,9 +1773,8 @@ const WaitConfig = ({ data, onUpdate, disabled }) => {
1740
1773
  designSystem.SingleSelect,
1741
1774
  {
1742
1775
  value: durationUnit,
1743
- onChange: handleUnitChange,
1776
+ onChange: (val) => handleUnitChange(String(val)),
1744
1777
  disabled,
1745
- label: "",
1746
1778
  children: DURATION_UNIT_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: opt.value, children: opt.label }, opt.value))
1747
1779
  }
1748
1780
  ) })
@@ -2382,6 +2414,8 @@ const EventTriggerConfig = ({ data, onUpdate, disabled }) => {
2382
2414
  const eventTrigger = data.config.eventTrigger || { events: [], logic: "or" };
2383
2415
  const events = eventTrigger.events || [];
2384
2416
  const logic = eventTrigger.logic || "or";
2417
+ const timeout = eventTrigger.timeout || 0;
2418
+ const timeoutUnit = eventTrigger.timeoutUnit || "minutes";
2385
2419
  const [inputText, setInputText] = React.useState("");
2386
2420
  const justSelectedRef = React.useRef(false);
2387
2421
  React.useEffect(() => {
@@ -2428,6 +2462,28 @@ const EventTriggerConfig = ({ data, onUpdate, disabled }) => {
2428
2462
  }
2429
2463
  });
2430
2464
  };
2465
+ const handleTimeoutChange = (value) => {
2466
+ onUpdate({
2467
+ config: {
2468
+ ...data.config,
2469
+ eventTrigger: {
2470
+ ...eventTrigger,
2471
+ timeout: value || 0
2472
+ }
2473
+ }
2474
+ });
2475
+ };
2476
+ const handleTimeoutUnitChange = (value) => {
2477
+ onUpdate({
2478
+ config: {
2479
+ ...data.config,
2480
+ eventTrigger: {
2481
+ ...eventTrigger,
2482
+ timeoutUnit: value
2483
+ }
2484
+ }
2485
+ });
2486
+ };
2431
2487
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 4, children: [
2432
2488
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { width: "100%" }, children: [
2433
2489
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2465,6 +2521,7 @@ const EventTriggerConfig = ({ data, onUpdate, disabled }) => {
2465
2521
  creatable: true,
2466
2522
  createMessage: (v) => `Использовать: "${v}"`,
2467
2523
  onCreateOption: (v) => {
2524
+ if (!v) return;
2468
2525
  handleAddEvent(v);
2469
2526
  },
2470
2527
  children: Object.entries(ANALYTICS_EVENTS).flatMap(
@@ -2606,6 +2663,51 @@ const EventTriggerConfig = ({ data, onUpdate, disabled }) => {
2606
2663
  }
2607
2664
  )
2608
2665
  ] }),
2666
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { width: "100%" }, children: [
2667
+ /* @__PURE__ */ jsxRuntime.jsx(
2668
+ designSystem.Typography,
2669
+ {
2670
+ variant: "sigma",
2671
+ style: {
2672
+ marginBottom: 10,
2673
+ display: "block",
2674
+ fontSize: 11,
2675
+ letterSpacing: "0.05em",
2676
+ color: theme.textMuted
2677
+ },
2678
+ children: "ТАЙМАУТ"
2679
+ }
2680
+ ),
2681
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 3, alignItems: "center", children: [
2682
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(
2683
+ designSystem.NumberInput,
2684
+ {
2685
+ value: timeout,
2686
+ onValueChange: handleTimeoutChange,
2687
+ disabled,
2688
+ step: 1
2689
+ }
2690
+ ) }),
2691
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: 140 }, children: /* @__PURE__ */ jsxRuntime.jsx(
2692
+ designSystem.SingleSelect,
2693
+ {
2694
+ value: timeoutUnit,
2695
+ onChange: (val) => handleTimeoutUnitChange(String(val)),
2696
+ disabled,
2697
+ children: DURATION_UNIT_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: opt.value, children: opt.label }, opt.value))
2698
+ }
2699
+ ) })
2700
+ ] }),
2701
+ /* @__PURE__ */ jsxRuntime.jsx(
2702
+ designSystem.Typography,
2703
+ {
2704
+ variant: "pi",
2705
+ textColor: "neutral500",
2706
+ style: { marginTop: 8, display: "block" },
2707
+ children: timeout > 0 ? `Если событие не произойдёт за ${timeout} ${timeoutUnit}, кампания продолжится автоматически` : "Установите 0 для бесконечного ожидания события"
2708
+ }
2709
+ )
2710
+ ] }),
2609
2711
  /* @__PURE__ */ jsxRuntime.jsx(
2610
2712
  "div",
2611
2713
  {
@@ -2624,19 +2726,31 @@ const EventTriggerConfig = ({ data, onUpdate, disabled }) => {
2624
2726
  fontSize: 12,
2625
2727
  lineHeight: 1.5
2626
2728
  },
2627
- children: events.length === 0 ? "Выберите события, которые должен совершить пользователь для продолжения кампании." : logic === "or" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2628
- "Кампания продолжится, когда пользователь выполнит",
2629
- " ",
2630
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "любое" }),
2631
- " из выбранных событий."
2632
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2633
- "Кампания продолжится только когда пользователь выполнит",
2634
- " ",
2635
- /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
2636
- "все ",
2637
- events.length
2729
+ children: events.length === 0 ? "Выберите события, которые должен совершить пользователь для продолжения кампании." : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2730
+ logic === "or" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2731
+ "Кампания продолжится, когда пользователь выполнит",
2732
+ " ",
2733
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "любое" }),
2734
+ " из выбранных событий"
2735
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2736
+ "Кампания продолжится только когда пользователь выполнит",
2737
+ " ",
2738
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
2739
+ "все ",
2740
+ events.length
2741
+ ] }),
2742
+ " выбранных события"
2638
2743
  ] }),
2639
- " выбранных события."
2744
+ timeout > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2745
+ " ",
2746
+ "или через ",
2747
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
2748
+ timeout,
2749
+ " ",
2750
+ timeoutUnit
2751
+ ] })
2752
+ ] }),
2753
+ "."
2640
2754
  ] })
2641
2755
  }
2642
2756
  )
@@ -2953,7 +3067,7 @@ const NodeEditPanel = ({
2953
3067
  {
2954
3068
  value: name,
2955
3069
  onChange: handleNameChange,
2956
- disabled: disabled || stepType === "entry",
3070
+ disabled,
2957
3071
  placeholder: "Enter step name..."
2958
3072
  }
2959
3073
  ) })
@@ -4673,7 +4787,7 @@ const StepFlowBuilderInner = React.forwardRef(
4673
4787
  }, [intlLabel]);
4674
4788
  const stepCount = steps.length;
4675
4789
  const validationError = React.useMemo(() => {
4676
- if (!validation || validation.isValid) return null;
4790
+ if (!validation || validation.isValid) return void 0;
4677
4791
  const errorCount = validation.errors.length;
4678
4792
  const errorWord = pluralize(errorCount, "ошибка", "ошибки", "ошибок");
4679
4793
  return `Поток содержит ${errorCount} ${errorWord} валидации. Исправьте все ошибки перед публикацией.`;
@@ -286,8 +286,8 @@ const ButtonsBuilder = forwardRef(
286
286
  ]
287
287
  }
288
288
  ),
289
- error && /* @__PURE__ */ jsx(Field.Error, { children: error }),
290
- hint && /* @__PURE__ */ jsx(Field.Hint, { children: hint })
289
+ error && /* @__PURE__ */ jsx(Field.Error, {}),
290
+ hint && /* @__PURE__ */ jsx(Field.Hint, {})
291
291
  ] }) });
292
292
  }
293
293
  );
@@ -437,6 +437,7 @@ const TriggerConfigField = React.forwardRef(
437
437
  creatable: true,
438
438
  createMessage: (v) => `Use custom event: "${v}"`,
439
439
  onCreateOption: (v) => {
440
+ if (!v) return;
440
441
  const eventValue = extractEventValue(v);
441
442
  handleUpdate({ eventName: eventValue });
442
443
  setInputText(getEventLabel(eventValue));
@@ -519,7 +520,7 @@ const TriggerConfigField = React.forwardRef(
519
520
  designSystem.SingleSelect,
520
521
  {
521
522
  value: config.delayUnit || "minutes",
522
- onChange: (val) => handleUpdate({ delayUnit: val }),
523
+ onChange: (val) => handleUpdate({ delayUnit: String(val) }),
523
524
  disabled,
524
525
  size: "S",
525
526
  children: [
@@ -642,7 +643,7 @@ const TriggerConfigField = React.forwardRef(
642
643
  designSystem.SingleSelect,
643
644
  {
644
645
  value: String(config.scheduleEveryMinutes ?? 5),
645
- onChange: (val) => handleUpdate({ scheduleEveryMinutes: parseInt(val, 10) || 5 }),
646
+ onChange: (val) => handleUpdate({ scheduleEveryMinutes: parseInt(String(val), 10) || 5 }),
646
647
  disabled,
647
648
  size: "S",
648
649
  children: [
@@ -760,8 +761,8 @@ const TriggerConfigField = React.forwardRef(
760
761
  ]
761
762
  }
762
763
  ),
763
- error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, { children: error }),
764
- hint && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, { children: hint })
764
+ error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {}),
765
+ hint && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
765
766
  ] }) });
766
767
  }
767
768
  );
@@ -145,7 +145,8 @@ const ValueInput = ({ metric, value, operator, onChange, disabled }) => {
145
145
  /* @__PURE__ */ jsx(
146
146
  Switch,
147
147
  {
148
- label: "",
148
+ onLabel: "",
149
+ offLabel: "",
149
150
  checked: boolVal,
150
151
  onChange: () => onChange(!boolVal),
151
152
  disabled
@@ -185,7 +186,7 @@ const ValueInput = ({ metric, value, operator, onChange, disabled }) => {
185
186
  SingleSelect,
186
187
  {
187
188
  value: unit,
188
- onChange: (newUnit) => onChange({ [newUnit]: numValue }),
189
+ onChange: (newUnit) => onChange({ [String(newUnit)]: numValue }),
189
190
  disabled,
190
191
  children: CANCEL_TIME_UNITS.map((u) => /* @__PURE__ */ jsx(SingleSelectOption, { value: u.value, children: u.label }, u.value))
191
192
  }
@@ -224,7 +225,7 @@ const RuleRow = ({ rule, onUpdate, onDelete, disabled }) => {
224
225
  SingleSelect,
225
226
  {
226
227
  value: rule.field,
227
- onChange: (val) => handleFieldChange(val),
228
+ onChange: (val) => handleFieldChange(String(val)),
228
229
  disabled,
229
230
  size: "S",
230
231
  children: CANCEL_METRICS.map((m) => /* @__PURE__ */ jsx(SingleSelectOption, { value: m.key, children: m.label }, m.key))
@@ -234,7 +235,7 @@ const RuleRow = ({ rule, onUpdate, onDelete, disabled }) => {
234
235
  SingleSelect,
235
236
  {
236
237
  value: rule.operator,
237
- onChange: (val) => onUpdate({ ...rule, operator: val }),
238
+ onChange: (val) => onUpdate({ ...rule, operator: String(val) }),
238
239
  disabled,
239
240
  size: "S",
240
241
  children: OPERATORS.filter((op) => availableOperators.includes(op.value)).map((op) => /* @__PURE__ */ jsx(SingleSelectOption, { value: op.value, children: op.label }, op.value))
@@ -346,8 +347,8 @@ const CancelConditionsField = forwardRef(
346
347
  }
347
348
  ) })
348
349
  ] }) }) }),
349
- error && /* @__PURE__ */ jsx(Field.Error, { children: error }),
350
- hint && /* @__PURE__ */ jsx(Field.Hint, { children: hint })
350
+ error && /* @__PURE__ */ jsx(Field.Error, {}),
351
+ hint && /* @__PURE__ */ jsx(Field.Hint, {})
351
352
  ] }) });
352
353
  }
353
354
  );
@@ -288,8 +288,8 @@ const ButtonsBuilder = React.forwardRef(
288
288
  ]
289
289
  }
290
290
  ),
291
- error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, { children: error }),
292
- hint && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, { children: hint })
291
+ error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {}),
292
+ hint && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
293
293
  ] }) });
294
294
  }
295
295
  );