@seamly/web-ui 21.0.9 → 22.0.0
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 +9228 -7777
- 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 +6999 -5996
- 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 +940 -370
- 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 +334 -110
- package/build/dist/lib/index.debug.min.js.map +1 -0
- package/build/dist/lib/index.js +2810 -5472
- 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 +10575 -13540
- 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 +1701 -5859
- 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 +11536 -14530
- 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/store/selectors.ts +23 -10
- package/src/javascripts/domains/store/slice.ts +63 -11
- package/src/javascripts/domains/store/store.types.ts +41 -1
- package/src/javascripts/domains/translations/components/options-button.tsx +1 -4
- package/src/javascripts/domains/translations/hooks.ts +11 -4
- 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 +109 -0
- 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 +7 -1
- package/src/javascripts/ui/components/core/seamly-file-upload.tsx +156 -0
- package/src/javascripts/ui/components/entry/abort-transaction-button/abort-transaction-button.tsx +45 -0
- 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/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/view/{index.js → index.tsx} +53 -4
- package/src/javascripts/ui/components/view/window-view/{index.js → index.tsx} +14 -2
- package/src/javascripts/ui/components/widgets/{in-out-transition.js → in-out-transition.tsx} +67 -28
- package/src/javascripts/ui/hooks/{seamly-api-hooks.js → seamly-api-hooks.ts} +1 -1
- 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-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()
|
|
@@ -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,11 @@ export interface StoreState {
|
|
|
144
178
|
enabledFromEntry: boolean
|
|
145
179
|
enabled: boolean
|
|
146
180
|
}
|
|
181
|
+
webNotifications: {
|
|
182
|
+
enabled: boolean
|
|
183
|
+
}
|
|
184
|
+
cobrowsing?: { enabled: boolean }
|
|
185
|
+
sendTranscript?: { enabled: boolean }
|
|
147
186
|
}
|
|
148
187
|
panelActive: boolean
|
|
149
188
|
optionActive: string
|
|
@@ -151,6 +190,7 @@ export interface StoreState {
|
|
|
151
190
|
}
|
|
152
191
|
showFileUpload: boolean
|
|
153
192
|
currentUploads: CurrentUpload[]
|
|
193
|
+
processingFileUploads: string[]
|
|
154
194
|
entryMeta: EntryMeta
|
|
155
195
|
seamlyContainerElement: null | HTMLElement
|
|
156
196
|
}
|
|
@@ -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>
|
|
@@ -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
|
|
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
|
|
@@ -13,6 +13,7 @@ const baseState = {
|
|
|
13
13
|
showFaq: false,
|
|
14
14
|
showDisclaimer: false,
|
|
15
15
|
showSuggestions: true,
|
|
16
|
+
preChat: true,
|
|
16
17
|
},
|
|
17
18
|
initialState: {},
|
|
18
19
|
unreadEvents: 0,
|
|
@@ -55,6 +56,7 @@ const baseState = {
|
|
|
55
56
|
optionsOverride: {},
|
|
56
57
|
},
|
|
57
58
|
currentUploads: [],
|
|
59
|
+
processingFileUploads: [],
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
const avatar =
|
|
@@ -701,12 +703,28 @@ const fileDownloadAgentMessage = {
|
|
|
701
703
|
},
|
|
702
704
|
}
|
|
703
705
|
|
|
706
|
+
const fileUploadAgentMessage = {
|
|
707
|
+
type: 'message',
|
|
708
|
+
payload: {
|
|
709
|
+
...fileDownloadPayload,
|
|
710
|
+
fromClient: false,
|
|
711
|
+
participant: 'agent',
|
|
712
|
+
id: randomId(),
|
|
713
|
+
},
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
sessionStorage.setItem(
|
|
717
|
+
`image-${fileDownloadAgentMessage.payload.id}`,
|
|
718
|
+
fileDownloadAgentMessage.payload.body.url,
|
|
719
|
+
)
|
|
720
|
+
|
|
704
721
|
const deletedFileDownloadAgentMessage = {
|
|
705
722
|
...fileDownloadAgentMessage,
|
|
706
723
|
payload: {
|
|
707
724
|
...fileDownloadAgentMessage.payload,
|
|
708
725
|
body: {
|
|
709
726
|
...fileDownloadAgentMessage.payload.body,
|
|
727
|
+
url: undefined,
|
|
710
728
|
},
|
|
711
729
|
id: randomId(),
|
|
712
730
|
},
|
|
@@ -722,6 +740,11 @@ const fileDownloadUserMessage = {
|
|
|
722
740
|
},
|
|
723
741
|
}
|
|
724
742
|
|
|
743
|
+
sessionStorage.setItem(
|
|
744
|
+
`image-${fileDownloadUserMessage.payload.id}`,
|
|
745
|
+
fileDownloadUserMessage.payload.body.url,
|
|
746
|
+
)
|
|
747
|
+
|
|
725
748
|
const emptyUrlFileDownloadUserMessage = {
|
|
726
749
|
...fileDownloadUserMessage,
|
|
727
750
|
payload: {
|
|
@@ -1143,6 +1166,7 @@ const standardState = {
|
|
|
1143
1166
|
userMessageWithLinks,
|
|
1144
1167
|
newTopicDivider,
|
|
1145
1168
|
imageMessage,
|
|
1169
|
+
fileUploadAgentMessage,
|
|
1146
1170
|
fileDownloadAgentMessage,
|
|
1147
1171
|
deletedFileDownloadAgentMessage,
|
|
1148
1172
|
userMessageLong,
|
|
@@ -1219,7 +1243,9 @@ const standardState = {
|
|
|
1219
1243
|
imageMessage,
|
|
1220
1244
|
videoMessage,
|
|
1221
1245
|
imageMessageWithLightbox,
|
|
1246
|
+
fileUploadAgentMessage,
|
|
1222
1247
|
fileDownloadAgentMessage,
|
|
1248
|
+
fileDownloadUserMessage,
|
|
1223
1249
|
],
|
|
1224
1250
|
},
|
|
1225
1251
|
systemMessages: {
|
|
@@ -1495,6 +1521,46 @@ const standardState = {
|
|
|
1495
1521
|
optionsOverride: {},
|
|
1496
1522
|
},
|
|
1497
1523
|
},
|
|
1524
|
+
inputLabel: {
|
|
1525
|
+
category: categoryKeys.features,
|
|
1526
|
+
headingText: 'Input label',
|
|
1527
|
+
...baseState,
|
|
1528
|
+
entryMeta: {
|
|
1529
|
+
default: 'text',
|
|
1530
|
+
active: 'text',
|
|
1531
|
+
options: {
|
|
1532
|
+
text: { limit: null },
|
|
1533
|
+
},
|
|
1534
|
+
optionsOverride: {
|
|
1535
|
+
text: {
|
|
1536
|
+
label: 'What is your name?',
|
|
1537
|
+
limit: null,
|
|
1538
|
+
placeholder: 'Please enter your name',
|
|
1539
|
+
},
|
|
1540
|
+
},
|
|
1541
|
+
},
|
|
1542
|
+
},
|
|
1543
|
+
abortTransactional: {
|
|
1544
|
+
category: categoryKeys.features,
|
|
1545
|
+
headingText: 'Abort transaction',
|
|
1546
|
+
...baseState,
|
|
1547
|
+
events: [shortTextMessage, userMessage],
|
|
1548
|
+
entryMeta: {
|
|
1549
|
+
default: 'text',
|
|
1550
|
+
active: 'text',
|
|
1551
|
+
options: {
|
|
1552
|
+
text: { limit: null },
|
|
1553
|
+
},
|
|
1554
|
+
optionsOverride: {},
|
|
1555
|
+
actions: {
|
|
1556
|
+
abortTransaction: {
|
|
1557
|
+
label: 'Ask for another question',
|
|
1558
|
+
topicFallbackMessage: 'Oops...',
|
|
1559
|
+
topicName: 'abort_transactional',
|
|
1560
|
+
},
|
|
1561
|
+
},
|
|
1562
|
+
},
|
|
1563
|
+
},
|
|
1498
1564
|
fileUploadToggle: {
|
|
1499
1565
|
category: categoryKeys.uploads,
|
|
1500
1566
|
headingText: 'File upload toggle button',
|
|
@@ -2193,6 +2259,49 @@ export const getStateObj = (layoutModes, customComponentEventBodies) => {
|
|
|
2193
2259
|
headerTitles,
|
|
2194
2260
|
},
|
|
2195
2261
|
},
|
|
2262
|
+
minimizedWindowPrechatDelayed: {
|
|
2263
|
+
category: categoryKeys.minimizedWindow,
|
|
2264
|
+
headingText: 'Minimized with delayed pre-chat messages',
|
|
2265
|
+
description: '',
|
|
2266
|
+
window: {
|
|
2267
|
+
...baseState,
|
|
2268
|
+
config: {
|
|
2269
|
+
...baseState.config,
|
|
2270
|
+
layoutMode: 'window',
|
|
2271
|
+
preChatEvents: [splashMessage],
|
|
2272
|
+
preChat: {
|
|
2273
|
+
enterDelay: 1000,
|
|
2274
|
+
exitAfter: 3000,
|
|
2275
|
+
},
|
|
2276
|
+
},
|
|
2277
|
+
visibility: {
|
|
2278
|
+
...baseState.visibility,
|
|
2279
|
+
visibility: visibilityStates.minimized,
|
|
2280
|
+
},
|
|
2281
|
+
participantInfo,
|
|
2282
|
+
headerTitles,
|
|
2283
|
+
},
|
|
2284
|
+
},
|
|
2285
|
+
minimizedWindowPrechatDisabled: {
|
|
2286
|
+
category: categoryKeys.minimizedWindow,
|
|
2287
|
+
headingText: 'Minimized with disabled pre-chat messages',
|
|
2288
|
+
description: '',
|
|
2289
|
+
window: {
|
|
2290
|
+
...baseState,
|
|
2291
|
+
config: {
|
|
2292
|
+
...baseState.config,
|
|
2293
|
+
layoutMode: 'window',
|
|
2294
|
+
preChatEvents: [splashMessage],
|
|
2295
|
+
preChat: false,
|
|
2296
|
+
},
|
|
2297
|
+
visibility: {
|
|
2298
|
+
...baseState.visibility,
|
|
2299
|
+
visibility: visibilityStates.minimized,
|
|
2300
|
+
},
|
|
2301
|
+
participantInfo,
|
|
2302
|
+
headerTitles,
|
|
2303
|
+
},
|
|
2304
|
+
},
|
|
2196
2305
|
}
|
|
2197
2306
|
: {}),
|
|
2198
2307
|
...inlineInterface,
|
|
@@ -8,6 +8,7 @@ import { useEvents } from 'ui/hooks/seamly-state-hooks'
|
|
|
8
8
|
import { useI18n } from 'domains/i18n/hooks'
|
|
9
9
|
import { useVisibility } from 'domains/visibility/hooks'
|
|
10
10
|
import { className } from 'lib/css'
|
|
11
|
+
import AbortTransactionButton from '../entry/abort-transaction-button/abort-transaction-button'
|
|
11
12
|
import ComponentFilter from './component-filter'
|
|
12
13
|
import Event from './event/event'
|
|
13
14
|
import Loader from './loader'
|
|
@@ -77,6 +78,7 @@ const Conversation = () => {
|
|
|
77
78
|
<Events />
|
|
78
79
|
</ComponentFilter>
|
|
79
80
|
{isLoading && <Loader />}
|
|
81
|
+
<AbortTransactionButton />
|
|
80
82
|
</ol>
|
|
81
83
|
</div>
|
|
82
84
|
</div>
|
package/src/javascripts/ui/components/conversation/event/chat-scroll/chat-scroll-provider.tsx
CHANGED
|
@@ -11,6 +11,8 @@ const ChatScrollProvider = ({ children }) => {
|
|
|
11
11
|
const eventRefs = useMemo(
|
|
12
12
|
() =>
|
|
13
13
|
events.reduce<Record<string, RefObject<HTMLElement>>>((acc, value) => {
|
|
14
|
+
if (!value.payload.id) return acc
|
|
15
|
+
|
|
14
16
|
acc[value.payload.id] = createRef()
|
|
15
17
|
return acc
|
|
16
18
|
}, {}),
|