@inspirer-dev/crm-dashboard 1.0.84 → 1.0.85

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.
@@ -10,16 +10,20 @@ import {
10
10
  Tooltip,
11
11
  Card,
12
12
  CardContent,
13
+ SingleSelect,
14
+ SingleSelectOption,
13
15
  } from '@strapi/design-system';
14
- import { Plus, Trash, ArrowUp, ArrowDown, Link as LinkIcon } from '@strapi/icons';
16
+ import { Plus, Trash, ArrowUp, ArrowDown, Link as LinkIcon, Layout } from '@strapi/icons';
15
17
  import { useTheme } from 'styled-components';
16
18
  import { generateId } from '../RulesBuilder/utils';
17
19
 
18
20
  type TelegramButton = {
19
21
  id: string;
20
22
  text: string;
21
- url: string;
23
+ url?: string;
22
24
  row?: number;
25
+ type?: 'url' | 'screen';
26
+ screenSlug?: string;
23
27
  };
24
28
 
25
29
  interface ButtonsBuilderProps {
@@ -37,26 +41,25 @@ interface ButtonsBuilderProps {
37
41
  hint?: string;
38
42
  }
39
43
 
44
+ const mapRawButton = (b: any): TelegramButton => ({
45
+ id: typeof b?.id === 'string' ? b.id : generateId(),
46
+ text: typeof b?.text === 'string' ? b.text : '',
47
+ url: typeof b?.url === 'string' ? b.url : '',
48
+ row: typeof b?.row === 'number' ? b.row : 0,
49
+ type: b?.type === 'screen' ? 'screen' : 'url',
50
+ screenSlug: typeof b?.screenSlug === 'string' ? b.screenSlug : '',
51
+ });
52
+
40
53
  const parseButtons = (value: string | TelegramButton[] | null | undefined): TelegramButton[] => {
41
54
  if (!value) return [];
42
55
  if (Array.isArray(value)) {
43
- return value.map((b) => ({
44
- id: typeof b?.id === 'string' ? b.id : generateId(),
45
- text: typeof b?.text === 'string' ? b.text : '',
46
- url: typeof b?.url === 'string' ? b.url : '',
47
- row: typeof b?.row === 'number' ? b.row : 0,
48
- }));
56
+ return value.map(mapRawButton);
49
57
  }
50
58
  if (typeof value === 'string') {
51
59
  try {
52
60
  const parsed = JSON.parse(value);
53
61
  if (!Array.isArray(parsed)) return [];
54
- return parsed.map((b) => ({
55
- id: typeof b?.id === 'string' ? b.id : generateId(),
56
- text: typeof b?.text === 'string' ? b.text : '',
57
- url: typeof b?.url === 'string' ? b.url : '',
58
- row: typeof b?.row === 'number' ? b.row : 0,
59
- }));
62
+ return parsed.map(mapRawButton);
60
63
  } catch {
61
64
  return [];
62
65
  }
@@ -103,35 +106,39 @@ const useThemeColors = () => {
103
106
  }), [isDark]);
104
107
  };
105
108
 
