@seamly/web-ui 21.0.8 → 21.0.9
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 +222 -224
- package/build/dist/lib/components.min.js +1 -1
- package/build/dist/lib/hooks.js +114 -9
- package/build/dist/lib/hooks.min.js +1 -1
- package/build/dist/lib/index.debug.js +49 -38
- package/build/dist/lib/index.debug.min.js +1 -1
- package/build/dist/lib/index.debug.min.js.LICENSE.txt +5 -1
- package/build/dist/lib/index.js +206 -213
- package/build/dist/lib/index.min.js +1 -1
- package/build/dist/lib/standalone.js +213 -244
- package/build/dist/lib/standalone.min.js +1 -1
- package/build/dist/lib/style-guide.js +192 -184
- package/build/dist/lib/style-guide.min.js +1 -1
- package/build/dist/lib/utils.js +190 -182
- package/build/dist/lib/utils.min.js +1 -1
- package/package.json +1 -1
- package/src/javascripts/domains/forms/provider.tsx +1 -1
- 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/translations/components/translation-status.tsx +4 -3
- package/src/javascripts/domains/translations/slice.ts +2 -0
- package/src/javascripts/ui/components/app-options/index.js +4 -3
- package/src/javascripts/ui/components/core/seamly-event-subscriber.ts +9 -13
- package/src/javascripts/ui/components/core/seamly-instance-functions-loader.js +5 -5
- package/src/javascripts/ui/components/entry/deprecated-toggle-button.js +4 -3
- package/src/javascripts/ui/components/faq/faq.js +5 -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/inline-view.js +1 -11
- package/src/javascripts/ui/components/view/window-view/index.js +1 -9
- package/src/javascripts/ui/components/view/window-view/window-open-button.js +4 -3
- 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/.DS_Store +0 -0
package/package.json
CHANGED
|
@@ -88,7 +88,7 @@ export default function FormProvider({
|
|
|
88
88
|
(e) => {
|
|
89
89
|
e.preventDefault()
|
|
90
90
|
// If the submitter is set to being aria-disabled, block the submit action
|
|
91
|
-
const ariaDisabled = e.submitter
|
|
91
|
+
const ariaDisabled = e.submitter.getAttribute('aria-disabled') === 'true'
|
|
92
92
|
setIsSubmitted(!ariaDisabled)
|
|
93
93
|
if (!ariaDisabled && validationIsValid) {
|
|
94
94
|
dispatch(setHasResponded(true))
|
|
@@ -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,
|
|
@@ -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
|
|
|
@@ -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
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { useSelector } from 'react-redux'
|
|
1
2
|
import Icon from 'ui/components/layout/icon'
|
|
2
3
|
import OptionsButton from 'ui/components/options/options-button'
|
|
3
4
|
import { useSeamlyOptions } from 'ui/hooks/seamly-hooks'
|
|
4
5
|
import { useI18n } from 'domains/i18n/hooks'
|
|
5
|
-
import {
|
|
6
|
+
import { selectHasError } from 'domains/interrupt/selectors'
|
|
6
7
|
import TranslationsOptionsButton from 'domains/translations/components/options-button'
|
|
7
8
|
import {
|
|
8
9
|
useLocaleNativeName,
|
|
@@ -13,14 +14,14 @@ import { className } from 'lib/css'
|
|
|
13
14
|
export default function AppOptions() {
|
|
14
15
|
const { menuOptions, allowOptionSelection } = useSeamlyOptions()
|
|
15
16
|
const { isAvailable: isTranslationsAvailable } = useTranslations()
|
|
16
|
-
const
|
|
17
|
+
const hasError = useSelector(selectHasError)
|
|
17
18
|
const { t, locale } = useI18n()
|
|
18
19
|
const localeNativeName = useLocaleNativeName(locale)
|
|
19
20
|
|
|
20
21
|
if (
|
|
21
22
|
(!isTranslationsAvailable &&
|
|
22
23
|
(!allowOptionSelection || !menuOptions.length)) ||
|
|
23
|
-
|
|
24
|
+
hasError
|
|
24
25
|
) {
|
|
25
26
|
return null
|
|
26
27
|
}
|
|
@@ -73,7 +73,7 @@ const SeamlyEventSubscriber = () => {
|
|
|
73
73
|
channel?.leave()
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
-
return () =>
|
|
76
|
+
return () => undefined
|
|
77
77
|
}, [api, api.connectionInfo, api.conversation])
|
|
78
78
|
|
|
79
79
|
useEffect(() => {
|
|
@@ -283,6 +283,10 @@ const SeamlyEventSubscriber = () => {
|
|
|
283
283
|
|
|
284
284
|
const { channel } = api.conversation
|
|
285
285
|
|
|
286
|
+
if (messageChannelRef.current) {
|
|
287
|
+
channel?.off('message', messageChannelRef.current)
|
|
288
|
+
}
|
|
289
|
+
|
|
286
290
|
messageChannelRef.current = channel.on('message', (payload) => {
|
|
287
291
|
if (!EMITTABLE_MESSAGE_TYPES.includes(payload.type)) {
|
|
288
292
|
return payload
|
|
@@ -301,13 +305,7 @@ const SeamlyEventSubscriber = () => {
|
|
|
301
305
|
|
|
302
306
|
return true
|
|
303
307
|
})
|
|
304
|
-
|
|
305
|
-
return () => {
|
|
306
|
-
api.conversation.channel?.off('message', messageChannelRef.current)
|
|
307
|
-
}
|
|
308
308
|
}
|
|
309
|
-
|
|
310
|
-
return () => undefined
|
|
311
309
|
}, [api, api.connectionInfo, api.conversation.channel, eventBus])
|
|
312
310
|
|
|
313
311
|
useEffect(() => {
|
|
@@ -315,6 +313,10 @@ const SeamlyEventSubscriber = () => {
|
|
|
315
313
|
api.conversation.onConnection(({ connected }) => {
|
|
316
314
|
if (!connected) return false
|
|
317
315
|
|
|
316
|
+
if (syncChannelRef.current) {
|
|
317
|
+
api.conversation.channel?.off('sync', syncChannelRef.current)
|
|
318
|
+
}
|
|
319
|
+
|
|
318
320
|
syncChannelRef.current = api.conversation.channel.on(
|
|
319
321
|
'sync',
|
|
320
322
|
(payload) => {
|
|
@@ -348,13 +350,7 @@ const SeamlyEventSubscriber = () => {
|
|
|
348
350
|
|
|
349
351
|
return true
|
|
350
352
|
})
|
|
351
|
-
|
|
352
|
-
return () => {
|
|
353
|
-
api.conversation.channel?.off('sync', syncChannelRef.current)
|
|
354
|
-
}
|
|
355
353
|
}
|
|
356
|
-
|
|
357
|
-
return () => undefined
|
|
358
354
|
}, [api, api.connectionInfo, api.conversation.channel, events, dispatch])
|
|
359
355
|
|
|
360
356
|
return null
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useContext, useEffect, useRef } from 'preact/hooks'
|
|
2
|
-
import { useDispatch } from 'react-redux'
|
|
2
|
+
import { useDispatch, useSelector } from 'react-redux'
|
|
3
3
|
import { userParticipantId } from 'config'
|
|
4
4
|
import {
|
|
5
5
|
useSeamlyActivityEventHandler,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import { actionTypes, sourceTypes } from 'ui/utils/seamly-utils'
|
|
13
13
|
import { useConfig } from 'domains/config/hooks'
|
|
14
14
|
import { updateConfig } from 'domains/config/slice'
|
|
15
|
-
import {
|
|
15
|
+
import { selectHasError } from 'domains/interrupt/selectors'
|
|
16
16
|
import { useTranslations } from 'domains/translations/hooks'
|
|
17
17
|
import { visibilityStates } from 'domains/visibility/constants'
|
|
18
18
|
import { useVisibility } from 'domains/visibility/hooks'
|
|
@@ -47,7 +47,7 @@ const SeamlyInstanceFunctionsLoader = () => {
|
|
|
47
47
|
const previousUnreadCount = useRef(null)
|
|
48
48
|
const previousVisibilityState = useRef(null)
|
|
49
49
|
const { isInline, isResolving } = useSeamlyLayoutMode()
|
|
50
|
-
const
|
|
50
|
+
const hasError = useSelector(selectHasError)
|
|
51
51
|
const currentConversationUrl = useSeamlyConversationUrl()
|
|
52
52
|
const prevConversationUrl = useRef(null)
|
|
53
53
|
const onActivityHandler = useSeamlyActivityEventHandler()
|
|
@@ -142,7 +142,7 @@ const SeamlyInstanceFunctionsLoader = () => {
|
|
|
142
142
|
)
|
|
143
143
|
|
|
144
144
|
useEffect(() => {
|
|
145
|
-
if (!isResolving && !
|
|
145
|
+
if (!isResolving && !hasError) {
|
|
146
146
|
// Check for app reset
|
|
147
147
|
if (
|
|
148
148
|
prevConversationUrl.current &&
|
|
@@ -178,7 +178,7 @@ const SeamlyInstanceFunctionsLoader = () => {
|
|
|
178
178
|
eventBus,
|
|
179
179
|
isInline,
|
|
180
180
|
isResolving,
|
|
181
|
-
|
|
181
|
+
hasError,
|
|
182
182
|
currentConversationUrl,
|
|
183
183
|
])
|
|
184
184
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useLayoutEffect, useRef } from 'preact/hooks'
|
|
2
|
+
import { useSelector } from 'react-redux'
|
|
2
3
|
import {
|
|
3
4
|
useFocusIfSeamlyContainedFocus,
|
|
4
5
|
useGeneratedId,
|
|
@@ -8,7 +9,7 @@ import {
|
|
|
8
9
|
useSkiplinkTargetFocusing,
|
|
9
10
|
} from 'ui/hooks/seamly-hooks'
|
|
10
11
|
import { useI18n } from 'domains/i18n/hooks'
|
|
11
|
-
import {
|
|
12
|
+
import { selectHasError } from 'domains/interrupt/selectors'
|
|
12
13
|
import { useVisibility } from 'domains/visibility/hooks'
|
|
13
14
|
import { className } from 'lib/css'
|
|
14
15
|
|
|
@@ -24,10 +25,10 @@ const DeprecatedToggleButton = ({ onOpenChat }) => {
|
|
|
24
25
|
const focusIfContained = useFocusIfSeamlyContainedFocus()
|
|
25
26
|
const currentAgent = useSeamlyCurrentAgent()
|
|
26
27
|
const agentSubtitle = useSeamlyHeaderData().subTitle
|
|
27
|
-
const
|
|
28
|
+
const hasError = useSelector(selectHasError)
|
|
28
29
|
const { headerCollapseButtonId } = useSeamlyStateContext()
|
|
29
30
|
|
|
30
|
-
const showAgentInfo = currentAgent && !
|
|
31
|
+
const showAgentInfo = currentAgent && !hasError
|
|
31
32
|
|
|
32
33
|
useLayoutEffect(() => {
|
|
33
34
|
// Because we can close the app from the external API we
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef } from 'preact/hooks'
|
|
2
|
+
import { useSelector } from 'react-redux'
|
|
2
3
|
import Icon from 'ui/components/layout/icon'
|
|
3
4
|
import InOutTransition, {
|
|
4
5
|
transitionStartStates,
|
|
@@ -17,7 +18,7 @@ import { runIfElementContainsOrHasFocus } from 'ui/utils/general-utils'
|
|
|
17
18
|
import { actionTypes } from 'ui/utils/seamly-utils'
|
|
18
19
|
import { useUserHasResponded } from 'domains/app/hooks'
|
|
19
20
|
import { useI18n } from 'domains/i18n/hooks'
|
|
20
|
-
import {
|
|
21
|
+
import { selectHasError } from 'domains/interrupt/selectors'
|
|
21
22
|
import { useTranslatedEventData } from 'domains/translations/hooks'
|
|
22
23
|
import { className } from 'lib/css'
|
|
23
24
|
|
|
@@ -27,7 +28,7 @@ const Faq = () => {
|
|
|
27
28
|
const sectionId = useGeneratedId()
|
|
28
29
|
const focusSkiplinkTarget = useSkiplinkTargetFocusing()
|
|
29
30
|
const { sendPolite } = useLiveRegion()
|
|
30
|
-
const
|
|
31
|
+
const hasError = useSelector(selectHasError)
|
|
31
32
|
const { hasCountdown, endCountdown } = useSeamlyIdleDetachCountdown()
|
|
32
33
|
const { hasPrompt, continueChat } = useSeamlyResumeConversationPrompt()
|
|
33
34
|
|
|
@@ -36,7 +37,7 @@ const Faq = () => {
|
|
|
36
37
|
payload: lastFaqEventPayload,
|
|
37
38
|
})
|
|
38
39
|
const faqs = useMemo(() => {
|
|
39
|
-
const newFaqs = lastFaqEventPayload && !
|
|
40
|
+
const newFaqs = lastFaqEventPayload && !hasError ? eventBody : []
|
|
40
41
|
const itemBaseClass = `faqs__item`
|
|
41
42
|
return newFaqs.map(({ categories = [], ...faqRest }) => ({
|
|
42
43
|
...faqRest,
|
|
@@ -51,7 +52,7 @@ const Faq = () => {
|
|
|
51
52
|
),
|
|
52
53
|
],
|
|
53
54
|
}))
|
|
54
|
-
}, [lastFaqEventPayload,
|
|
55
|
+
}, [lastFaqEventPayload, hasError, eventBody])
|
|
55
56
|
|
|
56
57
|
const prevFaqs = useRef(null)
|
|
57
58
|
const prevHasFaqs = useRef(false)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useSelector } from 'react-redux'
|
|
1
2
|
import {
|
|
2
3
|
useSeamlyCurrentAgent,
|
|
3
4
|
useSeamlyHeaderData,
|
|
@@ -5,7 +6,7 @@ import {
|
|
|
5
6
|
} from 'ui/hooks/seamly-hooks'
|
|
6
7
|
import { useStartChatIcon } from 'domains/config/hooks'
|
|
7
8
|
import { useI18n } from 'domains/i18n/hooks'
|
|
8
|
-
import {
|
|
9
|
+
import { selectHasError } from 'domains/interrupt/selectors'
|
|
9
10
|
import { useVisibility } from 'domains/visibility/hooks'
|
|
10
11
|
import { className } from 'lib/css'
|
|
11
12
|
import Icon from './icon'
|
|
@@ -16,10 +17,10 @@ const AgentInfo = () => {
|
|
|
16
17
|
const unreadMessageCount = useSeamlyUnreadCount()
|
|
17
18
|
const { isOpen } = useVisibility()
|
|
18
19
|
const currentAgent = useSeamlyCurrentAgent()
|
|
19
|
-
const
|
|
20
|
+
const hasError = useSelector(selectHasError)
|
|
20
21
|
const startChatIcon = useStartChatIcon()
|
|
21
22
|
const src = currentAgent?.avatar ?? startChatIcon
|
|
22
|
-
const displaySubtitle =
|
|
23
|
+
const displaySubtitle = hasError ? '' : subTitle
|
|
23
24
|
|
|
24
25
|
const classNames = ['message-count']
|
|
25
26
|
|
|
@@ -1,21 +1,20 @@
|
|
|
1
|
+
import { useSelector } from 'react-redux'
|
|
1
2
|
import AppOptions from 'ui/components/app-options'
|
|
2
3
|
import ChatScrollProvider from 'ui/components/conversation/event/chat-scroll/chat-scroll-provider'
|
|
3
4
|
import EntryContainer from 'ui/components/entry/entry-container'
|
|
4
5
|
import CollapseButton from 'ui/components/view/window-view/collapse-button'
|
|
5
|
-
import {
|
|
6
|
+
import { selectHasError } from 'domains/interrupt/selectors'
|
|
6
7
|
import TranslationStatus from 'domains/translations/components/translation-status'
|
|
7
8
|
import { useVisibility } from 'domains/visibility/hooks'
|
|
8
9
|
import { className } from 'lib/css'
|
|
10
|
+
import Interrupt from './interrupt'
|
|
9
11
|
|
|
10
|
-
function ChatFrame({ children
|
|
11
|
-
const
|
|
12
|
+
function ChatFrame({ children }) {
|
|
13
|
+
const hasError = useSelector(selectHasError)
|
|
12
14
|
const { isOpen } = useVisibility()
|
|
13
15
|
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
return <InterruptComponent {...meta} />
|
|
17
|
-
}
|
|
18
|
-
return null
|
|
16
|
+
if (hasError) {
|
|
17
|
+
return <Interrupt />
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
return (
|
|
@@ -1,20 +1,19 @@
|
|
|
1
|
+
import { useSelector } from 'react-redux'
|
|
1
2
|
import AppOptions from 'ui/components/app-options'
|
|
2
3
|
import ChatScrollProvider from 'ui/components/conversation/event/chat-scroll/chat-scroll-provider'
|
|
3
4
|
import EntryContainer from 'ui/components/entry/entry-container'
|
|
4
|
-
import {
|
|
5
|
+
import { selectHasError } from 'domains/interrupt/selectors'
|
|
5
6
|
import TranslationStatus from 'domains/translations/components/translation-status'
|
|
6
7
|
import { useVisibility } from 'domains/visibility/hooks'
|
|
7
8
|
import { className } from 'lib/css'
|
|
9
|
+
import Interrupt from './interrupt'
|
|
8
10
|
|
|
9
|
-
function ChatFrame({ children
|
|
10
|
-
const { hasInterrupt, meta } = useInterrupt()
|
|
11
|
+
function ChatFrame({ children }) {
|
|
11
12
|
const { isOpen } = useVisibility()
|
|
13
|
+
const hasError = useSelector(selectHasError)
|
|
12
14
|
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
-
return <InterruptComponent {...meta} />
|
|
16
|
-
}
|
|
17
|
-
return null
|
|
15
|
+
if (hasError) {
|
|
16
|
+
return <Interrupt />
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
return (
|
|
@@ -6,27 +6,18 @@ import {
|
|
|
6
6
|
useSeamlyCommands,
|
|
7
7
|
useSkiplinkTargetFocusing,
|
|
8
8
|
} from 'ui/hooks/seamly-hooks'
|
|
9
|
+
import { useInterrupt } from 'domains/interrupt/hooks'
|
|
9
10
|
import { className } from 'lib/css'
|
|
10
11
|
|
|
11
|
-
const Interrupt = ({
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
buttonText,
|
|
16
|
-
action,
|
|
17
|
-
srText,
|
|
18
|
-
}) => {
|
|
12
|
+
const Interrupt = () => {
|
|
13
|
+
const {
|
|
14
|
+
meta: { originalError, title, message, buttonText, action, srText },
|
|
15
|
+
} = useInterrupt()
|
|
19
16
|
const seamlyCommands = useSeamlyCommands()
|
|
20
17
|
const headingId = useGeneratedId()
|
|
21
18
|
const { sendPolite } = useLiveRegion()
|
|
22
19
|
const focusSkiplinkTarget = useSkiplinkTargetFocusing()
|
|
23
|
-
const isExpiredError = originalError
|
|
24
|
-
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
if (isExpiredError && seamlyCommands[action]) {
|
|
27
|
-
seamlyCommands[action]()
|
|
28
|
-
}
|
|
29
|
-
}, [action, seamlyCommands, isExpiredError])
|
|
20
|
+
const isExpiredError = originalError?.name === 'SeamlySessionExpiredError'
|
|
30
21
|
|
|
31
22
|
useEffect(() => {
|
|
32
23
|
if (!isExpiredError && srText) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { useSelector } from 'react-redux'
|
|
1
2
|
import useEventComponentMapping from 'ui/hooks/use-event-component-mapping'
|
|
2
3
|
import { useConfig } from 'domains/config/hooks'
|
|
3
|
-
import {
|
|
4
|
+
import { selectHasError } from 'domains/interrupt/selectors'
|
|
4
5
|
import { useVisibility } from 'domains/visibility/hooks'
|
|
5
6
|
import { className } from 'lib/css'
|
|
6
7
|
|
|
@@ -11,10 +12,10 @@ export function PreChatMessageEvent({ event }) {
|
|
|
11
12
|
|
|
12
13
|
export default function PreChatMessages() {
|
|
13
14
|
const { preChatEvents, layoutMode } = useConfig()
|
|
14
|
-
const
|
|
15
|
+
const hasError = useSelector(selectHasError)
|
|
15
16
|
const { isOpen } = useVisibility()
|
|
16
17
|
|
|
17
|
-
const isVisible = !(
|
|
18
|
+
const isVisible = !(hasError || !preChatEvents?.length || isOpen)
|
|
18
19
|
|
|
19
20
|
return (
|
|
20
21
|
isVisible && (
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef } from 'preact/hooks'
|
|
2
|
+
import { useSelector } from 'react-redux'
|
|
2
3
|
import SuggestionsList from 'ui/components/suggestions/suggestions-list'
|
|
3
4
|
import InOutTransition, {
|
|
4
5
|
transitionStartStates,
|
|
@@ -18,7 +19,7 @@ import { actionTypes } from 'ui/utils/seamly-utils'
|
|
|
18
19
|
import { useUserHasResponded } from 'domains/app/hooks'
|
|
19
20
|
import { useConfig } from 'domains/config/hooks'
|
|
20
21
|
import { useI18n } from 'domains/i18n/hooks'
|
|
21
|
-
import {
|
|
22
|
+
import { selectHasError } from 'domains/interrupt/selectors'
|
|
22
23
|
import { useTranslatedEventData } from 'domains/translations/hooks'
|
|
23
24
|
import { visibilityStates } from 'domains/visibility/constants'
|
|
24
25
|
import { useVisibility } from 'domains/visibility/hooks'
|
|
@@ -37,7 +38,7 @@ const Suggestions = ({ isAside = false }) => {
|
|
|
37
38
|
const containerRef = useRef(null)
|
|
38
39
|
const { sendPolite } = useLiveRegion()
|
|
39
40
|
// interrupt & countdown hooks
|
|
40
|
-
const
|
|
41
|
+
const hasError = useSelector(selectHasError)
|
|
41
42
|
const { hasCountdown, endCountdown } = useSeamlyIdleDetachCountdown()
|
|
42
43
|
const { hasPrompt, continueChat } = useSeamlyResumeConversationPrompt()
|
|
43
44
|
// data hooks
|
|
@@ -45,8 +46,8 @@ const Suggestions = ({ isAside = false }) => {
|
|
|
45
46
|
const payload = useSeamlyServiceData('suggestion')
|
|
46
47
|
const { body: eventBody } = useTranslatedEventData({ payload })
|
|
47
48
|
const suggestions = useMemo(
|
|
48
|
-
() => (payload && !
|
|
49
|
-
[payload,
|
|
49
|
+
() => (payload && !hasError ? eventBody : []),
|
|
50
|
+
[payload, hasError, eventBody],
|
|
50
51
|
)
|
|
51
52
|
|
|
52
53
|
const prevSuggestions = useRef(null)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { useCallback } from 'preact/hooks'
|
|
2
|
+
import { useSelector } from 'react-redux'
|
|
2
3
|
import ChatStatus from 'ui/components/chat-status'
|
|
3
4
|
import { useSkiplinkTargetFocusing } from 'ui/hooks/focus-helper-hooks'
|
|
4
5
|
import { useI18n } from 'domains/i18n/hooks'
|
|
5
|
-
import {
|
|
6
|
+
import { selectHasError } from 'domains/interrupt/selectors'
|
|
6
7
|
import {
|
|
7
8
|
useLocaleNativeName,
|
|
8
9
|
useTranslations,
|
|
@@ -12,7 +13,7 @@ import {
|
|
|
12
13
|
export default function TranslationChatStatus() {
|
|
13
14
|
const { t } = useI18n()
|
|
14
15
|
const { id } = useTranslationsContainer()
|
|
15
|
-
const
|
|
16
|
+
const hasError = useSelector(selectHasError)
|
|
16
17
|
const { disableTranslations, currentLocale } = useTranslations()
|
|
17
18
|
const localeNativeName = useLocaleNativeName(currentLocale)
|
|
18
19
|
const focusSkiplinkTarget = useSkiplinkTargetFocusing()
|
|
@@ -24,7 +25,7 @@ export default function TranslationChatStatus() {
|
|
|
24
25
|
focusSkiplinkTarget()
|
|
25
26
|
}, [disableTranslations, focusSkiplinkTarget])
|
|
26
27
|
|
|
27
|
-
if (
|
|
28
|
+
if (hasError) {
|
|
28
29
|
return null
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import Conversation from '../conversation/conversation'
|
|
2
2
|
import Chat from '../layout/chat'
|
|
3
3
|
import ChatFrame from '../layout/chat-frame'
|
|
4
|
-
import Interrupt from '../layout/interrupt'
|
|
5
4
|
|
|
6
5
|
const AppView = () => {
|
|
7
6
|
return (
|
|
8
7
|
<Chat>
|
|
9
|
-
<ChatFrame
|
|
8
|
+
<ChatFrame>
|
|
10
9
|
<Conversation />
|
|
11
10
|
</ChatFrame>
|
|
12
11
|
</Chat>
|
|
@@ -5,7 +5,6 @@ import DeprecatedToggleButton from '../entry/deprecated-toggle-button'
|
|
|
5
5
|
import AgentInfo from '../layout/agent-info'
|
|
6
6
|
import DeprecatedAppFrame from '../layout/deprecated-app-frame'
|
|
7
7
|
import Header from '../layout/header'
|
|
8
|
-
import Interrupt from '../layout/interrupt'
|
|
9
8
|
|
|
10
9
|
const ShowInlineView = ({ children }) => {
|
|
11
10
|
const { showInlineView, containerRef } = useShowInlineView()
|
|
@@ -24,7 +23,7 @@ const DeprecatedView = () => {
|
|
|
24
23
|
<Header onCloseChat={closeChat}>
|
|
25
24
|
<AgentInfo />
|
|
26
25
|
</Header>
|
|
27
|
-
<ChatFrame
|
|
26
|
+
<ChatFrame>
|
|
28
27
|
<Conversation />
|
|
29
28
|
</ChatFrame>
|
|
30
29
|
</DeprecatedAppFrame>
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { useInterrupt } from 'domains/interrupt/hooks'
|
|
2
1
|
import { useShowInlineView, useVisibility } from 'domains/visibility/hooks'
|
|
3
2
|
import { className } from 'lib/css'
|
|
4
3
|
import Conversation from '../conversation/conversation'
|
|
5
4
|
import Chat from '../layout/chat'
|
|
6
5
|
import ChatFrame from '../layout/chat-frame'
|
|
7
|
-
import Interrupt from '../layout/interrupt'
|
|
8
6
|
import PreChatMessages from '../layout/pre-chat-messages'
|
|
9
7
|
import Suggestions from '../suggestions'
|
|
10
8
|
import InOutTransition, {
|
|
@@ -15,12 +13,6 @@ const InlineView = () => {
|
|
|
15
13
|
const { showInlineView, containerRef } = useShowInlineView()
|
|
16
14
|
|
|
17
15
|
const { isOpen } = useVisibility()
|
|
18
|
-
const { hasInterrupt, meta } = useInterrupt()
|
|
19
|
-
|
|
20
|
-
if (hasInterrupt && !isOpen) {
|
|
21
|
-
return <Interrupt {...meta} />
|
|
22
|
-
}
|
|
23
|
-
|
|
24
16
|
return (
|
|
25
17
|
<>
|
|
26
18
|
<InOutTransition
|
|
@@ -44,9 +36,7 @@ const InlineView = () => {
|
|
|
44
36
|
>
|
|
45
37
|
<Chat ref={containerRef}>
|
|
46
38
|
{showInlineView && (
|
|
47
|
-
<ChatFrame
|
|
48
|
-
{isOpen && <Conversation />}
|
|
49
|
-
</ChatFrame>
|
|
39
|
+
<ChatFrame>{isOpen && <Conversation />}</ChatFrame>
|
|
50
40
|
)}
|
|
51
41
|
</Chat>
|
|
52
42
|
</InOutTransition>
|
|
@@ -3,14 +3,12 @@ import Conversation from 'ui/components/conversation/conversation'
|
|
|
3
3
|
import Text from 'ui/components/conversation/event/text'
|
|
4
4
|
import Chat from 'ui/components/layout/chat'
|
|
5
5
|
import ChatFrame from 'ui/components/layout/chat-frame'
|
|
6
|
-
import Interrupt from 'ui/components/layout/interrupt'
|
|
7
6
|
import PreChatMessages from 'ui/components/layout/pre-chat-messages'
|
|
8
7
|
import InOutTransition, {
|
|
9
8
|
transitionStartStates,
|
|
10
9
|
} from 'ui/components/widgets/in-out-transition'
|
|
11
10
|
import { useUserHasResponded } from 'domains/app/hooks'
|
|
12
11
|
import { useI18n } from 'domains/i18n/hooks'
|
|
13
|
-
import { useInterrupt } from 'domains/interrupt/hooks'
|
|
14
12
|
import { useVisibility } from 'domains/visibility/hooks'
|
|
15
13
|
import { className } from 'lib/css'
|
|
16
14
|
import WindowOpenButton from './window-open-button'
|
|
@@ -18,8 +16,6 @@ import WindowOpenButton from './window-open-button'
|
|
|
18
16
|
const WindowView = () => {
|
|
19
17
|
const { isOpen, openChat } = useVisibility()
|
|
20
18
|
const userHasResponded = useUserHasResponded()
|
|
21
|
-
const { hasInterrupt, meta } = useInterrupt()
|
|
22
|
-
|
|
23
19
|
const { t } = useI18n()
|
|
24
20
|
const continueChatText = t('window.chat.continue')
|
|
25
21
|
const continueChatEvent = useMemo(
|
|
@@ -33,10 +29,6 @@ const WindowView = () => {
|
|
|
33
29
|
[continueChatText],
|
|
34
30
|
)
|
|
35
31
|
|
|
36
|
-
if (hasInterrupt && !isOpen) {
|
|
37
|
-
return <Interrupt {...meta} />
|
|
38
|
-
}
|
|
39
|
-
|
|
40
32
|
return (
|
|
41
33
|
<>
|
|
42
34
|
<WindowOpenButton onClick={openChat} />
|
|
@@ -72,7 +64,7 @@ const WindowView = () => {
|
|
|
72
64
|
transitionStartState={transitionStartStates.notRendered}
|
|
73
65
|
>
|
|
74
66
|
<Chat>
|
|
75
|
-
<ChatFrame
|
|
67
|
+
<ChatFrame>
|
|
76
68
|
<Conversation />
|
|
77
69
|
</ChatFrame>
|
|
78
70
|
</Chat>
|