@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.
Files changed (194) hide show
  1. package/build/dist/lib/index.debug.js +598 -136
  2. package/build/dist/lib/index.debug.min.js +1 -1
  3. package/build/dist/lib/index.debug.min.js.LICENSE.txt +190 -22
  4. package/build/dist/lib/index.js +4745 -4468
  5. package/build/dist/lib/index.min.js +1 -1
  6. package/build/dist/lib/index.min.js.LICENSE.txt +1 -1
  7. package/build/dist/lib/standalone.js +4839 -4465
  8. package/build/dist/lib/standalone.min.js +1 -1
  9. package/build/dist/lib/standalone.min.js.LICENSE.txt +1 -1
  10. package/build/dist/lib/style-guide.js +1770 -980
  11. package/build/dist/lib/style-guide.min.js +1 -1
  12. package/build/dist/lib/styles.css +1 -1
  13. package/build/dist/lib/utils.js +0 -1
  14. package/build/dist/lib/utils.min.js +1 -1
  15. package/package.json +29 -29
  16. package/src/javascripts/api/index.js +33 -48
  17. package/src/javascripts/api/producer.js +9 -12
  18. package/src/javascripts/config.js +9 -11
  19. package/src/javascripts/domains/app/actions.js +43 -0
  20. package/src/javascripts/domains/app/hooks.js +6 -0
  21. package/src/javascripts/domains/app/index.js +6 -0
  22. package/src/javascripts/domains/app/reducer.js +16 -0
  23. package/src/javascripts/domains/app/selectors.js +8 -0
  24. package/src/javascripts/domains/app/utils.js +4 -0
  25. package/src/javascripts/domains/config/actions.js +4 -0
  26. package/src/javascripts/domains/config/hooks.js +6 -0
  27. package/src/javascripts/domains/config/index.js +8 -0
  28. package/src/javascripts/domains/config/middleware.js +22 -0
  29. package/src/javascripts/domains/config/reducer.js +63 -0
  30. package/src/javascripts/domains/config/selectors.js +23 -0
  31. package/src/javascripts/domains/config/utils.js +4 -0
  32. package/src/javascripts/domains/forms/actions.js +2 -4
  33. package/src/javascripts/domains/forms/hooks.js +10 -14
  34. package/src/javascripts/domains/forms/provider.js +4 -6
  35. package/src/javascripts/domains/forms/reducer.js +1 -2
  36. package/src/javascripts/domains/forms/selectors.js +4 -4
  37. package/src/javascripts/domains/forms/utils.js +5 -0
  38. package/src/javascripts/domains/i18n/actions.js +35 -0
  39. package/src/javascripts/domains/i18n/hooks.js +38 -0
  40. package/src/javascripts/domains/i18n/index.js +5 -80
  41. package/src/javascripts/domains/i18n/reducer.js +58 -0
  42. package/src/javascripts/domains/i18n/selectors.js +15 -0
  43. package/src/javascripts/domains/i18n/utils.js +9 -0
  44. package/src/javascripts/domains/interrupt/actions.js +4 -0
  45. package/src/javascripts/domains/interrupt/hooks.js +29 -0
  46. package/src/javascripts/domains/interrupt/index.js +9 -0
  47. package/src/javascripts/domains/interrupt/middleware.js +30 -0
  48. package/src/javascripts/domains/interrupt/reducer.js +21 -0
  49. package/src/javascripts/domains/interrupt/selectors.js +6 -0
  50. package/src/javascripts/domains/interrupt/utils.js +4 -0
  51. package/src/javascripts/domains/options/index.js +1 -0
  52. package/src/javascripts/domains/options/middleware.js +35 -0
  53. package/src/javascripts/domains/redux/create-redux-store.js +14 -6
  54. package/src/javascripts/domains/redux/hooks.js +3 -2
  55. package/src/javascripts/domains/redux/index.js +2 -1
  56. package/src/javascripts/domains/redux/provider.js +5 -0
  57. package/src/javascripts/domains/store/index.js +44 -0
  58. package/src/javascripts/{ui → domains}/store/state-reducer.js +4 -7
  59. package/src/javascripts/domains/translations/actions.js +4 -6
  60. package/src/javascripts/domains/translations/components/chat-status.js +7 -13
  61. package/src/javascripts/domains/translations/components/options-button.js +3 -3
  62. package/src/javascripts/domains/translations/components/options-dialog/form.js +12 -7
  63. package/src/javascripts/domains/translations/components/options-dialog/index.js +2 -5
  64. package/src/javascripts/domains/translations/hooks.js +1 -1
  65. package/src/javascripts/domains/translations/index.js +1 -0
  66. package/src/javascripts/domains/translations/middleware.js +43 -0
  67. package/src/javascripts/domains/translations/reducer.js +4 -11
  68. package/src/javascripts/domains/translations/selectors.js +3 -3
  69. package/src/javascripts/domains/translations/utils.js +4 -0
  70. package/src/javascripts/index.js +20 -5
  71. package/src/javascripts/lib/css.js +5 -5
  72. package/src/javascripts/lib/engine/index.js +39 -11
  73. package/src/javascripts/lib/external-api/index.js +6 -6
  74. package/src/javascripts/lib/mutex.js +30 -0
  75. package/src/javascripts/lib/parse-body.js +1 -1
  76. package/src/javascripts/lib/redux-helpers/index.js +25 -8
  77. package/src/javascripts/lib/split-url-params.js +2 -2
  78. package/src/javascripts/lib/store/providers/app-storage.js +1 -1
  79. package/src/javascripts/lib/store/providers/cookie-storage.js +1 -1
  80. package/src/javascripts/package/utils.js +0 -1
  81. package/src/javascripts/style-guide/components/app.js +12 -14
  82. package/src/javascripts/style-guide/components/links.js +6 -6
  83. package/src/javascripts/style-guide/components/static-core.js +32 -10
  84. package/src/javascripts/style-guide/state-helpers/index.js +1 -1
  85. package/src/javascripts/style-guide/states.js +29 -71
  86. package/src/javascripts/style-guide/style-guide-engine.js +13 -12
  87. package/src/javascripts/ui/components/chat-app.js +2 -2
  88. package/src/javascripts/ui/components/conversation/component-filter.js +2 -2
  89. package/src/javascripts/ui/components/conversation/conversation.js +2 -2
  90. package/src/javascripts/ui/components/conversation/event/card-component.js +24 -3
  91. package/src/javascripts/ui/components/conversation/event/carousel-component/components/pagination.js +2 -2
  92. package/src/javascripts/ui/components/conversation/event/carousel-component/index.js +4 -3
  93. package/src/javascripts/ui/components/conversation/event/carousel-message/components/slide.js +2 -1
  94. package/src/javascripts/ui/components/conversation/event/carousel-message/index.js +2 -2
  95. package/src/javascripts/ui/components/conversation/event/choice-prompt.js +5 -5
  96. package/src/javascripts/ui/components/conversation/event/divider/variants/new-translation.js +2 -2
  97. package/src/javascripts/ui/components/conversation/event/event-participant.js +3 -5
  98. package/src/javascripts/ui/components/conversation/event/hooks/use-event-link-click-handler.js +2 -2
  99. package/src/javascripts/ui/components/conversation/event/hooks/use-formatted-date.js +3 -3
  100. package/src/javascripts/ui/components/conversation/event/hooks/use-text-rendering.js +3 -3
  101. package/src/javascripts/ui/components/conversation/event/participant.js +2 -2
  102. package/src/javascripts/ui/components/conversation/event/upload.js +12 -27
  103. package/src/javascripts/ui/components/conversation/message-container.js +4 -6
  104. package/src/javascripts/ui/components/core/seamly-activity-monitor.js +4 -5
  105. package/src/javascripts/ui/components/core/seamly-core.js +6 -7
  106. package/src/javascripts/ui/components/core/seamly-event-subscriber.js +18 -17
  107. package/src/javascripts/ui/components/core/seamly-file-upload.js +5 -6
  108. package/src/javascripts/ui/components/core/seamly-idle-detach-counter.js +2 -6
  109. package/src/javascripts/ui/components/core/seamly-initializer.js +7 -60
  110. package/src/javascripts/ui/components/core/seamly-instance-functions-loader.js +10 -16
  111. package/src/javascripts/ui/components/core/seamly-live-region.js +1 -1
  112. package/src/javascripts/ui/components/core/seamly-new-notifications.js +5 -6
  113. package/src/javascripts/ui/components/core/seamly-read-state.js +8 -6
  114. package/src/javascripts/ui/components/entry/entry-container.js +7 -10
  115. package/src/javascripts/ui/components/entry/text-entry/hooks.js +6 -4
  116. package/src/javascripts/ui/components/entry/text-entry/text-entry-form.js +10 -3
  117. package/src/javascripts/ui/components/entry/toggle-button.js +24 -10
  118. package/src/javascripts/ui/components/entry/upload/file-upload-form.js +6 -3
  119. package/src/javascripts/ui/components/entry/upload/index.js +11 -13
  120. package/src/javascripts/ui/components/faq/faq.js +6 -6
  121. package/src/javascripts/ui/components/form-controls/error.js +22 -0
  122. package/src/javascripts/ui/components/form-controls/file-input.js +3 -9
  123. package/src/javascripts/ui/components/form-controls/select.js +1 -1
  124. package/src/javascripts/ui/components/form-controls/wrapper.js +2 -9
  125. package/src/javascripts/ui/components/layout/agent-info.js +4 -4
  126. package/src/javascripts/ui/components/layout/app-frame.js +15 -12
  127. package/src/javascripts/ui/components/layout/chat-frame.js +3 -5
  128. package/src/javascripts/ui/components/layout/header.js +4 -18
  129. package/src/javascripts/ui/components/layout/interrupt.js +6 -2
  130. package/src/javascripts/ui/components/layout/privacy-disclaimer.js +2 -2
  131. package/src/javascripts/ui/components/options/cobrowsing.js +3 -7
  132. package/src/javascripts/ui/components/options/options-button.js +9 -13
  133. package/src/javascripts/ui/components/options/options-frame.js +1 -1
  134. package/src/javascripts/ui/components/options/transcript/index.js +2 -2
  135. package/src/javascripts/ui/components/options/transcript/transcript-form.js +1 -1
  136. package/src/javascripts/ui/components/warnings/cobrowsing-active-frame.js +3 -6
  137. package/src/javascripts/ui/components/warnings/idle-detach-warning.js +2 -6
  138. package/src/javascripts/ui/components/warnings/resume-conversation-prompt.js +1 -1
  139. package/src/javascripts/ui/components/widgets/in-out-transition.js +2 -2
  140. package/src/javascripts/ui/components/widgets/lightbox.js +4 -4
  141. package/src/javascripts/ui/components/widgets/modal.js +3 -3
  142. package/src/javascripts/ui/components/widgets/upload-progress.js +3 -14
  143. package/src/javascripts/ui/hooks/component-helper-hooks.js +4 -15
  144. package/src/javascripts/ui/hooks/file-upload-hooks.js +3 -3
  145. package/src/javascripts/ui/hooks/focus-helper-hooks.js +4 -4
  146. package/src/javascripts/ui/hooks/live-region-hooks.js +2 -2
  147. package/src/javascripts/ui/hooks/seamly-api-hooks.js +0 -6
  148. package/src/javascripts/ui/hooks/seamly-entry-hooks.js +22 -25
  149. package/src/javascripts/ui/hooks/seamly-hooks.js +3 -10
  150. package/src/javascripts/ui/hooks/seamly-option-hooks.js +4 -4
  151. package/src/javascripts/ui/hooks/seamly-state-hooks.js +8 -16
  152. package/src/javascripts/ui/hooks/use-event-component-mapping.js +1 -1
  153. package/src/javascripts/ui/hooks/use-seamly-chat.js +1 -0
  154. package/src/javascripts/ui/hooks/use-seamly-commands.js +31 -54
  155. package/src/javascripts/ui/hooks/use-seamly-idle-detach-countdown.js +3 -3
  156. package/src/javascripts/ui/hooks/use-seamly-stored-visibility.js +3 -3
  157. package/src/javascripts/ui/hooks/use-seamly-visibility.js +6 -8
  158. package/src/javascripts/ui/hooks/use-single-file-upload.js +4 -1
  159. package/src/javascripts/ui/hooks/utility-hooks.js +2 -2
  160. package/src/javascripts/ui/utils/form-utils.js +3 -3
  161. package/src/javascripts/ui/utils/general-utils.js +21 -22
  162. package/src/javascripts/ui/utils/seamly-utils.js +15 -83
  163. package/src/javascripts/ui/utils/validations.js +10 -7
  164. package/src/stylesheets/1-settings/_config.scss +2 -1
  165. package/src/stylesheets/3-app/_app.scss +3 -4
  166. package/src/stylesheets/5-components/_card.scss +0 -1
  167. package/src/stylesheets/5-components/_faq.scss +3 -8
  168. package/src/stylesheets/5-components/_message.scss +10 -0
  169. package/src/stylesheets/5-components/_modal.scss +3 -3
  170. package/src/stylesheets/5-components/_options.scss +3 -2
  171. package/webpack/config.common.js +3 -3
  172. package/webpack/config.package.js +4 -22
  173. package/webpack/config.site.js +8 -6
  174. package/webpack/defaults.js +0 -3
  175. package/CHANGELOG.md +0 -561
  176. package/build/dist/translations/de-informal.js +0 -275
  177. package/build/dist/translations/de-informal.min.js +0 -1
  178. package/build/dist/translations/en.js +0 -275
  179. package/build/dist/translations/en.min.js +0 -1
  180. package/build/dist/translations/es-informal.js +0 -281
  181. package/build/dist/translations/es-informal.min.js +0 -1
  182. package/build/dist/translations/nl-formal.js +0 -275
  183. package/build/dist/translations/nl-formal.min.js +0 -1
  184. package/build/dist/translations/nl-informal.js +0 -275
  185. package/build/dist/translations/nl-informal.min.js +0 -1
  186. package/src/javascripts/lib/i18n.js +0 -46
  187. package/src/javascripts/ui/components/core/seamly-api.js +0 -44
  188. package/src/javascripts/ui/hooks/use-seamly-interrupt.js +0 -62
  189. package/src/javascripts/ui/store/index.js +0 -37
  190. package/translations/de-informal.js +0 -237
  191. package/translations/en.js +0 -234
  192. package/translations/es-informal.js +0 -243
  193. package/translations/nl-formal.js +0 -230
  194. package/translations/nl-informal.js +0 -230
