@pushwoosh/smart-components-kit 1.1.6 → 1.1.8

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.
@@ -1,9 +1,11 @@
1
1
  import { type FC, type PropsWithChildren } from 'react';
2
2
  import { type DynamicContent } from '@pushwoosh/dumb-components/RichMessageEditor/slate/types';
3
+ import type { SystemVariable } from './types';
3
4
  type SimpleDynamicContentPickerFormSmartProps = {
4
5
  dc?: DynamicContent;
5
6
  onChange: (dc: DynamicContent) => void;
6
7
  update?: () => void;
8
+ systemVariables?: SystemVariable[];
7
9
  };
8
10
  export declare const SimpleDynamicContentPickerFormSmart: FC<PropsWithChildren<SimpleDynamicContentPickerFormSmartProps>>;
9
11
  export {};
@@ -5,6 +5,7 @@ import { Horizontal, Vertical } from '@pushwoosh/kit-helpers';
5
5
  import { useDynamicContentTags } from './hooks';
6
6
  import { useLang } from './polyglot';
7
7
  import { SimpleTagPickerDiv } from './styled';
8
+ import { buildOptions } from './utils';
8
9
  const defaultDynamicContent = {
9
10
  tagName: '',
10
11
  modifier: 'regular',
@@ -14,6 +15,7 @@ export const SimpleDynamicContentPickerFormSmart = ({
14
15
  dc = defaultDynamicContent,
15
16
  onChange,
16
17
  update,
18
+ systemVariables,
17
19
  children
18
20
  }) => {
19
21
  const lang = useLang();
@@ -34,9 +36,10 @@ export const SimpleDynamicContentPickerFormSmart = ({
34
36
  })
35
37
  });
36
38
  }
37
- const tags = asyncResult.value || [];
38
- const currentTag = tags.find(tag => tag.name === dc.tagName) || {
39
+ const options = buildOptions(systemVariables ?? [], asyncResult.value || []);
40
+ const selectedTag = options.find(option => option.name === dc.tagName) || {
39
41
  name: '',
42
+ label: '',
40
43
  modifiers: ['regular']
41
44
  };
42
45
  return _jsxs(SimpleTagPickerDiv, {
@@ -51,18 +54,19 @@ export const SimpleDynamicContentPickerFormSmart = ({
51
54
  menuPlacement: "auto",
52
55
  value: {
53
56
  value: dc.tagName,
54
- label: dc.tagName
57
+ label: selectedTag.name ? selectedTag.label : dc.tagName
55
58
  },
56
59
  onChange: option => {
60
+ const picked = options.find(item => item.name === option.value);
57
61
  onChange({
58
62
  tagName: option.value,
59
- modifier: currentTag.modifiers[0],
63
+ modifier: (picked === null || picked === void 0 ? void 0 : picked.modifiers[0]) ?? 'regular',
60
64
  defaultValue: ''
61
65
  });
62
66
  },
63
- options: tags.map(tag => ({
64
- value: tag.name,
65
- label: tag.name
67
+ options: options.map(option => ({
68
+ value: option.name,
69
+ label: option.label
66
70
  }))
67
71
  }), _jsx(Select, {
68
72
  width: "auto",
@@ -77,11 +81,11 @@ export const SimpleDynamicContentPickerFormSmart = ({
77
81
  modifier: option.value
78
82
  });
79
83
  },
80
- options: currentTag.modifiers.map(modifier => ({
84
+ options: selectedTag.modifiers.map(modifier => ({
81
85
  value: modifier,
82
86
  label: modifier
83
87
  })),
84
- isDisabled: !currentTag.name
88
+ isDisabled: !selectedTag.name
85
89
  })]
86
90
  })
87
91
  }), _jsx(FieldBox, {
@@ -96,7 +100,7 @@ export const SimpleDynamicContentPickerFormSmart = ({
96
100
  defaultValue: e.target.value
97
101
  });
98
102
  },
99
- disabled: !currentTag.name
103
+ disabled: !selectedTag.name
100
104
  })
101
105
  }), children]
102
106
  });
@@ -1,3 +1,3 @@
1
1
  export { SimpleDynamicContentPickerFormSmart } from './SimpleDynamicContentPickerFormSmart';
2
- export type { VariedDynamicContent } from './types';
2
+ export type { VariedDynamicContent, SystemVariable, PickerOption } from './types';
3
3
  export * from './hooks';
@@ -2,6 +2,16 @@ import type { Tag } from '@pushwoosh/rpc-v2-http-api-data/tags';
2
2
  export type FullTagData = Tag & {
3
3
  modifiers: string[];
4
4
  };
