@seamly/web-ui 18.1.1 → 18.3.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 +286 -99
- package/build/dist/lib/index.debug.min.js +1 -1
- package/build/dist/lib/index.debug.min.js.LICENSE.txt +84 -16
- package/build/dist/lib/index.js +4104 -3887
- package/build/dist/lib/index.min.js +1 -1
- package/build/dist/lib/standalone.js +4351 -4084
- package/build/dist/lib/standalone.min.js +1 -1
- package/build/dist/lib/style-guide.js +746 -641
- 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/build/dist/translations/de-informal.js +0 -1
- package/build/dist/translations/de-informal.min.js +1 -1
- package/build/dist/translations/en.js +0 -1
- package/build/dist/translations/en.min.js +1 -1
- package/build/dist/translations/es-informal.js +0 -1
- package/build/dist/translations/es-informal.min.js +1 -1
- package/build/dist/translations/nl-formal.js +0 -1
- package/build/dist/translations/nl-formal.min.js +1 -1
- package/build/dist/translations/nl-informal.js +0 -1
- package/build/dist/translations/nl-informal.min.js +1 -1
- package/package.json +4 -2
- package/src/javascripts/api/index.js +9 -9
- package/src/javascripts/api/producer.js +8 -8
- package/src/javascripts/config.js +9 -11
- package/src/javascripts/domains/app/actions.js +25 -0
- package/src/javascripts/domains/app/index.js +3 -0
- package/src/javascripts/domains/config/actions.js +6 -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 +26 -0
- package/src/javascripts/domains/config/reducer.js +74 -0
- package/src/javascripts/domains/config/selectors.js +23 -0
- package/src/javascripts/domains/forms/actions.js +1 -1
- package/src/javascripts/domains/forms/hooks.js +10 -14
- package/src/javascripts/domains/forms/provider.js +4 -6
- package/src/javascripts/domains/forms/selectors.js +3 -3
- package/src/javascripts/domains/i18n/index.js +9 -5
- package/src/javascripts/domains/interrupt/actions.js +6 -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 +22 -0
- package/src/javascripts/domains/interrupt/selectors.js +5 -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 +2 -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 +38 -0
- package/src/javascripts/{ui → domains}/store/state-reducer.js +4 -7
- package/src/javascripts/domains/translations/actions.js +3 -3
- package/src/javascripts/domains/translations/components/chat-status.js +6 -12
- package/src/javascripts/domains/translations/components/options-button.js +3 -3
- package/src/javascripts/domains/translations/components/options-dialog/form.js +2 -2
- 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/reducer.js +2 -2
- package/src/javascripts/domains/translations/selectors.js +2 -2
- package/src/javascripts/index.js +17 -5
- package/src/javascripts/lib/css.js +5 -5
- package/src/javascripts/lib/engine/index.js +38 -11
- package/src/javascripts/lib/external-api/index.js +6 -6
- package/src/javascripts/lib/i18n.js +2 -2
- package/src/javascripts/lib/parse-body.js +1 -1
- package/src/javascripts/lib/redux-helpers/index.js +18 -4
- 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 +5 -12
- package/src/javascripts/style-guide/components/links.js +6 -6
- package/src/javascripts/style-guide/components/static-core.js +23 -7
- package/src/javascripts/style-guide/state-helpers/index.js +1 -1
- package/src/javascripts/style-guide/states.js +27 -67
- package/src/javascripts/style-guide/style-guide-engine.js +1 -1
- 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 +29 -4
- 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 +11 -6
- package/src/javascripts/ui/components/conversation/event/cta.js +1 -6
- package/src/javascripts/ui/components/conversation/event/divider/variants/new-translation.js +1 -1
- 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 +16 -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 -10
- package/src/javascripts/ui/components/core/seamly-live-region.js +1 -1
- package/src/javascripts/ui/components/core/seamly-new-notifications.js +1 -1
- package/src/javascripts/ui/components/core/seamly-read-state.js +2 -2
- package/src/javascripts/ui/components/entry/entry-container.js +7 -10
- package/src/javascripts/ui/components/entry/toggle-button.js +24 -10
- package/src/javascripts/ui/components/entry/upload/index.js +4 -11
- package/src/javascripts/ui/components/faq/faq.js +4 -4
- 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 +5 -5
- 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/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/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 +2 -13
- 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-entry-hooks.js +7 -6
- package/src/javascripts/ui/hooks/seamly-hooks.js +3 -9
- 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 +27 -49
- 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 +3 -3
- 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 +17 -11
- package/src/javascripts/ui/utils/seamly-utils.js +15 -83
- package/src/javascripts/ui/utils/validations.js +10 -7
- package/src/stylesheets/5-components/_card.scss +0 -1
- package/src/stylesheets/5-components/_choice-prompt.scss +5 -0
- package/src/stylesheets/5-components/_message.scss +10 -0
- package/src/stylesheets/5-components/_options.scss +3 -2
- package/translations/de-informal.js +0 -2
- package/translations/en.js +0 -2
- package/translations/es-informal.js +0 -2
- package/translations/nl-formal.js +0 -2
- package/translations/nl-informal.js +0 -2
- package/webpack/config.common.js +3 -3
- package/webpack/config.package.js +4 -4
- package/webpack/config.site.js +8 -6
- package/CHANGELOG.md +0 -551
- 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
|
@@ -106,7 +106,7 @@ export class API {
|
|
|
106
106
|
this.internalProducer = new EventProducer('API')
|
|
107
107
|
this.internal$ = xs.create(this.internalProducer).flatten()
|
|
108
108
|
this.connection$ = this.internal$.filter(
|
|
109
|
-
event => event.type === 'connection',
|
|
109
|
+
(event) => event.type === 'connection',
|
|
110
110
|
)
|
|
111
111
|
|
|
112
112
|
this.connection$.subscribe({
|
|
@@ -316,7 +316,7 @@ export class API {
|
|
|
316
316
|
.set('Authorization', `Bearer ${this.getAccessToken()}`)
|
|
317
317
|
.send(formData)
|
|
318
318
|
|
|
319
|
-
req.on('progress', function(e) {
|
|
319
|
+
req.on('progress', function (e) {
|
|
320
320
|
const { direction, percent } = e
|
|
321
321
|
if (direction === 'upload' && typeof progressCallback === 'function') {
|
|
322
322
|
progressCallback(percent)
|
|
@@ -324,12 +324,12 @@ export class API {
|
|
|
324
324
|
})
|
|
325
325
|
|
|
326
326
|
req
|
|
327
|
-
.then(uploadResponse => {
|
|
327
|
+
.then((uploadResponse) => {
|
|
328
328
|
if (successCallback) {
|
|
329
329
|
successCallback(uploadResponse)
|
|
330
330
|
}
|
|
331
331
|
})
|
|
332
|
-
.catch(err => {
|
|
332
|
+
.catch((err) => {
|
|
333
333
|
if (errorCallback) {
|
|
334
334
|
errorCallback(err.response)
|
|
335
335
|
} else {
|
|
@@ -353,7 +353,7 @@ export class API {
|
|
|
353
353
|
this.updateUrls(body)
|
|
354
354
|
return { accountConfig: body.config }
|
|
355
355
|
})
|
|
356
|
-
.catch(error => {
|
|
356
|
+
.catch((error) => {
|
|
357
357
|
if (error.status === 404) {
|
|
358
358
|
throw new SeamlyConfigurationError()
|
|
359
359
|
}
|
|
@@ -377,7 +377,7 @@ export class API {
|
|
|
377
377
|
|
|
378
378
|
return { initialState }
|
|
379
379
|
})
|
|
380
|
-
.catch(error => {
|
|
380
|
+
.catch((error) => {
|
|
381
381
|
if (error.status === 401) {
|
|
382
382
|
throw new SeamlyUnauthorizedError()
|
|
383
383
|
}
|
|
@@ -398,7 +398,7 @@ export class API {
|
|
|
398
398
|
promiseArray.push(this.getConversationIntitialState())
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
-
return Promise.all(promiseArray).then(responses => {
|
|
401
|
+
return Promise.all(promiseArray).then((responses) => {
|
|
402
402
|
const config = responses.reduce(
|
|
403
403
|
(configObj, partialConfig) => ({
|
|
404
404
|
...configObj,
|
|
@@ -415,7 +415,7 @@ export class API {
|
|
|
415
415
|
if (!this.connected || (waitForReady && !this.ready)) {
|
|
416
416
|
// Wait for connection
|
|
417
417
|
this.connection$
|
|
418
|
-
.filter(e => (waitForReady ? e.connected && e.ready : e.connected))
|
|
418
|
+
.filter((e) => (waitForReady ? e.connected && e.ready : e.connected))
|
|
419
419
|
.take(1)
|
|
420
420
|
.subscribe({
|
|
421
421
|
next: () => this.send(command, payload, waitForReady),
|
|
@@ -471,6 +471,6 @@ export class API {
|
|
|
471
471
|
}
|
|
472
472
|
|
|
473
473
|
stream() {
|
|
474
|
-
return this.internal$.filter(event => event.type !== 'connection')
|
|
474
|
+
return this.internal$.filter((event) => event.type !== 'connection')
|
|
475
475
|
}
|
|
476
476
|
}
|
|
@@ -17,7 +17,7 @@ export default class ConversationProducer {
|
|
|
17
17
|
|
|
18
18
|
this.connect()
|
|
19
19
|
|
|
20
|
-
this.socket.onError(err => {
|
|
20
|
+
this.socket.onError((err) => {
|
|
21
21
|
log('[SOCKET][ERROR]', err)
|
|
22
22
|
this.emit({
|
|
23
23
|
type: 'error',
|
|
@@ -34,7 +34,7 @@ export default class ConversationProducer {
|
|
|
34
34
|
})
|
|
35
35
|
})
|
|
36
36
|
|
|
37
|
-
this.channel.on('system', msg => {
|
|
37
|
+
this.channel.on('system', (msg) => {
|
|
38
38
|
switch (msg.type) {
|
|
39
39
|
case 'join_conversation_succeeded':
|
|
40
40
|
this.emit({ type: 'connection', connected: true, ready: true })
|
|
@@ -42,17 +42,17 @@ export default class ConversationProducer {
|
|
|
42
42
|
}
|
|
43
43
|
})
|
|
44
44
|
|
|
45
|
-
this.socket.onClose(msg => {
|
|
45
|
+
this.socket.onClose((msg) => {
|
|
46
46
|
log('[SOCKET]CLOSE')
|
|
47
47
|
this.emit({ type: 'connection', connected: false, ready: false })
|
|
48
48
|
})
|
|
49
49
|
|
|
50
|
-
this.channel.onClose(msg => {
|
|
50
|
+
this.channel.onClose((msg) => {
|
|
51
51
|
log('[CHANNEL]CLOSE')
|
|
52
52
|
this.emit({ type: 'connection', connected: false, ready: false })
|
|
53
53
|
})
|
|
54
54
|
|
|
55
|
-
this.channel.onError(msg => {
|
|
55
|
+
this.channel.onError((msg) => {
|
|
56
56
|
log('[CHANNEL][ERROR]', msg)
|
|
57
57
|
this.emit({ type: 'connection', connected: false, ready: false })
|
|
58
58
|
})
|
|
@@ -77,7 +77,7 @@ export default class ConversationProducer {
|
|
|
77
77
|
log('[CHANNEL][JOIN] OK')
|
|
78
78
|
this.emit({ type: 'connection', connected: true, ready: false })
|
|
79
79
|
})
|
|
80
|
-
.receive('error', err => {
|
|
80
|
+
.receive('error', (err) => {
|
|
81
81
|
log('[CHANNEL][JOIN] ERROR', err)
|
|
82
82
|
|
|
83
83
|
this.emit({ type: 'error', payload: { type: 'join_channel_erred' } })
|
|
@@ -105,13 +105,13 @@ export default class ConversationProducer {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
disconnect() {
|
|
108
|
-
return new Promise(resolve => {
|
|
108
|
+
return new Promise((resolve) => {
|
|
109
109
|
this.socket.disconnect(resolve)
|
|
110
110
|
})
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
listenTo(type, transform = null) {
|
|
114
|
-
this.channel.on(type, msg => {
|
|
114
|
+
this.channel.on(type, (msg) => {
|
|
115
115
|
log('[RECEIVE]', type, msg)
|
|
116
116
|
this.emit({
|
|
117
117
|
type,
|
|
@@ -2,17 +2,6 @@ export const CSS_NAME = 'cvco'
|
|
|
2
2
|
|
|
3
3
|
export const apiVersion = '2'
|
|
4
4
|
|
|
5
|
-
export const layoutMode = 'window' // "window", "inline" ("sidebar"), "modal"
|
|
6
|
-
|
|
7
|
-
export const appContainerClassNames = config => [
|
|
8
|
-
`app--layout-${config.layoutMode}`,
|
|
9
|
-
`namespace--${config.namespace}`,
|
|
10
|
-
]
|
|
11
|
-
|
|
12
|
-
export const typing = {
|
|
13
|
-
timeout: 2000, // How long to wait before we decide the user isn't typing
|
|
14
|
-
}
|
|
15
|
-
|
|
16
5
|
export const userParticipantId = 'seamly-client-participant'
|
|
17
6
|
|
|
18
7
|
// How long to debounce distinct changes in unread messages for before
|
|
@@ -32,6 +21,8 @@ export const maxCharacterSrDebounceDelay = 300
|
|
|
32
21
|
export const defaultTransitionTimeMs = 300
|
|
33
22
|
|
|
34
23
|
export const defaultConfig = {
|
|
24
|
+
namespace: 'default',
|
|
25
|
+
layoutMode: 'window', // "window", "inline" ("sidebar"), "modal"
|
|
35
26
|
messages: {
|
|
36
27
|
agent: {
|
|
37
28
|
showAvatar: false, // true, "inline"
|
|
@@ -46,4 +37,11 @@ export const defaultConfig = {
|
|
|
46
37
|
threshold: 3600000, // Default threshold is an hour in milliseconds
|
|
47
38
|
},
|
|
48
39
|
},
|
|
40
|
+
typing: {
|
|
41
|
+
timeout: 2000, // How long to wait before we decide the user isn't typing
|
|
42
|
+
},
|
|
43
|
+
appContainerClassNames: (config) => [
|
|
44
|
+
`app--layout-${config.layoutMode}`,
|
|
45
|
+
`namespace--${config.namespace}`,
|
|
46
|
+
],
|
|
49
47
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { seamlyActions } from '../../ui/utils/seamly-utils'
|
|
2
|
+
import { createDomain } from '../../lib/redux-helpers'
|
|
3
|
+
import { Actions as ConfigActions } from '../config'
|
|
4
|
+
import { Actions as InterruptActions } from '../interrupt'
|
|
5
|
+
|
|
6
|
+
const { createThunk } = createDomain('app')
|
|
7
|
+
|
|
8
|
+
export const initialize = createThunk(
|
|
9
|
+
'initialize',
|
|
10
|
+
(config) =>
|
|
11
|
+
async (dispatch, getState, { api }) => {
|
|
12
|
+
try {
|
|
13
|
+
dispatch(ConfigActions.initialize(config))
|
|
14
|
+
|
|
15
|
+
const { accountConfig = {}, initialState = {} } = await api.getConfig()
|
|
16
|
+
const { features } = accountConfig || {}
|
|
17
|
+
|
|
18
|
+
dispatch({ type: seamlyActions.SET_FEATURES, features })
|
|
19
|
+
|
|
20
|
+
dispatch({ type: seamlyActions.SET_INITIAL_STATE, initialState })
|
|
21
|
+
} catch (error) {
|
|
22
|
+
dispatch(InterruptActions.set(error))
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { initI18n } from '../i18n'
|
|
2
|
+
import * as Actions from './actions'
|
|
3
|
+
import { seamlyActions } from '../../ui/utils/seamly-utils'
|
|
4
|
+
|
|
5
|
+
export default function createMiddleware() {
|
|
6
|
+
return ({ dispatch }) =>
|
|
7
|
+
(next) =>
|
|
8
|
+
(action) => {
|
|
9
|
+
const result = next(action)
|
|
10
|
+
|
|
11
|
+
switch (action.type) {
|
|
12
|
+
case String(Actions.initialize):
|
|
13
|
+
case String(Actions.update):
|
|
14
|
+
if (action?.config?.translations) {
|
|
15
|
+
dispatch(initI18n(action.config.translations))
|
|
16
|
+
}
|
|
17
|
+
if (action?.config?.defaults?.agentName) {
|
|
18
|
+
dispatch({
|
|
19
|
+
type: seamlyActions.SET_HEADER_SUB_TITLE,
|
|
20
|
+
title: action?.config?.defaults?.agentName,
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return result
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { defaultConfig } from '../../config'
|
|
2
|
+
import { createReducer } from '../../lib/redux-helpers'
|
|
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
|
+
'typing',
|
|
29
|
+
'visible',
|
|
30
|
+
'visibilityCallback',
|
|
31
|
+
]
|
|
32
|
+
const updateState = (state, { config }) => {
|
|
33
|
+
const { messages, typing, ...partialConfig } = pick(config, configKeys)
|
|
34
|
+
let newState = state
|
|
35
|
+
if (Object.keys(partialConfig).length > 0) {
|
|
36
|
+
newState = {
|
|
37
|
+
...newState,
|
|
38
|
+
...partialConfig,
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (messages) {
|
|
42
|
+
newState = {
|
|
43
|
+
...newState,
|
|
44
|
+
messages: {
|
|
45
|
+
...newState.messages,
|
|
46
|
+
...messages,
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (typing) {
|
|
52
|
+
newState = {
|
|
53
|
+
...newState,
|
|
54
|
+
typing: {
|
|
55
|
+
...newState.typing,
|
|
56
|
+
...typing,
|
|
57
|
+
},
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return newState
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default createReducer(
|
|
64
|
+
'config',
|
|
65
|
+
{
|
|
66
|
+
[Actions.initialize]: (state, action) => {
|
|
67
|
+
return updateState(state, action)
|
|
68
|
+
},
|
|
69
|
+
[Actions.update]: (state, action) => {
|
|
70
|
+
return updateState(state, action)
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
initialState,
|
|
74
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createSelector } from 'reselect'
|
|
2
|
+
import { visibilityStates } from '../../ui/utils/seamly-utils'
|
|
3
|
+
import Reducer from './reducer'
|
|
4
|
+
|
|
5
|
+
export const selectState = (state) => state[String(Reducer)]
|
|
6
|
+
|
|
7
|
+
export const selectConfig = createSelector(selectState, (config) => {
|
|
8
|
+
let newConfig = {
|
|
9
|
+
visible:
|
|
10
|
+
config?.layoutMode === 'inline'
|
|
11
|
+
? visibilityStates.open
|
|
12
|
+
: visibilityStates.minimized,
|
|
13
|
+
appContainerClassNames: config.appContainerClassNames || [],
|
|
14
|
+
...config,
|
|
15
|
+
}
|
|
16
|
+
if (typeof newConfig.appContainerClassNames === 'function') {
|
|
17
|
+
newConfig = {
|
|
18
|
+
...newConfig,
|
|
19
|
+
appContainerClassNames: newConfig.appContainerClassNames(newConfig),
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return newConfig
|
|
23
|
+
})
|
|
@@ -4,7 +4,7 @@ const { createActions } = createDomain('forms')
|
|
|
4
4
|
|
|
5
5
|
export const [registerForm, deregisterForm] = createActions('form', {
|
|
6
6
|
register: (formId, persistData) => ({ formId, persistData }),
|
|
7
|
-
deregister: formId => ({ formId }),
|
|
7
|
+
deregister: (formId) => ({ formId }),
|
|
8
8
|
})
|
|
9
9
|
|
|
10
10
|
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) {
|
|
@@ -2,7 +2,7 @@ import { createSelector } from 'reselect'
|
|
|
2
2
|
import { getPropSelector } from '../redux/utils'
|
|
3
3
|
import Reducer from './reducer'
|
|
4
4
|
|
|
5
|
-
export const getState = state => state[String(Reducer)]
|
|
5
|
+
export const getState = (state) => state[String(Reducer)]
|
|
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
|
|
@@ -8,10 +8,14 @@ import en from '../../../../translations/en'
|
|
|
8
8
|
// Actions
|
|
9
9
|
const { createAction } = createDomain('i18n')
|
|
10
10
|
|
|
11
|
-
export const initI18n = createAction('init', overrides => ({
|
|
11
|
+
export const initI18n = createAction('init', (overrides) => ({
|
|
12
12
|
overrides,
|
|
13
13
|
}))
|
|
14
14
|
|
|
15
|
+
export const Actions = {
|
|
16
|
+
initI18n,
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
// Reducer
|
|
16
20
|
const defaultState = { translations: flattenObject(en), overrides: {} }
|
|
17
21
|
export const Reducer = createReducer(
|
|
@@ -28,14 +32,14 @@ export const Reducer = createReducer(
|
|
|
28
32
|
)
|
|
29
33
|
|
|
30
34
|
// Selectors
|
|
31
|
-
export const getState = state => state[String(Reducer)]
|
|
35
|
+
export const getState = (state) => state[String(Reducer)]
|
|
32
36
|
export const getTranslations = createSelector(
|
|
33
37
|
getState,
|
|
34
|
-
state => state.translations,
|
|
38
|
+
(state) => state.translations,
|
|
35
39
|
)
|
|
36
40
|
export const getOverrides = createSelector(
|
|
37
41
|
getState,
|
|
38
|
-
state => state.overrides || {},
|
|
42
|
+
(state) => state.overrides || {},
|
|
39
43
|
)
|
|
40
44
|
|
|
41
45
|
export const getCombinedTranslations = createSelector(
|
|
@@ -48,7 +52,7 @@ export const getCombinedTranslations = createSelector(
|
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
const defaultKeys = Object.keys(translations)
|
|
51
|
-
defaultKeys.forEach(key => {
|
|
55
|
+
defaultKeys.forEach((key) => {
|
|
52
56
|
if (overrideKeys.indexOf(key) === -1) {
|
|
53
57
|
console.error('Seamly: Missing translation key:', key)
|
|
54
58
|
}
|
|
@@ -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
|
+
}
|
|
@@ -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,22 @@
|
|
|
1
|
+
import { createReducer } from '../../lib/redux-helpers'
|
|
2
|
+
import * as Actions from './actions'
|
|
3
|
+
|
|
4
|
+
const initialState = {
|
|
5
|
+
error: undefined,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default createReducer(
|
|
9
|
+
'interrupt',
|
|
10
|
+
{
|
|
11
|
+
[Actions.set]: (state, { error }) => {
|
|
12
|
+
return {
|
|
13
|
+
...state,
|
|
14
|
+
error,
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
[Actions.clear]: () => {
|
|
18
|
+
return initialState
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
initialState,
|
|
22
|
+
)
|
|
@@ -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
|
+
}
|