@seamly/web-ui 20.8.1 → 21.0.1-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/components.js +14855 -20
- package/build/dist/lib/components.min.js +2 -1
- package/build/dist/lib/components.min.js.LICENSE.txt +48 -0
- package/build/dist/lib/config.js +9 -3
- package/build/dist/lib/config.min.js +1 -1
- package/build/dist/lib/contexts.js +14 -5
- package/build/dist/lib/contexts.min.js +1 -1
- package/build/dist/lib/deprecated-view.js +1 -1
- package/build/dist/lib/hooks.js +8446 -20
- package/build/dist/lib/hooks.min.js +2 -1
- package/build/dist/lib/hooks.min.js.LICENSE.txt +38 -0
- package/build/dist/lib/index.debug.js +585 -584
- package/build/dist/lib/index.debug.min.js +1 -1
- package/build/dist/lib/index.debug.min.js.LICENSE.txt +110 -110
- package/build/dist/lib/index.js +20279 -26454
- package/build/dist/lib/index.min.js +1 -1
- package/build/dist/lib/index.min.js.LICENSE.txt +6 -1
- package/build/dist/lib/standalone.js +27823 -34681
- package/build/dist/lib/standalone.min.js +1 -1
- package/build/dist/lib/standalone.min.js.LICENSE.txt +1 -1
- package/build/dist/lib/storage.js +6 -15
- package/build/dist/lib/style-guide.js +23181 -7921
- package/build/dist/lib/style-guide.min.js +1 -1
- package/build/dist/lib/style-guide.min.js.LICENSE.txt +10 -0
- package/build/dist/lib/styles-default-implementation.js +1 -1
- package/build/dist/lib/styles.js +1 -1
- package/build/dist/lib/utils.js +22149 -17
- package/build/dist/lib/utils.min.js +2 -1
- package/build/dist/lib/utils.min.js.LICENSE.txt +48 -0
- package/package.json +54 -52
- package/src/icons/icon_check-16.svg +14 -0
- package/src/icons/icon_check-32.svg +14 -0
- package/src/javascripts/api/conversation-connector.ts +149 -0
- package/src/javascripts/api/errors/seamly-base-error.js +19 -0
- package/src/javascripts/api/errors/seamly-unavailable-error.js +5 -7
- package/src/javascripts/api/{index.js → index.ts} +163 -116
- package/src/javascripts/config.types.ts +5 -4
- package/src/javascripts/domains/app/actions.ts +47 -46
- package/src/javascripts/domains/app/hooks.js +1 -1
- package/src/javascripts/domains/config/actions.ts +2 -8
- package/src/javascripts/domains/config/hooks.ts +1 -1
- package/src/javascripts/domains/config/selectors.ts +6 -6
- package/src/javascripts/domains/config/slice.ts +3 -3
- package/src/javascripts/domains/errors/index.ts +66 -0
- package/src/javascripts/domains/forms/context.ts +1 -1
- package/src/javascripts/domains/forms/forms.types.ts +3 -3
- package/src/javascripts/domains/forms/hooks.ts +10 -10
- package/src/javascripts/domains/forms/provider.tsx +9 -9
- package/src/javascripts/domains/i18n/actions.ts +11 -5
- package/src/javascripts/domains/i18n/hooks.ts +11 -8
- package/src/javascripts/domains/i18n/selectors.ts +10 -4
- package/src/javascripts/domains/i18n/slice.ts +0 -1
- package/src/javascripts/domains/interrupt/hooks.ts +1 -1
- package/src/javascripts/domains/interrupt/middleware.ts +1 -1
- package/src/javascripts/domains/store/index.ts +1 -1
- package/src/javascripts/domains/store/selectors.ts +16 -0
- package/src/javascripts/domains/store/slice.ts +47 -41
- package/src/javascripts/domains/store/store.types.ts +38 -10
- package/src/javascripts/domains/translations/components/{options-button.js → options-button.tsx} +30 -20
- package/src/javascripts/domains/translations/components/options-dialog/index.tsx +33 -0
- package/src/javascripts/domains/translations/components/options-dialog/translation-option.tsx +42 -0
- package/src/javascripts/domains/translations/components/options-dialog/translation-options.tsx +81 -0
- package/src/javascripts/domains/translations/components/translation-status.tsx +15 -0
- package/src/javascripts/domains/translations/hooks.ts +77 -11
- package/src/javascripts/domains/translations/slice.ts +20 -9
- package/src/javascripts/domains/translations/translations.types.ts +4 -2
- package/src/javascripts/domains/visibility/actions.ts +6 -10
- package/src/javascripts/domains/visibility/hooks.ts +33 -14
- package/src/javascripts/domains/visibility/selectors.ts +3 -2
- package/src/javascripts/domains/visibility/slice.ts +2 -6
- package/src/javascripts/index.ts +18 -22
- package/src/javascripts/lib/engine/{index.js → index.tsx} +25 -7
- package/src/javascripts/lib/url-helpers.ts +112 -0
- package/src/javascripts/package/components.js +15 -1
- package/src/javascripts/package/config.js +1 -1
- package/src/javascripts/package/contexts.js +5 -3
- package/src/javascripts/package/hooks.js +19 -1
- package/src/javascripts/package/utils.js +13 -3
- package/src/javascripts/schema.ts +28 -0
- package/src/javascripts/style-guide/components/app.js +16 -12
- package/src/javascripts/style-guide/components/links.js +6 -6
- package/src/javascripts/style-guide/components/static-core.js +14 -9
- package/src/javascripts/style-guide/components/view.js +2 -2
- package/src/javascripts/style-guide/states.js +132 -36
- package/src/javascripts/style-guide/style-guide-engine.js +2 -1
- package/src/javascripts/style-guide/style-guide-external-api.js +1 -1
- package/src/javascripts/ui/components/app-options/index.js +25 -6
- package/src/javascripts/ui/components/chat-app.js +1 -1
- package/src/javascripts/ui/components/chat-status/chat-status-action.tsx +30 -0
- package/src/javascripts/ui/components/chat-status/index.tsx +61 -0
- package/src/javascripts/ui/components/conversation/component-filter.js +9 -9
- package/src/javascripts/ui/components/conversation/{conversation.js → conversation.tsx} +32 -41
- package/src/javascripts/ui/components/conversation/event/card-component.js +2 -2
- package/src/javascripts/ui/components/conversation/event/card-message.js +1 -1
- package/src/javascripts/ui/components/conversation/event/carousel-component/components/controls.js +2 -2
- package/src/javascripts/ui/components/conversation/event/carousel-component/index.js +4 -4
- package/src/javascripts/ui/components/conversation/event/carousel-message/components/slide.js +2 -2
- package/src/javascripts/ui/components/conversation/event/carousel-message/index.js +1 -1
- package/src/javascripts/ui/components/conversation/event/chat-scroll/chat-scroll-context.ts +12 -0
- package/src/javascripts/ui/components/conversation/event/chat-scroll/chat-scroll-provider.tsx +46 -0
- package/src/javascripts/ui/components/conversation/event/chat-scroll/unread-messages-button.tsx +30 -0
- package/src/javascripts/ui/components/conversation/event/choice-prompt.js +12 -8
- package/src/javascripts/ui/components/conversation/event/conversation-suggestions.js +6 -6
- package/src/javascripts/ui/components/conversation/event/cta.js +2 -2
- package/src/javascripts/ui/components/conversation/event/divider/index.js +0 -1
- package/src/javascripts/ui/components/conversation/event/divider/variants/default.js +1 -1
- package/src/javascripts/ui/components/conversation/event/divider/variants/new-translation.js +17 -22
- package/src/javascripts/ui/components/conversation/event/divider/variants/time-indicator.js +2 -2
- package/src/javascripts/ui/components/conversation/event/event-participant.js +1 -1
- package/src/javascripts/ui/components/conversation/event/event.tsx +66 -0
- package/src/javascripts/ui/components/conversation/event/hooks/use-event-link-click-handler.js +1 -1
- package/src/javascripts/ui/components/conversation/event/hooks/use-formatted-date.js +1 -1
- package/src/javascripts/ui/components/conversation/event/image-lightbox.js +1 -1
- package/src/javascripts/ui/components/conversation/event/image.js +2 -2
- package/src/javascripts/ui/components/conversation/event/splash.js +1 -1
- package/src/javascripts/ui/components/conversation/event/translation.js +1 -1
- package/src/javascripts/ui/components/conversation/event/upload.js +2 -2
- package/src/javascripts/ui/components/conversation/event/video.js +2 -2
- package/src/javascripts/ui/components/conversation/event-divider.js +1 -1
- package/src/javascripts/ui/components/conversation/message-container.js +1 -1
- package/src/javascripts/ui/components/conversation/use-chat-scroll.ts +108 -0
- package/src/javascripts/ui/components/core/{seamly-activity-monitor.js → seamly-activity-monitor.tsx} +12 -5
- package/src/javascripts/ui/components/core/seamly-api-context.ts +7 -0
- package/src/javascripts/ui/components/core/seamly-chat.tsx +8 -0
- package/src/javascripts/ui/components/core/{seamly-core.js → seamly-core.tsx} +27 -14
- package/src/javascripts/ui/components/core/seamly-event-subscriber.ts +340 -0
- package/src/javascripts/ui/components/core/seamly-file-upload.js +2 -2
- package/src/javascripts/ui/components/core/seamly-idle-detach-counter.js +1 -1
- package/src/javascripts/ui/components/core/seamly-instance-functions-loader.js +24 -11
- package/src/javascripts/ui/components/core/seamly-live-region.js +4 -4
- package/src/javascripts/ui/components/core/seamly-new-notifications.js +3 -3
- package/src/javascripts/ui/components/core/seamly-read-state.js +2 -33
- package/src/javascripts/ui/components/entry/deprecated-toggle-button.js +4 -4
- package/src/javascripts/ui/components/entry/entry-container.js +8 -8
- package/src/javascripts/ui/components/entry/text-entry/hooks.js +3 -3
- package/src/javascripts/ui/components/entry/text-entry/index.js +3 -3
- package/src/javascripts/ui/components/entry/text-entry/text-entry-form.js +4 -4
- package/src/javascripts/ui/components/entry/upload/file-upload-form.js +3 -3
- package/src/javascripts/ui/components/entry/upload/index.js +5 -5
- package/src/javascripts/ui/components/entry/upload-toggle.js +6 -6
- package/src/javascripts/ui/components/faq/faq.js +14 -14
- package/src/javascripts/ui/components/form-controls/error.js +2 -2
- package/src/javascripts/ui/components/form-controls/file-input.js +3 -3
- package/src/javascripts/ui/components/layout/agent-info.js +3 -3
- package/src/javascripts/ui/components/layout/chat-frame.js +20 -12
- package/src/javascripts/ui/components/layout/chat.js +5 -5
- package/src/javascripts/ui/components/layout/deprecated-app-frame.js +6 -6
- package/src/javascripts/ui/components/layout/deprecated-chat-frame.js +34 -0
- package/src/javascripts/ui/components/layout/header.js +2 -2
- package/src/javascripts/ui/components/layout/icon.js +11 -9
- package/src/javascripts/ui/components/layout/interrupt.js +7 -5
- package/src/javascripts/ui/components/layout/pre-chat-messages.js +1 -1
- package/src/javascripts/ui/components/layout/privacy-disclaimer.js +2 -2
- package/src/javascripts/ui/components/options/options-button.js +5 -5
- package/src/javascripts/ui/components/options/{options-frame.js → options-frame.tsx} +52 -18
- package/src/javascripts/ui/components/options/transcript/index.js +9 -10
- package/src/javascripts/ui/components/options/transcript/transcript-form.js +2 -2
- package/src/javascripts/ui/components/suggestions/index.js +8 -8
- package/src/javascripts/ui/components/suggestions/suggestions-item.js +1 -1
- package/src/javascripts/{domains/translations/components/chat-status.js → ui/components/translation-chat-status/index.tsx} +13 -14
- package/src/javascripts/ui/components/translation-proposal/index.tsx +36 -0
- package/src/javascripts/ui/components/view/app-view.js +2 -7
- package/src/javascripts/ui/components/view/deprecated-view.js +8 -10
- package/src/javascripts/ui/components/view/index.js +6 -6
- package/src/javascripts/ui/components/view/inline-view.js +4 -8
- package/src/javascripts/ui/components/view/window-view/collapse-button.js +2 -2
- package/src/javascripts/ui/components/view/window-view/index.js +11 -17
- package/src/javascripts/ui/components/view/window-view/window-open-button.js +6 -6
- package/src/javascripts/ui/components/warnings/idle-detach-warning.js +3 -3
- package/src/javascripts/ui/components/warnings/prompt.js +1 -1
- package/src/javascripts/ui/components/warnings/resume-conversation-prompt.js +4 -4
- package/src/javascripts/ui/components/widgets/in-out-transition.js +20 -18
- package/src/javascripts/ui/components/widgets/lightbox.js +3 -3
- package/src/javascripts/ui/components/widgets/modal.js +2 -2
- package/src/javascripts/ui/components/widgets/upload-progress.js +2 -2
- package/src/javascripts/ui/hooks/file-upload-hooks.js +1 -1
- package/src/javascripts/ui/hooks/focus-helper-hooks.js +1 -1
- package/src/javascripts/ui/hooks/seamly-entry-hooks.js +6 -6
- package/src/javascripts/ui/hooks/seamly-hooks.js +11 -10
- package/src/javascripts/ui/hooks/seamly-option-hooks.js +6 -6
- package/src/javascripts/ui/hooks/{seamly-state-hooks.js → seamly-state-hooks.ts} +9 -6
- package/src/javascripts/ui/hooks/use-click-outside.ts +29 -0
- package/src/javascripts/ui/hooks/use-event-component-mapping.js +11 -10
- package/src/javascripts/ui/hooks/use-interval.js +1 -1
- package/src/javascripts/ui/hooks/use-seamly-actions.ts +29 -29
- package/src/javascripts/ui/hooks/use-seamly-chat.js +14 -24
- package/src/javascripts/ui/hooks/use-seamly-commands.js +20 -15
- package/src/javascripts/ui/hooks/use-seamly-idle-detach-countdown.js +8 -8
- package/src/javascripts/ui/hooks/use-seamly-resume-conversation-prompt.js +2 -2
- package/src/javascripts/ui/hooks/use-single-file-upload.js +1 -1
- package/src/javascripts/ui/hooks/utility-hooks.js +1 -1
- package/src/javascripts/ui/utils/general-utils.js +0 -23
- package/src/javascripts/ui/utils/seamly-utils.ts +10 -1
- package/src/javascripts/ui/utils/seamly-utils.types.ts +9 -0
- package/src/stylesheets/1-settings/_config.scss +1 -1
- package/src/stylesheets/3-chat/_chat.scss +24 -9
- package/src/stylesheets/5-components/_chat-status.scss +72 -16
- package/src/stylesheets/5-components/_conversation.scss +35 -1
- package/src/stylesheets/5-components/_disclaimer.scss +0 -5
- package/src/stylesheets/5-components/_options.scss +16 -6
- package/src/stylesheets/5-components/_translation-options.scss +51 -0
- package/src/stylesheets/6-default-implementation/_scrollbar.scss +1 -1
- package/src/stylesheets/7-deprecated/3-app/_app.scss +19 -4
- package/src/stylesheets/7-deprecated/5-components/_chat-status.scss +5 -0
- package/src/stylesheets/7-deprecated/5-components/_options.scss +1 -4
- package/src/stylesheets/7-deprecated/5-components/_translation-options.scss +49 -0
- package/src/stylesheets/deprecated-view.scss +1 -0
- package/src/stylesheets/styles.scss +1 -0
- package/webpack/config.common.js +4 -4
- package/webpack/config.package.js +10 -16
- package/webpack/config.site.js +4 -1
- package/webpack/config.test.js +2 -1
- package/build/dist/lib/deprecated-view.css +0 -1
- package/build/dist/lib/styles-default-implementation.css +0 -1
- package/build/dist/lib/styles.css +0 -1
- package/src/.DS_Store +0 -0
- package/src/javascripts/api/event-producer.js +0 -20
- package/src/javascripts/api/producer.js +0 -136
- package/src/javascripts/domains/errors/index.js +0 -37
- package/src/javascripts/domains/translations/components/options-dialog/form.js +0 -70
- package/src/javascripts/domains/translations/components/options-dialog/index.js +0 -87
- package/src/javascripts/ui/components/chat-status/index.js +0 -38
- package/src/javascripts/ui/components/conversation/event/event.js +0 -36
- package/src/javascripts/ui/components/core/seamly-api-context.js +0 -5
- package/src/javascripts/ui/components/core/seamly-event-subscriber.js +0 -279
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createAsyncThunk } from '@reduxjs/toolkit'
|
|
2
|
-
import SeamlyUnavailableError from 'api/errors/seamly-unavailable-error'
|
|
3
2
|
import { ThunkAPI } from 'domains/redux/redux.types'
|
|
4
3
|
|
|
5
4
|
export const initializeConfig = createAsyncThunk<any, void, ThunkAPI>(
|
|
@@ -28,13 +27,8 @@ export const initializeConfig = createAsyncThunk<any, void, ThunkAPI>(
|
|
|
28
27
|
locale,
|
|
29
28
|
connectWhenInView,
|
|
30
29
|
}
|
|
31
|
-
} catch (
|
|
32
|
-
|
|
33
|
-
return rejectWithValue({
|
|
34
|
-
name: err.name,
|
|
35
|
-
langKey: err.langKey,
|
|
36
|
-
message: err.message,
|
|
37
|
-
})
|
|
30
|
+
} catch (error) {
|
|
31
|
+
return rejectWithValue(error)
|
|
38
32
|
}
|
|
39
33
|
},
|
|
40
34
|
)
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { createSelector } from '@reduxjs/toolkit'
|
|
2
|
-
import {
|
|
2
|
+
import type { VisibilityOptions } from 'config.types'
|
|
3
|
+
import type { RootState } from 'domains/store'
|
|
3
4
|
import { visibilityStates } from 'domains/visibility/constants'
|
|
4
5
|
|
|
5
6
|
export const selectConfig = createSelector(
|
|
6
|
-
({ config }
|
|
7
|
+
({ config }: RootState) => config,
|
|
7
8
|
(config) => {
|
|
8
9
|
let newConfig = {
|
|
9
|
-
visible:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
: visibilityStates.minimized,
|
|
10
|
+
visible: (config?.layoutMode === 'inline'
|
|
11
|
+
? visibilityStates.open
|
|
12
|
+
: visibilityStates.minimized) as VisibilityOptions,
|
|
13
13
|
appContainerClassNames: config.appContainerClassNames || [],
|
|
14
14
|
...config,
|
|
15
15
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { defaultConfig } from 'config'
|
|
1
|
+
import { PayloadAction, createSlice } from '@reduxjs/toolkit'
|
|
3
2
|
import { Config } from 'config.types'
|
|
3
|
+
import { defaultConfig } from 'config'
|
|
4
|
+
import { pick } from 'ui/utils/general-utils'
|
|
4
5
|
import { initializeConfig, resetConfig } from 'domains/config/actions'
|
|
5
6
|
import type { ChannelEvent } from 'domains/store/store.types'
|
|
6
|
-
import { pick } from 'ui/utils/general-utils'
|
|
7
7
|
|
|
8
8
|
export const initialConfigState: Config = {
|
|
9
9
|
...defaultConfig,
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createAction } from '@reduxjs/toolkit'
|
|
2
|
+
import SeamlyBaseError from 'api/errors/seamly-base-error'
|
|
3
|
+
import SeamlyConfigurationError from 'api/errors/seamly-configuration-error'
|
|
4
|
+
import SeamlyGeneralError from 'api/errors/seamly-general-error'
|
|
5
|
+
import SeamlyOfflineError from 'api/errors/seamly-offline-error'
|
|
6
|
+
import SeamlySessionExpiredError from 'api/errors/seamly-session-expired-error'
|
|
7
|
+
import SeamlyUnauthorizedError from 'api/errors/seamly-unauthorized-error'
|
|
8
|
+
import SeamlyUnavailableError from 'api/errors/seamly-unavailable-error'
|
|
9
|
+
import { selectConfig } from 'domains/config/selectors'
|
|
10
|
+
|
|
11
|
+
const ErrorTypes = {
|
|
12
|
+
SeamlyGeneralError,
|
|
13
|
+
SeamlyConfigurationError,
|
|
14
|
+
SeamlySessionExpiredError,
|
|
15
|
+
SeamlyOfflineError,
|
|
16
|
+
SeamlyUnauthorizedError,
|
|
17
|
+
SeamlyUnavailableError,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const catchError = createAction('catch-error', (error) => ({
|
|
21
|
+
payload: error,
|
|
22
|
+
}))
|
|
23
|
+
|
|
24
|
+
export function createErrorsMiddleware({ api: seamlyApi }) {
|
|
25
|
+
return ({ getState }) => {
|
|
26
|
+
const handleError = (action) => {
|
|
27
|
+
const { errorCallback, namespace, api, layoutMode } = selectConfig(
|
|
28
|
+
getState(),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const { error, type } = action
|
|
32
|
+
|
|
33
|
+
const errorType = ErrorTypes[error?.name]
|
|
34
|
+
? new ErrorTypes[error.name](error)
|
|
35
|
+
: new SeamlyBaseError(error)
|
|
36
|
+
|
|
37
|
+
errorCallback?.(errorType, {
|
|
38
|
+
namespace,
|
|
39
|
+
api,
|
|
40
|
+
layoutMode,
|
|
41
|
+
conversationUrl: seamlyApi.getConversationUrl(),
|
|
42
|
+
action: type ? action : undefined,
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return (next) => (action) => {
|
|
47
|
+
try {
|
|
48
|
+
if (action.payload?.originalEvent?.payload) {
|
|
49
|
+
handleError({
|
|
50
|
+
error: action.payload,
|
|
51
|
+
type: action.payload?.originalEvent?.payload?.type,
|
|
52
|
+
})
|
|
53
|
+
} else if (action.payload?.originalError) {
|
|
54
|
+
handleError({
|
|
55
|
+
error: action.payload,
|
|
56
|
+
type: undefined,
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
return next(action)
|
|
60
|
+
} catch (error) {
|
|
61
|
+
handleError({ error })
|
|
62
|
+
throw error
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export type FormContextType = {
|
|
2
|
-
handleSubmit: (
|
|
2
|
+
handleSubmit: (_e: Event) => void
|
|
3
3
|
isSubmitted: boolean
|
|
4
4
|
isValid: boolean
|
|
5
5
|
formId?: string
|
|
6
|
-
updateControlValue: (
|
|
7
|
-
updateControlTouched: (
|
|
6
|
+
updateControlValue: (_name: string, _value: string) => void
|
|
7
|
+
updateControlTouched: (_name: string, _value: boolean) => void
|
|
8
8
|
errors?: Record<string, unknown>
|
|
9
9
|
validationSchema?: Record<string, unknown>
|
|
10
10
|
values?: Record<string, string>
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { deregisterControl, registerControl } from 'domains/forms/slice'
|
|
2
|
-
import {
|
|
3
|
-
getFormById,
|
|
4
|
-
getControlValueByName,
|
|
5
|
-
getControlTouchedByName,
|
|
6
|
-
} from 'domains/forms/selectors'
|
|
7
1
|
import {
|
|
2
|
+
useCallback,
|
|
8
3
|
useContext,
|
|
9
|
-
useMemo,
|
|
10
4
|
useEffect,
|
|
11
5
|
useLayoutEffect,
|
|
12
|
-
|
|
6
|
+
useMemo,
|
|
13
7
|
} from 'preact/hooks'
|
|
14
8
|
import { useDispatch, useSelector } from 'react-redux'
|
|
9
|
+
import type { FormContextType } from 'domains/forms/forms.types'
|
|
10
|
+
import {
|
|
11
|
+
getControlTouchedByName,
|
|
12
|
+
getControlValueByName,
|
|
13
|
+
getFormById,
|
|
14
|
+
} from 'domains/forms/selectors'
|
|
15
|
+
import { deregisterControl, registerControl } from 'domains/forms/slice'
|
|
16
|
+
import type { RootState } from 'domains/store'
|
|
15
17
|
import FormContext from './context'
|
|
16
18
|
import { validate } from './utils'
|
|
17
|
-
import type { RootState } from 'domains/store'
|
|
18
|
-
import type { FormContextType } from 'domains/forms/forms.types'
|
|
19
19
|
|
|
20
20
|
export function useFormContext(): FormContextType {
|
|
21
21
|
return useContext(FormContext)
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useCallback,
|
|
3
|
+
useEffect,
|
|
4
|
+
useLayoutEffect,
|
|
5
|
+
useMemo,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'preact/hooks'
|
|
8
|
+
import { useDispatch, useSelector } from 'react-redux'
|
|
1
9
|
import { setHasResponded } from 'domains/app/slice'
|
|
2
10
|
import { Provider } from 'domains/forms/context'
|
|
3
11
|
import { useValidations } from 'domains/forms/hooks'
|
|
4
12
|
import { getFormValuesByFormId } from 'domains/forms/selectors'
|
|
5
13
|
import {
|
|
6
14
|
deregisterForm,
|
|
7
|
-
registerForm,
|
|
8
15
|
updateControlTouched as dispatchControlTouched,
|
|
9
16
|
updateControlValue as dispatchControlValue,
|
|
17
|
+
registerForm,
|
|
10
18
|
} from 'domains/forms/slice'
|
|
11
19
|
import type { RootState } from 'domains/store'
|
|
12
|
-
import {
|
|
13
|
-
useCallback,
|
|
14
|
-
useEffect,
|
|
15
|
-
useLayoutEffect,
|
|
16
|
-
useMemo,
|
|
17
|
-
useState,
|
|
18
|
-
} from 'preact/hooks'
|
|
19
|
-
import { useDispatch, useSelector } from 'react-redux'
|
|
20
20
|
|
|
21
21
|
export default function FormProvider({
|
|
22
22
|
children,
|
|
@@ -11,12 +11,16 @@ export const setLocale = createAsyncThunk<
|
|
|
11
11
|
ThunkAPI
|
|
12
12
|
>(
|
|
13
13
|
'setLocale',
|
|
14
|
-
async (locale, { extra: { api } }) => {
|
|
15
|
-
|
|
14
|
+
async (locale, { extra: { api }, rejectWithValue }) => {
|
|
15
|
+
try {
|
|
16
|
+
const response = await api.getTranslations(locale)
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
return {
|
|
19
|
+
translations: response,
|
|
20
|
+
locale,
|
|
21
|
+
}
|
|
22
|
+
} catch (error) {
|
|
23
|
+
return rejectWithValue(error)
|
|
20
24
|
}
|
|
21
25
|
},
|
|
22
26
|
{
|
|
@@ -29,6 +33,8 @@ export const setLocale = createAsyncThunk<
|
|
|
29
33
|
// Already fetched or in progress, don't need to re-fetch
|
|
30
34
|
return false
|
|
31
35
|
}
|
|
36
|
+
|
|
37
|
+
return true
|
|
32
38
|
},
|
|
33
39
|
},
|
|
34
40
|
)
|
|
@@ -3,12 +3,15 @@ import {
|
|
|
3
3
|
pluralTypeHandler,
|
|
4
4
|
selectTypeHandler,
|
|
5
5
|
} from '@ultraq/icu-message-formatter'
|
|
6
|
-
import { RootState } from 'domains/store'
|
|
7
6
|
import { useCallback } from 'preact/hooks'
|
|
8
7
|
import { useSelector } from 'react-redux'
|
|
9
|
-
import
|
|
8
|
+
import {
|
|
9
|
+
selectInitialLocale,
|
|
10
|
+
selectIsLoading,
|
|
11
|
+
selectLocale,
|
|
12
|
+
selectTranslations,
|
|
13
|
+
} from 'domains/i18n/selectors'
|
|
10
14
|
|
|
11
|
-
// The passed in locale (en-GB) is only used to call Intl.PluralRules.select() in
|
|
12
15
|
// pluralTypeHandler. Since we only use exact plural matches (=0, =1 etc) we can
|
|
13
16
|
// safely use en-GB all the time.
|
|
14
17
|
const formatter = new MessageFormatter('en-GB', {
|
|
@@ -17,13 +20,13 @@ const formatter = new MessageFormatter('en-GB', {
|
|
|
17
20
|
})
|
|
18
21
|
|
|
19
22
|
export function useI18n() {
|
|
20
|
-
const translations = useSelector(
|
|
21
|
-
const locale = useSelector(
|
|
22
|
-
const initialLocale = useSelector(
|
|
23
|
-
const isLoading = useSelector(
|
|
23
|
+
const translations = useSelector(selectTranslations)
|
|
24
|
+
const locale = useSelector(selectLocale)
|
|
25
|
+
const initialLocale = useSelector(selectInitialLocale)
|
|
26
|
+
const isLoading = useSelector(selectIsLoading)
|
|
24
27
|
|
|
25
28
|
const t = useCallback(
|
|
26
|
-
(key, values = {}) => {
|
|
29
|
+
(key: string, values = {}) => {
|
|
27
30
|
const translation = translations[key]
|
|
28
31
|
if (!translation) {
|
|
29
32
|
if (isLoading) return null
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
import { createSelector } from '
|
|
1
|
+
import { createSelector } from '@reduxjs/toolkit'
|
|
2
|
+
import type { RootState } from 'domains/store'
|
|
2
3
|
|
|
3
4
|
export const selectTranslations = createSelector(
|
|
4
|
-
({ i18n }) => i18n,
|
|
5
|
+
({ i18n }: RootState) => i18n,
|
|
5
6
|
({ translations }) => translations,
|
|
6
7
|
)
|
|
7
8
|
|
|
8
9
|
export const selectInitialLocale = createSelector(
|
|
9
|
-
({ i18n }) => i18n,
|
|
10
|
+
({ i18n }: RootState) => i18n,
|
|
10
11
|
({ initialLocale }) => initialLocale,
|
|
11
12
|
)
|
|
12
13
|
|
|
13
14
|
export const selectLocale = createSelector(
|
|
14
|
-
({ i18n }) => i18n,
|
|
15
|
+
({ i18n }: RootState) => i18n,
|
|
15
16
|
({ locale }) => locale,
|
|
16
17
|
)
|
|
18
|
+
|
|
19
|
+
export const selectIsLoading = createSelector(
|
|
20
|
+
({ i18n }: RootState) => i18n,
|
|
21
|
+
({ isLoading }) => isLoading,
|
|
22
|
+
)
|
|
@@ -22,7 +22,7 @@ export default function createInterruptMiddleware({ api }) {
|
|
|
22
22
|
if (
|
|
23
23
|
!handledErrorTypes.some((ErrorType) => payload.name === ErrorType.name)
|
|
24
24
|
) {
|
|
25
|
-
throw new
|
|
25
|
+
throw new SeamlyGeneralError(payload)
|
|
26
26
|
} else if (payload.action === 'reset') {
|
|
27
27
|
// [SMLY-942] We clear the store before a reset to force a new conversation if the page is refreshed before the conversation is reset
|
|
28
28
|
api.disconnect().then(() => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { configureStore } from '@reduxjs/toolkit'
|
|
2
|
+
import { useDispatch } from 'react-redux'
|
|
2
3
|
import appReducer from 'domains/app/slice'
|
|
3
4
|
import configReducer from 'domains/config/slice'
|
|
4
5
|
import { createErrorsMiddleware } from 'domains/errors'
|
|
@@ -11,7 +12,6 @@ import stateReducer from 'domains/store/slice'
|
|
|
11
12
|
import createI18nMiddleware from 'domains/translations/middleware'
|
|
12
13
|
import translationReducer from 'domains/translations/slice'
|
|
13
14
|
import visibilityReducer from 'domains/visibility/slice'
|
|
14
|
-
import { useDispatch } from 'react-redux'
|
|
15
15
|
|
|
16
16
|
export function createStore({ initialState, api, eventBus, config }) {
|
|
17
17
|
const store = configureStore({
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createSelector } from '@reduxjs/toolkit'
|
|
2
|
+
import { selectEvents } from 'ui/hooks/seamly-state-hooks'
|
|
3
|
+
import { readStates } from 'ui/utils/seamly-utils'
|
|
4
|
+
import { isUnreadMessage } from 'domains/store/slice'
|
|
5
|
+
|
|
6
|
+
export const selectUnreadEventIds = createSelector(selectEvents, (events) => {
|
|
7
|
+
return events
|
|
8
|
+
.filter((event) => {
|
|
9
|
+
return (
|
|
10
|
+
isUnreadMessage(event) &&
|
|
11
|
+
event.type !== 'service_data' &&
|
|
12
|
+
event.payload?.messageStatus === readStates.received
|
|
13
|
+
)
|
|
14
|
+
})
|
|
15
|
+
.map((event) => event.payload.id)
|
|
16
|
+
})
|
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
import { createSlice,
|
|
1
|
+
import { PayloadAction, createSlice, isAnyOf } from '@reduxjs/toolkit'
|
|
2
|
+
import { ConversationHistoryResponse } from 'api'
|
|
3
|
+
import { getTimeFromSeconds } from 'ui/utils/general-utils'
|
|
4
|
+
import {
|
|
5
|
+
entryTypes,
|
|
6
|
+
eventTypes,
|
|
7
|
+
featureKeys,
|
|
8
|
+
payloadTypes,
|
|
9
|
+
readStates,
|
|
10
|
+
} from 'ui/utils/seamly-utils'
|
|
2
11
|
import { initializeApp, resetApp } from 'domains/app/actions'
|
|
3
12
|
import { initializeConfig } from 'domains/config/actions'
|
|
4
|
-
import {
|
|
13
|
+
import type {
|
|
14
|
+
AckEvent,
|
|
5
15
|
ChannelEvent,
|
|
6
16
|
EntryMeta,
|
|
7
|
-
HistoryEvents,
|
|
8
|
-
HistoryResponse,
|
|
9
17
|
MessageParticipant,
|
|
10
|
-
ParticipantInfo,
|
|
11
18
|
ServiceInfo,
|
|
12
19
|
StoreState,
|
|
13
20
|
} from 'domains/store/store.types'
|
|
14
21
|
import { randomId } from 'lib/id'
|
|
15
|
-
import { getTimeFromSeconds } from 'ui/utils/general-utils'
|
|
16
|
-
import {
|
|
17
|
-
entryTypes,
|
|
18
|
-
eventTypes,
|
|
19
|
-
featureKeys,
|
|
20
|
-
payloadTypes,
|
|
21
|
-
readStates,
|
|
22
|
-
} from 'ui/utils/seamly-utils'
|
|
23
22
|
|
|
24
23
|
export const isUnreadMessage = ({ type, payload }: ChannelEvent) =>
|
|
25
24
|
(type === eventTypes.message && !payload.fromClient) ||
|
|
@@ -36,7 +35,7 @@ export const orderHistory = (events: ChannelEvent[]) => {
|
|
|
36
35
|
|
|
37
36
|
export const mergeHistory = (
|
|
38
37
|
stateEvents: ChannelEvent[],
|
|
39
|
-
historyEvents:
|
|
38
|
+
historyEvents: ConversationHistoryResponse['events'],
|
|
40
39
|
) => {
|
|
41
40
|
const newStateEvents = stateEvents.filter(
|
|
42
41
|
(stateEvent) =>
|
|
@@ -102,10 +101,10 @@ const participantReducer = (participantInfo, action) => {
|
|
|
102
101
|
|
|
103
102
|
const calculateNewEntryMeta = (
|
|
104
103
|
entryMeta: EntryMeta,
|
|
105
|
-
channelEvent
|
|
104
|
+
channelEvent?: ChannelEvent,
|
|
106
105
|
) => {
|
|
107
106
|
const entry =
|
|
108
|
-
channelEvent
|
|
107
|
+
channelEvent?.type === 'message' ? channelEvent?.payload.entry : {}
|
|
109
108
|
|
|
110
109
|
const { blockAutoEntrySwitch } = entryMeta
|
|
111
110
|
|
|
@@ -133,6 +132,7 @@ const calculateNewEntryMeta = (
|
|
|
133
132
|
|
|
134
133
|
export const initialStoreState: StoreState = {
|
|
135
134
|
events: [],
|
|
135
|
+
isLastEventFromClient: false,
|
|
136
136
|
initialState: {
|
|
137
137
|
userResponded: false,
|
|
138
138
|
},
|
|
@@ -243,15 +243,19 @@ export const storeSlice = createSlice({
|
|
|
243
243
|
|
|
244
244
|
if (incrementUnread) {
|
|
245
245
|
state.unreadEvents += 1
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
246
|
+
if (eventType !== 'service_data') {
|
|
247
|
+
action.payload.payload.messageStatus = payload.fromClient
|
|
248
|
+
? readStates.read
|
|
249
|
+
: readStates.received
|
|
250
|
+
}
|
|
249
251
|
}
|
|
250
252
|
|
|
251
253
|
action.payload.payload.key = randomId()
|
|
252
254
|
state.events.push(action.payload)
|
|
255
|
+
|
|
256
|
+
state.isLastEventFromClient = payload.fromClient
|
|
253
257
|
},
|
|
254
|
-
ackEvent: (state, { payload }) => {
|
|
258
|
+
ackEvent: (state, { payload: { payload } }: PayloadAction<AckEvent>) => {
|
|
255
259
|
// If any ACKs are sent without transactionID the conversation crashes.
|
|
256
260
|
// Ensure that this edge case is handled gracefully.
|
|
257
261
|
if (!payload.transactionId) {
|
|
@@ -260,22 +264,17 @@ export const storeSlice = createSlice({
|
|
|
260
264
|
}
|
|
261
265
|
|
|
262
266
|
const matchedEvent = state.events.find(
|
|
263
|
-
(m) =>
|
|
267
|
+
(m) =>
|
|
268
|
+
m.payload.transactionId === payload.transactionId &&
|
|
269
|
+
(!payload.type || m.type === payload.type),
|
|
264
270
|
)
|
|
265
271
|
|
|
266
272
|
const { id, occurredAt } = payload
|
|
267
273
|
if (matchedEvent) {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
? {
|
|
273
|
-
...m,
|
|
274
|
-
payload: { ...m.payload, id, occurredAt },
|
|
275
|
-
}
|
|
276
|
-
: m,
|
|
277
|
-
),
|
|
278
|
-
)
|
|
274
|
+
matchedEvent.payload.id = id
|
|
275
|
+
matchedEvent.payload.occurredAt = occurredAt
|
|
276
|
+
|
|
277
|
+
state.events = orderHistory(state.events)
|
|
279
278
|
}
|
|
280
279
|
},
|
|
281
280
|
clearEvents: (state) => {
|
|
@@ -283,15 +282,16 @@ export const storeSlice = createSlice({
|
|
|
283
282
|
state.loadedImageEventIds = []
|
|
284
283
|
state.events = []
|
|
285
284
|
},
|
|
286
|
-
setEventsRead: (state, { payload }) => {
|
|
285
|
+
setEventsRead: (state, { payload }: PayloadAction<string[]>) => {
|
|
287
286
|
state.unreadEvents = 0
|
|
288
287
|
state.events.forEach((event) => {
|
|
289
288
|
if (payload.indexOf(event.payload.id) !== -1) {
|
|
290
289
|
event.payload = {
|
|
291
290
|
...event.payload,
|
|
292
|
-
...(event.
|
|
293
|
-
messageStatus
|
|
294
|
-
|
|
291
|
+
...(event.type !== 'service_data' &&
|
|
292
|
+
event.payload.messageStatus === readStates.received && {
|
|
293
|
+
messageStatus: readStates.read,
|
|
294
|
+
}),
|
|
295
295
|
}
|
|
296
296
|
}
|
|
297
297
|
return event
|
|
@@ -311,7 +311,7 @@ export const storeSlice = createSlice({
|
|
|
311
311
|
serviceData,
|
|
312
312
|
resumeConversationPrompt,
|
|
313
313
|
},
|
|
314
|
-
}: PayloadAction<
|
|
314
|
+
}: PayloadAction<ConversationHistoryResponse>,
|
|
315
315
|
) => {
|
|
316
316
|
const events = mergeHistory(state.events, history)
|
|
317
317
|
|
|
@@ -341,14 +341,14 @@ export const storeSlice = createSlice({
|
|
|
341
341
|
}
|
|
342
342
|
|
|
343
343
|
const { entry } = activeServiceSettings
|
|
344
|
-
const
|
|
344
|
+
const upload = entry?.options?.upload
|
|
345
345
|
|
|
346
346
|
const historyNewEntryMeta = calculateNewEntryMeta(
|
|
347
347
|
{
|
|
348
348
|
...state.entryMeta,
|
|
349
349
|
...entry,
|
|
350
|
-
active: entry
|
|
351
|
-
options: { ...(entry
|
|
350
|
+
active: entry?.default || payloadTypes.text,
|
|
351
|
+
options: { ...(entry?.options ? entry.options : {}) },
|
|
352
352
|
},
|
|
353
353
|
events[events.length - 1],
|
|
354
354
|
)
|
|
@@ -366,7 +366,7 @@ export const storeSlice = createSlice({
|
|
|
366
366
|
newFeatures = {
|
|
367
367
|
...newFeatures,
|
|
368
368
|
uploads: {
|
|
369
|
-
enabled: !!(upload && upload
|
|
369
|
+
enabled: !!(upload && upload?.enabled),
|
|
370
370
|
enabledFromEntry: entryType === entryTypes.upload,
|
|
371
371
|
},
|
|
372
372
|
}
|
|
@@ -601,6 +601,12 @@ export const storeSlice = createSlice({
|
|
|
601
601
|
if (!payload.initialState) return
|
|
602
602
|
state.initialState = payload.initialState
|
|
603
603
|
})
|
|
604
|
+
.addMatcher(
|
|
605
|
+
isAnyOf(initIdleDetachCountdown, initResumeConversationPrompt),
|
|
606
|
+
(state) => {
|
|
607
|
+
state.isLastEventFromClient = false
|
|
608
|
+
},
|
|
609
|
+
)
|
|
604
610
|
},
|
|
605
611
|
})
|
|
606
612
|
|