@@ -0,0 +1,30 @@
1
+ import SeamlyGeneralError from '../../api/errors/seamly-general-error'
2
+ import SeamlyConfigurationError from '../../api/errors/seamly-configuration-error'
3
+ import SeamlySessionExpiredError from '../../api/errors/seamly-session-expired-error'
4
+ import SeamlyOfflineError from '../../api/errors/seamly-offline-error'
5
+ import SeamlyUnauthorizedError from '../../api/errors/seamly-unauthorized-error'
6
+ import * as Actions from './actions'
7
+
8
+ const handledErrorTypes = [
9
+ SeamlyGeneralError,
10
+ SeamlyConfigurationError,
11
+ SeamlySessionExpiredError,
12
+ SeamlyOfflineError,
13
+ SeamlyUnauthorizedError,
14
+ ]
15
+
16
+ export default function createMiddleware() {
17
+ return () => (next) => (action) => {
18
+ if (action.type === String(Actions.set)) {
19
+ if (
20
+ !handledErrorTypes.some(
21
+ (ErrorType) => action.error instanceof ErrorType,
22
+ )
23
+ ) {
24
+ throw action.error
25
+ }
26
+ }
27
+
28
+ return next(action)
29
+ }
30
+ }
@@ -0,0 +1,21 @@
1
+ import { createReducer } from './utils'
2
+ import * as Actions from './actions'
3
+
4
+ const initialState = {
5
+ error: undefined,
6
+ }
7
+
8
+ export default createReducer(
9
+ {
10
+ [Actions.set]: (state, { error }) => {
11
+ return {
12
+ ...state,
13
+ error,
14
+ }
15
+ },
16
+ [Actions.clear]: () => {
17
+ return initialState
18
+ },
19
+ },
20
+ initialState,
21
+ )
@@ -0,0 +1,6 @@
1
+ import { createSelector } from 'reselect'
2
+ import { selectState } from './utils'
3
+
4
+ export const selectError = createSelector(selectState, ({ error }) => error)
5
+
6
+ export { selectState }
@@ -0,0 +1,4 @@
1
+ import { createDomain } from '../../lib/redux-helpers'
2
+
3
+ export const { createAction, createReducer, selectState } =
4
+ createDomain('interrupt')
@@ -0,0 +1 @@
1
+ export { default as createMiddleware } from './middleware'
@@ -0,0 +1,35 @@
1
+ import { featureKeys, seamlyActions } from '../../ui/utils/seamly-utils'
2
+ import { Actions as InterruptActions } from '../interrupt'
3
+ import SeamlyOfflineError from '../../api/errors/seamly-offline-error'
4
+
5
+ export default function createMiddleware({ api }) {
6
+ return ({ dispatch }) =>
7
+ (next) =>
8
+ (action) => {
9
+ const result = next(action)
10
+
11
+ switch (action.type) {
12
+ // This is needed for backwards compatibility. If there's an error,
13
+ // Cobrowsing has to be disabled in order to not "re-start" into co-browsing
14
+ case String(InterruptActions.set):
15
+ if (!(action.error instanceof SeamlyOfflineError)) {
16
+ dispatch({
17
+ type: seamlyActions.SET_USER_SELECTED_OPTION,
18
+ option: featureKeys.cobrowsing,
19
+ value: false,
20
+ })
21
+ }
22
+ break
23
+ case seamlyActions.SET_USER_SELECTED_OPTIONS:
24
+ api.store.set('options', action.options)
25
+ break
26
+ case seamlyActions.SET_USER_SELECTED_OPTION:
27
+ api.store.set('options', {
28
+ ...(api.store.get('options') || {}),
29
+ [action.option]: action.value,
30
+ })
31
+ break
32
+ }
33
+ return result
34
+ }
35
+ }
@@ -1,13 +1,21 @@
1
- import { combineReducers, createStore } from 'redux'
1
+ import { combineReducers, createStore, applyMiddleware, compose } from 'redux'
2
2
 