106
- const TelegramButtonPreview: React.FC<{ text: string; url: string }> = ({ text, url }) => (
107
- <a
108
- href={url || '#'}
109
- target="_blank"
110
- rel="noopener noreferrer"
111
- onClick={(e) => !url && e.preventDefault()}
112
- style={{
113
- display: 'inline-flex',
114
- alignItems: 'center',
115
- justifyContent: 'center',
116
- gap: '6px',
117
- padding: '8px 16px',
118
- backgroundColor: '#3390ec',
119
- color: '#ffffff',
120
- borderRadius: '8px',
121
- textDecoration: 'none',
122
- fontSize: '14px',
123
- fontWeight: 500,
124
- cursor: url ? 'pointer' : 'default',
125
- transition: 'background-color 0.15s ease',
126
- minWidth: '80px',
127
- }}
128
- onMouseEnter={(e) => url && (e.currentTarget.style.backgroundColor = '#2b7ed8')}
129
- onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = '#3390ec')}
130
- >
131
- <LinkIcon width={14} height={14} style={{ opacity: 0.9 }} />
132
- <span>{text || '(empty)'}</span>
133
- </a>
134
- );
109
+ const TelegramButtonPreview: React.FC<{ text: string; btnType?: 'url' | 'screen' }> = ({ text, btnType }) => {
110
+ const isScreen = btnType === 'screen';
111
+ const bgColor = isScreen ? '#7c3aed' : '#3390ec';
112
+ const bgHover = isScreen ? '#6d28d9' : '#2b7ed8';
113
+ return (
114
+ <span
115
+ style={{
116
+ display: 'inline-flex',
117
+ alignItems: 'center',
118
+ justifyContent: 'center',
119
+ gap: '6px',
120
+ padding: '8px 16px',
121
+ backgroundColor: bgColor,
122
+ color: '#ffffff',
123
+ borderRadius: '8px',
124
+ textDecoration: 'none',
125
+ fontSize: '14px',
126
+ fontWeight: 500,
127
+ cursor: 'default',
128
+ transition: 'background-color 0.15s ease',
129
+ minWidth: '80px',
130
+ }}
131
+ onMouseEnter={(e) => (e.currentTarget.style.backgroundColor = bgHover)}
132
+ onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = bgColor)}
133
+ >
134
+ {isScreen
135
+ ? <Layout width={14} height={14} style={{ opacity: 0.9 }} />
136
+ : <LinkIcon width={14} height={14} style={{ opacity: 0.9 }} />
137
+ }
138
+ <span>{text || '(empty)'}</span>
139
+ </span>
140
+ );
141
+ };
135
142
 