5
+ export type SystemVariable = {
6
+ name: string;
7
+ label?: string;
8
+ modifiers?: string[];
9
+ };
10
+ export type PickerOption = {
11
+ name: string;
12
+ label: string;
13
+ modifiers: string[];
14
+ };
5
15
  export type TagDynamicContent = {
6
16
  kind: 'tag';
7
17
  dc: {
@@ -1,2 +1,3 @@
1
- import { type VariedDynamicContent } from './types';
1
+ import { type FullTagData, type PickerOption, type SystemVariable, type VariedDynamicContent } from './types';
2
+ export declare function buildOptions(systemVariables: SystemVariable[], tags: FullTagData[]): PickerOption[];
2
3
  export declare function createDefaultDynamicContent(kind: 'tag' | 'event' | 'customText'): VariedDynamicContent;
@@ -1,3 +1,17 @@
1
+ export function buildOptions(systemVariables, tags) {
2
+ const taken = new Set(systemVariables.map(v => v.name));
3
+ const system = systemVariables.map(v => ({
4
+ name: v.name,
5
+ label: v.label ?? v.name,
6
+ modifiers: v.modifiers ?? ['regular']
7
+ }));
8
+ const rest = tags.filter(tag => !taken.has(tag.name)).map(tag => ({
9
+ name: tag.name,
10
+ label: tag.name,
11
+ modifiers: tag.modifiers
12
+ }));
13
+ return [...system, ...rest];
14
+ }
1
15
  export function createDefaultDynamicContent(kind) {
2
16
  switch (kind) {
3
17
  case 'tag':
@@ -4,7 +4,7 @@ import { Horizontal, useAsync } from '@pushwoosh/kit-helpers';
4
4
  import { useSPAContext } from '@pushwoosh/spa-context';
5
5
  import { langCodes } from './constants';
6
6
  import { LanguagesSelectForm } from './LanguagesSelectForm';
7
- import { useGetLangName } from './utils';
7
+ import { canonicalizeLangCode, useGetLangName } from './utils';
8
8
  export const LanguagesSelectFormLoader = ({
9
9
  application,
10
10
  value,
@@ -22,8 +22,8 @@ export const LanguagesSelectFormLoader = ({
22
22
  application,
23
23
  name: 'Language'
24
24
  });
25
- const valuesLangCodes = values.map(v => v.value);
26
- const allLangCodes = Array.from(new Set([...valuesLangCodes, ...langCodes]).values());
25
+ const valuesLangCodes = values.map(v => canonicalizeLangCode(v.value));
26
+ const allLangCodes = Array.from(new Set([...valuesLangCodes, ...langCodes.map(canonicalizeLangCode)]).values());
27
27
  return allLangCodes.toSorted((a, b) => {
28
28
  return a.localeCompare(b, systemLanguage, {
29
29
  sensitivity: 'base'
@@ -33,7 +33,7 @@ export const LanguagesSelectFormLoader = ({
33
33
  return {
34
34
  code,
35
35
  name: getLangName(code),
36
- subscribers: ((_values$find = values.find(val => val.value === code)) === null || _values$find === void 0 ? void 0 : _values$find.count) || 0
36
+ subscribers: ((_values$find = values.find(val => canonicalizeLangCode(val.value) === code)) === null || _values$find === void 0 ? void 0 : _values$find.count) || 0
37
37
  };
38
38
  });
39
39
  }, [application, getLangName, systemLanguage]);
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Normalizes a language code to its canonical form (e.g. `zh-hant` -> `zh-Hant`).
3
+ * Canonicalization (rather than lowercasing) keeps codes in the same form that
4
+ * devices are tagged with on the backend, so subscriber counts match and
5
+ * targeting hits real devices. Falls back to the raw code on invalid input.
6
+ */
7
+ export declare function canonicalizeLangCode(code: string): string;
1
8
  export declare function fetchLastSelection(): string[];
2
9
  export declare function saveLastSelection(languages: string[]): void;
3
10
  export declare function useGetLangName(displayLang: string): (l: string) => string;
@@ -1,5 +1,19 @@
1
1
  import { useState } from 'react';
2
+ import { languages } from '@pushwoosh/kit-constants';
2
3
  import { LAST_SELECTION_KEY } from './constants';
4
+ /**
5
+ * Normalizes a language code to its canonical form (e.g. `zh-hant` -> `zh-Hant`).
6
+ * Canonicalization (rather than lowercasing) keeps codes in the same form that
7
+ * devices are tagged with on the backend, so subscriber counts match and
8
+ * targeting hits real devices. Falls back to the raw code on invalid input.
9
+ */
10
+ export function canonicalizeLangCode(code) {
11
+ try {
12
+ return Intl.getCanonicalLocales(code)[0] ?? code;
13
+ } catch {
14
+ return code;
15
+ }
16
+ }
3
17
  export function fetchLastSelection() {
4
18
  var _localStorage$getItem;
5
19
  return ((_localStorage$getItem = localStorage.getItem(LAST_SELECTION_KEY)) === null || _localStorage$getItem === void 0 ? void 0 : _localStorage$getItem.split(',')) || [];
@@ -18,11 +32,17 @@ export function useGetLangName(displayLang) {
18
32
  return 'Default language';
19
33
  }
20
34
  try {
21
- return idn.of(lang) || lang;
22
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
23
- } catch (_error) {
24
- return lang;
35
+ const name = idn.of(lang);
36
+ // Browser ICU is often trimmed and returns the code itself for rare
37
+ // languages (ve/vo/za, ...). Treat that as "no name" and fall through.
38
+ if (name && name !== lang) {
39
+ return name;
40
+ }
41
+ } catch {
42
+ // ignore — fall back to the static dictionary below
25
43
  }
44
+ // Static ISO-639 dictionary is complete, so rare codes still get a name.
45
+ return languages[lang.toLowerCase()] ?? lang;
26
46
  };
27
47
  });
28
48
  return getLangName;
@@ -1,8 +1,10 @@
1
1
  import { type FC } from 'react';
2
2
  import { type DynamicContent } from '@pushwoosh/dumb-components/RichMessageEditor/slate/types';
3
+ import { type SystemVariable } from '../DynamicContentPickerForm';
3
4
  type NewDynamicContentFormProps = {
4
5
  update?: () => void;
5
6
  onSubmit: (dc: DynamicContent) => void;
7
+ systemVariables?: SystemVariable[];
6
8
  };
7
9
  export declare const NewDynamicContentForm: FC<NewDynamicContentFormProps>;
8
10
  export {};
@@ -2,11 +2,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
3
  import { Button } from '@pushwoosh/dumb-components';
4
4
  import { Horizontal } from '@pushwoosh/kit-helpers';
5
- import { SimpleDynamicContentPickerFormSmart } from '../DynamicContentPickerForm';
6
5
  import { useLang } from './polyglot';
6
+ import { SimpleDynamicContentPickerFormSmart } from '../DynamicContentPickerForm';
7
7
  export const NewDynamicContentForm = ({
8
8
  update,
9
- onSubmit
9
+ onSubmit,
10
+ systemVariables
10
11
  }) => {
11
12
  const [dc, setDc] = useState();
12
13
  const lang = useLang();
@@ -14,6 +15,7 @@ export const NewDynamicContentForm = ({
14
15
  dc: dc,
15
16
  onChange: setDc,
16
17
  update: update,
18
+ systemVariables: systemVariables,
17
19
  children: _jsx(Horizontal, {
18
20
  "$justifyContent": "end",
19
21
  children: _jsx(Button, {
@@ -1,5 +1,8 @@
1
1
  import { type FC } from 'react';
2
2
  import { type RichMessageEditorProps } from '@pushwoosh/dumb-components/RichMessageEditor/RichMessageEditor.types';
3
- type RichMessageEditorSmartProps = Omit<RichMessageEditorProps, 'renderDynamicContent'>;
3
+ import { type SystemVariable } from '../DynamicContentPickerForm';
4
+ type RichMessageEditorSmartProps = Omit<RichMessageEditorProps, 'renderDynamicContent'> & {
5
+ systemVariables?: SystemVariable[];
6
+ };
4
7
  export declare const RichMessageEditorSmart: FC<RichMessageEditorSmartProps>;
5
8
  export {};
@@ -1,8 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { RichMessageEditor } from '@pushwoosh/dumb-components';
3
- import { SimpleDynamicContentPickerFormSmart } from '../DynamicContentPickerForm';
4
3
  import { NewDynamicContentForm } from './NewDynamicContentForm';
5
- export const RichMessageEditorSmart = props => {
4
+ import { SimpleDynamicContentPickerFormSmart } from '../DynamicContentPickerForm';
5
+ export const RichMessageEditorSmart = ({
6
+ systemVariables,
7
+ ...props
8
+ }) => {
6
9
  return _jsx(RichMessageEditor, {
7
10
  ...props,
8
11
  renderDynamicContent: ({
@@ -12,10 +15,12 @@ export const RichMessageEditorSmart = props => {
12
15
  }) => dc ? _jsx(SimpleDynamicContentPickerFormSmart, {
13
16
  dc: dc,
14
17
  onChange: onChange,
15
- update: update
18
+ update: update,
19
+ systemVariables: systemVariables
16
20
  }) : _jsx(NewDynamicContentForm, {
17
21
  update: update,
18
- onSubmit: onChange
22
+ onSubmit: onChange,
23
+ systemVariables: systemVariables
19
24
  })
20
25
  });
21
26
  };
package/package.json CHANGED
@@ -48,5 +48,5 @@
48
48
  "react": "^16.14.0 || ^18.0.0",
49
49
  "react-dom": "^16.14.0 || ^18.0.0"
50
50
  },
51
- "version": "1.1.6"
51
+ "version": "1.1.8"
52
52
  }