@seamly/web-ui 21.0.8 → 22.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/dist/lib/components.js +9295 -7845
- package/build/dist/lib/components.js.map +1 -0
- package/build/dist/lib/components.min.js +2 -1
- package/build/dist/lib/components.min.js.LICENSE.txt +2 -2
- package/build/dist/lib/components.min.js.map +1 -0
- package/build/dist/lib/config.js +2 -1
- package/build/dist/lib/config.js.map +1 -0
- package/build/dist/lib/config.min.js +2 -1
- package/build/dist/lib/config.min.js.map +1 -0
- package/build/dist/lib/contexts.js +2 -1
- package/build/dist/lib/contexts.js.map +1 -0
- package/build/dist/lib/contexts.min.js +2 -1
- package/build/dist/lib/contexts.min.js.map +1 -0
- package/build/dist/lib/deprecated-view.css +1 -1
- package/build/dist/lib/deprecated-view.js +1 -1
- package/build/dist/lib/hooks.js +6839 -5731
- package/build/dist/lib/hooks.js.map +1 -0
- package/build/dist/lib/hooks.min.js +2 -1
- package/build/dist/lib/hooks.min.js.map +1 -0
- package/build/dist/lib/index.debug.js +964 -383
- package/build/dist/lib/index.debug.js.map +1 -0
- package/build/dist/lib/index.debug.min.js +2 -1
- package/build/dist/lib/index.debug.min.js.LICENSE.txt +336 -108
- package/build/dist/lib/index.debug.min.js.map +1 -0
- package/build/dist/lib/index.js +2991 -5659
- package/build/dist/lib/index.js.map +1 -0
- package/build/dist/lib/index.min.js +2 -1
- package/build/dist/lib/index.min.js.LICENSE.txt +2 -2
- package/build/dist/lib/index.min.js.map +1 -0
- package/build/dist/lib/sounds/beep.mp3 +0 -0
- package/build/dist/lib/standalone.js +9454 -12449
- package/build/dist/lib/standalone.js.map +1 -0
- package/build/dist/lib/standalone.min.js +2 -1
- package/build/dist/lib/standalone.min.js.LICENSE.txt +1 -1
- package/build/dist/lib/standalone.min.js.map +1 -0
- package/build/dist/lib/storage.js +2 -1
- package/build/dist/lib/storage.js.map +1 -0
- package/build/dist/lib/storage.min.js +2 -1
- package/build/dist/lib/storage.min.js.map +1 -0
- package/build/dist/lib/style-guide.js +1828 -6015
- package/build/dist/lib/style-guide.js.map +1 -0
- package/build/dist/lib/style-guide.min.js +2 -1
- package/build/dist/lib/style-guide.min.js.LICENSE.txt +2 -2
- package/build/dist/lib/style-guide.min.js.map +1 -0
- package/build/dist/lib/styles-default-implementation.css +1 -1
- package/build/dist/lib/styles-default-implementation.js +1 -1
- package/build/dist/lib/styles.css +1 -1
- package/build/dist/lib/styles.js +1 -1
- package/build/dist/lib/utils.js +11601 -14586
- package/build/dist/lib/utils.js.map +1 -0
- package/build/dist/lib/utils.min.js +2 -1
- package/build/dist/lib/utils.min.js.LICENSE.txt +1 -6
- package/build/dist/lib/utils.min.js.map +1 -0
- package/package.json +58 -48
- package/src/javascripts/api/conversation-connector.ts +2 -0
- package/src/javascripts/api/errors/seamly-api-error.ts +15 -0
- package/src/javascripts/api/index.ts +168 -94
- package/src/javascripts/config.ts +1 -1
- package/src/javascripts/config.types.ts +18 -11
- package/src/javascripts/domains/config/selectors.ts +1 -1
- package/src/javascripts/domains/config/slice.ts +12 -0
- package/src/javascripts/domains/forms/forms.types.ts +1 -0
- package/src/javascripts/domains/forms/hooks.ts +10 -2
- package/src/javascripts/domains/i18n/slice.ts +2 -0
- package/src/javascripts/domains/interrupt/hooks.ts +15 -7
- package/src/javascripts/domains/interrupt/selectors.ts +4 -0
- package/src/javascripts/domains/interrupt/slice.ts +2 -2
- package/src/javascripts/domains/store/selectors.ts +23 -10
- package/src/javascripts/domains/store/slice.ts +63 -11
- package/src/javascripts/domains/store/store.types.ts +39 -1
- package/src/javascripts/domains/translations/components/options-button.tsx +1 -4
- package/src/javascripts/domains/translations/components/translation-status.tsx +4 -3
- package/src/javascripts/domains/translations/hooks.ts +11 -4
- package/src/javascripts/domains/translations/slice.ts +2 -0
- package/src/javascripts/index.ts +2 -0
- package/src/javascripts/lib/url-helpers.ts +24 -0
- package/src/javascripts/schema.ts +10 -0
- package/src/javascripts/style-guide/states.js +65 -0
- package/src/javascripts/ui/components/app-options/index.js +4 -3
- package/src/javascripts/ui/components/conversation/conversation.tsx +2 -0
- package/src/javascripts/ui/components/conversation/event/chat-scroll/chat-scroll-provider.tsx +2 -0
- package/src/javascripts/ui/components/conversation/event/choice-prompt.js +1 -1
- package/src/javascripts/ui/components/conversation/event/text.js +1 -1
- package/src/javascripts/ui/components/conversation/event/upload.js +50 -9
- package/src/javascripts/ui/components/conversation/use-chat-scroll.ts +3 -2
- package/src/javascripts/ui/components/core/seamly-event-subscriber.ts +16 -14
- package/src/javascripts/ui/components/core/seamly-file-upload.tsx +156 -0
- package/src/javascripts/ui/components/core/seamly-instance-functions-loader.js +5 -5
- package/src/javascripts/ui/components/entry/abort-transaction-button/abort-transaction-button.tsx +45 -0
- package/src/javascripts/ui/components/entry/deprecated-toggle-button.js +4 -3
- package/src/javascripts/ui/components/entry/text-entry/hooks.ts +108 -0
- package/src/javascripts/ui/components/entry/text-entry/index.js +7 -4
- package/src/javascripts/ui/components/entry/text-entry/{text-entry-form.js → text-entry-form.tsx} +8 -22
- package/src/javascripts/ui/components/faq/faq.js +5 -4
- package/src/javascripts/ui/components/form-controls/{input.js → input.tsx} +13 -2
- package/src/javascripts/ui/components/form-controls/{wrapper.js → wrapper.tsx} +8 -4
- package/src/javascripts/ui/components/layout/agent-info.js +4 -3
- package/src/javascripts/ui/components/layout/chat-frame.js +7 -8
- package/src/javascripts/ui/components/layout/deprecated-chat-frame.js +7 -8
- package/src/javascripts/ui/components/layout/interrupt.js +6 -15
- package/src/javascripts/ui/components/layout/pre-chat-messages.js +4 -3
- package/src/javascripts/ui/components/suggestions/index.js +5 -4
- package/src/javascripts/ui/components/translation-chat-status/index.tsx +4 -3
- package/src/javascripts/ui/components/view/app-view.js +1 -2
- package/src/javascripts/ui/components/view/deprecated-view.js +1 -2
- package/src/javascripts/ui/components/view/{index.js → index.tsx} +53 -4
- package/src/javascripts/ui/components/view/inline-view.js +1 -11
- package/src/javascripts/ui/components/view/window-view/{index.js → index.tsx} +15 -11
- package/src/javascripts/ui/components/view/window-view/window-open-button.js +4 -3
- package/src/javascripts/ui/components/widgets/{in-out-transition.js → in-out-transition.tsx} +67 -28
- package/src/javascripts/ui/hooks/sounds/beep.mp3 +0 -0
- package/src/javascripts/ui/hooks/use-click-outside.ts +5 -3
- package/src/javascripts/ui/hooks/use-notifications.ts +114 -0
- package/src/javascripts/ui/hooks/{use-seamly-chat.js → use-seamly-chat.ts} +5 -1
- package/src/javascripts/ui/hooks/use-session-expired-command.ts +17 -0
- package/src/javascripts/ui/hooks/use-timeout.ts +20 -0
- package/src/stylesheets/3-chat/_chat.scss +3 -5
- package/src/stylesheets/4-base/_formelements.scss +0 -36
- package/src/stylesheets/5-components/_abort-transaction.scss +10 -0
- package/src/stylesheets/5-components/_buttons.scss +18 -3
- package/src/stylesheets/5-components/_character-limit.scss +2 -2
- package/src/stylesheets/5-components/_chat-status.scss +26 -37
- package/src/stylesheets/5-components/_choice-prompt.scss +9 -10
- package/src/stylesheets/5-components/_conversation.scss +9 -62
- package/src/stylesheets/5-components/_disclaimer.scss +11 -3
- package/src/stylesheets/5-components/_error.scss +3 -2
- package/src/stylesheets/5-components/_idle.scss +3 -8
- package/src/stylesheets/5-components/_input.scss +34 -13
- package/src/stylesheets/5-components/_interrupt.scss +3 -10
- package/src/stylesheets/5-components/_loader.scss +1 -2
- package/src/stylesheets/5-components/_message-author.scss +2 -4
- package/src/stylesheets/5-components/_message-body.scss +33 -10
- package/src/stylesheets/5-components/_message-card.scss +2 -10
- package/src/stylesheets/5-components/_message-carousel.scss +4 -4
- package/src/stylesheets/5-components/_message-cta.scss +0 -6
- package/src/stylesheets/5-components/_message.scss +1 -0
- package/src/stylesheets/5-components/_modal.scss +2 -5
- package/src/stylesheets/5-components/_options.scss +17 -22
- package/src/stylesheets/5-components/_pre-chat-messages.scss +3 -1
- package/src/stylesheets/5-components/_prompt.scss +3 -7
- package/src/stylesheets/5-components/_skip-link.scss +2 -1
- package/src/stylesheets/5-components/_suggestions.scss +2 -2
- package/src/stylesheets/5-components/_translation-options.scss +5 -2
- package/src/stylesheets/5-components/_unread-messages.scss +33 -0
- package/src/stylesheets/5-components/_upload.scss +20 -27
- package/src/stylesheets/6-default-implementation/_hover.scss +14 -17
- package/src/stylesheets/7-deprecated/1-settings/_config.scss +17 -0
- package/src/stylesheets/7-deprecated/3-app/_app.scss +2 -1
- package/src/stylesheets/7-deprecated/5-components/_card.scss +1 -0
- package/src/stylesheets/7-deprecated/5-components/_chat-status.scss +66 -20
- package/src/stylesheets/7-deprecated/5-components/_conversation.scss +1 -4
- package/src/stylesheets/7-deprecated/5-components/_input.scss +6 -1
- package/src/stylesheets/7-deprecated/5-components/_interrupt.scss +1 -4
- package/src/stylesheets/7-deprecated/5-components/_message.scss +49 -12
- package/src/stylesheets/7-deprecated/5-components/_translation-options.scss +30 -37
- package/src/stylesheets/7-deprecated/5-components/_unread-messages.scss +38 -0
- package/src/stylesheets/deprecated-view.scss +1 -0
- package/src/stylesheets/styles.scss +2 -0
- package/webpack/config.common.js +6 -1
- package/webpack/config.package.js +18 -0
- package/webpack/defaults.js +1 -1
- package/src/javascripts/ui/components/core/seamly-file-upload.js +0 -86
- package/src/javascripts/ui/components/entry/text-entry/hooks.js +0 -46
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
useMemo,
|
|
7
7
|
} from 'preact/hooks'
|
|
8
8
|
import { useDispatch, useSelector } from 'react-redux'
|
|
9
|
-
import type { FormContextType } from 'domains/forms/forms.types'
|
|
9
|
+
import type { ControlState, FormContextType } from 'domains/forms/forms.types'
|
|
10
10
|
import {
|
|
11
11
|
getControlTouchedByName,
|
|
12
12
|
getControlValueByName,
|
|
@@ -42,7 +42,15 @@ export function useValidations(values, validationSchema) {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
export function useFormControl(name)
|
|
45
|
+
export function useFormControl(name): [
|
|
46
|
+
{
|
|
47
|
+
name: string
|
|
48
|
+
onInput: (_e: any) => void
|
|
49
|
+
onBlur: () => void
|
|
50
|
+
value: string
|
|
51
|
+
},
|
|
52
|
+
ControlState,
|
|
53
|
+
] {
|
|
46
54
|
const dispatch = useDispatch()
|
|
47
55
|
const { formId, updateControlValue, updateControlTouched, errors } =
|
|
48
56
|
useFormContext()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit'
|
|
2
|
+
import { resetApp } from 'domains/app/actions'
|
|
2
3
|
import { initializeConfig } from 'domains/config/actions'
|
|
3
4
|
import { setLocale } from 'domains/i18n/actions'
|
|
4
5
|
import { I18nState } from 'domains/i18n/i18n.types'
|
|
@@ -46,6 +47,7 @@ export const i18nSlice = createSlice({
|
|
|
46
47
|
extraReducers: (builder) => {
|
|
47
48
|
// Add reducers for additional action types here, and handle loading state as needed
|
|
48
49
|
builder
|
|
50
|
+
.addCase(resetApp.pending, () => initialState)
|
|
49
51
|
.addCase(initializeConfig.fulfilled, (state, { payload }) => {
|
|
50
52
|
state.initialLocale = payload.locale
|
|
51
53
|
})
|
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import { useMemo } from 'preact/hooks'
|
|
2
2
|
import { useSelector } from 'react-redux'
|
|
3
3
|
import { useI18n } from 'domains/i18n/hooks'
|
|
4
|
-
import
|
|
4
|
+
import { selectError, selectHasError } from './selectors'
|
|
5
5
|
|
|
6
6
|
export function useInterrupt() {
|
|
7
7
|
const { t } = useI18n()
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const hasInterrupt = Boolean(error)
|
|
8
|
+
const error = useSelector(selectError)
|
|
9
|
+
const hasError = useSelector(selectHasError)
|
|
11
10
|
|
|
12
11
|
const meta = useMemo(() => {
|
|
13
|
-
if (!
|
|
12
|
+
if (!hasError) {
|
|
13
|
+
return {
|
|
14
|
+
title: undefined,
|
|
15
|
+
message: undefined,
|
|
16
|
+
srText: undefined,
|
|
17
|
+
buttonText: undefined,
|
|
18
|
+
originalError: undefined,
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
14
22
|
const { langKey, action } = error
|
|
15
23
|
const title = t(`${langKey}.title`)
|
|
16
24
|
const message = t(`${langKey}.message`)
|
|
@@ -23,7 +31,7 @@ export function useInterrupt() {
|
|
|
23
31
|
...(action && langKey ? { buttonText } : {}),
|
|
24
32
|
originalError: error,
|
|
25
33
|
}
|
|
26
|
-
}, [
|
|
34
|
+
}, [hasError, error, t])
|
|
27
35
|
|
|
28
|
-
return {
|
|
36
|
+
return { hasError, meta, error }
|
|
29
37
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createSlice, isAnyOf } from '@reduxjs/toolkit'
|
|
2
|
-
import { initializeApp
|
|
2
|
+
import { initializeApp } from 'domains/app/actions'
|
|
3
3
|
import { initializeConfig } from 'domains/config/actions'
|
|
4
4
|
import { setLocale } from 'domains/i18n/actions'
|
|
5
5
|
import { initializeVisibility, setVisibility } from 'domains/visibility/actions'
|
|
@@ -19,7 +19,7 @@ export const interruptSlice = createSlice({
|
|
|
19
19
|
},
|
|
20
20
|
extraReducers: (builder) => {
|
|
21
21
|
builder
|
|
22
|
-
.addCase(
|
|
22
|
+
.addCase(initializeConfig.pending, () => initialState)
|
|
23
23
|
.addMatcher(
|
|
24
24
|
isAnyOf(
|
|
25
25
|
initializeApp.rejected,
|
|
@@ -2,15 +2,28 @@ import { createSelector } from '@reduxjs/toolkit'
|
|
|
2
2
|
import { selectEvents } from 'ui/hooks/seamly-state-hooks'
|
|
3
3
|
import { readStates } from 'ui/utils/seamly-utils'
|
|
4
4
|
import { isUnreadMessage } from 'domains/store/slice'
|
|
5
|
+
import { RootState } from '.'
|
|
5
6
|
|
|
6
|
-
export const
|
|
7
|
-
return events
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
})
|
|
15
|
-
.map((event) => event.payload.id)
|
|
7
|
+
export const selectUnreadEvents = createSelector(selectEvents, (events) => {
|
|
8
|
+
return events.filter((event) => {
|
|
9
|
+
return (
|
|
10
|
+
isUnreadMessage(event) &&
|
|
11
|
+
event.type !== 'service_data' &&
|
|
12
|
+
event.payload?.messageStatus === readStates.received
|
|
13
|
+
)
|
|
14
|
+
})
|
|
16
15
|
})
|
|
16
|
+
export const selectLastUnreadEvent = createSelector(
|
|
17
|
+
selectUnreadEvents,
|
|
18
|
+
(events) => events.at(-1),
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
export const selectUnreadEventIds = createSelector(
|
|
22
|
+
selectUnreadEvents,
|
|
23
|
+
(events) => events.map((event) => event.payload.id),
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
export const selectShowNotifications = createSelector(
|
|
27
|
+
({ state }: RootState) => state.options.features?.webNotifications,
|
|
28
|
+
(webNotifications) => webNotifications?.enabled,
|
|
29
|
+
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PayloadAction, createSlice, isAnyOf } from '@reduxjs/toolkit'
|
|
2
|
-
import { ConversationHistoryResponse } from 'api'
|
|
2
|
+
import type { ConversationHistoryResponse } from 'api'
|
|
3
3
|
import { getTimeFromSeconds } from 'ui/utils/general-utils'
|
|
4
4
|
import {
|
|
5
5
|
entryTypes,
|
|
@@ -13,6 +13,7 @@ import { initializeConfig } from 'domains/config/actions'
|
|
|
13
13
|
import type {
|
|
14
14
|
AckEvent,
|
|
15
15
|
ChannelEvent,
|
|
16
|
+
CurrentUploadPayload,
|
|
16
17
|
EntryMeta,
|
|
17
18
|
MessageParticipant,
|
|
18
19
|
ServiceInfo,
|
|
@@ -21,6 +22,7 @@ import type {
|
|
|
21
22
|
import { randomId } from 'lib/id'
|
|
22
23
|
|
|
23
24
|
export const isUnreadMessage = ({ type, payload }: ChannelEvent) =>
|
|
25
|
+
document.visibilityState === 'hidden' ||
|
|
24
26
|
(type === eventTypes.message && !payload.fromClient) ||
|
|
25
27
|
(type === eventTypes.info && payload.type === payloadTypes.text)
|
|
26
28
|
|
|
@@ -104,12 +106,19 @@ const calculateNewEntryMeta = (
|
|
|
104
106
|
channelEvent?: ChannelEvent,
|
|
105
107
|
) => {
|
|
106
108
|
const entry =
|
|
107
|
-
channelEvent?.type === 'message'
|
|
109
|
+
channelEvent?.type === 'message'
|
|
110
|
+
? channelEvent?.payload.translatedEntry || channelEvent?.payload.entry
|
|
111
|
+
: {}
|
|
108
112
|
|
|
109
113
|
const { blockAutoEntrySwitch } = entryMeta
|
|
114
|
+
const actions = channelEvent?.payload?.actions || {}
|
|
110
115
|
|
|
111
116
|
if (!entry) {
|
|
112
|
-
return {
|
|
117
|
+
return {
|
|
118
|
+
...entryMeta,
|
|
119
|
+
optionsOverride: {},
|
|
120
|
+
actions,
|
|
121
|
+
}
|
|
113
122
|
}
|
|
114
123
|
|
|
115
124
|
const { type, options } = entry
|
|
@@ -127,6 +136,7 @@ const calculateNewEntryMeta = (
|
|
|
127
136
|
...entryMeta.optionsOverride,
|
|
128
137
|
[type]: options || {},
|
|
129
138
|
},
|
|
139
|
+
actions,
|
|
130
140
|
}
|
|
131
141
|
}
|
|
132
142
|
|
|
@@ -151,6 +161,7 @@ export const initialStoreState: StoreState = {
|
|
|
151
161
|
resumeConversationPrompt: false,
|
|
152
162
|
serviceInfo: {
|
|
153
163
|
activeServiceSessionId: '',
|
|
164
|
+
proactiveMessages: false,
|
|
154
165
|
},
|
|
155
166
|
participantInfo: {
|
|
156
167
|
participants: {},
|
|
@@ -166,13 +177,18 @@ export const initialStoreState: StoreState = {
|
|
|
166
177
|
headerCollapseButtonId: randomId(),
|
|
167
178
|
serviceData: {},
|
|
168
179
|
options: {
|
|
169
|
-
features: {
|
|
180
|
+
features: {
|
|
181
|
+
webNotifications: {
|
|
182
|
+
enabled: false,
|
|
183
|
+
},
|
|
184
|
+
},
|
|
170
185
|
panelActive: false,
|
|
171
186
|
optionActive: '',
|
|
172
187
|
userSelectedOptions: {},
|
|
173
188
|
},
|
|
174
189
|
showFileUpload: false,
|
|
175
190
|
currentUploads: [],
|
|
191
|
+
processingFileUploads: [],
|
|
176
192
|
entryMeta: {
|
|
177
193
|
default: entryTypes.text,
|
|
178
194
|
active: entryTypes.text,
|
|
@@ -180,6 +196,7 @@ export const initialStoreState: StoreState = {
|
|
|
180
196
|
blockAutoEntrySwitch: false,
|
|
181
197
|
options: {},
|
|
182
198
|
optionsOverride: {},
|
|
199
|
+
actions: {},
|
|
183
200
|
},
|
|
184
201
|
seamlyContainerElement: null,
|
|
185
202
|
}
|
|
@@ -393,6 +410,8 @@ export const storeSlice = createSlice({
|
|
|
393
410
|
state.serviceInfo = {
|
|
394
411
|
...state.serviceInfo,
|
|
395
412
|
activeServiceSessionId,
|
|
413
|
+
proactiveMessages:
|
|
414
|
+
activeServiceSettings?.proactiveMessages?.enabled || false,
|
|
396
415
|
}
|
|
397
416
|
|
|
398
417
|
state.serviceData = {
|
|
@@ -402,7 +421,7 @@ export const storeSlice = createSlice({
|
|
|
402
421
|
|
|
403
422
|
state.options = {
|
|
404
423
|
...state.options,
|
|
405
|
-
features: newFeatures
|
|
424
|
+
features: newFeatures,
|
|
406
425
|
}
|
|
407
426
|
state.entryMeta =
|
|
408
427
|
!newFeaturesHasUpload &&
|
|
@@ -497,15 +516,15 @@ export const storeSlice = createSlice({
|
|
|
497
516
|
state.options.features[payload.key].enabled = payload.enabled
|
|
498
517
|
},
|
|
499
518
|
clearFeatures: (state) => {
|
|
500
|
-
|
|
501
|
-
|
|
519
|
+
state.options.features = {
|
|
520
|
+
webNotifications: state.options.features.webNotifications,
|
|
521
|
+
}
|
|
502
522
|
},
|
|
503
523
|
showOption: (state, { payload }) => {
|
|
504
524
|
state.options.panelActive = true
|
|
505
525
|
state.options.optionActive = payload
|
|
506
526
|
},
|
|
507
527
|
hideOption: (state) => {
|
|
508
|
-
// case HIDE_OPTION:
|
|
509
528
|
state.options.panelActive = false
|
|
510
529
|
state.options.optionActive = ''
|
|
511
530
|
},
|
|
@@ -523,6 +542,7 @@ export const storeSlice = createSlice({
|
|
|
523
542
|
state.entryMeta.active = payload.default
|
|
524
543
|
state.entryMeta.options = payload.options || {}
|
|
525
544
|
state.entryMeta.optionsOverride = {}
|
|
545
|
+
state.entryMeta.actions = {}
|
|
526
546
|
},
|
|
527
547
|
setActiveEntryType: (state, { payload }) => {
|
|
528
548
|
state.entryMeta.active = payload
|
|
@@ -530,7 +550,13 @@ export const storeSlice = createSlice({
|
|
|
530
550
|
setUserEntryType: (state, { payload }) => {
|
|
531
551
|
state.entryMeta.userSelected = payload
|
|
532
552
|
},
|
|
533
|
-
|
|
553
|
+
clearAbortTransaction: (state) => {
|
|
554
|
+
state.entryMeta.actions = {}
|
|
555
|
+
},
|
|
556
|
+
registerUpload: (
|
|
557
|
+
state,
|
|
558
|
+
{ payload }: PayloadAction<Omit<CurrentUploadPayload, 'progress'>>,
|
|
559
|
+
) => {
|
|
534
560
|
state.currentUploads.push({
|
|
535
561
|
id: payload.fileId,
|
|
536
562
|
name: payload.fileName,
|
|
@@ -541,7 +567,12 @@ export const storeSlice = createSlice({
|
|
|
541
567
|
uploadHandle: payload.uploadHandle,
|
|
542
568
|
})
|
|
543
569
|
},
|
|
544
|
-
setUploadProgress: (
|
|
570
|
+
setUploadProgress: (
|
|
571
|
+
state,
|
|
572
|
+
{
|
|
573
|
+
payload,
|
|
574
|
+
}: PayloadAction<Omit<CurrentUploadPayload, 'uploadHandle' | 'fileName'>>,
|
|
575
|
+
) => {
|
|
545
576
|
state.currentUploads = state.currentUploads.map((fileUpload) => {
|
|
546
577
|
if (fileUpload.id === payload.fileId) {
|
|
547
578
|
return {
|
|
@@ -555,6 +586,14 @@ export const storeSlice = createSlice({
|
|
|
555
586
|
return fileUpload
|
|
556
587
|
})
|
|
557
588
|
},
|
|
589
|
+
startProcessingImage: (state, { payload }: PayloadAction<string>) => {
|
|
590
|
+
state.processingFileUploads.push(payload)
|
|
591
|
+
},
|
|
592
|
+
doneProcessingImage: (state, { payload }: PayloadAction<string>) => {
|
|
593
|
+
state.processingFileUploads = state.processingFileUploads.filter(
|
|
594
|
+
(fileId) => fileId !== payload,
|
|
595
|
+
)
|
|
596
|
+
},
|
|
558
597
|
setUploadError: (state, { payload }) => {
|
|
559
598
|
state.currentUploads = state.currentUploads.map((fileUpload) => {
|
|
560
599
|
if (fileUpload.id === payload.fileId) {
|
|
@@ -569,7 +608,10 @@ export const storeSlice = createSlice({
|
|
|
569
608
|
return fileUpload
|
|
570
609
|
})
|
|
571
610
|
},
|
|
572
|
-
setUploadComplete: (
|
|
611
|
+
setUploadComplete: (
|
|
612
|
+
state,
|
|
613
|
+
{ payload }: PayloadAction<CurrentUploadPayload['fileId']>,
|
|
614
|
+
) => {
|
|
573
615
|
state.currentUploads = state.currentUploads.map((fileUpload) => {
|
|
574
616
|
if (fileUpload.id === payload) {
|
|
575
617
|
return {
|
|
@@ -586,6 +628,12 @@ export const storeSlice = createSlice({
|
|
|
586
628
|
setSeamlyContainerElement: (state, { payload }) => {
|
|
587
629
|
state.seamlyContainerElement = payload
|
|
588
630
|
},
|
|
631
|
+
setProactiveMessages: (
|
|
632
|
+
state,
|
|
633
|
+
{ payload }: PayloadAction<ServiceInfo['proactiveMessages']>,
|
|
634
|
+
) => {
|
|
635
|
+
state.serviceInfo.proactiveMessages = payload
|
|
636
|
+
},
|
|
589
637
|
},
|
|
590
638
|
extraReducers: (builder) => {
|
|
591
639
|
builder
|
|
@@ -640,14 +688,18 @@ export const {
|
|
|
640
688
|
setSeamlyContainerElement,
|
|
641
689
|
setServiceDataItem,
|
|
642
690
|
setServiceEntryMetadata,
|
|
691
|
+
clearAbortTransaction,
|
|
643
692
|
setUploadComplete,
|
|
644
693
|
setUploadError,
|
|
645
694
|
setUploadProgress,
|
|
695
|
+
startProcessingImage,
|
|
696
|
+
doneProcessingImage,
|
|
646
697
|
setUserEntryType,
|
|
647
698
|
setUserSelectedOption,
|
|
648
699
|
setUserSelectedOptions,
|
|
649
700
|
showOption,
|
|
650
701
|
stopIdleDetachCountdownCounter,
|
|
702
|
+
setProactiveMessages,
|
|
651
703
|
} = storeSlice.actions
|
|
652
704
|
|
|
653
705
|
export default storeSlice.reducer
|
|
@@ -20,6 +20,14 @@ export type AckEvent = {
|
|
|
20
20
|
type DefaultEventProps = {
|
|
21
21
|
timeIndicator?: number
|
|
22
22
|
key?: string
|
|
23
|
+
translatedEntry?: components['schemas']['MessageMessage']['entry']
|
|
24
|
+
actions?: {
|
|
25
|
+
abortTransaction?: {
|
|
26
|
+
label: string
|
|
27
|
+
topicFallbackMessage: string
|
|
28
|
+
topicName: string
|
|
29
|
+
}
|
|
30
|
+
}
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
export type MessageInfo = components['schemas']['MessageInfo'] &
|
|
@@ -32,6 +40,12 @@ export interface InfoEvent {
|
|
|
32
40
|
export type MessageMessage = components['schemas']['MessageMessage'] & {
|
|
33
41
|
key?: string
|
|
34
42
|
}
|
|
43
|
+
|
|
44
|
+
export type MessageUpload = components['schemas']['MessageMessage'] & {
|
|
45
|
+
body: components['schemas']['MessageBodyUpload'] &
|
|
46
|
+
components['schemas']['MessageBodyVideo']
|
|
47
|
+
}
|
|
48
|
+
|
|
35
49
|
export interface MessageEvent {
|
|
36
50
|
type: 'message'
|
|
37
51
|
payload: MessageMessage & DefaultEventProps
|
|
@@ -71,7 +85,12 @@ export type HistoryResponse = {
|
|
|
71
85
|
export type HistoryEvents = HistoryResponse['events']
|
|
72
86
|
|
|
73
87
|
export type EntryMetaOptions =
|
|
74
|
-
History['activeServiceSettings']['entry']['options']
|
|
88
|
+
History['activeServiceSettings']['entry']['options'] & {
|
|
89
|
+
text?: History['activeServiceSettings']['entry']['options']['text'] & {
|
|
90
|
+
placeholder?: string
|
|
91
|
+
label?: string
|
|
92
|
+
}
|
|
93
|
+
}
|
|
75
94
|
|
|
76
95
|
export type EntryMeta = {
|
|
77
96
|
default: typeof entryTypes.text
|
|
@@ -80,6 +99,13 @@ export type EntryMeta = {
|
|
|
80
99
|
blockAutoEntrySwitch: boolean
|
|
81
100
|
options: EntryMetaOptions
|
|
82
101
|
optionsOverride: EntryMetaOptions
|
|
102
|
+
actions?: {
|
|
103
|
+
abortTransaction?: {
|
|
104
|
+
label: string
|
|
105
|
+
topicFallbackMessage: string
|
|
106
|
+
topicName: string
|
|
107
|
+
}
|
|
108
|
+
}
|
|
83
109
|
}
|
|
84
110
|
|
|
85
111
|
export type ParticipantInfo = {
|
|
@@ -96,8 +122,16 @@ export interface CurrentUpload {
|
|
|
96
122
|
complete: boolean
|
|
97
123
|
}
|
|
98
124
|
|
|
125
|
+
export interface CurrentUploadPayload {
|
|
126
|
+
fileId: CurrentUpload['id']
|
|
127
|
+
progress: CurrentUpload['progress']
|
|
128
|
+
fileName: CurrentUpload['name']
|
|
129
|
+
uploadHandle: CurrentUpload['uploadHandle']
|
|
130
|
+
}
|
|
131
|
+
|
|
99
132
|
export type ServiceInfo = {
|
|
100
133
|
activeServiceSessionId: string
|
|
134
|
+
proactiveMessages: boolean
|
|
101
135
|
}
|
|
102
136
|
|
|
103
137
|
export interface StoreState {
|
|
@@ -144,6 +178,9 @@ export interface StoreState {
|
|
|
144
178
|
enabledFromEntry: boolean
|
|
145
179
|
enabled: boolean
|
|
146
180
|
}
|
|
181
|
+
webNotifications: {
|
|
182
|
+
enabled: boolean
|
|
183
|
+
}
|
|
147
184
|
}
|
|
148
185
|
panelActive: boolean
|
|
149
186
|
optionActive: string
|
|
@@ -151,6 +188,7 @@ export interface StoreState {
|
|
|
151
188
|
}
|
|
152
189
|
showFileUpload: boolean
|
|
153
190
|
currentUploads: CurrentUpload[]
|
|
191
|
+
processingFileUploads: string[]
|
|
154
192
|
entryMeta: EntryMeta
|
|
155
193
|
seamlyContainerElement: null | HTMLElement
|
|
156
194
|
}
|
|
@@ -58,9 +58,6 @@ export default function TranslationsOptionsButton({
|
|
|
58
58
|
onKeyDown={onMainKeyDownHandler}
|
|
59
59
|
>
|
|
60
60
|
<InOutTransition
|
|
61
|
-
onOutTransitionComplete={() => undefined}
|
|
62
|
-
onInTransitionComplete={() => undefined}
|
|
63
|
-
timeout={0}
|
|
64
61
|
transitionStartState={transitionStartStates.notRendered}
|
|
65
62
|
isActive={menuIsOpen}
|
|
66
63
|
>
|
|
@@ -83,7 +80,7 @@ export default function TranslationsOptionsButton({
|
|
|
83
80
|
onKeyDown={handleToggleKeyDown}
|
|
84
81
|
ref={toggleButton}
|
|
85
82
|
aria-haspopup="dialog"
|
|
86
|
-
aria-expanded={menuIsOpen
|
|
83
|
+
aria-expanded={menuIsOpen}
|
|
87
84
|
>
|
|
88
85
|
{children}
|
|
89
86
|
</button>
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { useSelector } from 'react-redux'
|
|
1
2
|
import TranslationChatStatus from 'ui/components/translation-chat-status'
|
|
2
3
|
import TranslationProposal from 'ui/components/translation-proposal'
|
|
3
|
-
import {
|
|
4
|
+
import { selectHasError } from 'domains/interrupt/selectors'
|
|
4
5
|
import { useTranslations } from 'domains/translations/hooks'
|
|
5
6
|
|
|
6
7
|
export default function TranslationStatus() {
|
|
7
|
-
const
|
|
8
|
+
const hasError = useSelector(selectHasError)
|
|
8
9
|
|
|
9
10
|
const { isActive } = useTranslations()
|
|
10
|
-
if (
|
|
11
|
+
if (hasError) {
|
|
11
12
|
return null
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -85,32 +85,39 @@ export function useTranslatedEventData(channelEvent: ChannelEvent): {
|
|
|
85
85
|
const getTranslations = (): {
|
|
86
86
|
body: EventDataBody
|
|
87
87
|
translatedBody: TranslatedEventDataBody
|
|
88
|
+
translation?: any
|
|
88
89
|
} => {
|
|
89
|
-
if (!channelEvent
|
|
90
|
+
if (!channelEvent?.payload)
|
|
90
91
|
return { body: undefined, translatedBody: undefined }
|
|
91
92
|
if (channelEvent.type === 'participant') {
|
|
92
93
|
return {
|
|
93
94
|
body: channelEvent.payload?.participant.introduction,
|
|
94
95
|
translatedBody:
|
|
95
96
|
channelEvent.payload?.participant?.translatedIntroduction,
|
|
97
|
+
translation:
|
|
98
|
+
// @ts-ignore
|
|
99
|
+
channelEvent.payload?.participant?.translation,
|
|
96
100
|
}
|
|
97
101
|
}
|
|
98
102
|
|
|
99
103
|
return {
|
|
100
104
|
body: channelEvent.payload.body,
|
|
101
105
|
translatedBody: channelEvent.payload.translatedBody,
|
|
106
|
+
// @ts-ignore
|
|
107
|
+
translation: channelEvent?.payload?.translation,
|
|
102
108
|
}
|
|
103
109
|
}
|
|
104
110
|
|
|
105
|
-
const { translatedBody, body } = getTranslations()
|
|
111
|
+
const { translatedBody, translation, body } = getTranslations()
|
|
106
112
|
const hasTranslation = !!translatedBody
|
|
107
113
|
const isTranslated = useSelector(selectIsTranslated(channelEvent))
|
|
108
114
|
|
|
109
115
|
return {
|
|
110
|
-
|
|
116
|
+
// @ts-ignore
|
|
117
|
+
body: hasTranslation && isTranslated ? translatedBody : body,
|
|
111
118
|
hasTranslation,
|
|
112
119
|
isTranslated: isTranslated && hasTranslation,
|
|
113
|
-
locale:
|
|
120
|
+
locale: translation?.locale,
|
|
114
121
|
}
|
|
115
122
|
}
|
|
116
123
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PayloadAction, createSlice, nanoid } from '@reduxjs/toolkit'
|
|
2
|
+
import { resetApp } from 'domains/app/actions'
|
|
2
3
|
import { initializeConfig } from 'domains/config/actions'
|
|
3
4
|
import { addEvent, setHistory } from 'domains/store/slice'
|
|
4
5
|
import type { ChannelEvent, HistoryResponse } from 'domains/store/store.types'
|
|
@@ -93,6 +94,7 @@ export const translationSlice = createSlice({
|
|
|
93
94
|
},
|
|
94
95
|
extraReducers: (builder) => {
|
|
95
96
|
builder
|
|
97
|
+
.addCase(resetApp.pending, () => translationsInitialState)
|
|
96
98
|
.addCase(initializeConfig.fulfilled, (state, { payload }) => {
|
|
97
99
|
const feature = payload?.features?.translation
|
|
98
100
|
if (!feature) return
|
package/src/javascripts/index.ts
CHANGED
|
@@ -40,6 +40,30 @@ export const setSearchParam = (key: string, value: string): void => {
|
|
|
40
40
|
window.location.href = url.toString()
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
// Adds search parameters to the url
|
|
44
|
+
export const setSearchParams = (params: Record<string, string>): void => {
|
|
45
|
+
const url = new URL(window.location.href)
|
|
46
|
+
const { searchParams } = url
|
|
47
|
+
|
|
48
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
49
|
+
searchParams.set(key, value)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
url.search = searchParams.toString()
|
|
53
|
+
window.location.href = url.toString()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Removes a search parameter from the url
|
|
57
|
+
export const removeSearchParam = (...keys: string[]): void => {
|
|
58
|
+
const url = new URL(window.location.href)
|
|
59
|
+
const { searchParams } = url
|
|
60
|
+
|
|
61
|
+
keys.forEach((key) => searchParams.delete(key))
|
|
62
|
+
|
|
63
|
+
url.search = searchParams.toString()
|
|
64
|
+
window.history.replaceState({}, null, url)
|
|
65
|
+
}
|
|
66
|
+
|
|
43
67
|
// Replace search parameters with those found in URL search parameters or sessionStorage
|
|
44
68
|
export const replaceSearchParams = <T extends string>(
|
|
45
69
|
...keys: T[]
|
|
@@ -251,6 +251,11 @@ export interface components {
|
|
|
251
251
|
EntryText: {
|
|
252
252
|
/** @description Settings of the text entry */
|
|
253
253
|
options?: {
|
|
254
|
+
/**
|
|
255
|
+
* @description A custom label to show above the input field
|
|
256
|
+
* @example Your name:
|
|
257
|
+
*/
|
|
258
|
+
label?: string | null
|
|
254
259
|
/**
|
|
255
260
|
* @description Whether or not the expected input is language neutral. A postal code or a last name for example are independent of language.
|
|
256
261
|
* @example false
|
|
@@ -261,6 +266,11 @@ export interface components {
|
|
|
261
266
|
* @example 100
|
|
262
267
|
*/
|
|
263
268
|
limit?: number | null
|
|
269
|
+
/**
|
|
270
|
+
* @description A custom placeholder to show in the input field
|
|
271
|
+
* @example Your message (max. 100 characters)
|
|
272
|
+
*/
|
|
273
|
+
placeholder?: string | null
|
|
264
274
|
}
|
|
265
275
|
/**
|
|
266
276
|
* @description Entry type
|