136
143
  const ButtonsBuilder = forwardRef<HTMLDivElement, ButtonsBuilderProps>(
137
144
  ({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
@@ -150,7 +157,7 @@ const ButtonsBuilder = forwardRef<HTMLDivElement, ButtonsBuilderProps>(
150
157
  const addButton = () => {
151
158
  update([
152
159
  ...buttons,
153
- { id: generateId(), text: 'Button', url: 'https://cases.gg', row: 0 },
160
+ { id: generateId(), text: 'Button', url: 'https://cases.gg', row: 0, type: 'url', screenSlug: '' },
154
161
  ]);
155
162
  };
156
163
 
@@ -222,7 +229,8 @@ const ButtonsBuilder = forwardRef<HTMLDivElement, ButtonsBuilderProps>(
222
229
  ) : (
223
230
  <Flex direction="column" gap={2}>
224
231
  {buttons.map((btn, idx) => {
225
- const urlOk = btn.url.length === 0 ? true : isValidUrl(btn.url);
232
+ const isScreen = btn.type === 'screen';
233
+ const urlOk = isScreen || (btn.url ?? '').length === 0 || isValidUrl(btn.url ?? '');
226
234
  return (
227
235
  <Card
228
236
  key={btn.id}
@@ -251,31 +259,59 @@ const ButtonsBuilder = forwardRef<HTMLDivElement, ButtonsBuilderProps>(
251
259
  </Typography>
252
260
  </Box>
253
261
 
254
- <Box style={{ flex: 1, minWidth: 120 }}>
255
- <TextInput
256
- placeholder="Button text"
257
- value={btn.text}
258
- onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
259
- updateButton(btn.id, { text: e.target.value })
262
+ <Box style={{ width: 100, flexShrink: 0 }}>
263
+ <SingleSelect
264
+ value={btn.type || 'url'}
265
+ onChange={(val: string) =>
266
+ updateButton(btn.id, { type: val as 'url' | 'screen' })
260
267
  }
261
268
  disabled={disabled}
262
269
  size="S"
263
- />
270
+ >
271
+ <SingleSelectOption value="url">URL</SingleSelectOption>
272
+ <SingleSelectOption value="screen">Screen</SingleSelectOption>
273
+ </SingleSelect>
264
274
  </Box>
265
275
 
266
- <Box style={{ flex: 2, minWidth: 180 }}>
276
+ <Box style={{ flex: 1, minWidth: 120 }}>
267
277
  <TextInput
268
- placeholder="https://..."
269
- value={btn.url}
278
+ placeholder="Button text"
279
+ value={btn.text}
270
280
  onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
271
- updateButton(btn.id, { url: e.target.value })
281
+ updateButton(btn.id, { text: e.target.value })
272
282
  }
273
283
  disabled={disabled}
274
284
  size="S"
275
- hasError={!urlOk}
276
285
  />
277
286
  </Box>
278
287
 
288
+ {isScreen ? (
289
+ <Box style={{ flex: 2, minWidth: 180 }}>
290
+ <TextInput
291
+ placeholder="screen-slug"
292
+ value={btn.screenSlug ?? ''}
293
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
294
+ updateButton(btn.id, { screenSlug: e.target.value })
295
+ }
296
+ disabled={disabled}
297
+ size="S"
298
+ />
299
+ </Box>
300
+ ) : (
301
+ <Box style={{ flex: 2, minWidth: 180 }}>
302
+ <TextInput
303
+ placeholder="https://..."
304
+ value={btn.url ?? ''}
305
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
306
+ updateButton(btn.id, { url: e.target.value })
307
+ }
308
+ disabled={disabled}
309
+ size="S"
310
+ hasError={!urlOk}
311
+ />
312
+ </Box>
313
+ )}
314
+
279
315
  <Box style={{ width: 60 }}>
280
316
  <TextInput
281
317
  type="number"
@@ -359,7 +395,7 @@ const ButtonsBuilder = forwardRef<HTMLDivElement, ButtonsBuilderProps>(
359
395
  {previewRows.map((row) => (
360
396
  <Flex key={row.row} gap={2} wrap="wrap" justifyContent="center">
361
397
  {row.items.map((b) => (
362
- <TelegramButtonPreview key={b.id} text={b.text} url={b.url} />
398
+ <TelegramButtonPreview key={b.id} text={b.text} btnType={b.type} />
363
399
  ))}
364
400
  </Flex>
365
401
  ))}
@@ -47,9 +47,9 @@ const parseValue = (value: string | TriggerParamsValue | null | undefined): Trig
47
47
  };
48
48
 
49
49
  const serialize = (params: TriggerParamsValue): string => {
50
- const out: Record<string, number | null> = {};
50
+ const out: Record<string, number> = {};
51
51
  for (const [key, val] of Object.entries(params)) {
52
- out[key] = typeof val === 'number' ? val : null;
52
+ if (typeof val === 'number') out[key] = val;
53
53
  }
54
54
  return JSON.stringify(out);
55
55
  };
@@ -34,8 +34,10 @@ export type RulesConfig = RuleGroup;
34
34
 
35
35
  export interface TelegramButton {
36
36
  text: string;
37
- url: string;
37
+ url?: string;
38
38
  row?: number;
39
+ type?: 'url' | 'screen';
40
+ screenSlug?: string;
39
41
  }
40
42
 
41
43
  export interface CrmTemplate {
@@ -118,7 +118,7 @@ const parseValue = (value) => {
118
118
  const serialize = (params) => {
119
119
  const out = {};
120
120
  for (const [key, val] of Object.entries(params)) {
121
- out[key] = typeof val === "number" ? val : null;
121
+ if (typeof val === "number") out[key] = val;
122
122
  }
123
123
  return JSON.stringify(out);
124
124
  };
@@ -1,29 +1,27 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { forwardRef, useState, useEffect, useMemo } from "react";
3
- import { Field, Flex, Box, Typography, Button, Card, CardContent, TextInput, Tooltip, IconButton } from "@strapi/design-system";
4
- import { Plus, ArrowUp, ArrowDown, Trash, Link } from "@strapi/icons";
3
+ import { Field, Flex, Box, Typography, Button, Card, CardContent, SingleSelect, SingleSelectOption, TextInput, Tooltip, IconButton } from "@strapi/design-system";
4
+ import { Plus, ArrowUp, ArrowDown, Trash, Layout, Link } from "@strapi/icons";
5
5
  import { useTheme } from "styled-components";
6
6
  import { m as generateId } from "./utils-BHneBJ7U.mjs";
7
+ const mapRawButton = (b) => ({
8
+ id: typeof b?.id === "string" ? b.id : generateId(),
9
+ text: typeof b?.text === "string" ? b.text : "",
10
+ url: typeof b?.url === "string" ? b.url : "",
11
+ row: typeof b?.row === "number" ? b.row : 0,
12
+ type: b?.type === "screen" ? "screen" : "url",
13
+ screenSlug: typeof b?.screenSlug === "string" ? b.screenSlug : ""
14
+ });
7
15
  const parseButtons = (value) => {
8
16
  if (!value) return [];
9
17
  if (Array.isArray(value)) {
10
- return value.map((b) => ({
11
- id: typeof b?.id === "string" ? b.id : generateId(),
12
- text: typeof b?.text === "string" ? b.text : "",
13
- url: typeof b?.url === "string" ? b.url : "",
14
- row: typeof b?.row === "number" ? b.row : 0
15
- }));
18
+ return value.map(mapRawButton);
16
19
  }
17
20
  if (typeof value === "string") {
18
21
  try {
19
22
  const parsed = JSON.parse(value);
20
23
  if (!Array.isArray(parsed)) return [];
21
- return parsed.map((b) => ({
22
- id: typeof b?.id === "string" ? b.id : generateId(),
23
- text: typeof b?.text === "string" ? b.text : "",
24
- url: typeof b?.url === "string" ? b.url : "",
25
- row: typeof b?.row === "number" ? b.row : 0
26
- }));
24
+ return parsed.map(mapRawButton);
27
25
  } catch {
28
26
  return [];
29
27
  }
@@ -59,37 +57,38 @@ const useThemeColors = () => {
59
57
  }
60
58
  }), [isDark]);
61
59
  };
62
- const TelegramButtonPreview = ({ text, url }) => /* @__PURE__ */ jsxs(
63
- "a",
64
- {
65
- href: url || "#",
66
- target: "_blank",
67
- rel: "noopener noreferrer",
68
- onClick: (e) => !url && e.preventDefault(),
69
- style: {
70
- display: "inline-flex",
71
- alignItems: "center",
72
- justifyContent: "center",
73
- gap: "6px",
74
- padding: "8px 16px",
75
- backgroundColor: "#3390ec",
76
- color: "#ffffff",
77
- borderRadius: "8px",
78
- textDecoration: "none",
79
- fontSize: "14px",
80
- fontWeight: 500,
81
- cursor: url ? "pointer" : "default",
82
- transition: "background-color 0.15s ease",
83
- minWidth: "80px"
84
- },
85
- onMouseEnter: (e) => url && (e.currentTarget.style.backgroundColor = "#2b7ed8"),
86
- onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "#3390ec",
87
- children: [
88
- /* @__PURE__ */ jsx(Link, { width: 14, height: 14, style: { opacity: 0.9 } }),
89
- /* @__PURE__ */ jsx("span", { children: text || "(empty)" })
90
- ]
91
- }
92
- );
60
+ const TelegramButtonPreview = ({ text, btnType }) => {
61
+ const isScreen = btnType === "screen";
62
+ const bgColor = isScreen ? "#7c3aed" : "#3390ec";
63
+ const bgHover = isScreen ? "#6d28d9" : "#2b7ed8";
64
+ return /* @__PURE__ */ jsxs(
65
+ "span",
66
+ {
67
+ style: {
68
+ display: "inline-flex",
69
+ alignItems: "center",
70
+ justifyContent: "center",
71
+ gap: "6px",
72
+ padding: "8px 16px",
73
+ backgroundColor: bgColor,
74
+ color: "#ffffff",
75
+ borderRadius: "8px",
76
+ textDecoration: "none",
77
+ fontSize: "14px",
78
+ fontWeight: 500,
79
+ cursor: "default",
80
+ transition: "background-color 0.15s ease",
81
+ minWidth: "80px"
82
+ },
83
+ onMouseEnter: (e) => e.currentTarget.style.backgroundColor = bgHover,
84
+ onMouseLeave: (e) => e.currentTarget.style.backgroundColor = bgColor,
85
+ children: [
86
+ isScreen ? /* @__PURE__ */ jsx(Layout, { width: 14, height: 14, style: { opacity: 0.9 } }) : /* @__PURE__ */ jsx(Link, { width: 14, height: 14, style: { opacity: 0.9 } }),
87
+ /* @__PURE__ */ jsx("span", { children: text || "(empty)" })
88
+ ]
89
+ }
90
+ );
91
+ };
93
92
  const ButtonsBuilder = forwardRef(
94
93
  ({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
95
94
  const [buttons, setButtons] = useState(() => parseButtons(value));
@@ -104,7 +103,7 @@ const ButtonsBuilder = forwardRef(
104
103
  const addButton = () => {
105
104
  update([
106
105
  ...buttons,
107
- { id: generateId(), text: "Button", url: "https://cases.gg", row: 0 }
106
+ { id: generateId(), text: "Button", url: "https://cases.gg", row: 0, type: "url", screenSlug: "" }
108
107
  ]);
109
108
  };
110
109
  const updateButton = (id, patch) => {
@@ -162,7 +161,8 @@ const ButtonsBuilder = forwardRef(
162
161
  ]
163
162
  }
164
163
  ) : /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 2, children: buttons.map((btn, idx) => {
165
- const urlOk = btn.url.length === 0 ? true : isValidUrl(btn.url);
164
+ const isScreen = btn.type === "screen";
165
+ const urlOk = isScreen || (btn.url ?? "").length === 0 || isValidUrl(btn.url ?? "");
166
166
  return /* @__PURE__ */ jsx(
167
167
  Card,
168
168
  {
@@ -189,6 +189,19 @@ const ButtonsBuilder = forwardRef(
189
189
  children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "primary600", children: idx + 1 })
190
190
  }
191
191
  ),
192
+ /* @__PURE__ */ jsx(Box, { style: { width: 100, flexShrink: 0 }, children: /* @__PURE__ */ jsxs(
193
+ SingleSelect,
194
+ {
195
+ value: btn.type || "url",
196
+ onChange: (val) => updateButton(btn.id, { type: val }),
197
+ disabled,
198
+ size: "S",
199
+ children: [
200
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "url", children: "URL" }),
201
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "screen", children: "Screen" })
202
+ ]
203
+ }
204
+ ) }),
192
205
  /* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth: 120 }, children: /* @__PURE__ */ jsx(
193
206
  TextInput,
194
207
  {
@@ -199,11 +212,20 @@ const ButtonsBuilder = forwardRef(
199
212
  size: "S"
200
213
  }
201
214
  ) }),
202
- /* @__PURE__ */ jsx(Box, { style: { flex: 2, minWidth: 180 }, children: /* @__PURE__ */ jsx(
215
+ isScreen ? /* @__PURE__ */ jsx(Box, { style: { flex: 2, minWidth: 180 }, children: /* @__PURE__ */ jsx(
216
+ TextInput,
217
+ {
218
+ placeholder: "screen-slug",
219
+ value: btn.screenSlug ?? "",
220
+ onChange: (e) => updateButton(btn.id, { screenSlug: e.target.value }),
221
+ disabled,
222
+ size: "S"
223
+ }
224
+ ) }) : /* @__PURE__ */ jsx(Box, { style: { flex: 2, minWidth: 180 }, children: /* @__PURE__ */ jsx(
203
225
  TextInput,
204
226
  {
205
227
  placeholder: "https://...",
206
- value: btn.url,
228
+ value: btn.url ?? "",
207
229
  onChange: (e) => updateButton(btn.id, { url: e.target.value }),
208
230
  disabled,
209
231
  size: "S",
@@ -282,7 +304,7 @@ const ButtonsBuilder = forwardRef(
282
304
  children: "PREVIEW"
283
305
  }
284
306
  ),
285
- /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 2, alignItems: "center", children: previewRows.map((row) => /* @__PURE__ */ jsx(Flex, { gap: 2, wrap: "wrap", justifyContent: "center", children: row.items.map((b) => /* @__PURE__ */ jsx(TelegramButtonPreview, { text: b.text, url: b.url }, b.id)) }, row.row)) })
307
+ /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 2, alignItems: "center", children: previewRows.map((row) => /* @__PURE__ */ jsx(Flex, { gap: 2, wrap: "wrap", justifyContent: "center", children: row.items.map((b) => /* @__PURE__ */ jsx(TelegramButtonPreview, { text: b.text, btnType: b.type }, b.id)) }, row.row)) })
286
308
  ]
287
309
  }
288
310
  ),
@@ -116,7 +116,7 @@ const parseValue = (value) => {
116
116
  const serialize = (params) => {
117
117
  const out = {};
118
118
  for (const [key, val] of Object.entries(params)) {
119
- out[key] = typeof val === "number" ? val : null;
119
+ if (typeof val === "number") out[key] = val;
120
120
  }
121
121
  return JSON.stringify(out);
122
122
  };
@@ -6,26 +6,24 @@ const designSystem = require("@strapi/design-system");
6
6
  const icons = require("@strapi/icons");
7
7
  const styledComponents = require("styled-components");
8
8
  const utils = require("./utils-CAs_GSGv.js");
9
+ const mapRawButton = (b) => ({
10
+ id: typeof b?.id === "string" ? b.id : utils.generateId(),
11
+ text: typeof b?.text === "string" ? b.text : "",
12
+ url: typeof b?.url === "string" ? b.url : "",
13
+ row: typeof b?.row === "number" ? b.row : 0,
14
+ type: b?.type === "screen" ? "screen" : "url",
15
+ screenSlug: typeof b?.screenSlug === "string" ? b.screenSlug : ""
16
+ });
9
17
  const parseButtons = (value) => {
10
18
  if (!value) return [];
11
19
  if (Array.isArray(value)) {
12
- return value.map((b) => ({
13
- id: typeof b?.id === "string" ? b.id : utils.generateId(),
14
- text: typeof b?.text === "string" ? b.text : "",
15
- url: typeof b?.url === "string" ? b.url : "",
16
- row: typeof b?.row === "number" ? b.row : 0
17
- }));
20
+ return value.map(mapRawButton);
18
21
  }
19
22
  if (typeof value === "string") {
20
23
  try {
21
24
  const parsed = JSON.parse(value);
22
25
  if (!Array.isArray(parsed)) return [];
23
- return parsed.map((b) => ({
24
- id: typeof b?.id === "string" ? b.id : utils.generateId(),
25
- text: typeof b?.text === "string" ? b.text : "",
26
- url: typeof b?.url === "string" ? b.url : "",
27
- row: typeof b?.row === "number" ? b.row : 0
28
- }));
26
+ return parsed.map(mapRawButton);
29
27
  } catch {
30
28
  return [];
31
29
  }
@@ -61,37 +59,38 @@ const useThemeColors = () => {
61
59
  }
62
60
  }), [isDark]);
63
61
  };
64
- const TelegramButtonPreview = ({ text, url }) => /* @__PURE__ */ jsxRuntime.jsxs(
65
- "a",
66
- {
67
- href: url || "#",
68
- target: "_blank",
69
- rel: "noopener noreferrer",
70
- onClick: (e) => !url && e.preventDefault(),
71
- style: {
72
- display: "inline-flex",
73
- alignItems: "center",
74
- justifyContent: "center",
75
- gap: "6px",
76
- padding: "8px 16px",
77
- backgroundColor: "#3390ec",
78
- color: "#ffffff",
79
- borderRadius: "8px",
80
- textDecoration: "none",
81
- fontSize: "14px",
82
- fontWeight: 500,
83
- cursor: url ? "pointer" : "default",
84
- transition: "background-color 0.15s ease",
85
- minWidth: "80px"
86
- },
87
- onMouseEnter: (e) => url && (e.currentTarget.style.backgroundColor = "#2b7ed8"),
88
- onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "#3390ec",
89
- children: [
90
- /* @__PURE__ */ jsxRuntime.jsx(icons.Link, { width: 14, height: 14, style: { opacity: 0.9 } }),
91
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: text || "(empty)" })
92
- ]
93
- }
94
- );
62
+ const TelegramButtonPreview = ({ text, btnType }) => {
63
+ const isScreen = btnType === "screen";
64
+ const bgColor = isScreen ? "#7c3aed" : "#3390ec";
65
+ const bgHover = isScreen ? "#6d28d9" : "#2b7ed8";
66
+ return /* @__PURE__ */ jsxRuntime.jsxs(
67
+ "span",
68
+ {
69
+ style: {
70
+ display: "inline-flex",
71
+ alignItems: "center",
72
+ justifyContent: "center",
73
+ gap: "6px",
74
+ padding: "8px 16px",
75
+ backgroundColor: bgColor,
76
+ color: "#ffffff",
77
+ borderRadius: "8px",
78
+ textDecoration: "none",
79
+ fontSize: "14px",
80
+ fontWeight: 500,
81
+ cursor: "default",
82
+ transition: "background-color 0.15s ease",
83
+ minWidth: "80px"
84
+ },
85
+ onMouseEnter: (e) => e.currentTarget.style.backgroundColor = bgHover,
86
+ onMouseLeave: (e) => e.currentTarget.style.backgroundColor = bgColor,
87
+ children: [
88
+ isScreen ? /* @__PURE__ */ jsxRuntime.jsx(icons.Layout, { width: 14, height: 14, style: { opacity: 0.9 } }) : /* @__PURE__ */ jsxRuntime.jsx(icons.Link, { width: 14, height: 14, style: { opacity: 0.9 } }),
89
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: text || "(empty)" })
90
+ ]
91
+ }
92
+ );
93
+ };
95
94
  const ButtonsBuilder = React.forwardRef(
96
95
  ({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
97
96
  const [buttons, setButtons] = React.useState(() => parseButtons(value));
@@ -106,7 +105,7 @@ const ButtonsBuilder = React.forwardRef(
106
105
  const addButton = () => {
107
106
  update([
108
107
  ...buttons,
109
- { id: utils.generateId(), text: "Button", url: "https://cases.gg", row: 0 }
108
+ { id: utils.generateId(), text: "Button", url: "https://cases.gg", row: 0, type: "url", screenSlug: "" }
110
109
  ]);
111
110
  };
112
111
  const updateButton = (id, patch) => {
@@ -164,7 +163,8 @@ const ButtonsBuilder = React.forwardRef(
164
163
  ]
165
164
  }
166
165
  ) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 2, children: buttons.map((btn, idx) => {
167
- const urlOk = btn.url.length === 0 ? true : isValidUrl(btn.url);
166
+ const isScreen = btn.type === "screen";
167
+ const urlOk = isScreen || (btn.url ?? "").length === 0 || isValidUrl(btn.url ?? "");
168
168
  return /* @__PURE__ */ jsxRuntime.jsx(
169
169
  designSystem.Card,
170
170
  {
@@ -191,6 +191,19 @@ const ButtonsBuilder = React.forwardRef(
191
191
  children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "primary600", children: idx + 1 })
192
192
  }
193
193
  ),
194
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: 100, flexShrink: 0 }, children: /* @__PURE__ */ jsxRuntime.jsxs(
195
+ designSystem.SingleSelect,
196
+ {
197
+ value: btn.type || "url",
198
+ onChange: (val) => updateButton(btn.id, { type: val }),
199
+ disabled,
200
+ size: "S",
201
+ children: [
202
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "url", children: "URL" }),
203
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "screen", children: "Screen" })
204
+ ]
205
+ }
206
+ ) }),
194
207
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1, minWidth: 120 }, children: /* @__PURE__ */ jsxRuntime.jsx(
195
208
  designSystem.TextInput,
196
209
  {
@@ -201,11 +214,20 @@ const ButtonsBuilder = React.forwardRef(
201
214
  size: "S"
202
215
  }
203
216
  ) }),
