@seamly/web-ui 18.2.0 → 19.0.0-beta.1
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 +598 -136
- package/build/dist/lib/index.debug.min.js +1 -1
- package/build/dist/lib/index.debug.min.js.LICENSE.txt +190 -22
- package/build/dist/lib/index.js +4745 -4468
- 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 +4839 -4465
- 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 +1770 -980
- package/build/dist/lib/style-guide.min.js +1 -1
- package/build/dist/lib/styles.css +1 -1
- package/build/dist/lib/utils.js +0 -1
- package/build/dist/lib/utils.min.js +1 -1
- package/package.json +29 -29
- package/src/javascripts/api/index.js +33 -48
- package/src/javascripts/api/producer.js +9 -12
- package/src/javascripts/config.js +9 -11
- package/src/javascripts/domains/app/actions.js +43 -0
- package/src/javascripts/domains/app/hooks.js +6 -0
- package/src/javascripts/domains/app/index.js +6 -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 +4 -0
- package/src/javascripts/domains/config/hooks.js +6 -0
- package/src/javascripts/domains/config/index.js +8 -0
- package/src/javascripts/domains/config/middleware.js +22 -0
- package/src/javascripts/domains/config/reducer.js +63 -0
- package/src/javascripts/domains/config/selectors.js +23 -0
- package/src/javascripts/domains/config/utils.js +4 -0
- package/src/javascripts/domains/forms/actions.js +2 -4
- package/src/javascripts/domains/forms/hooks.js +10 -14
- package/src/javascripts/domains/forms/provider.js +4 -6
- package/src/javascripts/domains/forms/reducer.js +1 -2
- package/src/javascripts/domains/forms/selectors.js +4 -4
- 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 -80
- 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 +4 -0
- package/src/javascripts/domains/interrupt/hooks.js +29 -0
- package/src/javascripts/domains/interrupt/index.js +9 -0
- package/src/javascripts/domains/interrupt/middleware.js +30 -0
- package/src/javascripts/domains/interrupt/reducer.js +21 -0
- package/src/javascripts/domains/interrupt/selectors.js +6 -0
- package/src/javascripts/domains/interrupt/utils.js +4 -0
- package/src/javascripts/domains/options/index.js +1 -0
- package/src/javascripts/domains/options/middleware.js +35 -0
- package/src/javascripts/domains/redux/create-redux-store.js +14 -6
- package/src/javascripts/domains/redux/hooks.js +3 -2
- package/src/javascripts/domains/redux/index.js +2 -1
- package/src/javascripts/domains/redux/provider.js +5 -0
- package/src/javascripts/domains/store/index.js +44 -0
- package/src/javascripts/{ui → domains}/store/state-reducer.js +4 -7
- package/src/javascripts/domains/translations/actions.js +4 -6
- package/src/javascripts/domains/translations/components/chat-status.js +7 -13
- package/src/javascripts/domains/translations/components/options-button.js +3 -3
- package/src/javascripts/domains/translations/components/options-dialog/form.js +12 -7
- package/src/javascripts/domains/translations/components/options-dialog/index.js +2 -5
- package/src/javascripts/domains/translations/hooks.js +1 -1
- 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 +4 -11
- package/src/javascripts/domains/translations/selectors.js +3 -3
- package/src/javascripts/domains/translations/utils.js +4 -0
- package/src/javascripts/index.js +20 -5
- package/src/javascripts/lib/css.js +5 -5
- package/src/javascripts/lib/engine/index.js +39 -11
- package/src/javascripts/lib/external-api/index.js +6 -6
- package/src/javascripts/lib/mutex.js +30 -0
- package/src/javascripts/lib/parse-body.js +1 -1
- package/src/javascripts/lib/redux-helpers/index.js +25 -8
- package/src/javascripts/lib/split-url-params.js +2 -2
- package/src/javascripts/lib/store/providers/app-storage.js +1 -1
- package/src/javascripts/lib/store/providers/cookie-storage.js +1 -1
- package/src/javascripts/package/utils.js +0 -1
- package/src/javascripts/style-guide/components/app.js +12 -14
- package/src/javascripts/style-guide/components/links.js +6 -6
- package/src/javascripts/style-guide/components/static-core.js +32 -10
- package/src/javascripts/style-guide/state-helpers/index.js +1 -1
- package/src/javascripts/style-guide/states.js +29 -71
- package/src/javascripts/style-guide/style-guide-engine.js +13 -12
- package/src/javascripts/ui/components/chat-app.js +2 -2
- package/src/javascripts/ui/components/conversation/component-filter.js +2 -2
- package/src/javascripts/ui/components/conversation/conversation.js +2 -2
- package/src/javascripts/ui/components/conversation/event/card-component.js +24 -3
- package/src/javascripts/ui/components/conversation/event/carousel-component/components/pagination.js +2 -2
- package/src/javascripts/ui/components/conversation/event/carousel-component/index.js +4 -3
- package/src/javascripts/ui/components/conversation/event/carousel-message/components/slide.js +2 -1
- package/src/javascripts/ui/components/conversation/event/carousel-message/index.js +2 -2
- package/src/javascripts/ui/components/conversation/event/choice-prompt.js +5 -5
- package/src/javascripts/ui/components/conversation/event/divider/variants/new-translation.js +2 -2
- package/src/javascripts/ui/components/conversation/event/event-participant.js +3 -5
- package/src/javascripts/ui/components/conversation/event/hooks/use-event-link-click-handler.js +2 -2
- package/src/javascripts/ui/components/conversation/event/hooks/use-formatted-date.js +3 -3
- package/src/javascripts/ui/components/conversation/event/hooks/use-text-rendering.js +3 -3
- package/src/javascripts/ui/components/conversation/event/participant.js +2 -2
- package/src/javascripts/ui/components/conversation/event/upload.js +12 -27
- package/src/javascripts/ui/components/conversation/message-container.js +4 -6
- package/src/javascripts/ui/components/core/seamly-activity-monitor.js +4 -5
- package/src/javascripts/ui/components/core/seamly-core.js +6 -7
- package/src/javascripts/ui/components/core/seamly-event-subscriber.js +18 -17
- package/src/javascripts/ui/components/core/seamly-file-upload.js +5 -6
- package/src/javascripts/ui/components/core/seamly-idle-detach-counter.js +2 -6
- package/src/javascripts/ui/components/core/seamly-initializer.js +7 -60
- package/src/javascripts/ui/components/core/seamly-instance-functions-loader.js +10 -16
- package/src/javascripts/ui/components/core/seamly-live-region.js +1 -1
- package/src/javascripts/ui/components/core/seamly-new-notifications.js +5 -6
- package/src/javascripts/ui/components/core/seamly-read-state.js +8 -6
- package/src/javascripts/ui/components/entry/entry-container.js +7 -10
- 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/toggle-button.js +24 -10
- package/src/javascripts/ui/components/entry/upload/file-upload-form.js +6 -3
- package/src/javascripts/ui/components/entry/upload/index.js +11 -13
- package/src/javascripts/ui/components/faq/faq.js +6 -6
- package/src/javascripts/ui/components/form-controls/error.js +22 -0
- package/src/javascripts/ui/components/form-controls/file-input.js +3 -9
- package/src/javascripts/ui/components/form-controls/select.js +1 -1
- package/src/javascripts/ui/components/form-controls/wrapper.js +2 -9
- package/src/javascripts/ui/components/layout/agent-info.js +4 -4
- package/src/javascripts/ui/components/layout/app-frame.js +15 -12
- package/src/javascripts/ui/components/layout/chat-frame.js +3 -5
- package/src/javascripts/ui/components/layout/header.js +4 -18
- package/src/javascripts/ui/components/layout/interrupt.js +6 -2
- package/src/javascripts/ui/components/layout/privacy-disclaimer.js +2 -2
- package/src/javascripts/ui/components/options/cobrowsing.js +3 -7
- package/src/javascripts/ui/components/options/options-button.js +9 -13
- package/src/javascripts/ui/components/options/options-frame.js +1 -1
- package/src/javascripts/ui/components/options/transcript/index.js +2 -2
- package/src/javascripts/ui/components/options/transcript/transcript-form.js +1 -1
- package/src/javascripts/ui/components/warnings/cobrowsing-active-frame.js +3 -6
- package/src/javascripts/ui/components/warnings/idle-detach-warning.js +2 -6
- package/src/javascripts/ui/components/warnings/resume-conversation-prompt.js +1 -1
- package/src/javascripts/ui/components/widgets/in-out-transition.js +2 -2
- package/src/javascripts/ui/components/widgets/lightbox.js +4 -4
- package/src/javascripts/ui/components/widgets/modal.js +3 -3
- package/src/javascripts/ui/components/widgets/upload-progress.js +3 -14
- package/src/javascripts/ui/hooks/component-helper-hooks.js +4 -15
- package/src/javascripts/ui/hooks/file-upload-hooks.js +3 -3
- package/src/javascripts/ui/hooks/focus-helper-hooks.js +4 -4
- package/src/javascripts/ui/hooks/live-region-hooks.js +2 -2
- package/src/javascripts/ui/hooks/seamly-api-hooks.js +0 -6
- package/src/javascripts/ui/hooks/seamly-entry-hooks.js +22 -25
- package/src/javascripts/ui/hooks/seamly-hooks.js +3 -10
- package/src/javascripts/ui/hooks/seamly-option-hooks.js +4 -4
- package/src/javascripts/ui/hooks/seamly-state-hooks.js +8 -16
- package/src/javascripts/ui/hooks/use-event-component-mapping.js +1 -1
- package/src/javascripts/ui/hooks/use-seamly-chat.js +1 -0
- package/src/javascripts/ui/hooks/use-seamly-commands.js +31 -54
- package/src/javascripts/ui/hooks/use-seamly-idle-detach-countdown.js +3 -3
- package/src/javascripts/ui/hooks/use-seamly-stored-visibility.js +3 -3
- package/src/javascripts/ui/hooks/use-seamly-visibility.js +6 -8
- package/src/javascripts/ui/hooks/use-single-file-upload.js +4 -1
- package/src/javascripts/ui/hooks/utility-hooks.js +2 -2
- package/src/javascripts/ui/utils/form-utils.js +3 -3
- package/src/javascripts/ui/utils/general-utils.js +21 -22
- package/src/javascripts/ui/utils/seamly-utils.js +15 -83
- package/src/javascripts/ui/utils/validations.js +10 -7
- package/src/stylesheets/1-settings/_config.scss +2 -1
- package/src/stylesheets/3-app/_app.scss +3 -4
- package/src/stylesheets/5-components/_card.scss +0 -1
- package/src/stylesheets/5-components/_faq.scss +3 -8
- package/src/stylesheets/5-components/_message.scss +10 -0
- package/src/stylesheets/5-components/_modal.scss +3 -3
- package/src/stylesheets/5-components/_options.scss +3 -2
- package/webpack/config.common.js +3 -3
- package/webpack/config.package.js +4 -22
- package/webpack/config.site.js +8 -6
- package/webpack/defaults.js +0 -3
- package/CHANGELOG.md +0 -561
- package/build/dist/translations/de-informal.js +0 -275
- package/build/dist/translations/de-informal.min.js +0 -1
- package/build/dist/translations/en.js +0 -275
- package/build/dist/translations/en.min.js +0 -1
- package/build/dist/translations/es-informal.js +0 -281
- package/build/dist/translations/es-informal.min.js +0 -1
- package/build/dist/translations/nl-formal.js +0 -275
- package/build/dist/translations/nl-formal.min.js +0 -1
- package/build/dist/translations/nl-informal.js +0 -275
- package/build/dist/translations/nl-informal.min.js +0 -1
- package/src/javascripts/lib/i18n.js +0 -46
- package/src/javascripts/ui/components/core/seamly-api.js +0 -44
- package/src/javascripts/ui/hooks/use-seamly-interrupt.js +0 -62
- package/src/javascripts/ui/store/index.js +0 -37
- package/translations/de-informal.js +0 -237
- package/translations/en.js +0 -234
- package/translations/es-informal.js +0 -243
- package/translations/nl-formal.js +0 -230
- package/translations/nl-informal.js +0 -230
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { seamlyActions } from '../../ui/utils/seamly-utils'
|
|
2
|
+
import { Actions as ConfigActions } from '../config'
|
|
3
|
+
import { Actions as InterruptActions } from '../interrupt'
|
|
4
|
+
import { Actions as I18nActions } from '../i18n'
|
|
5
|
+
import { createAction, createThunk } from './utils'
|
|
6
|
+
|
|
7
|
+
export const setHasResponded = createAction(
|
|
8
|
+
'setHasResponded',
|
|
9
|
+
(hasResponded) => ({ hasResponded }),
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
export const initialize = createThunk(
|
|
13
|
+
'initialize',
|
|
14
|
+
(config) =>
|
|
15
|
+
async (dispatch, getState, { api }) => {
|
|
16
|
+
try {
|
|
17
|
+
dispatch(ConfigActions.initialize(config))
|
|
18
|
+
|
|
19
|
+
const { features, defaultLocale } = await api.getConfig()
|
|
20
|
+
dispatch({ type: seamlyActions.SET_FEATURES, features })
|
|
21
|
+
|
|
22
|
+
let locale = config?.context?.locale || defaultLocale
|
|
23
|
+
dispatch(I18nActions.setInitialLocale(locale))
|
|
24
|
+
try {
|
|
25
|
+
if (api.hasConversation()) {
|
|
26
|
+
const initialState = await api.getConversationIntitialState()
|
|
27
|
+
dispatch({ type: seamlyActions.SET_INITIAL_STATE, initialState })
|
|
28
|
+
|
|
29
|
+
locale = initialState.translation?.locale || locale
|
|
30
|
+
|
|
31
|
+
if ('userResponded' in initialState) {
|
|
32
|
+
dispatch(setHasResponded(initialState.userResponded))
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
} catch (error) {
|
|
36
|
+
dispatch(InterruptActions.set(error))
|
|
37
|
+
}
|
|
38
|
+
await dispatch(I18nActions.setLocale(locale))
|
|
39
|
+
} catch (error) {
|
|
40
|
+
dispatch(InterruptActions.set(error))
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createReducer } from './utils'
|
|
2
|
+
import * as Actions from './actions'
|
|
3
|
+
|
|
4
|
+
const initialState = {
|
|
5
|
+
userHasResponded: false,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default createReducer(
|
|
9
|
+
{
|
|
10
|
+
[Actions.setHasResponded]: (state, { hasResponded }) => ({
|
|
11
|
+
...state,
|
|
12
|
+
userHasResponded: hasResponded,
|
|
13
|
+
}),
|
|
14
|
+
},
|
|
15
|
+
initialState,
|
|
16
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as Actions from './actions'
|
|
2
|
+
import { seamlyActions } from '../../ui/utils/seamly-utils'
|
|
3
|
+
|
|
4
|
+
export default function createMiddleware() {
|
|
5
|
+
return ({ dispatch }) =>
|
|
6
|
+
(next) =>
|
|
7
|
+
(action) => {
|
|
8
|
+
const result = next(action)
|
|
9
|
+
|
|
10
|
+
switch (action.type) {
|
|
11
|
+
case String(Actions.initialize):
|
|
12
|
+
case String(Actions.update):
|
|
13
|
+
if (action?.config?.defaults?.agentName) {
|
|
14
|
+
dispatch({
|
|
15
|
+
type: seamlyActions.SET_HEADER_SUB_TITLE,
|
|
16
|
+
title: action?.config?.defaults?.agentName,
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return result
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { defaultConfig } from '../../config'
|
|
2
|
+
import { createReducer } from './utils'
|
|
3
|
+
import * as Actions from './actions'
|
|
4
|
+
import { pick } from '../../ui/utils/general-utils'
|
|
5
|
+
|
|
6
|
+
const initialState = {
|
|
7
|
+
...defaultConfig,
|
|
8
|
+
hideOnNoUserResponse: false,
|
|
9
|
+
showDisclaimer: false,
|
|
10
|
+
showFaq: false,
|
|
11
|
+
customComponents: {},
|
|
12
|
+
defaults: {},
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const configKeys = [
|
|
16
|
+
'hideOnNoUserResponse',
|
|
17
|
+
'showDisclaimer',
|
|
18
|
+
'showFaq',
|
|
19
|
+
'namespace',
|
|
20
|
+
'customComponents',
|
|
21
|
+
'defaults',
|
|
22
|
+
'layoutMode',
|
|
23
|
+
'api',
|
|
24
|
+
'zIndex',
|
|
25
|
+
'context',
|
|
26
|
+
'appContainerClassNames',
|
|
27
|
+
'messages',
|
|
28
|
+
'visible',
|
|
29
|
+
'visibilityCallback',
|
|
30
|
+
]
|
|
31
|
+
const updateState = (state, { config }) => {
|
|
32
|
+
const { messages, ...partialConfig } = pick(config, configKeys)
|
|
33
|
+
let newState = state
|
|
34
|
+
if (Object.keys(partialConfig).length > 0) {
|
|
35
|
+
newState = {
|
|
36
|
+
...newState,
|
|
37
|
+
...partialConfig,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (messages) {
|
|
41
|
+
newState = {
|
|
42
|
+
...newState,
|
|
43
|
+
messages: {
|
|
44
|
+
...newState.messages,
|
|
45
|
+
...messages,
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return newState
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default createReducer(
|
|
54
|
+
{
|
|
55
|
+
[Actions.initialize]: (state, action) => {
|
|
56
|
+
return updateState(state, action)
|
|
57
|
+
},
|
|
58
|
+
[Actions.update]: (state, action) => {
|
|
59
|
+
return updateState(state, action)
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
initialState,
|
|
63
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createSelector } from 'reselect'
|
|
2
|
+
import { visibilityStates } from '../../ui/utils/seamly-utils'
|
|
3
|
+
import { selectState } from './utils'
|
|
4
|
+
|
|
5
|
+
export const selectConfig = createSelector(selectState, (config) => {
|
|
6
|
+
let newConfig = {
|
|
7
|
+
visible:
|
|
8
|
+
config?.layoutMode === 'inline'
|
|
9
|
+
? visibilityStates.open
|
|
10
|
+
: visibilityStates.minimized,
|
|
11
|
+
appContainerClassNames: config.appContainerClassNames || [],
|
|
12
|
+
...config,
|
|
13
|
+
}
|
|
14
|
+
if (typeof newConfig.appContainerClassNames === 'function') {
|
|
15
|
+
newConfig = {
|
|
16
|
+
...newConfig,
|
|
17
|
+
appContainerClassNames: newConfig.appContainerClassNames(newConfig),
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return newConfig
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
export { selectState }
|
|
@@ -1,10 +1,8 @@
|
|
|
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 }),
|
|
7
|
-
deregister: formId => ({ formId }),
|
|
5
|
+
deregister: (formId) => ({ formId }),
|
|
8
6
|
})
|
|
9
7
|
|
|
10
8
|
export const [
|
|
@@ -29,10 +29,10 @@ export function useForm() {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export function useValidations(values, validationSchema) {
|
|
32
|
-
const errors = useMemo(
|
|
33
|
-
values,
|
|
34
|
-
validationSchema,
|
|
35
|
-
|
|
32
|
+
const errors = useMemo(
|
|
33
|
+
() => validate(values, validationSchema),
|
|
34
|
+
[values, validationSchema],
|
|
35
|
+
)
|
|
36
36
|
return {
|
|
37
37
|
isValid: Object.keys(errors).length === 0,
|
|
38
38
|
errors,
|
|
@@ -41,12 +41,8 @@ export function useValidations(values, validationSchema) {
|
|
|
41
41
|
|
|
42
42
|
export function useFormControl(name) {
|
|
43
43
|
const dispatch = useStoreDispatch()
|
|
44
|
-
const {
|
|
45
|
-
|
|
46
|
-
updateControlValue,
|
|
47
|
-
updateControlTouched,
|
|
48
|
-
errors,
|
|
49
|
-
} = useFormContext()
|
|
44
|
+
const { formId, updateControlValue, updateControlTouched, errors } =
|
|
45
|
+
useFormContext()
|
|
50
46
|
const form = useSelectorWithProps(getFormById, { formId }, [formId])
|
|
51
47
|
const isRegistered = !!form
|
|
52
48
|
const isRegisteredRef = useRef()
|
|
@@ -77,10 +73,10 @@ export function useFormControl(name) {
|
|
|
77
73
|
}, [isRegistered, formId, name, dispatch])
|
|
78
74
|
|
|
79
75
|
// preact uses onInput instead of onChange
|
|
80
|
-
const onInput = useCallback(
|
|
81
|
-
name,
|
|
82
|
-
updateControlValue,
|
|
83
|
-
|
|
76
|
+
const onInput = useCallback(
|
|
77
|
+
(e) => updateControlValue(name, e.target.value),
|
|
78
|
+
[name, updateControlValue],
|
|
79
|
+
)
|
|
84
80
|
|
|
85
81
|
const onBlur = useCallback(() => {
|
|
86
82
|
updateControlTouched(name, true)
|
|
@@ -25,10 +25,8 @@ export default function FormProvider({
|
|
|
25
25
|
])
|
|
26
26
|
const [isSubmitted, setIsSubmitted] = useState(false)
|
|
27
27
|
const [externalErrors, setExternalErrors] = useState({})
|
|
28
|
-
const {
|
|
29
|
-
|
|
30
|
-
errors: validationErrors,
|
|
31
|
-
} = useValidations(values, validationSchema)
|
|
28
|
+
const { isValid: validationIsValid, errors: validationErrors } =
|
|
29
|
+
useValidations(values, validationSchema)
|
|
32
30
|
const errors = useMemo(
|
|
33
31
|
() => ({
|
|
34
32
|
...validationErrors,
|
|
@@ -68,7 +66,7 @@ export default function FormProvider({
|
|
|
68
66
|
// Function to manually set an error
|
|
69
67
|
const setError = useCallback(
|
|
70
68
|
(name, error) => {
|
|
71
|
-
setExternalErrors(val => {
|
|
69
|
+
setExternalErrors((val) => {
|
|
72
70
|
return {
|
|
73
71
|
...val,
|
|
74
72
|
[name]: error,
|
|
@@ -79,7 +77,7 @@ export default function FormProvider({
|
|
|
79
77
|
)
|
|
80
78
|
|
|
81
79
|
const handleSubmit = useCallback(
|
|
82
|
-
e => {
|
|
80
|
+
(e) => {
|
|
83
81
|
e.preventDefault()
|
|
84
82
|
setIsSubmitted(true)
|
|
85
83
|
if (validationIsValid) {
|
|
@@ -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,
|
|
@@ -12,12 +12,12 @@ export const getFormById = createSelector(
|
|
|
12
12
|
|
|
13
13
|
export const getFormControlsByFormId = createSelector(
|
|
14
14
|
getFormById,
|
|
15
|
-
form => form?.controls || {},
|
|
15
|
+
(form) => form?.controls || {},
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
export const getFormValuesByFormId = createSelector(
|
|
19
19
|
getFormControlsByFormId,
|
|
20
|
-
controls => {
|
|
20
|
+
(controls) => {
|
|
21
21
|
const valuesObj = {}
|
|
22
22
|
Object.entries(controls).forEach(([key, { value }]) => {
|
|
23
23
|
valuesObj[key] = value
|
|
@@ -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,82 +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
|
-
// Reducer
|
|
16
|
-
const defaultState = { translations: flattenObject(en), overrides: {} }
|
|
17
|
-
export const Reducer = createReducer(
|
|
18
|
-
'i18n',
|
|
19
|
-
{
|
|
20
|
-
[initI18n]: (state, { overrides }) => {
|
|
21
|
-
return {
|
|
22
|
-
...state,
|
|
23
|
-
overrides: overrides ? flattenObject(overrides) : undefined,
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
defaultState,
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
// Selectors
|
|
31
|
-
export const getState = state => state[String(Reducer)]
|
|
32
|
-
export const getTranslations = createSelector(
|
|
33
|
-
getState,
|
|
34
|
-
state => state.translations,
|
|
35
|
-
)
|
|
36
|
-
export const getOverrides = createSelector(
|
|
37
|
-
getState,
|
|
38
|
-
state => state.overrides || {},
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
export const getCombinedTranslations = createSelector(
|
|
42
|
-
getTranslations,
|
|
43
|
-
getOverrides,
|
|
44
|
-
(translations, overrides) => {
|
|
45
|
-
const overrideKeys = Object.keys(overrides)
|
|
46
|
-
if (overrideKeys.length === 0) {
|
|
47
|
-
return translations
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const defaultKeys = Object.keys(translations)
|
|
51
|
-
defaultKeys.forEach(key => {
|
|
52
|
-
if (overrideKeys.indexOf(key) === -1) {
|
|
53
|
-
console.error('Seamly: Missing translation key:', key)
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
return {
|
|
58
|
-
...translations,
|
|
59
|
-
...overrides,
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
// Hooks
|
|
65
|
-
export function useI18n() {
|
|
66
|
-
const translations = useSelector(getCombinedTranslations)
|
|
67
|
-
const t = useCallback(
|
|
68
|
-
(key, values = {}) => {
|
|
69
|
-
const translation = translations[key]
|
|
70
|
-
if (typeof translation === 'function') {
|
|
71
|
-
return translation(values)
|
|
72
|
-
} else {
|
|
73
|
-
return translation
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
[translations],
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
return {
|
|
80
|
-
t,
|
|
81
|
-
}
|
|
82
|
-
}
|
|
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 }
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useMemo } from 'preact/hooks'
|
|
2
|
+
import { useI18n } from '../i18n'
|
|
3
|
+
import { useSelector } from '../redux'
|
|
4
|
+
import * as Selectors from './selectors'
|
|
5
|
+
|
|
6
|
+
export function useInterrupt() {
|
|
7
|
+
const { t } = useI18n()
|
|
8
|
+
|
|
9
|
+
const error = useSelector(Selectors.selectError)
|
|
10
|
+
const hasInterrupt = Boolean(error)
|
|
11
|
+
|
|
12
|
+
const meta = useMemo(() => {
|
|
13
|
+
if (!error) return {}
|
|
14
|
+
const { langKey, action } = error
|
|
15
|
+
const title = t(`${langKey}.title`)
|
|
16
|
+
const message = t(`${langKey}.message`)
|
|
17
|
+
const srText = t(`${langKey}.srText`)
|
|
18
|
+
const buttonText = t(`${langKey}.buttonText`)
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
...(langKey ? { title, message, srText } : {}),
|
|
22
|
+
...(action ? { action } : {}),
|
|
23
|
+
...(action && langKey ? { buttonText } : {}),
|
|
24
|
+
originalError: error,
|
|
25
|
+
}
|
|
26
|
+
}, [t, error])
|
|
27
|
+
|
|
28
|
+
return { hasInterrupt, meta, error }
|
|
29
|
+
}
|