@seamly/web-ui 18.3.0-beta.1 → 19.0.0-beta.2
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.
- package/build/dist/lib/index.debug.js +348 -73
- package/build/dist/lib/index.debug.min.js +1 -1
- package/build/dist/lib/index.debug.min.js.LICENSE.txt +108 -8
- package/build/dist/lib/index.js +5247 -5187
- package/build/dist/lib/index.min.js +1 -1
- package/build/dist/lib/index.min.js.LICENSE.txt +1 -1
- package/build/dist/lib/standalone.js +2334 -2225
- package/build/dist/lib/standalone.min.js +1 -1
- package/build/dist/lib/standalone.min.js.LICENSE.txt +1 -1
- package/build/dist/lib/style-guide.js +1480 -796
- package/build/dist/lib/style-guide.min.js +1 -1
- package/build/dist/lib/styles.css +1 -1
- package/package.json +27 -28
- package/src/javascripts/api/index.js +25 -40
- package/src/javascripts/api/producer.js +3 -6
- package/src/javascripts/config.js +3 -3
- package/src/javascripts/domains/app/actions.js +24 -6
- package/src/javascripts/domains/app/hooks.js +6 -0
- package/src/javascripts/domains/app/index.js +3 -0
- package/src/javascripts/domains/app/reducer.js +16 -0
- package/src/javascripts/domains/app/selectors.js +8 -0
- package/src/javascripts/domains/app/utils.js +4 -0
- package/src/javascripts/domains/config/actions.js +1 -3
- package/src/javascripts/domains/config/middleware.js +0 -4
- package/src/javascripts/domains/config/reducer.js +2 -13
- package/src/javascripts/domains/config/selectors.js +3 -3
- package/src/javascripts/domains/config/utils.js +4 -0
- package/src/javascripts/domains/forms/actions.js +1 -3
- package/src/javascripts/domains/forms/reducer.js +1 -2
- package/src/javascripts/domains/forms/selectors.js +2 -2
- package/src/javascripts/domains/forms/utils.js +5 -0
- package/src/javascripts/domains/i18n/actions.js +35 -0
- package/src/javascripts/domains/i18n/hooks.js +38 -0
- package/src/javascripts/domains/i18n/index.js +5 -84
- package/src/javascripts/domains/i18n/reducer.js +58 -0
- package/src/javascripts/domains/i18n/selectors.js +15 -0
- package/src/javascripts/domains/i18n/utils.js +9 -0
- package/src/javascripts/domains/interrupt/actions.js +1 -3
- package/src/javascripts/domains/interrupt/reducer.js +1 -2
- package/src/javascripts/domains/interrupt/selectors.js +3 -2
- package/src/javascripts/domains/interrupt/utils.js +4 -0
- package/src/javascripts/domains/redux/hooks.js +1 -0
- package/src/javascripts/domains/store/index.js +7 -1
- package/src/javascripts/domains/translations/actions.js +1 -3
- package/src/javascripts/domains/translations/components/chat-status.js +1 -1
- package/src/javascripts/domains/translations/components/options-dialog/form.js +11 -6
- package/src/javascripts/domains/translations/index.js +1 -0
- package/src/javascripts/domains/translations/middleware.js +43 -0
- package/src/javascripts/domains/translations/reducer.js +2 -9
- package/src/javascripts/domains/translations/selectors.js +2 -2
- package/src/javascripts/domains/translations/utils.js +4 -0
- package/src/javascripts/index.js +3 -0
- package/src/javascripts/lib/engine/index.js +1 -0
- package/src/javascripts/lib/mutex.js +30 -0
- package/src/javascripts/lib/redux-helpers/index.js +11 -8
- package/src/javascripts/style-guide/components/app.js +7 -2
- package/src/javascripts/style-guide/components/static-core.js +9 -3
- package/src/javascripts/style-guide/states.js +8 -8
- package/src/javascripts/style-guide/style-guide-engine.js +14 -11
- package/src/javascripts/ui/components/conversation/event/divider/variants/new-translation.js +1 -1
- package/src/javascripts/ui/components/conversation/event/upload.js +2 -2
- package/src/javascripts/ui/components/core/seamly-activity-monitor.js +2 -0
- package/src/javascripts/ui/components/core/seamly-event-subscriber.js +2 -0
- package/src/javascripts/ui/components/core/seamly-instance-functions-loader.js +1 -7
- package/src/javascripts/ui/components/core/seamly-new-notifications.js +5 -6
- package/src/javascripts/ui/components/core/seamly-read-state.js +6 -4
- package/src/javascripts/ui/components/entry/text-entry/hooks.js +6 -4
- package/src/javascripts/ui/components/entry/text-entry/text-entry-form.js +10 -3
- package/src/javascripts/ui/components/entry/upload/file-upload-form.js +6 -3
- package/src/javascripts/ui/components/entry/upload/index.js +8 -3
- package/src/javascripts/ui/components/faq/faq.js +2 -2
- package/src/javascripts/ui/components/layout/app-frame.js +11 -8
- package/src/javascripts/ui/components/layout/interrupt.js +6 -2
- package/src/javascripts/ui/components/warnings/resume-conversation-prompt.js +1 -1
- package/src/javascripts/ui/components/widgets/upload-progress.js +1 -1
- package/src/javascripts/ui/hooks/seamly-api-hooks.js +0 -6
- package/src/javascripts/ui/hooks/seamly-entry-hooks.js +17 -21
- package/src/javascripts/ui/hooks/seamly-hooks.js +0 -1
- package/src/javascripts/ui/hooks/use-seamly-commands.js +5 -6
- package/src/javascripts/ui/hooks/use-seamly-visibility.js +3 -5
- package/src/javascripts/ui/hooks/use-single-file-upload.js +4 -1
- package/src/javascripts/ui/utils/general-utils.js +6 -13
- package/src/stylesheets/1-settings/_config.scss +2 -1
- package/src/stylesheets/3-app/_app.scss +3 -4
- package/src/stylesheets/5-components/_faq.scss +3 -8
- package/src/stylesheets/5-components/_modal.scss +3 -3
- package/webpack/config.package.js +0 -18
- package/webpack/config.site.js +6 -0
- package/webpack/defaults.js +0 -3
- package/CHANGELOG.md +0 -572
- package/build/dist/translations/de-informal.js +0 -274
- package/build/dist/translations/de-informal.min.js +0 -1
- package/build/dist/translations/en.js +0 -274
- package/build/dist/translations/en.min.js +0 -1
- package/build/dist/translations/es-informal.js +0 -280
- package/build/dist/translations/es-informal.min.js +0 -1
- package/build/dist/translations/nl-formal.js +0 -274
- package/build/dist/translations/nl-formal.min.js +0 -1
- package/build/dist/translations/nl-informal.js +0 -274
- package/build/dist/translations/nl-informal.min.js +0 -1
- package/src/javascripts/lib/i18n.js +0 -46
- package/translations/de-informal.js +0 -235
- package/translations/en.js +0 -232
- package/translations/es-informal.js +0 -241
- package/translations/nl-formal.js +0 -228
- package/translations/nl-informal.js +0 -228
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defaultConfig } from '../../config'
|
|
2
|
-
import { createReducer } from '
|
|
2
|
+
import { createReducer } from './utils'
|
|
3
3
|
import * as Actions from './actions'
|
|
4
4
|
import { pick } from '../../ui/utils/general-utils'
|
|
5
5
|
|
|
@@ -25,12 +25,11 @@ const configKeys = [
|
|
|
25
25
|
'context',
|
|
26
26
|
'appContainerClassNames',
|
|
27
27
|
'messages',
|
|
28
|
-
'typing',
|
|
29
28
|
'visible',
|
|
30
29
|
'visibilityCallback',
|
|
31
30
|
]
|
|
32
31
|
const updateState = (state, { config }) => {
|
|
33
|
-
const { messages,
|
|
32
|
+
const { messages, ...partialConfig } = pick(config, configKeys)
|
|
34
33
|
let newState = state
|
|
35
34
|
if (Object.keys(partialConfig).length > 0) {
|
|
36
35
|
newState = {
|
|
@@ -48,20 +47,10 @@ const updateState = (state, { config }) => {
|
|
|
48
47
|
}
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
if (typing) {
|
|
52
|
-
newState = {
|
|
53
|
-
...newState,
|
|
54
|
-
typing: {
|
|
55
|
-
...newState.typing,
|
|
56
|
-
...typing,
|
|
57
|
-
},
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
50
|
return newState
|
|
61
51
|
}
|
|
62
52
|
|
|
63
53
|
export default createReducer(
|
|
64
|
-
'config',
|
|
65
54
|
{
|
|
66
55
|
[Actions.initialize]: (state, action) => {
|
|
67
56
|
return updateState(state, action)
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { createSelector } from 'reselect'
|
|
2
2
|
import { visibilityStates } from '../../ui/utils/seamly-utils'
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
export const selectState = (state) => state[String(Reducer)]
|
|
3
|
+
import { selectState } from './utils'
|
|
6
4
|
|
|
7
5
|
export const selectConfig = createSelector(selectState, (config) => {
|
|
8
6
|
let newConfig = {
|
|
@@ -21,3 +19,5 @@ export const selectConfig = createSelector(selectState, (config) => {
|
|
|
21
19
|
}
|
|
22
20
|
return newConfig
|
|
23
21
|
})
|
|
22
|
+
|
|
23
|
+
export { selectState }
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const { createActions } = createDomain('forms')
|
|
1
|
+
import { createActions } from './utils'
|
|
4
2
|
|
|
5
3
|
export const [registerForm, deregisterForm] = createActions('form', {
|
|
6
4
|
register: (formId, persistData) => ({ formId, persistData }),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createReducer } from '
|
|
1
|
+
import { createReducer } from './utils'
|
|
2
2
|
import * as Actions from './actions'
|
|
3
3
|
|
|
4
4
|
const initialState = {}
|
|
@@ -31,7 +31,6 @@ function updateFormControl(state, formId, name, controlState) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export default createReducer(
|
|
34
|
-
'form',
|
|
35
34
|
{
|
|
36
35
|
// Form handlers
|
|
37
36
|
[Actions.registerForm]: (state, { formId, persistData }) => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createSelector } from 'reselect'
|
|
2
2
|
import { getPropSelector } from '../redux/utils'
|
|
3
|
-
import
|
|
3
|
+
import { selectState } from './utils'
|
|
4
4
|
|
|
5
|
-
export const getState =
|
|
5
|
+
export const getState = selectState
|
|
6
6
|
|
|
7
7
|
export const getFormById = createSelector(
|
|
8
8
|
getState,
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { createDomain } from '../../lib/redux-helpers'
|
|
2
|
+
|
|
3
|
+
export const { createActions, createReducer, selectState } =
|
|
4
|
+
createDomain('forms')
|
|
5
|
+
|
|
1
6
|
export function validate(values, schema = {}) {
|
|
2
7
|
return Object.entries(schema).reduce((errors, [key, validations]) => {
|
|
3
8
|
if (validations && !Array.isArray(validations)) {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import createMutex from '../../lib/mutex'
|
|
2
|
+
import { selectLocale } from './selectors'
|
|
3
|
+
import { createAction, createActions, createThunk } from './utils'
|
|
4
|
+
|
|
5
|
+
export const setInitialLocale = createAction('setInitialLocale', (locale) => ({
|
|
6
|
+
locale,
|
|
7
|
+
}))
|
|
8
|
+
|
|
9
|
+
export const [setLocaleStart, setLocaleResolve, setLocaleReject] =
|
|
10
|
+
createActions('setLocale', {
|
|
11
|
+
start: (locale) => ({ locale }),
|
|
12
|
+
resolve: (locale, translations) => ({ locale, translations }),
|
|
13
|
+
reject: (locale, error) => ({ locale, error }),
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const mutex = createMutex()
|
|
17
|
+
export const setLocale = createThunk(
|
|
18
|
+
'setLocale',
|
|
19
|
+
(locale) =>
|
|
20
|
+
async (dispatch, getState, { api }) => {
|
|
21
|
+
await mutex.runExclusively(async () => {
|
|
22
|
+
const currentLocale = selectLocale(getState())
|
|
23
|
+
if (currentLocale === locale) {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
dispatch(setLocaleStart(locale))
|
|
27
|
+
try {
|
|
28
|
+
const translations = await api.getTranslations(locale)
|
|
29
|
+
dispatch(setLocaleResolve(locale, translations))
|
|
30
|
+
} catch (error) {
|
|
31
|
+
dispatch(setLocaleReject(locale, error))
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
},
|
|
35
|
+
)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useCallback } from 'preact/hooks'
|
|
2
|
+
import {
|
|
3
|
+
MessageFormatter,
|
|
4
|
+
pluralTypeHandler,
|
|
5
|
+
selectTypeHandler,
|
|
6
|
+
} from '@ultraq/icu-message-formatter'
|
|
7
|
+
import { useSelector } from '../redux'
|
|
8
|
+
import * as Selectors from './selectors'
|
|
9
|
+
|
|
10
|
+
// The passed in locale (en-GB) is only used to call Intl.PluralRules.select() in
|
|
11
|
+
// pluralTypeHandler. Since we only use exact plural matches (=0, =1 etc) we can
|
|
12
|
+
// safely use en-GB all the time.
|
|
13
|
+
const formatter = new MessageFormatter('en-GB', {
|
|
14
|
+
plural: pluralTypeHandler,
|
|
15
|
+
select: selectTypeHandler,
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export function useI18n() {
|
|
19
|
+
const translations = useSelector(Selectors.selectTranslations)
|
|
20
|
+
const locale = useSelector(Selectors.selectLocale)
|
|
21
|
+
const initialLocale = useSelector(Selectors.selectInitialLocale)
|
|
22
|
+
const t = useCallback(
|
|
23
|
+
(key, values = {}) => {
|
|
24
|
+
const translation = translations[key]
|
|
25
|
+
if (!translation) {
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
return formatter.format(translation, values)
|
|
29
|
+
},
|
|
30
|
+
[translations],
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
t,
|
|
35
|
+
locale,
|
|
36
|
+
initialLocale,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -1,86 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { createDomain, createReducer } from '../../lib/redux-helpers'
|
|
4
|
-
import { useSelector } from '../redux'
|
|
5
|
-
import { flattenObject } from '../../ui/utils/general-utils'
|
|
6
|
-
import en from '../../../../translations/en'
|
|
1
|
+
import * as Actions from './actions'
|
|
2
|
+
import * as Selectors from './selectors'
|
|
7
3
|
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
export * from './hooks'
|
|
5
|
+
export { default as Reducer } from './reducer'
|
|
10
6
|
|
|
11
|
-
export
|
|
12
|
-
overrides,
|
|
13
|
-
}))
|
|
14
|
-
|
|
15
|
-
export const Actions = {
|
|
16
|
-
initI18n,
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Reducer
|
|
20
|
-
const defaultState = { translations: flattenObject(en), overrides: {} }
|
|
21
|
-
export const Reducer = createReducer(
|
|
22
|
-
'i18n',
|
|
23
|
-
{
|
|
24
|
-
[initI18n]: (state, { overrides }) => {
|
|
25
|
-
return {
|
|
26
|
-
...state,
|
|
27
|
-
overrides: overrides ? flattenObject(overrides) : undefined,
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
defaultState,
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
// Selectors
|
|
35
|
-
export const getState = (state) => state[String(Reducer)]
|
|
36
|
-
export const getTranslations = createSelector(
|
|
37
|
-
getState,
|
|
38
|
-
(state) => state.translations,
|
|
39
|
-
)
|
|
40
|
-
export const getOverrides = createSelector(
|
|
41
|
-
getState,
|
|
42
|
-
(state) => state.overrides || {},
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
export const getCombinedTranslations = createSelector(
|
|
46
|
-
getTranslations,
|
|
47
|
-
getOverrides,
|
|
48
|
-
(translations, overrides) => {
|
|
49
|
-
const overrideKeys = Object.keys(overrides)
|
|
50
|
-
if (overrideKeys.length === 0) {
|
|
51
|
-
return translations
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const defaultKeys = Object.keys(translations)
|
|
55
|
-
defaultKeys.forEach((key) => {
|
|
56
|
-
if (overrideKeys.indexOf(key) === -1) {
|
|
57
|
-
console.error('Seamly: Missing translation key:', key)
|
|
58
|
-
}
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
...translations,
|
|
63
|
-
...overrides,
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
// Hooks
|
|
69
|
-
export function useI18n() {
|
|
70
|
-
const translations = useSelector(getCombinedTranslations)
|
|
71
|
-
const t = useCallback(
|
|
72
|
-
(key, values = {}) => {
|
|
73
|
-
const translation = translations[key]
|
|
74
|
-
if (typeof translation === 'function') {
|
|
75
|
-
return translation(values)
|
|
76
|
-
} else {
|
|
77
|
-
return translation
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
[translations],
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
return {
|
|
84
|
-
t,
|
|
85
|
-
}
|
|
86
|
-
}
|
|
7
|
+
export { Actions, Selectors }
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as Actions from './actions'
|
|
2
|
+
import { createReducer } from './utils'
|
|
3
|
+
|
|
4
|
+
const defaultState = {
|
|
5
|
+
translations: {
|
|
6
|
+
'errors.configError.message':
|
|
7
|
+
'We are sorry this happened, please retry at a later time.',
|
|
8
|
+
'errors.configError.srText':
|
|
9
|
+
'A chat configuration error occurred. Our apologies, please retry at a later time.',
|
|
10
|
+
'errors.configError.title': 'Chat configuration error.',
|
|
11
|
+
'errors.general.buttonText': 'Restart chat',
|
|
12
|
+
'errors.general.message': 'Do you want to start a new chat session?',
|
|
13
|
+
'errors.general.srText':
|
|
14
|
+
'Something went wrong with the chat session. You can restart the chat.',
|
|
15
|
+
'errors.general.title': 'Something went wrong',
|
|
16
|
+
'errors.seamlyOffline.message':
|
|
17
|
+
'There might be a problem with your or our network connection. The chat session should resume as soon the connection is available again.',
|
|
18
|
+
'errors.seamlyOffline.srText':
|
|
19
|
+
'The chat has connection issues. There might be a problem with your or our network connection. The chat session should resume as soon as the connection is available again.',
|
|
20
|
+
'errors.seamlyOffline.title': 'Connection issues',
|
|
21
|
+
},
|
|
22
|
+
isLoading: false,
|
|
23
|
+
initialLocale: undefined,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default createReducer(
|
|
27
|
+
{
|
|
28
|
+
[Actions.setInitialLocale]: (state, { locale }) => ({
|
|
29
|
+
...state,
|
|
30
|
+
initialLocale: locale,
|
|
31
|
+
}),
|
|
32
|
+
[Actions.setLocaleStart]: (state) => ({
|
|
33
|
+
...state,
|
|
34
|
+
isLoading: true,
|
|
35
|
+
}),
|
|
36
|
+
[Actions.setLocaleResolve]: (state, { locale, translations }) => {
|
|
37
|
+
return {
|
|
38
|
+
...state,
|
|
39
|
+
isLoading: false,
|
|
40
|
+
locale,
|
|
41
|
+
translations: Object.keys(translations)
|
|
42
|
+
.sort()
|
|
43
|
+
.reduce(
|
|
44
|
+
(accum, key) => ({
|
|
45
|
+
...accum,
|
|
46
|
+
[key]: translations[key],
|
|
47
|
+
}),
|
|
48
|
+
{},
|
|
49
|
+
),
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
[Actions.setLocaleReject]: (state) => ({
|
|
53
|
+
...state,
|
|
54
|
+
isLoading: false,
|
|
55
|
+
}),
|
|
56
|
+
},
|
|
57
|
+
defaultState,
|
|
58
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createSelector } from 'reselect'
|
|
2
|
+
import { selectState } from './utils'
|
|
3
|
+
|
|
4
|
+
export const selectTranslations = createSelector(
|
|
5
|
+
selectState,
|
|
6
|
+
(state) => state.translations,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
export const selectInitialLocale = createSelector(
|
|
10
|
+
selectState,
|
|
11
|
+
(state) => state.initialLocale,
|
|
12
|
+
)
|
|
13
|
+
export const selectLocale = createSelector(selectState, (state) => state.locale)
|
|
14
|
+
|
|
15
|
+
export { selectState }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createReducer } from '
|
|
1
|
+
import { createReducer } from './utils'
|
|
2
2
|
import * as Actions from './actions'
|
|
3
3
|
|
|
4
4
|
const initialState = {
|
|
@@ -6,7 +6,6 @@ const initialState = {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export default createReducer(
|
|
9
|
-
'interrupt',
|
|
10
9
|
{
|
|
11
10
|
[Actions.set]: (state, { error }) => {
|
|
12
11
|
return {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createSelector } from 'reselect'
|
|
2
|
-
import
|
|
2
|
+
import { selectState } from './utils'
|
|
3
3
|
|
|
4
|
-
export const selectState = (state) => state[String(Reducer)]
|
|
5
4
|
export const selectError = createSelector(selectState, ({ error }) => error)
|
|
5
|
+
|
|
6
|
+
export { selectState }
|
|
@@ -26,6 +26,7 @@ export function useSelector(selector, deps = []) {
|
|
|
26
26
|
// instead of accepting a stabilized selector, we stick to the signature
|
|
27
27
|
// of useCallback, as that makes the exposed api much more dev-friendly
|
|
28
28
|
// otherwise you'd have to stabilize selectors externally
|
|
29
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
29
30
|
const selectorCb = useCallback(selector, deps)
|
|
30
31
|
// we're keeping the selector in a ref to compare against
|
|
31
32
|
// we need this both in the store subscription and for
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import thunkMiddleware from 'redux-thunk'
|
|
2
2
|
import { createReduxStore } from '../redux'
|
|
3
|
+
import { Reducer as appReducer } from '../app'
|
|
3
4
|
import {
|
|
4
5
|
createMiddleware as createConfigMiddleware,
|
|
5
6
|
Reducer as configReducer,
|
|
6
7
|
} from '../config'
|
|
7
8
|
import { Reducer as formReducer } from '../forms'
|
|
8
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
Reducer as translationsReducer,
|
|
11
|
+
createMiddleware as createI18nMiddleware,
|
|
12
|
+
} from '../translations'
|
|
9
13
|
import { Reducer as i18nReducer } from '../i18n'
|
|
10
14
|
import {
|
|
11
15
|
Reducer as interruptReducer,
|
|
@@ -18,6 +22,7 @@ export function createStore({ initialState, api } = {}) {
|
|
|
18
22
|
const store = createReduxStore({
|
|
19
23
|
reducers: {
|
|
20
24
|
state: stateReducer,
|
|
25
|
+
[String(appReducer)]: appReducer,
|
|
21
26
|
[String(configReducer)]: configReducer,
|
|
22
27
|
[String(formReducer)]: formReducer,
|
|
23
28
|
[String(translationsReducer)]: translationsReducer,
|
|
@@ -32,6 +37,7 @@ export function createStore({ initialState, api } = {}) {
|
|
|
32
37
|
createConfigMiddleware(),
|
|
33
38
|
createInterruptMiddleware(),
|
|
34
39
|
createOptionsMiddleware({ api }),
|
|
40
|
+
createI18nMiddleware(),
|
|
35
41
|
],
|
|
36
42
|
})
|
|
37
43
|
return store
|
|
@@ -31,7 +31,7 @@ export default function TranslationsChatStatus() {
|
|
|
31
31
|
<ChatStatus
|
|
32
32
|
type="translations"
|
|
33
33
|
id={id}
|
|
34
|
-
label={t('translations.status.label', languageName)}
|
|
34
|
+
label={t('translations.status.label', { language: languageName })}
|
|
35
35
|
onButtonClick={handleClickStop}
|
|
36
36
|
buttonText={t('translations.status.stopText')}
|
|
37
37
|
srButtonText={t('translations.status.srStopText')}
|
|
@@ -8,7 +8,7 @@ import Select from '../../../../ui/components/form-controls/select'
|
|
|
8
8
|
function TranslationsOptionsDialogForm({ controlName, descriptionId }) {
|
|
9
9
|
const { t } = useI18n()
|
|
10
10
|
const { isActive, languages, currentLocale } = useTranslations()
|
|
11
|
-
|
|
11
|
+
const { locale: uiLocale } = useI18n()
|
|
12
12
|
const languageName = useMemo(() => {
|
|
13
13
|
return languages?.find((lang) => lang.locale === currentLocale)?.nativeName
|
|
14
14
|
}, [languages, currentLocale])
|
|
@@ -16,12 +16,17 @@ function TranslationsOptionsDialogForm({ controlName, descriptionId }) {
|
|
|
16
16
|
const options = useMemo(() => {
|
|
17
17
|
return [
|
|
18
18
|
{ value: '', label: t('translations.settings.defaultOptionLabel') },
|
|
19
|
-
...languages
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
...languages
|
|
20
|
+
.filter(
|
|
21
|
+
(language) =>
|
|
22
|
+
language.locale.toLowerCase() !== String(uiLocale).toLowerCase(),
|
|
23
|
+
)
|
|
24
|
+
.map((language) => ({
|
|
25
|
+
value: language.locale,
|
|
26
|
+
label: language.nativeName,
|
|
27
|
+
})),
|
|
23
28
|
]
|
|
24
|
-
}, [t, languages])
|
|
29
|
+
}, [t, languages, uiLocale])
|
|
25
30
|
|
|
26
31
|
return (
|
|
27
32
|
<Form noValidate="true">
|
|
@@ -2,6 +2,7 @@ import * as Actions from './actions'
|
|
|
2
2
|
import * as Selectors from './selectors'
|
|
3
3
|
|
|
4
4
|
export * from './hooks'
|
|
5
|
+
export { default as createMiddleware } from './middleware'
|
|
5
6
|
export { default as Reducer } from './reducer'
|
|
6
7
|
export { default as OptionsButton } from './components/options-button'
|
|
7
8
|
export { default as ChatStatus } from './components/chat-status'
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as Actions from './actions'
|
|
2
|
+
import { seamlyActions } from '../../ui/utils/seamly-utils'
|
|
3
|
+
import { Actions as I18nActions, Selectors as I18nSelectors } from '../i18n'
|
|
4
|
+
|
|
5
|
+
export default function createMiddleware() {
|
|
6
|
+
return ({ dispatch, getState }) =>
|
|
7
|
+
(next) =>
|
|
8
|
+
(action) => {
|
|
9
|
+
const result = next(action)
|
|
10
|
+
|
|
11
|
+
switch (action.type) {
|
|
12
|
+
case String(seamlyActions.SET_HISTORY):
|
|
13
|
+
if (action.history?.translation?.enabled) {
|
|
14
|
+
dispatch(Actions.enable(action.history.translation.locale))
|
|
15
|
+
}
|
|
16
|
+
break
|
|
17
|
+
case String(seamlyActions.SET_INITIAL_STATE):
|
|
18
|
+
if (action.initialState?.translation?.enabled) {
|
|
19
|
+
dispatch(Actions.enable(action.initialState.translation.locale))
|
|
20
|
+
dispatch(I18nActions.setLocale(action.locale))
|
|
21
|
+
}
|
|
22
|
+
break
|
|
23
|
+
case String(seamlyActions.ADD_EVENT):
|
|
24
|
+
if (
|
|
25
|
+
action.event.type === 'info' &&
|
|
26
|
+
action.event?.payload?.body?.subtype === 'new_translation' &&
|
|
27
|
+
action.event.payload.body.translationEnabled
|
|
28
|
+
) {
|
|
29
|
+
dispatch(
|
|
30
|
+
I18nActions.setLocale(
|
|
31
|
+
action.event.payload.body.translationLocale,
|
|
32
|
+
),
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
break
|
|
36
|
+
case String(Actions.disable):
|
|
37
|
+
const initialLocale = I18nSelectors.selectInitialLocale(getState())
|
|
38
|
+
dispatch(I18nActions.setLocale(initialLocale))
|
|
39
|
+
break
|
|
40
|
+
}
|
|
41
|
+
return result
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createReducer } from '
|
|
1
|
+
import { createReducer } from './utils'
|
|
2
2
|
import { seamlyActions } from '../../ui/utils/seamly-utils'
|
|
3
3
|
import { randomId } from '../../lib/id'
|
|
4
4
|
import * as Actions from './actions'
|
|
@@ -13,7 +13,6 @@ const initialState = {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export default createReducer(
|
|
16
|
-
'translations',
|
|
17
16
|
{
|
|
18
17
|
[seamlyActions.SET_FEATURES]: (state, action) => {
|
|
19
18
|
const feature = action?.features?.translation
|
|
@@ -27,13 +26,7 @@ export default createReducer(
|
|
|
27
26
|
languages: feature.languages || [],
|
|
28
27
|
}
|
|
29
28
|
},
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
...state,
|
|
33
|
-
isActive: history?.translation?.enabled,
|
|
34
|
-
currentLocale: history?.translation?.locale,
|
|
35
|
-
}
|
|
36
|
-
},
|
|
29
|
+
|
|
37
30
|
[seamlyActions.CLEAR_FEATURES]: () => initialState,
|
|
38
31
|
[Actions.enable]: (state, { locale }) => {
|
|
39
32
|
return {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createSelector } from 'reselect'
|
|
2
2
|
import { getPropSelector } from '../redux/utils'
|
|
3
|
-
import
|
|
3
|
+
import { selectState } from './utils'
|
|
4
4
|
|
|
5
|
-
export const getState =
|
|
5
|
+
export const getState = selectState
|
|
6
6
|
|
|
7
7
|
export const getOriginalPayloadIds = createSelector(
|
|
8
8
|
getState,
|
package/src/javascripts/index.js
CHANGED
|
@@ -137,6 +137,9 @@ export { default as View } from './ui/components/layout/view'
|
|
|
137
137
|
// Used by: StyleGuide
|
|
138
138
|
export { visibilityStates } from './ui/utils/seamly-utils'
|
|
139
139
|
|
|
140
|
+
// Used by: StyleGuide
|
|
141
|
+
export { API } from './api'
|
|
142
|
+
|
|
140
143
|
// Used by: StyleGuide
|
|
141
144
|
export { default as SeamlyGeneralError } from './api/errors/seamly-general-error'
|
|
142
145
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export default function createMutex() {
|
|
2
|
+
let isRunning = false
|
|
3
|
+
const tasks = []
|
|
4
|
+
|
|
5
|
+
const next = async () => {
|
|
6
|
+
if (!isRunning) {
|
|
7
|
+
while (tasks.length) {
|
|
8
|
+
const task = tasks.shift()
|
|
9
|
+
isRunning = true
|
|
10
|
+
// eslint-disable-next-line no-await-in-loop
|
|
11
|
+
await task().catch(() => {})
|
|
12
|
+
isRunning = false
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const runExclusively = async (task) => {
|
|
17
|
+
const prms = new Promise((resolve, reject) => {
|
|
18
|
+
tasks.push(async () => {
|
|
19
|
+
try {
|
|
20
|
+
resolve(await task())
|
|
21
|
+
} catch (e) {
|
|
22
|
+
reject(e)
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
next()
|
|
27
|
+
return prms
|
|
28
|
+
}
|
|
29
|
+
return { next, runExclusively }
|
|
30
|
+
}
|