204
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 2, minWidth: 180 }, children: /* @__PURE__ */ jsxRuntime.jsx(
217
+ isScreen ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 2, minWidth: 180 }, children: /* @__PURE__ */ jsxRuntime.jsx(
218
+ designSystem.TextInput,
219
+ {
220
+ placeholder: "screen-slug",
221
+ value: btn.screenSlug ?? "",
222
+ onChange: (e) => updateButton(btn.id, { screenSlug: e.target.value }),
223
+ disabled,
224
+ size: "S"
225
+ }
226
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 2, minWidth: 180 }, children: /* @__PURE__ */ jsxRuntime.jsx(
205
227
  designSystem.TextInput,
206
228
  {
207
229
  placeholder: "https://...",
208
- value: btn.url,
230
+ value: btn.url ?? "",
209
231
  onChange: (e) => updateButton(btn.id, { url: e.target.value }),
210
232
  disabled,
211
233
  size: "S",
@@ -284,7 +306,7 @@ const ButtonsBuilder = React.forwardRef(
284
306
  children: "PREVIEW"
285
307
  }
286
308
  ),
287
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 2, alignItems: "center", children: previewRows.map((row) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, wrap: "wrap", justifyContent: "center", children: row.items.map((b) => /* @__PURE__ */ jsxRuntime.jsx(TelegramButtonPreview, { text: b.text, url: b.url }, b.id)) }, row.row)) })
309
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 2, alignItems: "center", children: previewRows.map((row) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, wrap: "wrap", justifyContent: "center", children: row.items.map((b) => /* @__PURE__ */ jsxRuntime.jsx(TelegramButtonPreview, { text: b.text, btnType: b.type }, b.id)) }, row.row)) })
288
310
  ]