3
- let enhancer
3
+ let composeEnhancers = compose
4
4
  if (process.env.NODE_ENV === 'development') {
5
5
  /* eslint-disable no-underscore-dangle */
6
- enhancer =
7
- typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__?.()
6
+ composeEnhancers =
7
+ window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || composeEnhancers
8
8
  /* eslint-enable no-underscore-dangle */
9
9
  }
10
10
 
11
- export default function createReduxStore(reducers = {}, initialState = {}) {
12
- return createStore(combineReducers(reducers), initialState, enhancer)
11
+ export default function createReduxStore({
12
+ reducers = {},
13
+ initialState = {},
14
+ middlewares = [],
15
+ } = {}) {
16
+ return createStore(
17
+ combineReducers(reducers),
18
+ initialState,
19
+ composeEnhancers(applyMiddleware(...middlewares)),
20
+ )
13
21
  }
@@ -19,13 +19,14 @@ export function useStoreDispatch() {
19
19
  export function useSelector(selector, deps = []) {
20
20
  const store = useStoreContext()
21
21
  // we need a force-update because we're manually updating a ref instead of a useState
22
- const [, forceUpdate] = useReducer(x => x + 1, 0)
22
+ const [, forceUpdate] = useReducer((x) => x + 1, 0)
23
23
  // we're keeping the value to compare against
24
24
  const valueRef = useRef()
25
25
 
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
@@ -74,6 +75,6 @@ export const useSelectorWithProps = function useSelectorWithProps(
74
75
  // equalityFn = arrayContentEquals,
75
76
  ) {
76
77
  // eslint-disable-next-line react-hooks/exhaustive-deps
77
- const wrappedMapper = useCallback(state => selector(state, props), inputs)
78
+ const wrappedMapper = useCallback((state) => selector(state, props), inputs)
78
79
  return useSelector(wrappedMapper, inputs)
79
80
  }
@@ -1,4 +1,5 @@
1
- import StoreContext, { Provider as StoreProvider } from './context'
1
+ import StoreContext from './context'
2
+ import StoreProvider from './provider'
2
3
  import createReduxStore from './create-redux-store'
3
4
  import {
4
5
  useStoreContext,
@@ -0,0 +1,5 @@
1
+ import { Provider } from './context'
2
+
3
+ export default function StoreProvider({ store, children }) {
4
+ return <Provider value={store}>{children}</Provider>
5
+ }
@@ -0,0 +1,44 @@
1
+ import thunkMiddleware from 'redux-thunk'
2
+ import { createReduxStore } from '../redux'
3
+ import { Reducer as appReducer } from '../app'
4
+ import {
5
+ createMiddleware as createConfigMiddleware,
6
+ Reducer as configReducer,
7
+ } from '../config'
8
+ import { Reducer as formReducer } from '../forms'
9
+ import {
10
+ Reducer as translationsReducer,
11
+ createMiddleware as createI18nMiddleware,
12
+ } from '../translations'
13
+ import { Reducer as i18nReducer } from '../i18n'
14
+ import {
15
+ Reducer as interruptReducer,
16
+ createMiddleware as createInterruptMiddleware,
17
+ } from '../interrupt'
18
+ import { createMiddleware as createOptionsMiddleware } from '../options'
19
+ import stateReducer from './state-reducer'
20
+
21
+ export function createStore({ initialState, api } = {}) {
22
+ const store = createReduxStore({
23
+ reducers: {
24
+ state: stateReducer,
25
+ [String(appReducer)]: appReducer,
26
+ [String(configReducer)]: configReducer,
27
+ [String(formReducer)]: formReducer,
28
+ [String(translationsReducer)]: translationsReducer,
29
+ [String(i18nReducer)]: i18nReducer,
30
+ [String(interruptReducer)]: interruptReducer,
31
+ },
32
+ initialState,
33
+ middlewares: [
34
+ thunkMiddleware.withExtraArgument({
35
+ api,
36
+ }),
37
+ createConfigMiddleware(),
38
+ createInterruptMiddleware(),
39
+ createOptionsMiddleware({ api }),
40
+ createI18nMiddleware(),
41
+ ],
42
+ })
43
+ return store
44
+ }
@@ -1,13 +1,14 @@
1
+ // Legacy state reducer. Do not add new features here but extract/create new reducers as needed
2
+
1
3
  import { randomId } from '../../lib/id'
2
4
  import {
3
5
  entryTypes,
4
6
  seamlyStateReducer,
5
7
  visibilityStates,
6
- } from '../utils/seamly-utils'
8
+ } from '../../ui/utils/seamly-utils'
7
9
 
8
10
  const initialState = {
9
11
  events: [],
10
- config: { hideOnNoUserResponse: false },
11
12
  initialState: {},
12
13
  unreadEvents: 0,
13
14
  isLoading: false,
@@ -25,15 +26,11 @@ const initialState = {
25
26
  title: null,
26
27
  subTitle: '',
27
28
  },
28
- interrupt: {
29
- hasInterrupt: false,
30
- meta: {},
31
- },
32
29
  historyLoaded: false,
33
30
  skiplinkTargetId: randomId(),
34
31
  optionsButtonId: randomId(),
35
32
  cobrowsingContainerId: randomId(),
36
- showDisclaimer: false,
33
+ headerCollapseButtonId: randomId(),
37
34
  serviceData: {},
38
35
  options: {
39
36
  features: {},
@@ -1,13 +1,11 @@
1
- import { createDomain } from '../../lib/redux-helpers'
2
-
3
- const { createActions } = createDomain('translations')
1
+ import { createActions } from './utils'
4
2
 
5
3
  export const [enable, disable] = createActions('translate', {
6
- enable: locale => ({ locale }),
4
+ enable: (locale) => ({ locale }),
7
5
  disable: () => ({}),
8
6
  })
9
7
 
10
8
  export const [enableEvent, disableEvent] = createActions('event', {
11
- enable: payloadId => ({ payloadId }),
12
- disable: payloadId => ({ payloadId }),
9
+ enable: (payloadId) => ({ payloadId }),
10
+ disable: (payloadId) => ({ payloadId }),
13
11
  })
@@ -1,27 +1,21 @@
1
1
  import { useCallback, useMemo } from 'preact/hooks'
2
2
  import ChatStatus from '../../../ui/components/chat-status'
3
3
  import { useI18n } from '../../i18n'
4
- import {
5
- useSeamlyInterrupt,
6
- useSkiplinkTargetFocusing,
7
- } from '../../../ui/hooks/seamly-hooks'
4
+ import { useSkiplinkTargetFocusing } from '../../../ui/hooks/seamly-hooks'
8
5
  import { useTranslationsContainer, useTranslations } from '../hooks'
6
+ import { useInterrupt } from '../../interrupt'
9
7
 
10
8
  export default function TranslationsChatStatus() {
11
9
  const { t } = useI18n()
12
10
  const { id } = useTranslationsContainer()
13
- const { hasInterrupt } = useSeamlyInterrupt()
11
+ const { hasInterrupt } = useInterrupt()
14
12
 
15
- const {
16
- isActive,
17
- disableTranslations,
18
- languages,
19
- currentLocale,
20
- } = useTranslations()
13
+ const { isActive, disableTranslations, languages, currentLocale } =
14
+ useTranslations()
21
15
  const focusSkiplinkTarget = useSkiplinkTargetFocusing()
22
16
 
23
17
  const languageName = useMemo(() => {
24
- return languages?.find(lang => lang.locale === currentLocale)?.nativeName
18
+ return languages?.find((lang) => lang.locale === currentLocale)?.nativeName
25
19
  }, [languages, currentLocale])
26
20
 
27
21
  const handleClickStop = useCallback(() => {
@@ -37,7 +31,7 @@ export default function TranslationsChatStatus() {
37
31
  <ChatStatus
38
32
  type="translations"
39
33
  id={id}
40
- label={t('translations.status.label', languageName)}
34
+ label={t('translations.status.label', { language: languageName })}
41
35
  onButtonClick={handleClickStop}
42
36
  buttonText={t('translations.status.stopText')}
43
37
  srButtonText={t('translations.status.srStopText')}
@@ -15,7 +15,7 @@ export default function TranslationsOptionButton() {
15
15
  const toggleButton = useRef(null)
16
16
  const toggleButtonId = useGeneratedId()
17
17
 
18
- const onMainKeyDownHandler = e => {
18
+ const onMainKeyDownHandler = (e) => {
19
19
  if (!menuIsOpen) {
20
20
  return
21
21
  }
@@ -31,9 +31,9 @@ export default function TranslationsOptionButton() {
31
31
  }
32
32
 
33
33
  const handleToggleClick = () => {
34
- setMenuIsOpen(o => !o)
34
+ setMenuIsOpen((o) => !o)
35
35
  }
36
- const handleToggleKeyDown = e => {
36
+ const handleToggleKeyDown = (e) => {
37
37
  if (getKey(e) === keyNames.ArrowDown) {
38
38
  setMenuIsOpen(true)
39
39
  e.preventDefault()
@@ -8,20 +8,25 @@ 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
- return languages?.find(lang => lang.locale === currentLocale)?.nativeName
13
+ return languages?.find((lang) => lang.locale === currentLocale)?.nativeName
14
14
  }, [languages, currentLocale])
15
15
 
16
16
  const options = useMemo(() => {
17
17
  return [
18
18
  { value: '', label: t('translations.settings.defaultOptionLabel') },
19
- ...languages.map(language => ({
20
- value: language.locale,
21
- label: language.nativeName,
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">
@@ -14,11 +14,8 @@ export const inputName = 'locale'
14
14
  function TranslationsOptionsDialog({ onClose }) {
15
15
  const { t } = useI18n()
16
16
 
17
- const {
18
- isActive,
19
- enableTranslations,
20
- disableTranslations,
21
- } = useTranslations()
17
+ const { isActive, enableTranslations, disableTranslations } =
18
+ useTranslations()
22
19
 
23
20
  const descriptionId = useGeneratedId()
24
21
  const { focusContainer } = useTranslationsContainer()
@@ -12,7 +12,7 @@ export function useTranslations() {
12
12
  const { sendAction } = useSeamlyCommands()
13
13
  const dispatch = useStoreDispatch()
14
14
  const enableTranslations = useStableCallback(
15
- locale => {
15
+ (locale) => {
16
16
  sendAction({
17
17
  type: actionTypes.setTranslation,
18
18
  body: { enabled: true, locale },
@@ -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 '../../lib/redux-helpers'
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
- [seamlyActions.SET_HISTORY]: (state, { history }) => {
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 {
@@ -42,7 +35,7 @@ export default createReducer(
42
35
  currentLocale: locale,
43
36
  }
44
37
  },
45
- [Actions.disable]: state => {
38
+ [Actions.disable]: (state) => {
46
39
  return {
47
40
  ...state,
48
41
  isActive: false,
@@ -56,7 +49,7 @@ export default createReducer(
56
49
  return {
57
50
  ...state,
58
51
  originalPayloadIds: state.originalPayloadIds.filter(
59
- id => id !== payloadId,
52
+ (id) => id !== payloadId,
60
53
  ),
61
54
  }
62
55
  },
@@ -1,12 +1,12 @@
1
1
  import { createSelector } from 'reselect'
2
2
  import { getPropSelector } from '../redux/utils'
3
- import Reducer from './reducer'
3
+ import { selectState } from './utils'
4
4
 
5
- export const getState = state => state[String(Reducer)]
5
+ export const getState = selectState
6
6
 
7
7
  export const getOriginalPayloadIds = createSelector(
8
8
  getState,
9
- state => state.originalPayloadIds,
9
+ (state) => state.originalPayloadIds,
10
10
  )
11
11
 
12
12
  export const getIsPayloadTranslated = createSelector(
@@ -0,0 +1,4 @@
1
+ import { createDomain } from '../../lib/redux-helpers'
2
+
3
+ export const { createActions, createReducer, selectState } =
4
+ createDomain('translations')
@@ -41,9 +41,6 @@ export { eventTypes } from './ui/utils/seamly-utils'
41
41
  // Used by: StyleGuide
42
42
  export { default as ExternalApi } from './lib/external-api'
43
43
 
44
- // Used by: StyleGuide
45
- export { getSeamlyConfig } from './ui/utils/seamly-utils'
46
-
47
44
  // Used by: StyleGuide
48
45
  export { getUrlParams } from './ui/utils/general-utils'
49
46
 
@@ -78,7 +75,7 @@ export { SeamlyEventBusContext } from './ui/components/core/seamly-api-context'
78
75
  export { SeamlyLiveRegionContext } from './ui/components/core/seamly-live-region-context'
79
76
 
80
77
  // Used by: StyleGuide
81
- export { default as StoreProvider } from './ui/store'
78
+ export { StoreProvider } from './domains/redux'
82
79
 
83
80
  // Used by: Client
84
81
  export { useChoicePrompt } from './ui/components/conversation/event/choice-prompt'
@@ -93,7 +90,7 @@ export { useSeamlyChat } from './ui/hooks/seamly-hooks'
93
90
  export { useSeamlyCommands } from './ui/hooks/seamly-hooks'
94
91
 
95
92
  // Used by: Client
96
- export { useSeamlyConfig } from './ui/hooks/seamly-hooks'
93
+ export { useConfig as useSeamlyConfig } from './domains/config'
97
94
 
98
95
  // Used by: Client
99
96
  export { useEvents } from './ui/hooks/seamly-hooks'
@@ -139,3 +136,21 @@ export { default as View } from './ui/components/layout/view'
139
136
  // Used by: Client
140
137
  // Used by: StyleGuide
141
138
  export { visibilityStates } from './ui/utils/seamly-utils'
139
+
140
+ // Used by: StyleGuide
141
+ export { API } from './api'
142
+
143
+ // Used by: StyleGuide
144
+ export { default as SeamlyGeneralError } from './api/errors/seamly-general-error'
145
+
146
+ // Used by: StyleGuide
147
+ export { default as SeamlyConfigurationError } from './api/errors/seamly-configuration-error'
148
+
149
+ // Used by: StyleGuide
150
+ export { default as SeamlySessionExpiredError } from './api/errors/seamly-session-expired-error'
151
+
152
+ // Used by: StyleGuide
153
+ export { default as SeamlyOfflineError } from './api/errors/seamly-offline-error'
154
+
155
+ // Used by: StyleGuide
156
+ export { default as SeamlyUnauthorizedError } from './api/errors/seamly-unauthorized-error'
@@ -10,7 +10,7 @@ import { CSS_NAME } from '../config'
10
10
  export const className = (...classes) =>
11
11
  classes
12
12
  .flat()
13
- .map(c => {
13
+ .map((c) => {
14
14
  if (typeof c === 'object') {
15
15
  return Object.entries(c)
16
16
  .map(([key, value]) => (value ? key : ''))
@@ -18,9 +18,9 @@ export const className = (...classes) =>
18
18
  }
19
19
  return c
20
20
  })
21
- .filter(c => typeof c === 'string')
22
- .map(c => c.split(' '))
21
+ .filter((c) => typeof c === 'string')
22
+ .map((c) => c.split(' '))
23
23
  .flat()
24
- .filter(c => c.length)
25
- .map(c => [CSS_NAME, c].join('-'))
24
+ .filter((c) => c.length)
25
+ .map((c) => [CSS_NAME, c].join('-'))
26
26
  .join(' ')