@inspirer-dev/crm-dashboard 1.0.84 → 1.0.86

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,62 @@ 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, {
267
+ type: val as 'url' | 'screen',
268
+ ...(val === 'url' ? { screenSlug: '' } : { url: '' }),
269
+ })
260
270
  }
261
271
  disabled={disabled}
262
272
  size="S"
263
- />
273
+ >
274
+ <SingleSelectOption value="url">URL</SingleSelectOption>
275
+ <SingleSelectOption value="screen">Screen</SingleSelectOption>
276
+ </SingleSelect>
264
277
  </Box>
265
278
 
266
- <Box style={{ flex: 2, minWidth: 180 }}>
279
+ <Box style={{ flex: 1, minWidth: 120 }}>
267
280
  <TextInput
268
- placeholder="https://..."
269
- value={btn.url}
281
+ placeholder="Button text"
282
+ value={btn.text}
270
283
  onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
271
- updateButton(btn.id, { url: e.target.value })
284
+ updateButton(btn.id, { text: e.target.value })
272
285
  }
273
286
  disabled={disabled}
274
287
  size="S"
275
- hasError={!urlOk}
276
288
  />
277
289
  </Box>
278
290
 
291
+ {isScreen ? (
292
+ <Box style={{ flex: 2, minWidth: 180 }}>
293
+ <TextInput
294
+ placeholder="screen-slug"
295
+ value={btn.screenSlug ?? ''}
296
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
297
+ updateButton(btn.id, { screenSlug: e.target.value })
298
+ }
299
+ disabled={disabled}
300
+ size="S"
301
+ />
302
+ </Box>
303
+ ) : (
304
+ <Box style={{ flex: 2, minWidth: 180 }}>
305
+ <TextInput
306
+ placeholder="https://..."
307
+ value={btn.url ?? ''}
308
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
309
+ updateButton(btn.id, { url: e.target.value })
310
+ }
311
+ disabled={disabled}
312
+ size="S"
313
+ hasError={!urlOk}
314
+ />
315
+ </Box>
316
+ )}
317
+
279
318
  <Box style={{ width: 60 }}>
280
319
  <TextInput
281
320
  type="number"
@@ -359,7 +398,7 @@ const ButtonsBuilder = forwardRef<HTMLDivElement, ButtonsBuilderProps>(
359
398
  {previewRows.map((row) => (
360
399
  <Flex key={row.row} gap={2} wrap="wrap" justifyContent="center">
361
400
  {row.items.map((b) => (
362
- <TelegramButtonPreview key={b.id} text={b.text} url={b.url} />
401
+ <TelegramButtonPreview key={b.id} text={b.text} btnType={b.type} />
363
402
  ))}
364
403
  </Flex>
365
404
  ))}