@peassoft/mnr-web-topline 4.0.1 → 4.1.0

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,8 +1,4 @@
1
- import type { NonEmptyArray } from '../../types/helpers.js';
2
- type UiLangDescriptor = {
3
- code: string;
4
- name: string;
5
- };
6
- export declare function getSupportedUiLangs(): NonEmptyArray<UiLangDescriptor>;
7
- export declare function getDefaultUiLangForUser(): UiLangDescriptor;
8
- export {};
1
+ import { type SupportedLanguage } from '@peassoft/mnr-langs';
2
+ import type { ToplineUser } from '../../types/data.js';
3
+ export declare function getPageLang(): SupportedLanguage;
4
+ export declare function getInitialUiLang(user: ToplineUser): string;
@@ -1,20 +1,8 @@
1
- const supportedUiLangs = [{
2
- code: 'en',
3
- name: 'English'
4
- }, {
5
- code: 'ru',
6
- name: 'Русский'
7
- }];
8
- export function getSupportedUiLangs() {
9
- return window.structuredClone(supportedUiLangs);
1
+ import { defaultLanguage, validateLanguage } from '@peassoft/mnr-langs';
2
+ export function getPageLang() {
3
+ const currPageLang = document.querySelector('html')?.lang;
4
+ return validateLanguage(currPageLang) || defaultLanguage;
10
5
  }
11
- export function getDefaultUiLangForUser() {
12
- for (const lang of window.navigator.languages) {
13
- const normalizedLangCode = lang.slice(0, 2).toLowerCase();
14
- const matchedDescriptor = supportedUiLangs.find(x => x.code === normalizedLangCode);
15
- if (matchedDescriptor) {
16
- return window.structuredClone(matchedDescriptor);
17
- }
18
- }
19
- return supportedUiLangs[0];
6
+ export function getInitialUiLang(user) {
7
+ return user.uiLang ?? getPageLang();
20
8
  }
@@ -1,5 +1,5 @@
1
1
  import getInitialUserName from './get-initial-user-name.js';
2
- import getInitialUiLang from './get-initial-ui-lang.js';
2
+ import { getInitialUiLang } from '../../../../modules/ui-lang/index.js';
3
3
  export default function hasChanges(user, currData) {
4
4
  if (getInitialUserName(user) !== currData.userName) {
5
5
  return true;
@@ -1,17 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useState, useMemo, useCallback } from 'react';
3
+ import { supportedLanguagesDescriptors } from '@peassoft/mnr-langs';
3
4
  import { InputField } from '@peassoft/mnr-web-ui-kit/input-field/index.js';
4
5
  import { Select } from '@peassoft/mnr-web-ui-kit/select/index.js';
5
6
  import { TextButton } from '@peassoft/mnr-web-ui-kit/text-button/index.js';
6
7
  import { Button } from '@peassoft/mnr-web-ui-kit/button/index.js';
7
8
  import { ErrorMessage } from '@peassoft/mnr-web-ui-kit/error-message/index.js';
8
9
  import { createUserDataChangeBeacon } from '../../../../modules/user-data-change-beacon/index.js';
9
- import { getSupportedUiLangs } from '../../../../modules/ui-lang/index.js';
10
10
  import { updateUser } from '../../../../modules/local-db/index.js';
11
11
  import { innerToplineService, ToplineEventName } from '../../../../modules/topline-service/index.js';
12
12
  import saveUserData from '../../actions/save-user-data/index.js';
13
+ import { getInitialUiLang } from '../../../../modules/ui-lang/index.js';
13
14
  import getInitialUserName from './get-initial-user-name.js';
14
- import getInitialUiLang from './get-initial-ui-lang.js';
15
15
  import hasChanges from './has-changes.js';
16
16
  export default function Root(props) {
17
17
  const {
@@ -23,7 +23,7 @@ export default function Root(props) {
23
23
  const [uiLang, setUiLang] = useState(getInitialUiLang(user));
24
24
  const [isInProgress, setIsInProgress] = useState(false);
25
25
  const [hasSavingError, setHasSavingError] = useState(false);
26
- const uiLangOptions = useMemo(() => getSupportedUiLangs().map(langDescriptor => ({
26
+ const uiLangOptions = useMemo(() => supportedLanguagesDescriptors().map(langDescriptor => ({
27
27
  id: langDescriptor.code,
28
28
  value: langDescriptor.name
29
29
  })), []);
@@ -1,9 +1,10 @@
1
+ import type { SupportedLanguage } from '@peassoft/mnr-langs';
1
2
  import type { ToplineUser } from '../../../../types/data.js';
2
3
  export type UserData = {
3
4
  email: string;
4
5
  password: string;
5
6
  userName?: string;
6
- uiLang?: string;
7
+ uiLang: SupportedLanguage;
7
8
  };
8
9
  export type ReturnValue = {
9
10
  user: ToplineUser | null;
@@ -1,14 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useContext, useState, useCallback, useEffect, createRef } from 'react';
2
+ import { useContext, useState, useCallback, useMemo, useEffect, createRef } from 'react';
3
+ import { supportedLanguagesDescriptors } from '@peassoft/mnr-langs';
3
4
  import Modal from '../../../../shared/components/modal/index.js';
4
5
  import Alternative from '../../../../shared/components/alternative/index.js';
5
6
  import { InputField } from '@peassoft/mnr-web-ui-kit/input-field/index.js';
6
7
  import { Button } from '@peassoft/mnr-web-ui-kit/button/index.js';
7
8
  import { ErrorMessage } from '@peassoft/mnr-web-ui-kit/error-message/index.js';
9
+ import { Select } from '@peassoft/mnr-web-ui-kit/select/index.js';
8
10
  import { ToplineContext } from '../../../shell/index.js';
9
11
  import { globalRefs } from '../../../../modules/focus-marshal/index.js';
10
12
  import validateEmail from '../../../../modules/validators/email.js';
11
13
  import validatePassword from '../../../../modules/validators/password.js';
14
+ import { getPageLang } from '../../../../modules/ui-lang/index.js';
12
15
  import performSignup from '../../actions/perform-signup/index.js';
13
16
  export default function Signup(props) {
14
17
  const {
@@ -20,6 +23,7 @@ export default function Signup(props) {
20
23
  const [email, setEmail] = useState('');
21
24
  const [isEmailValid, setIsEmailValid] = useState(true);
22
25
  const [userName, setUserName] = useState('');
26
+ const [uiLang, setUiLang] = useState(getPageLang());
23
27
  const [password, setPassword] = useState('');
24
28
  const [isPasswordValid, setIsPasswordValid] = useState(true);
25
29
  const [passwordConfirmation, setPasswordConfirmation] = useState('');
@@ -29,8 +33,13 @@ export default function Signup(props) {
29
33
  const {
30
34
  handleUserChange
31
35
  } = useContext(ToplineContext);
36
+ const uiLangOptions = useMemo(() => supportedLanguagesDescriptors().map(langDescriptor => ({
37
+ id: langDescriptor.code,
38
+ value: langDescriptor.name
39
+ })), []);
32
40
  const handleEmailChange = useCallback(newValue => setEmail(newValue.trim()), []);
33
41
  const handleUserNameChange = useCallback(newValue => setUserName(newValue), []);
42
+ const handleUiLangChange = useCallback(val => setUiLang(val), []);
34
43
  const handlePasswordChange = useCallback(newValue => setPassword(newValue.trim()), []);
35
44
  const handlePasswordConfirmationChange = useCallback(newValue => setPasswordConfirmation(newValue.trim()), []);
36
45
  const handleEmailBlur = useCallback(() => setIsEmailValid(validateEmail(email)), [email]);
@@ -58,7 +67,7 @@ export default function Signup(props) {
58
67
  ...(userName ? {
59
68
  userName: userName.trim()
60
69
  } : {}),
61
- uiLang: document.documentElement.lang
70
+ uiLang
62
71
  };
63
72
  const {
64
73
  user,
@@ -80,7 +89,7 @@ export default function Signup(props) {
80
89
  default:
81
90
  throw new Error('Unknown error of a login request');
82
91
  }
83
- }, [email, password, passwordConfirmation, userName, onClose, handleUserChange]);
92
+ }, [email, uiLang, password, passwordConfirmation, userName, onClose, handleUserChange]);
84
93
  const handleTabOnLastElement = useCallback(() => globalRefs.modalFirstItem.current?.focus(), []);
85
94
  const handleShiftTabOnFirstElement = useCallback(() => lastElementRef.current?.focus(), [lastElementRef]);
86
95
  useEffect(() => globalRefs.modalFirstItem.current?.focus(), []);
@@ -107,6 +116,11 @@ export default function Signup(props) {
107
116
  label: "Your name",
108
117
  value: userName,
109
118
  onChange: handleUserNameChange
119
+ }), _jsx(Select, {
120
+ label: "Preferred language for user interface",
121
+ items: uiLangOptions,
122
+ selectedItemId: uiLang,
123
+ onChange: handleUiLangChange
110
124
  }), _jsx(InputField, {
111
125
  type: 'password',
112
126
  autocompleteAttribute: 'new-password',
@@ -1,8 +1,4 @@
1
- import type { NonEmptyArray } from '../../types/helpers.js';
2
- type UiLangDescriptor = {
3
- code: string;
4
- name: string;
5
- };
6
- export declare function getSupportedUiLangs(): NonEmptyArray<UiLangDescriptor>;
7
- export declare function getDefaultUiLangForUser(): UiLangDescriptor;
8
- export {};
1
+ import { type SupportedLanguage } from '@peassoft/mnr-langs';
2
+ import type { ToplineUser } from '../../types/data.js';
3
+ export declare function getPageLang(): SupportedLanguage;
4
+ export declare function getInitialUiLang(user: ToplineUser): string;
@@ -1,20 +1,8 @@
1
- const supportedUiLangs = [{
2
- code: 'en',
3
- name: 'English'
4
- }, {
5
- code: 'ru',
6
- name: 'Русский'
7
- }];
8
- export function getSupportedUiLangs() {
9
- return window.structuredClone(supportedUiLangs);
1
+ import { defaultLanguage, validateLanguage } from '@peassoft/mnr-langs';
2
+ export function getPageLang() {
3
+ const currPageLang = document.querySelector('html')?.lang;
4
+ return validateLanguage(currPageLang) || defaultLanguage;
10
5
  }
11
- export function getDefaultUiLangForUser() {
12
- for (const lang of window.navigator.languages) {
13
- const normalizedLangCode = lang.slice(0, 2).toLowerCase();
14
- const matchedDescriptor = supportedUiLangs.find(x => x.code === normalizedLangCode);
15
- if (matchedDescriptor) {
16
- return window.structuredClone(matchedDescriptor);
17
- }
18
- }
19
- return supportedUiLangs[0];
6
+ export function getInitialUiLang(user) {
7
+ return user.uiLang ?? getPageLang();
20
8
  }
@@ -1,5 +1,5 @@
1
1
  import getInitialUserName from './get-initial-user-name.js';
2
- import getInitialUiLang from './get-initial-ui-lang.js';
2
+ import { getInitialUiLang } from '../../../../modules/ui-lang/index.js';
3
3
  export default function hasChanges(user, currData) {
4
4
  if (getInitialUserName(user) !== currData.userName) {
5
5
  return true;
@@ -1,17 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useState, useMemo, useCallback } from 'react';
3
+ import { supportedLanguagesDescriptors } from '@peassoft/mnr-langs';
3
4
  import { InputField } from '@peassoft/mnr-web-ui-kit/input-field/index.js';
4
5
  import { Select } from '@peassoft/mnr-web-ui-kit/select/index.js';
5
6
  import { TextButton } from '@peassoft/mnr-web-ui-kit/text-button/index.js';
6
7
  import { Button } from '@peassoft/mnr-web-ui-kit/button/index.js';
7
8
  import { ErrorMessage } from '@peassoft/mnr-web-ui-kit/error-message/index.js';
8
9
  import { createUserDataChangeBeacon } from '../../../../modules/user-data-change-beacon/index.js';
9
- import { getSupportedUiLangs } from '../../../../modules/ui-lang/index.js';
10
10
  import { updateUser } from '../../../../modules/local-db/index.js';
11
11
  import { innerToplineService, ToplineEventName } from '../../../../modules/topline-service/index.js';
12
12
  import saveUserData from '../../actions/save-user-data/index.js';
13
+ import { getInitialUiLang } from '../../../../modules/ui-lang/index.js';
13
14
  import getInitialUserName from './get-initial-user-name.js';
14
- import getInitialUiLang from './get-initial-ui-lang.js';
15
15
  import hasChanges from './has-changes.js';
16
16
  export default function Root(props) {
17
17
  const {
@@ -23,7 +23,7 @@ export default function Root(props) {
23
23
  const [uiLang, setUiLang] = useState(getInitialUiLang(user));
24
24
  const [isInProgress, setIsInProgress] = useState(false);
25
25
  const [hasSavingError, setHasSavingError] = useState(false);
26
- const uiLangOptions = useMemo(() => getSupportedUiLangs().map(langDescriptor => ({
26
+ const uiLangOptions = useMemo(() => supportedLanguagesDescriptors().map(langDescriptor => ({
27
27
  id: langDescriptor.code,
28
28
  value: langDescriptor.name
29
29
  })), []);
@@ -1,9 +1,10 @@
1
+ import type { SupportedLanguage } from '@peassoft/mnr-langs';
1
2
  import type { ToplineUser } from '../../../../types/data.js';
2
3
  export type UserData = {
3
4
  email: string;
4
5
  password: string;
5
6
  userName?: string;
6
- uiLang?: string;
7
+ uiLang: SupportedLanguage;
7
8
  };
8
9
  export type ReturnValue = {
9
10
  user: ToplineUser | null;
@@ -1,14 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useContext, useState, useCallback, useEffect, createRef } from 'react';
2
+ import { useContext, useState, useCallback, useMemo, useEffect, createRef } from 'react';
3
+ import { supportedLanguagesDescriptors } from '@peassoft/mnr-langs';
3
4
  import Modal from '../../../../shared/components/modal/index.js';
4
5
  import Alternative from '../../../../shared/components/alternative/index.js';
5
6
  import { InputField } from '@peassoft/mnr-web-ui-kit/input-field/index.js';
6
7
  import { Button } from '@peassoft/mnr-web-ui-kit/button/index.js';
7
8
  import { ErrorMessage } from '@peassoft/mnr-web-ui-kit/error-message/index.js';
9
+ import { Select } from '@peassoft/mnr-web-ui-kit/select/index.js';
8
10
  import { ToplineContext } from '../../../shell/index.js';
9
11
  import { globalRefs } from '../../../../modules/focus-marshal/index.js';
10
12
  import validateEmail from '../../../../modules/validators/email.js';
11
13
  import validatePassword from '../../../../modules/validators/password.js';
14
+ import { getPageLang } from '../../../../modules/ui-lang/index.js';
12
15
  import performSignup from '../../actions/perform-signup/index.js';
13
16
  export default function Signup(props) {
14
17
  const {
@@ -20,6 +23,7 @@ export default function Signup(props) {
20
23
  const [email, setEmail] = useState('');
21
24
  const [isEmailValid, setIsEmailValid] = useState(true);
22
25
  const [userName, setUserName] = useState('');
26
+ const [uiLang, setUiLang] = useState(getPageLang());
23
27
  const [password, setPassword] = useState('');
24
28
  const [isPasswordValid, setIsPasswordValid] = useState(true);
25
29
  const [passwordConfirmation, setPasswordConfirmation] = useState('');
@@ -29,8 +33,13 @@ export default function Signup(props) {
29
33
  const {
30
34
  handleUserChange
31
35
  } = useContext(ToplineContext);
36
+ const uiLangOptions = useMemo(() => supportedLanguagesDescriptors().map(langDescriptor => ({
37
+ id: langDescriptor.code,
38
+ value: langDescriptor.name
39
+ })), []);
32
40
  const handleEmailChange = useCallback(newValue => setEmail(newValue.trim()), []);
33
41
  const handleUserNameChange = useCallback(newValue => setUserName(newValue), []);
42
+ const handleUiLangChange = useCallback(val => setUiLang(val), []);
34
43
  const handlePasswordChange = useCallback(newValue => setPassword(newValue.trim()), []);
35
44
  const handlePasswordConfirmationChange = useCallback(newValue => setPasswordConfirmation(newValue.trim()), []);
36
45
  const handleEmailBlur = useCallback(() => setIsEmailValid(validateEmail(email)), [email]);
@@ -58,7 +67,7 @@ export default function Signup(props) {
58
67
  ...(userName ? {
59
68
  userName: userName.trim()
60
69
  } : {}),
61
- uiLang: document.documentElement.lang
70
+ uiLang
62
71
  };
63
72
  const {
64
73
  user,
@@ -80,7 +89,7 @@ export default function Signup(props) {
80
89
  default:
81
90
  throw new Error('Unknown error of a login request');
82
91
  }
83
- }, [email, password, passwordConfirmation, userName, onClose, handleUserChange]);
92
+ }, [email, uiLang, password, passwordConfirmation, userName, onClose, handleUserChange]);
84
93
  const handleTabOnLastElement = useCallback(() => globalRefs.modalFirstItem.current?.focus(), []);
85
94
  const handleShiftTabOnFirstElement = useCallback(() => lastElementRef.current?.focus(), [lastElementRef]);
86
95
  useEffect(() => globalRefs.modalFirstItem.current?.focus(), []);
@@ -107,6 +116,11 @@ export default function Signup(props) {
107
116
  label: "Ваше имя",
108
117
  value: userName,
109
118
  onChange: handleUserNameChange
119
+ }), _jsx(Select, {
120
+ label: "Предпочитаемый язык для пользовательского интерфейса",
121
+ items: uiLangOptions,
122
+ selectedItemId: uiLang,
123
+ onChange: handleUiLangChange
110
124
  }), _jsx(InputField, {
111
125
  type: 'password',
112
126
  autocompleteAttribute: 'new-password',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peassoft/mnr-web-topline",
3
- "version": "4.0.1",
3
+ "version": "4.1.0",
4
4
  "description": "Peassoft Topline widget for mem'n'rev web applications",
5
5
  "type": "module",
6
6
  "exports": {
@@ -42,7 +42,7 @@
42
42
  "@vitejs/plugin-react": "^5.1.4",
43
43
  "autoprefixer": "^10.3.4",
44
44
  "clean-webpack-plugin": "^4.0.0",
45
- "copy-webpack-plugin": "^13.0.0",
45
+ "copy-webpack-plugin": "^14.0.0",
46
46
  "cpy-cli": "^7.0.0",
47
47
  "css-loader": "^7.1.2",
48
48
  "eslint": "^9.8.0",
@@ -67,6 +67,7 @@
67
67
  },
68
68
  "dependencies": {
69
69
  "@memnrev/web-error": "^0.4.1",
70
+ "@peassoft/mnr-langs": "^1.2.0",
70
71
  "email-validator": "^2.0.4",
71
72
  "md5": "^2.3.0",
72
73
  "react-error-boundary": "^6.0.0",
@@ -1,2 +0,0 @@
1
- import type { ToplineUser } from '../../../../types/data.js';
2
- export default function getInitialUiLang(user: ToplineUser): string;
@@ -1,4 +0,0 @@
1
- import { getDefaultUiLangForUser } from '../../../../modules/ui-lang/index.js';
2
- export default function getInitialUiLang(user) {
3
- return user.uiLang ?? getDefaultUiLangForUser().code;
4
- }
@@ -1,2 +0,0 @@
1
- import type { ToplineUser } from '../../../../types/data.js';
2
- export default function getInitialUiLang(user: ToplineUser): string;
@@ -1,4 +0,0 @@
1
- import { getDefaultUiLangForUser } from '../../../../modules/ui-lang/index.js';
2
- export default function getInitialUiLang(user) {
3
- return user.uiLang ?? getDefaultUiLangForUser().code;
4
- }