@seamly/web-ui 20.8.0-beta.4 → 20.8.0-beta.5
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/hooks.js +0 -1
- package/build/dist/lib/hooks.min.js +1 -1
- package/build/dist/lib/index.debug.js +21 -10
- package/build/dist/lib/index.debug.min.js +1 -1
- package/build/dist/lib/index.debug.min.js.LICENSE.txt +4 -0
- package/build/dist/lib/index.js +138 -30
- package/build/dist/lib/index.min.js +1 -1
- package/build/dist/lib/standalone.js +142 -30
- package/build/dist/lib/standalone.min.js +1 -1
- package/build/dist/lib/style-guide.js +56 -58
- package/build/dist/lib/style-guide.min.js +1 -1
- package/package.json +1 -1
- package/src/javascripts/domains/app/actions.ts +9 -3
- package/src/javascripts/domains/config/actions.ts +2 -0
- package/src/javascripts/domains/i18n/actions.ts +24 -14
- package/src/javascripts/domains/i18n/hooks.ts +6 -1
- package/src/javascripts/domains/i18n/i18n.types.ts +3 -1
- package/src/javascripts/domains/i18n/slice.ts +7 -1
- package/src/javascripts/domains/translations/middleware.js +1 -0
- package/src/javascripts/domains/visibility/slice.ts +15 -7
- package/src/javascripts/index.ts +1 -1
- package/src/javascripts/lib/engine/index.js +7 -1
- package/src/javascripts/package/hooks.js +0 -1
- package/src/javascripts/ui/hooks/seamly-hooks.js +0 -3
- package/src/javascripts/ui/hooks/use-seamly-actions.ts +102 -0
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createAsyncThunk } from '@reduxjs/toolkit'
|
|
1
|
+
import { createAsyncThunk, unwrapResult } from '@reduxjs/toolkit'
|
|
2
2
|
import SeamlySessionExpiredError from 'api/errors/seamly-session-expired-error'
|
|
3
3
|
import SeamlyUnavailableError from 'api/errors/seamly-unavailable-error'
|
|
4
4
|
import { Config } from 'config.types'
|
|
@@ -47,7 +47,6 @@ export const initializeApp = createAsyncThunk<
|
|
|
47
47
|
body: { enabled: true, locale },
|
|
48
48
|
})
|
|
49
49
|
}
|
|
50
|
-
dispatch(setLocale(locale))
|
|
51
50
|
return { initialState: undefined, locale, config }
|
|
52
51
|
}
|
|
53
52
|
} catch (e) {
|
|
@@ -81,7 +80,14 @@ export const resetApp = createAsyncThunk<unknown, void, ThunkAPI>(
|
|
|
81
80
|
|
|
82
81
|
dispatch(resetConfig())
|
|
83
82
|
await dispatch(initializeConfig())
|
|
84
|
-
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const { locale } = await dispatch(initializeApp()).unwrap()
|
|
86
|
+
await dispatch(setLocale(locale))
|
|
87
|
+
} catch (rejectedValueOrSerializedError) {
|
|
88
|
+
// nothing to do
|
|
89
|
+
}
|
|
90
|
+
|
|
85
91
|
dispatch(initializeVisibility())
|
|
86
92
|
},
|
|
87
93
|
)
|
|
@@ -16,6 +16,7 @@ export const initializeConfig = createAsyncThunk<any, void, ThunkAPI>(
|
|
|
16
16
|
} = await api.getConfig()
|
|
17
17
|
|
|
18
18
|
const locale = config?.context?.locale || defaultLocale
|
|
19
|
+
const { connectWhenInView } = config
|
|
19
20
|
|
|
20
21
|
return {
|
|
21
22
|
features,
|
|
@@ -25,6 +26,7 @@ export const initializeConfig = createAsyncThunk<any, void, ThunkAPI>(
|
|
|
25
26
|
userParticipant,
|
|
26
27
|
startChatIcon,
|
|
27
28
|
locale,
|
|
29
|
+
connectWhenInView,
|
|
28
30
|
}
|
|
29
31
|
} catch (e) {
|
|
30
32
|
const err = new SeamlyUnavailableError()
|
|
@@ -1,24 +1,34 @@
|
|
|
1
1
|
import { createAsyncThunk } from '@reduxjs/toolkit'
|
|
2
|
-
import {
|
|
2
|
+
import type { I18nState } from 'domains/i18n/i18n.types'
|
|
3
3
|
import { ThunkAPI } from 'domains/redux/redux.types'
|
|
4
4
|
|
|
5
5
|
export const setLocale = createAsyncThunk<
|
|
6
6
|
{
|
|
7
|
-
translations:
|
|
8
|
-
locale:
|
|
7
|
+
translations: I18nState['translations']
|
|
8
|
+
locale: I18nState['locale']
|
|
9
9
|
},
|
|
10
10
|
string,
|
|
11
11
|
ThunkAPI
|
|
12
|
-
>(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
12
|
+
>(
|
|
13
|
+
'setLocale',
|
|
14
|
+
async (locale, { extra: { api } }) => {
|
|
15
|
+
const response = await api.getTranslations(locale)
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
return {
|
|
18
|
+
translations: response,
|
|
19
|
+
locale,
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
condition: (locale, { getState }) => {
|
|
24
|
+
const {
|
|
25
|
+
i18n: { isLoading, locale: stateLocale },
|
|
26
|
+
} = getState()
|
|
19
27
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
28
|
+
if (locale === stateLocale || isLoading) {
|
|
29
|
+
// Already fetched or in progress, don't need to re-fetch
|
|
30
|
+
return false
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
)
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
pluralTypeHandler,
|
|
4
4
|
selectTypeHandler,
|
|
5
5
|
} from '@ultraq/icu-message-formatter'
|
|
6
|
+
import { RootState } from 'domains/store'
|
|
6
7
|
import { useCallback } from 'preact/hooks'
|
|
7
8
|
import { useSelector } from 'react-redux'
|
|
8
9
|
import * as Selectors from './selectors'
|
|
@@ -19,16 +20,20 @@ export function useI18n() {
|
|
|
19
20
|
const translations = useSelector(Selectors.selectTranslations)
|
|
20
21
|
const locale = useSelector(Selectors.selectLocale)
|
|
21
22
|
const initialLocale = useSelector(Selectors.selectInitialLocale)
|
|
23
|
+
const isLoading = useSelector((state: RootState) => state.i18n.isLoading)
|
|
24
|
+
|
|
22
25
|
const t = useCallback(
|
|
23
26
|
(key, values = {}) => {
|
|
24
27
|
const translation = translations[key]
|
|
25
28
|
if (!translation) {
|
|
29
|
+
if (isLoading) return null
|
|
30
|
+
|
|
26
31
|
console.warn(`Translation key: ${key} is missing in locale: ${locale}`)
|
|
27
32
|
return null
|
|
28
33
|
}
|
|
29
34
|
return formatter.format(translation, values)
|
|
30
35
|
},
|
|
31
|
-
[translations, locale],
|
|
36
|
+
[translations, locale, isLoading],
|
|
32
37
|
)
|
|
33
38
|
|
|
34
39
|
return {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { operations } from 'schema'
|
|
2
|
+
|
|
1
3
|
export interface I18nState {
|
|
2
|
-
translations:
|
|
4
|
+
translations: operations['getAccountTranslations']['responses']['200']['content']['application/json']['translations']
|
|
3
5
|
isLoading: boolean
|
|
4
6
|
initialLocale?: string
|
|
5
7
|
locale?: string
|
|
@@ -50,9 +50,15 @@ export const i18nSlice = createSlice({
|
|
|
50
50
|
.addCase(initializeConfig.fulfilled, (state, { payload }) => {
|
|
51
51
|
state.initialLocale = payload.locale
|
|
52
52
|
})
|
|
53
|
+
.addCase(setLocale.pending, (state) => {
|
|
54
|
+
state.isLoading = true
|
|
55
|
+
})
|
|
56
|
+
.addCase(setLocale.rejected, (state) => {
|
|
57
|
+
state.isLoading = false
|
|
58
|
+
})
|
|
53
59
|
.addCase(setLocale.fulfilled, (state, { payload }) => {
|
|
60
|
+
state.isLoading = false
|
|
54
61
|
if (!payload?.translations) {
|
|
55
|
-
state.isLoading = false
|
|
56
62
|
return
|
|
57
63
|
}
|
|
58
64
|
|
|
@@ -27,6 +27,7 @@ export default function createI18nMiddleware({ dispatch, getState }) {
|
|
|
27
27
|
case setInitialState.type:
|
|
28
28
|
if (payload?.translation?.enabled) {
|
|
29
29
|
dispatch(enableTranslation(payload.translation.locale))
|
|
30
|
+
dispatch(setLocale(payload.locale))
|
|
30
31
|
}
|
|
31
32
|
break
|
|
32
33
|
case addEvent.type:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
|
2
2
|
import { VisibilityOptions } from 'config.types'
|
|
3
|
+
import { initializeConfig } from 'domains/config/actions'
|
|
3
4
|
import { setVisibility } from 'domains/visibility/actions'
|
|
4
5
|
import { visibilityStates } from 'domains/visibility/constants'
|
|
5
6
|
import type { VisibilityState } from 'domains/visibility/visibility.types'
|
|
@@ -21,14 +22,21 @@ export const visibilitySlice = createSlice({
|
|
|
21
22
|
},
|
|
22
23
|
},
|
|
23
24
|
extraReducers: (builder) => {
|
|
24
|
-
builder
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
builder
|
|
26
|
+
.addCase(
|
|
27
|
+
setVisibility.fulfilled,
|
|
28
|
+
(state, { payload: visibility }: PayloadAction<VisibilityOptions>) => {
|
|
29
|
+
if (visibility) {
|
|
30
|
+
state.visibility = visibility
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
)
|
|
34
|
+
.addCase(initializeConfig.fulfilled, (state, { payload }) => {
|
|
35
|
+
// We only want to (always) show the inlineView when connectWhenInView is disabled
|
|
36
|
+
if (!payload.connectWhenInView) {
|
|
37
|
+
state.showInlineView = !payload.connectWhenInView
|
|
29
38
|
}
|
|
30
|
-
}
|
|
31
|
-
)
|
|
39
|
+
})
|
|
32
40
|
},
|
|
33
41
|
})
|
|
34
42
|
|
package/src/javascripts/index.ts
CHANGED
|
@@ -80,7 +80,6 @@ export {
|
|
|
80
80
|
useGeneratedId,
|
|
81
81
|
useSeamlyChat,
|
|
82
82
|
useSeamlyCommands,
|
|
83
|
-
useSeamlyDispatchContext,
|
|
84
83
|
useSeamlyEventStream,
|
|
85
84
|
useSeamlyIdleDetachCountdown,
|
|
86
85
|
useSeamlyMessageContainerClassNames,
|
|
@@ -90,3 +89,4 @@ export {
|
|
|
90
89
|
export { getUrlParams, getUrlSearchString } from './ui/utils/general-utils'
|
|
91
90
|
// Used by: Client
|
|
92
91
|
export { eventTypes } from './ui/utils/seamly-utils'
|
|
92
|
+
export { useSeamlyActions } from 'ui/hooks/use-seamly-actions'
|
|
@@ -3,6 +3,7 @@ import { initializeApp } from 'domains/app/actions'
|
|
|
3
3
|
|
|
4
4
|
import { initializeConfig } from 'domains/config/actions'
|
|
5
5
|
import { setConfig } from 'domains/config/slice'
|
|
6
|
+
import { setLocale } from 'domains/i18n/actions'
|
|
6
7
|
|
|
7
8
|
import { createStore } from 'domains/store'
|
|
8
9
|
import { initializeVisibility } from 'domains/visibility/actions'
|
|
@@ -65,7 +66,12 @@ export default class Engine {
|
|
|
65
66
|
|
|
66
67
|
store.dispatch(setConfig(renderConfig))
|
|
67
68
|
await store.dispatch(initializeConfig())
|
|
68
|
-
|
|
69
|
+
try {
|
|
70
|
+
const { locale } = await store.dispatch(initializeApp()).unwrap()
|
|
71
|
+
await store.dispatch(setLocale(locale))
|
|
72
|
+
} catch (rejectedValueOrSerializedError) {
|
|
73
|
+
// nothing to do
|
|
74
|
+
}
|
|
69
75
|
store.dispatch(initializeVisibility())
|
|
70
76
|
|
|
71
77
|
if (View) {
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { useEffect } from 'preact/hooks'
|
|
2
|
-
import { useDispatch } from 'react-redux'
|
|
3
|
-
|
|
4
2
|
// Import extracted hooks here for use inside this file
|
|
5
3
|
import { useSeamlyApiContext } from './seamly-api-hooks'
|
|
6
4
|
// Export extracted hooks here,
|
|
@@ -49,7 +47,6 @@ export {
|
|
|
49
47
|
useGeneratedId,
|
|
50
48
|
useStableCallback,
|
|
51
49
|
} from './utility-hooks'
|
|
52
|
-
export { useDispatch as useSeamlyDispatchContext }
|
|
53
50
|
|
|
54
51
|
// This hook isn't used within the core
|
|
55
52
|
// But it is used in implementations
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addEvent,
|
|
3
|
+
clearEvents,
|
|
4
|
+
setHistory,
|
|
5
|
+
setEventsRead,
|
|
6
|
+
setLoadedImageEventIds,
|
|
7
|
+
ackEvent,
|
|
8
|
+
setIsLoading,
|
|
9
|
+
setParticipant,
|
|
10
|
+
setHeaderTitle,
|
|
11
|
+
setHeaderSubTitle,
|
|
12
|
+
resetHistoryLoadedFlag,
|
|
13
|
+
setActiveService,
|
|
14
|
+
initIdleDetachCountdown,
|
|
15
|
+
decrementIdleDetachCountdownCounter,
|
|
16
|
+
stopIdleDetachCountdownCounter,
|
|
17
|
+
clearIdleDetachCountdown,
|
|
18
|
+
initResumeConversationPrompt,
|
|
19
|
+
clearResumeConversationPrompt,
|
|
20
|
+
setServiceDataItem,
|
|
21
|
+
setFeatures,
|
|
22
|
+
setFeatureEnabledState,
|
|
23
|
+
clearFeatures,
|
|
24
|
+
setInitialState,
|
|
25
|
+
setUserSelectedOptions,
|
|
26
|
+
setUserSelectedOption,
|
|
27
|
+
showOption,
|
|
28
|
+
hideOption,
|
|
29
|
+
setServiceEntryMetadata,
|
|
30
|
+
setBlockAutoEntrySwitch,
|
|
31
|
+
setActiveEntryType,
|
|
32
|
+
setUserEntryType,
|
|
33
|
+
registerUpload,
|
|
34
|
+
setUploadProgress,
|
|
35
|
+
setUploadComplete,
|
|
36
|
+
setUploadError,
|
|
37
|
+
clearAllUploads,
|
|
38
|
+
setSeamlyContainerElement,
|
|
39
|
+
} from 'domains/store/slice'
|
|
40
|
+
import {
|
|
41
|
+
ChannelEvent,
|
|
42
|
+
HistoryResponse,
|
|
43
|
+
ParticipantEvent,
|
|
44
|
+
} from 'domains/store/store.types'
|
|
45
|
+
import { useDispatch } from 'react-redux'
|
|
46
|
+
|
|
47
|
+
export const useSeamlyActions = () => {
|
|
48
|
+
const dispatch = useDispatch()
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
addEvent: (event: ChannelEvent) => dispatch(addEvent(event)),
|
|
52
|
+
clearEvents: () => dispatch(clearEvents()),
|
|
53
|
+
setHistory: (history?: HistoryResponse) => dispatch(setHistory(history)),
|
|
54
|
+
setEventsRead: (payload) => dispatch(setEventsRead(payload)),
|
|
55
|
+
setLoadedImageEventIds: (ids: string[]) =>
|
|
56
|
+
dispatch(setLoadedImageEventIds(ids)),
|
|
57
|
+
ackEvent: (event) => dispatch(ackEvent(event)),
|
|
58
|
+
setIsLoading: (isLoading: boolean) => dispatch(setIsLoading(isLoading)),
|
|
59
|
+
setParticipant: (participant: ParticipantEvent) =>
|
|
60
|
+
dispatch(setParticipant(participant)),
|
|
61
|
+
setHeaderTitle: (title: string) => dispatch(setHeaderTitle(title)),
|
|
62
|
+
setHeaderSubTitle: (title: string) => dispatch(setHeaderSubTitle(title)),
|
|
63
|
+
resetHistoryLoadedFlag: () => dispatch(resetHistoryLoadedFlag()),
|
|
64
|
+
setActiveService: () => dispatch(setActiveService()),
|
|
65
|
+
initIdleDetachCountdown: (payload) =>
|
|
66
|
+
dispatch(initIdleDetachCountdown(payload)),
|
|
67
|
+
decrementIdleDetachCountdownCounter: () =>
|
|
68
|
+
dispatch(decrementIdleDetachCountdownCounter()),
|
|
69
|
+
stopIdleDetachCountdownCounter: () =>
|
|
70
|
+
dispatch(stopIdleDetachCountdownCounter()),
|
|
71
|
+
clearIdleDetachCountdown: () => dispatch(clearIdleDetachCountdown()),
|
|
72
|
+
initResumeConversationPrompt: () =>
|
|
73
|
+
dispatch(initResumeConversationPrompt()),
|
|
74
|
+
clearResumeConversationPrompt: () =>
|
|
75
|
+
dispatch(clearResumeConversationPrompt()),
|
|
76
|
+
setServiceDataItem: (payload) => dispatch(setServiceDataItem(payload)),
|
|
77
|
+
setFeatures: (payload) => dispatch(setFeatures(payload)),
|
|
78
|
+
setFeatureEnabledState: (payload) =>
|
|
79
|
+
dispatch(setFeatureEnabledState(payload)),
|
|
80
|
+
clearFeatures: () => dispatch(clearFeatures()),
|
|
81
|
+
setInitialState: (initialState) => dispatch(setInitialState(initialState)),
|
|
82
|
+
setUserSelectedOptions: (payload) =>
|
|
83
|
+
dispatch(setUserSelectedOptions(payload)),
|
|
84
|
+
setUserSelectedOption: (payload) =>
|
|
85
|
+
dispatch(setUserSelectedOption(payload)),
|
|
86
|
+
showOption: (payload) => dispatch(showOption(payload)),
|
|
87
|
+
hideOption: () => dispatch(hideOption()),
|
|
88
|
+
setServiceEntryMetadata: (payload) =>
|
|
89
|
+
dispatch(setServiceEntryMetadata(payload)),
|
|
90
|
+
setBlockAutoEntrySwitch: (payload) =>
|
|
91
|
+
dispatch(setBlockAutoEntrySwitch(payload)),
|
|
92
|
+
setActiveEntryType: (payload) => dispatch(setActiveEntryType(payload)),
|
|
93
|
+
setUserEntryType: (payload) => dispatch(setUserEntryType(payload)),
|
|
94
|
+
registerUpload: (payload) => dispatch(registerUpload(payload)),
|
|
95
|
+
setUploadProgress: (payload) => dispatch(setUploadProgress(payload)),
|
|
96
|
+
setUploadComplete: (payload) => dispatch(setUploadComplete(payload)),
|
|
97
|
+
setUploadError: (payload) => dispatch(setUploadError(payload)),
|
|
98
|
+
clearAllUploads: () => dispatch(clearAllUploads()),
|
|
99
|
+
setSeamlyContainerElement: (payload) =>
|
|
100
|
+
dispatch(setSeamlyContainerElement(payload)),
|
|
101
|
+
}
|
|
102
|
+
}
|