289
311
  }
290
312
  ),
@@ -107,7 +107,7 @@ const index = {
107
107
  components: {
108
108
  Input: async () => Promise.resolve().then(() => require(
109
109
  /* webpackChunkName: "crm-telegram-buttons" */
110
- "../_chunks/index-Cg0G_bTE.js"
110
+ "../_chunks/index-u-jR-zfs.js"
111
111
  ))
112
112
  },
113
113
  options: {
@@ -155,7 +155,7 @@ const index = {
155
155
  components: {
156
156
  Input: async () => Promise.resolve().then(() => require(
157
157
  /* webpackChunkName: "crm-trigger-params" */
158
- "../_chunks/index-Cmo9If32.js"
158
+ "../_chunks/index-CqRPcaXV.js"
159
159
  ))
160
160
  },
161
161
  options: {
@@ -106,7 +106,7 @@ const index = {
106
106
  components: {
107
107
  Input: async () => import(
108
108
  /* webpackChunkName: "crm-telegram-buttons" */
109
- "../_chunks/index-BKfFI_Jo.mjs"
109
+ "../_chunks/index-DRhcN7TG.mjs"
110
110
  )
111
111
  },
112
112
  options: {
@@ -154,7 +154,7 @@ const index = {
154
154
  components: {
155
155
  Input: async () => import(
156
156
  /* webpackChunkName: "crm-trigger-params" */
157
- "../_chunks/index-Bot_XlI2.mjs"
157
+ "../_chunks/index-DnyoVNLo.mjs"
158
158
  )
159
159
  },
160
160
  options: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inspirer-dev/crm-dashboard",
3
- "version": "1.0.84",
3
+ "version": "1.0.85",
4
4
  "description": "CRM Dashboard and Tools",
5
5
  "strapi": {
6
6
  "name": "crm-dashboard",