@seamly/web-ui 20.8.1 → 21.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/deprecated-view.js +1 -1
- package/build/dist/lib/index.debug.js +585 -584
- package/build/dist/lib/index.debug.min.js +1 -1
- package/build/dist/lib/index.debug.min.js.LICENSE.txt +110 -110
- package/build/dist/lib/index.js +20269 -26441
- package/build/dist/lib/index.min.js +1 -1
- package/build/dist/lib/index.min.js.LICENSE.txt +6 -1
- package/build/dist/lib/standalone.js +27728 -34583
- package/build/dist/lib/standalone.min.js +1 -1
- package/build/dist/lib/standalone.min.js.LICENSE.txt +1 -1
- package/build/dist/lib/storage.js +6 -15
- package/build/dist/lib/style-guide.js +9660 -8970
- package/build/dist/lib/style-guide.min.js +1 -1
- package/build/dist/lib/styles-default-implementation.js +1 -1
- package/build/dist/lib/styles.js +1 -1
- package/build/dist/lib/utils.js +85 -3
- package/build/dist/lib/utils.min.js +1 -1
- package/package.json +54 -52
- package/src/icons/icon_check-16.svg +14 -0
- package/src/icons/icon_check-32.svg +14 -0
- package/src/javascripts/api/conversation-connector.ts +149 -0
- package/src/javascripts/api/errors/seamly-base-error.js +19 -0
- package/src/javascripts/api/errors/seamly-unavailable-error.js +5 -7
- package/src/javascripts/api/{index.js → index.ts} +163 -116
- package/src/javascripts/config.types.ts +5 -4
- package/src/javascripts/domains/app/actions.ts +47 -46
- package/src/javascripts/domains/app/hooks.js +1 -1
- package/src/javascripts/domains/config/actions.ts +2 -8
- package/src/javascripts/domains/config/hooks.ts +1 -1
- package/src/javascripts/domains/config/selectors.ts +6 -6
- package/src/javascripts/domains/config/slice.ts +3 -3
- package/src/javascripts/domains/errors/index.ts +66 -0
- package/src/javascripts/domains/forms/context.ts +1 -1
- package/src/javascripts/domains/forms/forms.types.ts +3 -3
- package/src/javascripts/domains/forms/hooks.ts +10 -10
- package/src/javascripts/domains/forms/provider.tsx +9 -9
- package/src/javascripts/domains/i18n/actions.ts +11 -5
- package/src/javascripts/domains/i18n/hooks.ts +11 -8
- package/src/javascripts/domains/i18n/selectors.ts +10 -4
- package/src/javascripts/domains/i18n/slice.ts +0 -1
- package/src/javascripts/domains/interrupt/hooks.ts +1 -1
- package/src/javascripts/domains/interrupt/middleware.ts +1 -1
- package/src/javascripts/domains/store/index.ts +1 -1
- package/src/javascripts/domains/store/selectors.ts +16 -0
- package/src/javascripts/domains/store/slice.ts +47 -41
- package/src/javascripts/domains/store/store.types.ts +38 -10
- package/src/javascripts/domains/translations/components/{options-button.js → options-button.tsx} +30 -20
- package/src/javascripts/domains/translations/components/options-dialog/index.tsx +33 -0
- package/src/javascripts/domains/translations/components/options-dialog/translation-option.tsx +37 -0
- package/src/javascripts/domains/translations/components/options-dialog/translation-options.tsx +85 -0
- package/src/javascripts/domains/translations/components/translation-status.tsx +15 -0
- package/src/javascripts/domains/translations/hooks.ts +77 -11
- package/src/javascripts/domains/translations/slice.ts +20 -9
- package/src/javascripts/domains/translations/translations.types.ts +4 -2
- package/src/javascripts/domains/visibility/actions.ts +6 -10
- package/src/javascripts/domains/visibility/hooks.ts +33 -14
- package/src/javascripts/domains/visibility/selectors.ts +3 -2
- package/src/javascripts/domains/visibility/slice.ts +2 -6
- package/src/javascripts/index.ts +19 -21
- package/src/javascripts/lib/engine/{index.js → index.tsx} +25 -7
- package/src/javascripts/lib/url-helpers.ts +112 -0
- package/src/javascripts/package/utils.js +5 -2
- package/src/javascripts/schema.ts +28 -0
- package/src/javascripts/style-guide/components/app.js +16 -12
- package/src/javascripts/style-guide/components/links.js +6 -6
- package/src/javascripts/style-guide/components/static-core.js +6 -3
- package/src/javascripts/style-guide/components/view.js +1 -1
- package/src/javascripts/style-guide/states.js +129 -31
- package/src/javascripts/style-guide/style-guide-engine.js +1 -1
- package/src/javascripts/ui/components/app-options/index.js +25 -6
- package/src/javascripts/ui/components/chat-app.js +1 -1
- package/src/javascripts/ui/components/chat-status/chat-status-action.tsx +30 -0
- package/src/javascripts/ui/components/chat-status/index.tsx +61 -0
- package/src/javascripts/ui/components/conversation/component-filter.js +9 -9
- package/src/javascripts/ui/components/conversation/{conversation.js → conversation.tsx} +32 -41
- package/src/javascripts/ui/components/conversation/event/card-component.js +2 -2
- package/src/javascripts/ui/components/conversation/event/card-message.js +1 -1
- package/src/javascripts/ui/components/conversation/event/carousel-component/components/controls.js +2 -2
- package/src/javascripts/ui/components/conversation/event/carousel-component/index.js +4 -4
- package/src/javascripts/ui/components/conversation/event/carousel-message/components/slide.js +2 -2
- package/src/javascripts/ui/components/conversation/event/carousel-message/index.js +1 -1
- package/src/javascripts/ui/components/conversation/event/chat-scroll/chat-scroll-context.ts +12 -0
- package/src/javascripts/ui/components/conversation/event/chat-scroll/chat-scroll-provider.tsx +46 -0
- package/src/javascripts/ui/components/conversation/event/chat-scroll/unread-messages-button.tsx +27 -0
- package/src/javascripts/ui/components/conversation/event/choice-prompt.js +12 -8
- package/src/javascripts/ui/components/conversation/event/conversation-suggestions.js +6 -6
- package/src/javascripts/ui/components/conversation/event/cta.js +2 -2
- package/src/javascripts/ui/components/conversation/event/divider/index.js +0 -1
- package/src/javascripts/ui/components/conversation/event/divider/variants/default.js +1 -1
- package/src/javascripts/ui/components/conversation/event/divider/variants/new-translation.js +17 -22
- package/src/javascripts/ui/components/conversation/event/divider/variants/time-indicator.js +2 -2
- package/src/javascripts/ui/components/conversation/event/event-participant.js +1 -1
- package/src/javascripts/ui/components/conversation/event/event.tsx +66 -0
- package/src/javascripts/ui/components/conversation/event/hooks/use-event-link-click-handler.js +1 -1
- package/src/javascripts/ui/components/conversation/event/hooks/use-formatted-date.js +1 -1
- package/src/javascripts/ui/components/conversation/event/image-lightbox.js +1 -1
- package/src/javascripts/ui/components/conversation/event/image.js +2 -2
- package/src/javascripts/ui/components/conversation/event/splash.js +1 -1
- package/src/javascripts/ui/components/conversation/event/translation.js +1 -1
- package/src/javascripts/ui/components/conversation/event/upload.js +2 -2
- package/src/javascripts/ui/components/conversation/event/video.js +2 -2
- package/src/javascripts/ui/components/conversation/event-divider.js +1 -1
- package/src/javascripts/ui/components/conversation/message-container.js +1 -1
- package/src/javascripts/ui/components/conversation/use-chat-scroll.ts +108 -0
- package/src/javascripts/ui/components/core/{seamly-activity-monitor.js → seamly-activity-monitor.tsx} +12 -5
- package/src/javascripts/ui/components/core/seamly-api-context.ts +7 -0
- package/src/javascripts/ui/components/core/seamly-chat.tsx +8 -0
- package/src/javascripts/ui/components/core/{seamly-core.js → seamly-core.tsx} +27 -14
- package/src/javascripts/ui/components/core/seamly-event-subscriber.ts +340 -0
- package/src/javascripts/ui/components/core/seamly-file-upload.js +2 -2
- package/src/javascripts/ui/components/core/seamly-idle-detach-counter.js +1 -1
- package/src/javascripts/ui/components/core/seamly-instance-functions-loader.js +24 -11
- package/src/javascripts/ui/components/core/seamly-live-region.js +4 -4
- package/src/javascripts/ui/components/core/seamly-new-notifications.js +3 -3
- package/src/javascripts/ui/components/core/seamly-read-state.js +2 -33
- package/src/javascripts/ui/components/entry/deprecated-toggle-button.js +4 -4
- package/src/javascripts/ui/components/entry/entry-container.js +8 -8
- package/src/javascripts/ui/components/entry/text-entry/hooks.js +3 -3
- package/src/javascripts/ui/components/entry/text-entry/index.js +3 -3
- package/src/javascripts/ui/components/entry/text-entry/text-entry-form.js +4 -4
- package/src/javascripts/ui/components/entry/upload/file-upload-form.js +3 -3
- package/src/javascripts/ui/components/entry/upload/index.js +5 -5
- package/src/javascripts/ui/components/entry/upload-toggle.js +6 -6
- package/src/javascripts/ui/components/faq/faq.js +14 -14
- package/src/javascripts/ui/components/form-controls/error.js +2 -2
- package/src/javascripts/ui/components/form-controls/file-input.js +3 -3
- package/src/javascripts/ui/components/layout/agent-info.js +3 -3
- package/src/javascripts/ui/components/layout/chat-frame.js +20 -12
- package/src/javascripts/ui/components/layout/chat.js +5 -5
- package/src/javascripts/ui/components/layout/deprecated-app-frame.js +6 -6
- package/src/javascripts/ui/components/layout/deprecated-chat-frame.js +34 -0
- package/src/javascripts/ui/components/layout/header.js +2 -2
- package/src/javascripts/ui/components/layout/icon.js +11 -9
- package/src/javascripts/ui/components/layout/interrupt.js +7 -5
- package/src/javascripts/ui/components/layout/pre-chat-messages.js +1 -1
- package/src/javascripts/ui/components/layout/privacy-disclaimer.js +2 -2
- package/src/javascripts/ui/components/options/options-button.js +5 -5
- package/src/javascripts/ui/components/options/{options-frame.js → options-frame.tsx} +52 -18
- package/src/javascripts/ui/components/options/transcript/index.js +9 -10
- package/src/javascripts/ui/components/options/transcript/transcript-form.js +2 -2
- package/src/javascripts/ui/components/suggestions/index.js +8 -8
- package/src/javascripts/ui/components/suggestions/suggestions-item.js +1 -1
- package/src/javascripts/{domains/translations/components/chat-status.js → ui/components/translation-chat-status/index.tsx} +13 -14
- package/src/javascripts/ui/components/translation-proposal/index.tsx +36 -0
- package/src/javascripts/ui/components/view/app-view.js +2 -7
- package/src/javascripts/ui/components/view/deprecated-view.js +8 -10
- package/src/javascripts/ui/components/view/index.js +6 -6
- package/src/javascripts/ui/components/view/inline-view.js +4 -8
- package/src/javascripts/ui/components/view/window-view/collapse-button.js +2 -2
- package/src/javascripts/ui/components/view/window-view/index.js +11 -17
- package/src/javascripts/ui/components/view/window-view/window-open-button.js +6 -6
- package/src/javascripts/ui/components/warnings/idle-detach-warning.js +3 -3
- package/src/javascripts/ui/components/warnings/prompt.js +1 -1
- package/src/javascripts/ui/components/warnings/resume-conversation-prompt.js +4 -4
- package/src/javascripts/ui/components/widgets/in-out-transition.js +20 -18
- package/src/javascripts/ui/components/widgets/lightbox.js +3 -3
- package/src/javascripts/ui/components/widgets/modal.js +2 -2
- package/src/javascripts/ui/components/widgets/upload-progress.js +2 -2
- package/src/javascripts/ui/hooks/file-upload-hooks.js +1 -1
- package/src/javascripts/ui/hooks/focus-helper-hooks.js +1 -1
- package/src/javascripts/ui/hooks/seamly-entry-hooks.js +6 -6
- package/src/javascripts/ui/hooks/seamly-hooks.js +11 -10
- package/src/javascripts/ui/hooks/seamly-option-hooks.js +6 -6
- package/src/javascripts/ui/hooks/{seamly-state-hooks.js → seamly-state-hooks.ts} +9 -6
- package/src/javascripts/ui/hooks/use-click-outside.ts +29 -0
- package/src/javascripts/ui/hooks/use-event-component-mapping.js +11 -10
- package/src/javascripts/ui/hooks/use-interval.js +1 -1
- package/src/javascripts/ui/hooks/use-seamly-actions.ts +29 -29
- package/src/javascripts/ui/hooks/use-seamly-chat.js +13 -23
- package/src/javascripts/ui/hooks/use-seamly-commands.js +20 -15
- package/src/javascripts/ui/hooks/use-seamly-idle-detach-countdown.js +8 -8
- package/src/javascripts/ui/hooks/use-seamly-resume-conversation-prompt.js +2 -2
- package/src/javascripts/ui/hooks/use-single-file-upload.js +1 -1
- package/src/javascripts/ui/hooks/utility-hooks.js +1 -1
- package/src/javascripts/ui/utils/general-utils.js +0 -23
- package/src/javascripts/ui/utils/seamly-utils.ts +10 -1
- package/src/javascripts/ui/utils/seamly-utils.types.ts +9 -0
- package/src/stylesheets/1-settings/_config.scss +1 -1
- package/src/stylesheets/3-chat/_chat.scss +23 -5
- package/src/stylesheets/5-components/_chat-status.scss +72 -16
- package/src/stylesheets/5-components/_conversation.scss +35 -1
- package/src/stylesheets/5-components/_disclaimer.scss +0 -5
- package/src/stylesheets/5-components/_options.scss +16 -2
- package/src/stylesheets/5-components/_translation-options.scss +39 -0
- package/src/stylesheets/6-default-implementation/_scrollbar.scss +1 -1
- package/src/stylesheets/7-deprecated/3-app/_app.scss +19 -4
- package/src/stylesheets/7-deprecated/5-components/_chat-status.scss +5 -0
- package/src/stylesheets/7-deprecated/5-components/_options.scss +1 -0
- package/src/stylesheets/7-deprecated/5-components/_translation-options.scss +39 -0
- package/src/stylesheets/deprecated-view.scss +1 -0
- package/src/stylesheets/styles.scss +1 -0
- package/webpack/config.common.js +4 -4
- package/webpack/config.package.js +10 -16
- package/webpack/config.site.js +4 -1
- package/webpack/config.test.js +2 -1
- package/build/dist/lib/deprecated-view.css +0 -1
- package/build/dist/lib/styles-default-implementation.css +0 -1
- package/build/dist/lib/styles.css +0 -1
- package/src/.DS_Store +0 -0
- package/src/javascripts/api/event-producer.js +0 -20
- package/src/javascripts/api/producer.js +0 -136
- package/src/javascripts/domains/errors/index.js +0 -37
- package/src/javascripts/domains/translations/components/options-dialog/form.js +0 -70
- package/src/javascripts/domains/translations/components/options-dialog/index.js +0 -87
- package/src/javascripts/ui/components/chat-status/index.js +0 -38
- package/src/javascripts/ui/components/conversation/event/event.js +0 -36
- package/src/javascripts/ui/components/core/seamly-api-context.js +0 -5
- package/src/javascripts/ui/components/core/seamly-event-subscriber.js +0 -279
|
@@ -1,33 +1,47 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCallback, useMemo } from 'preact/hooks'
|
|
2
|
+
import { useDispatch, useSelector } from 'react-redux'
|
|
3
|
+
import {
|
|
4
|
+
useElementFocusingById,
|
|
5
|
+
useSeamlyCommands,
|
|
6
|
+
} from 'ui/hooks/seamly-hooks'
|
|
7
|
+
import {
|
|
8
|
+
TRANSLATION_PROPOSAL,
|
|
9
|
+
actionTypes,
|
|
10
|
+
sourceTypes,
|
|
11
|
+
} from 'ui/utils/seamly-utils'
|
|
12
|
+
import { ValueOf } from 'ui/utils/seamly-utils.types'
|
|
13
|
+
import { useI18n } from 'domains/i18n/hooks'
|
|
14
|
+
import type { RootState } from 'domains/store'
|
|
2
15
|
import {
|
|
3
16
|
ChannelEvent,
|
|
4
17
|
InfoEvent,
|
|
5
18
|
MessageEvent,
|
|
6
19
|
ParticipantEvent,
|
|
20
|
+
ServiceDataEvent,
|
|
7
21
|
} from 'domains/store/store.types'
|
|
8
22
|
import { selectIsTranslated } from 'domains/translations/selectors'
|
|
9
23
|
import {
|
|
10
24
|
disableTranslation,
|
|
25
|
+
disableTranslationProposalPrompt,
|
|
11
26
|
enableTranslation,
|
|
12
27
|
} from 'domains/translations/slice'
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
useElementFocusingById,
|
|
17
|
-
useSeamlyCommands,
|
|
18
|
-
} from 'ui/hooks/seamly-hooks'
|
|
19
|
-
import { actionTypes } from 'ui/utils/seamly-utils'
|
|
28
|
+
import type { Language } from 'domains/translations/translations.types'
|
|
29
|
+
import { useVisibility } from 'domains/visibility/hooks'
|
|
20
30
|
|
|
21
31
|
export function useTranslations() {
|
|
22
32
|
const { sendAction } = useSeamlyCommands()
|
|
23
33
|
const dispatch = useDispatch()
|
|
24
34
|
const enableTranslations = useCallback(
|
|
25
|
-
(
|
|
35
|
+
(
|
|
36
|
+
locale: Language['locale'],
|
|
37
|
+
source: ValueOf<typeof sourceTypes> = sourceTypes.translationChoice,
|
|
38
|
+
) => {
|
|
26
39
|
sendAction({
|
|
27
40
|
type: actionTypes.setTranslation,
|
|
28
|
-
body: { enabled: true, locale },
|
|
41
|
+
body: { enabled: true, locale, source },
|
|
29
42
|
})
|
|
30
43
|
dispatch(enableTranslation(locale))
|
|
44
|
+
dispatch(disableTranslationProposalPrompt())
|
|
31
45
|
},
|
|
32
46
|
[sendAction, dispatch],
|
|
33
47
|
)
|
|
@@ -37,7 +51,7 @@ export function useTranslations() {
|
|
|
37
51
|
}, [sendAction, dispatch])
|
|
38
52
|
|
|
39
53
|
const { languages, isActive, isAvailable, currentLocale } = useSelector(
|
|
40
|
-
({ translations }) => translations,
|
|
54
|
+
({ translations }: RootState) => translations,
|
|
41
55
|
)
|
|
42
56
|
|
|
43
57
|
return {
|
|
@@ -54,11 +68,13 @@ type EventDataBody =
|
|
|
54
68
|
| ParticipantEvent['payload']['participant']['introduction']
|
|
55
69
|
| MessageEvent['payload']['body']
|
|
56
70
|
| InfoEvent['payload']['body']
|
|
71
|
+
| ServiceDataEvent['payload']['body']
|
|
57
72
|
|
|
58
73
|
type TranslatedEventDataBody =
|
|
59
74
|
| ParticipantEvent['payload']['participant']['translatedIntroduction']
|
|
60
75
|
| MessageEvent['payload']['translatedBody']
|
|
61
76
|
| InfoEvent['payload']['translatedBody']
|
|
77
|
+
| ServiceDataEvent['payload']['translatedBody']
|
|
62
78
|
|
|
63
79
|
export function useTranslatedEventData(channelEvent: ChannelEvent): {
|
|
64
80
|
body: EventDataBody
|
|
@@ -112,3 +128,53 @@ export function useLocaleNativeName(locale: string) {
|
|
|
112
128
|
[locale, languages],
|
|
113
129
|
)
|
|
114
130
|
}
|
|
131
|
+
|
|
132
|
+
export const useTranslationProposal = () => {
|
|
133
|
+
const { isActive, languages } = useTranslations()
|
|
134
|
+
|
|
135
|
+
const dispatch = useDispatch()
|
|
136
|
+
const { sendAction } = useSeamlyCommands()
|
|
137
|
+
|
|
138
|
+
const { translationProposal } = useSelector(
|
|
139
|
+
(state: RootState) => state.translations,
|
|
140
|
+
)
|
|
141
|
+
const { enableTranslations } = useTranslations()
|
|
142
|
+
const { isOpen } = useVisibility()
|
|
143
|
+
const { locale } = useI18n()
|
|
144
|
+
const proposedLocale = translationProposal?.proposedLocale
|
|
145
|
+
const proposedLocaleNativeName = useLocaleNativeName(proposedLocale)
|
|
146
|
+
|
|
147
|
+
const showProposal = useMemo(
|
|
148
|
+
() =>
|
|
149
|
+
translationProposal !== null &&
|
|
150
|
+
!isActive &&
|
|
151
|
+
isOpen &&
|
|
152
|
+
locale !== proposedLocale &&
|
|
153
|
+
languages.some((language) => language.locale === proposedLocale),
|
|
154
|
+
[translationProposal, isActive, isOpen, locale, proposedLocale, languages],
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
const dismissTranslationProposal = () => {
|
|
158
|
+
sendAction({
|
|
159
|
+
type: actionTypes.dismiss,
|
|
160
|
+
body: { type: TRANSLATION_PROPOSAL },
|
|
161
|
+
})
|
|
162
|
+
dispatch(disableTranslationProposalPrompt())
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const activateTranslationProposal = () => {
|
|
166
|
+
enableTranslations(
|
|
167
|
+
translationProposal?.proposedLocale,
|
|
168
|
+
sourceTypes.translationProposal,
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
activateTranslationProposal,
|
|
174
|
+
dismissTranslationProposal,
|
|
175
|
+
proposedLocale,
|
|
176
|
+
proposedLocaleNativeName,
|
|
177
|
+
showProposal,
|
|
178
|
+
translationProposal,
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
TranslationEvent,
|
|
3
|
-
TranslationState,
|
|
4
|
-
} from 'domains/translations/translations.types'
|
|
5
|
-
import { createSlice, nanoid, PayloadAction } from '@reduxjs/toolkit'
|
|
6
|
-
import { initializeApp } from 'domains/app/actions'
|
|
1
|
+
import { PayloadAction, createSlice, nanoid } from '@reduxjs/toolkit'
|
|
7
2
|
import { initializeConfig } from 'domains/config/actions'
|
|
8
|
-
import { addEvent,
|
|
9
|
-
import { ChannelEvent } from 'domains/store/store.types'
|
|
3
|
+
import { addEvent, setHistory } from 'domains/store/slice'
|
|
4
|
+
import type { ChannelEvent, HistoryResponse } from 'domains/store/store.types'
|
|
5
|
+
import type { TranslationState } from 'domains/translations/translations.types'
|
|
10
6
|
|
|
11
7
|
export const translationsInitialState: TranslationState = {
|
|
12
8
|
isActive: false,
|
|
@@ -15,6 +11,7 @@ export const translationsInitialState: TranslationState = {
|
|
|
15
11
|
languages: [],
|
|
16
12
|
containerId: nanoid(),
|
|
17
13
|
translatedEventGroups: {},
|
|
14
|
+
translationProposal: null,
|
|
18
15
|
}
|
|
19
16
|
|
|
20
17
|
const getLastGroupId = (events: ChannelEvent[], id: string) => {
|
|
@@ -42,7 +39,7 @@ const getLastGroupId = (events: ChannelEvent[], id: string) => {
|
|
|
42
39
|
const [[groupId, eventIds]] = Object.entries(eventGroup)
|
|
43
40
|
|
|
44
41
|
const lastGroupId = events
|
|
45
|
-
|
|
42
|
+
// @ts-ignore
|
|
46
43
|
.filter((event) => event.payload?.type === 'divider')
|
|
47
44
|
.map((event) => event.payload.id)
|
|
48
45
|
.at(-1)
|
|
@@ -84,6 +81,15 @@ export const translationSlice = createSlice({
|
|
|
84
81
|
state.lastGroupId = lastGroupId
|
|
85
82
|
state.translatedEventGroups[groupId] = eventIds
|
|
86
83
|
},
|
|
84
|
+
disableTranslationProposalPrompt: (state) => {
|
|
85
|
+
state.translationProposal = null
|
|
86
|
+
},
|
|
87
|
+
setTranslationProposalPrompt: (
|
|
88
|
+
state,
|
|
89
|
+
{ payload }: PayloadAction<HistoryResponse['translationProposal']>,
|
|
90
|
+
) => {
|
|
91
|
+
state.translationProposal = payload
|
|
92
|
+
},
|
|
87
93
|
},
|
|
88
94
|
extraReducers: (builder) => {
|
|
89
95
|
builder
|
|
@@ -94,6 +100,9 @@ export const translationSlice = createSlice({
|
|
|
94
100
|
state.isAvailable = feature.enabled === true
|
|
95
101
|
state.languages = feature.languages
|
|
96
102
|
})
|
|
103
|
+
.addCase(setHistory, (state, { payload }) => {
|
|
104
|
+
state.translationProposal = payload.translationProposal
|
|
105
|
+
})
|
|
97
106
|
.addCase(addEvent, (state, { payload }) => {
|
|
98
107
|
if (state.translatedEventGroups[state.lastGroupId]) {
|
|
99
108
|
state.translatedEventGroups[state.lastGroupId].push(
|
|
@@ -109,6 +118,8 @@ export const {
|
|
|
109
118
|
disableTranslation,
|
|
110
119
|
enableEventsTranslation,
|
|
111
120
|
disableEventsTranslation,
|
|
121
|
+
setTranslationProposalPrompt,
|
|
122
|
+
disableTranslationProposalPrompt,
|
|
112
123
|
} = translationSlice.actions
|
|
113
124
|
|
|
114
125
|
export default translationSlice.reducer
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { operations } from 'schema'
|
|
1
|
+
import type { components, operations } from 'schema'
|
|
2
|
+
import { HistoryResponse } from 'domains/store/store.types'
|
|
2
3
|
|
|
4
|
+
export type Language = components['schemas']['Translation']
|
|
3
5
|
export type Languages =
|
|
4
6
|
operations['getAccountConfig']['responses']['201']['content']['application/json']['config']['features']['translation']['languages']
|
|
5
7
|
|
|
@@ -7,7 +9,6 @@ export type TranslationEvent = {
|
|
|
7
9
|
id: string
|
|
8
10
|
items: string[]
|
|
9
11
|
}
|
|
10
|
-
|
|
11
12
|
export interface TranslationState {
|
|
12
13
|
isActive: boolean
|
|
13
14
|
currentLocale?: string
|
|
@@ -16,4 +17,5 @@ export interface TranslationState {
|
|
|
16
17
|
containerId: string
|
|
17
18
|
translatedEventGroups: Record<string, string[]>
|
|
18
19
|
lastGroupId?: string
|
|
20
|
+
translationProposal?: HistoryResponse['translationProposal'] | null
|
|
19
21
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { createAsyncThunk } from '@reduxjs/toolkit'
|
|
2
|
-
import { VisibilityOptions } from 'config.types'
|
|
2
|
+
import type { VisibilityOptions } from 'config.types'
|
|
3
|
+
import { selectState } from 'ui/hooks/seamly-state-hooks'
|
|
3
4
|
import { selectUserHasResponded } from 'domains/app/selectors'
|
|
4
5
|
import * as ConfigSelectors from 'domains/config/selectors'
|
|
5
|
-
import { ThunkAPI } from 'domains/redux/redux.types'
|
|
6
|
-
import { setFromStorage } from 'domains/visibility/slice'
|
|
6
|
+
import type { ThunkAPI } from 'domains/redux/redux.types'
|
|
7
7
|
import { calculateVisibility } from 'domains/visibility/utils'
|
|
8
|
-
import { VisibilityState } from 'domains/visibility/visibility.types'
|
|
9
|
-
import { selectState } from 'ui/hooks/seamly-state-hooks'
|
|
10
8
|
import { StoreKey, visibilityStates } from './constants'
|
|
11
9
|
import * as Selectors from './selectors'
|
|
12
10
|
|
|
@@ -17,7 +15,7 @@ const validVisibilityStates = [
|
|
|
17
15
|
]
|
|
18
16
|
export const setVisibility = createAsyncThunk<
|
|
19
17
|
VisibilityOptions,
|
|
20
|
-
|
|
18
|
+
VisibilityOptions,
|
|
21
19
|
ThunkAPI
|
|
22
20
|
>(
|
|
23
21
|
'setVisibility',
|
|
@@ -70,10 +68,8 @@ export const initializeVisibility = createAsyncThunk<unknown, void, ThunkAPI>(
|
|
|
70
68
|
// initialize stored visibility
|
|
71
69
|
const { layoutMode } = ConfigSelectors.selectConfig(getState())
|
|
72
70
|
|
|
73
|
-
const storedVisibility =
|
|
74
|
-
|
|
75
|
-
dispatch(setFromStorage(storedVisibility))
|
|
76
|
-
}
|
|
71
|
+
const storedVisibility =
|
|
72
|
+
api.store.get(StoreKey)?.[layoutMode] || visibilityStates.initialize
|
|
77
73
|
|
|
78
74
|
dispatch(setVisibility(storedVisibility))
|
|
79
75
|
return storedVisibility
|
|
@@ -1,44 +1,63 @@
|
|
|
1
|
+
import type { VisibilityOptions } from 'config.types'
|
|
2
|
+
import { RefObject, createRef } from 'preact'
|
|
3
|
+
import { useCallback, useEffect, useState } from 'preact/hooks'
|
|
4
|
+
import { useDispatch, useSelector } from 'react-redux'
|
|
1
5
|
import { useConfig } from 'domains/config/hooks'
|
|
2
6
|
import { useAppDispatch } from 'domains/store'
|
|
3
7
|
import { setVisibility } from 'domains/visibility/actions'
|
|
4
8
|
import { setShowInlineView } from 'domains/visibility/slice'
|
|
5
|
-
import { VisibilityState } from 'domains/visibility/visibility.types'
|
|
6
|
-
import { useCallback, useEffect, useRef, useState } from 'preact/hooks'
|
|
7
|
-
import { useDispatch, useSelector } from 'react-redux'
|
|
8
9
|
import { visibilityStates } from './constants'
|
|
9
|
-
import
|
|
10
|
+
import { selectShowInlineView, selectVisibility } from './selectors'
|
|
10
11
|
|
|
11
12
|
export const useVisibility = () => {
|
|
12
13
|
const dispatch = useAppDispatch()
|
|
13
|
-
const visible = useSelector(
|
|
14
|
+
const visible = useSelector(selectVisibility)
|
|
14
15
|
const isVisible = visible ? visible !== visibilityStates.hidden : false
|
|
15
16
|
const isOpen = visible === visibilityStates.open
|
|
16
17
|
const isMinimized = visible === visibilityStates.minimized
|
|
17
18
|
|
|
18
19
|
const dispatchVisibility = useCallback(
|
|
19
|
-
(visibility:
|
|
20
|
+
(visibility: VisibilityOptions) => dispatch(setVisibility(visibility)),
|
|
20
21
|
[dispatch],
|
|
21
22
|
)
|
|
22
23
|
|
|
24
|
+
const openChat = () => {
|
|
25
|
+
dispatchVisibility(visibilityStates.open as VisibilityOptions)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const closeChat = () => {
|
|
29
|
+
dispatchVisibility(visibilityStates.minimized as VisibilityOptions)
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
return {
|
|
24
33
|
isVisible,
|
|
25
34
|
isOpen,
|
|
26
35
|
isMinimized,
|
|
27
36
|
visible,
|
|
28
37
|
setVisibility: dispatchVisibility,
|
|
38
|
+
openChat,
|
|
39
|
+
closeChat,
|
|
29
40
|
}
|
|
30
41
|
}
|
|
31
42
|
|
|
43
|
+
type UseIntersectOptions = {
|
|
44
|
+
/** Stops observing when the root element is visible. */
|
|
45
|
+
freezeOnceVisible?: boolean
|
|
46
|
+
/** Determines if useIntersect is enabled. */
|
|
47
|
+
enabled?: boolean
|
|
48
|
+
/** The node ref to apply the intersection to */
|
|
49
|
+
containerRef?: RefObject<any>
|
|
50
|
+
}
|
|
51
|
+
|
|
32
52
|
/**
|
|
33
53
|
* Custom hook which enables initializing of IntersectionObserver on any node ref.
|
|
34
|
-
* @param {object} options Hook options.
|
|
35
|
-
* @param {boolean=} options.freezeOnceVisible Stops observing when the root element is visible.
|
|
36
|
-
* @param {boolean=} options.enabled Determines if useIntersect is enabled.
|
|
37
54
|
*/
|
|
38
|
-
const useIntersect = ({
|
|
55
|
+
export const useIntersect = ({
|
|
56
|
+
freezeOnceVisible = false,
|
|
57
|
+
enabled = true,
|
|
58
|
+
containerRef = createRef(),
|
|
59
|
+
}: UseIntersectOptions) => {
|
|
39
60
|
const [entry, setEntry] = useState(null)
|
|
40
|
-
const containerRef = useRef(null)
|
|
41
|
-
|
|
42
61
|
const isVisible = !!entry?.isIntersecting || !enabled
|
|
43
62
|
const frozen = isVisible && freezeOnceVisible
|
|
44
63
|
|
|
@@ -63,7 +82,7 @@ const useIntersect = ({ freezeOnceVisible = false, enabled = true }) => {
|
|
|
63
82
|
observer.observe(node)
|
|
64
83
|
|
|
65
84
|
return () => observer.disconnect()
|
|
66
|
-
}, [enabled, frozen])
|
|
85
|
+
}, [containerRef, enabled, frozen])
|
|
67
86
|
|
|
68
87
|
return { isVisible, containerRef }
|
|
69
88
|
}
|
|
@@ -71,7 +90,7 @@ const useIntersect = ({ freezeOnceVisible = false, enabled = true }) => {
|
|
|
71
90
|
export const useShowInlineView = () => {
|
|
72
91
|
const dispatch = useDispatch()
|
|
73
92
|
const { connectWhenInView } = useConfig()
|
|
74
|
-
const showInlineView = useSelector(
|
|
93
|
+
const showInlineView = useSelector(selectShowInlineView)
|
|
75
94
|
|
|
76
95
|
const { containerRef, isVisible } = useIntersect({
|
|
77
96
|
enabled: connectWhenInView,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createSelector } from '@reduxjs/toolkit'
|
|
2
|
+
import type { RootState } from 'domains/store'
|
|
2
3
|
|
|
3
4
|
export const selectVisibility = createSelector(
|
|
4
|
-
({ visibility }) => visibility,
|
|
5
|
+
({ visibility }: RootState) => visibility,
|
|
5
6
|
(state) => state.visibility,
|
|
6
7
|
)
|
|
7
8
|
|
|
8
9
|
export const selectShowInlineView = createSelector(
|
|
9
|
-
({ visibility }) => visibility,
|
|
10
|
+
({ visibility }: RootState) => visibility,
|
|
10
11
|
(state) => state.showInlineView,
|
|
11
12
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { VisibilityOptions } from 'config.types'
|
|
1
|
+
import { PayloadAction, createSlice } from '@reduxjs/toolkit'
|
|
2
|
+
import type { VisibilityOptions } from 'config.types'
|
|
3
3
|
import { initializeConfig } from 'domains/config/actions'
|
|
4
4
|
import { setVisibility } from 'domains/visibility/actions'
|
|
5
5
|
import { visibilityStates } from 'domains/visibility/constants'
|
|
@@ -14,9 +14,6 @@ export const visibilitySlice = createSlice({
|
|
|
14
14
|
name: 'visibility',
|
|
15
15
|
initialState,
|
|
16
16
|
reducers: {
|
|
17
|
-
setFromStorage: (state, action) => {
|
|
18
|
-
state.visibility = action.payload
|
|
19
|
-
},
|
|
20
17
|
setShowInlineView: (state) => {
|
|
21
18
|
state.showInlineView = true
|
|
22
19
|
},
|
|
@@ -40,7 +37,6 @@ export const visibilitySlice = createSlice({
|
|
|
40
37
|
},
|
|
41
38
|
})
|
|
42
39
|
|
|
43
|
-
export const { setFromStorage } = visibilitySlice.actions
|
|
44
40
|
export const { setShowInlineView } = visibilitySlice.actions
|
|
45
41
|
|
|
46
42
|
export default visibilitySlice.reducer
|
package/src/javascripts/index.ts
CHANGED
|
@@ -5,14 +5,6 @@ import initializeExternalApi from './lib/external-api/initialize-api'
|
|
|
5
5
|
export default initializeExternalApi
|
|
6
6
|
|
|
7
7
|
// Used by: StyleGuide
|
|
8
|
-
export { API } from './api'
|
|
9
|
-
|
|
10
|
-
// Used by: StyleGuide
|
|
11
|
-
export { Provider as SeamlyStoreProvider } from 'react-redux'
|
|
12
|
-
// Used by: StyleGuide
|
|
13
|
-
export { default as SeamlyGeneralError } from './api/errors/seamly-general-error'
|
|
14
|
-
// Used by: StyleGuide
|
|
15
|
-
export { default as SeamlyOfflineError } from './api/errors/seamly-offline-error'
|
|
16
8
|
// Used by: Client
|
|
17
9
|
export { useConfig as useSeamlyConfig } from 'domains/config/hooks'
|
|
18
10
|
// Used by: Client
|
|
@@ -23,18 +15,12 @@ export {
|
|
|
23
15
|
useTranslations,
|
|
24
16
|
useTranslationsContainer,
|
|
25
17
|
} from 'domains/translations/hooks'
|
|
18
|
+
export { visibilityStates } from 'domains/visibility/constants'
|
|
26
19
|
// Used by: Client
|
|
27
20
|
export { useVisibility as useSeamlyVisibility } from 'domains/visibility/hooks'
|
|
28
|
-
export { visibilityStates } from 'domains/visibility/constants'
|
|
29
21
|
export { calculateVisibility } from 'domains/visibility/utils'
|
|
30
|
-
// Used by: Client
|
|
31
|
-
export { className } from './lib/css'
|
|
32
22
|
// Used by: StyleGuide
|
|
33
|
-
export {
|
|
34
|
-
// Used by: StyleGuide
|
|
35
|
-
export { default as ExternalApi } from './lib/external-api'
|
|
36
|
-
// Used by: StyleGuide
|
|
37
|
-
export { randomId } from './lib/id'
|
|
23
|
+
export { Provider as SeamlyStoreProvider } from 'react-redux'
|
|
38
24
|
// Used by: StyleGuide
|
|
39
25
|
export { default as ComponentFilter } from 'ui/components/conversation/component-filter'
|
|
40
26
|
// Used by: Client
|
|
@@ -74,6 +60,23 @@ export { default as Interrupt } from 'ui/components/layout/interrupt'
|
|
|
74
60
|
export { default as View } from 'ui/components/view'
|
|
75
61
|
// Used by: Client
|
|
76
62
|
export { default as DeprecatedView } from 'ui/components/view/deprecated-view'
|
|
63
|
+
export { useSeamlyActions } from 'ui/hooks/use-seamly-actions'
|
|
64
|
+
// Used by: StyleGuide
|
|
65
|
+
// Used by: Client
|
|
66
|
+
export { eventTypes } from 'ui/utils/seamly-utils'
|
|
67
|
+
export { API } from './api'
|
|
68
|
+
// Used by: StyleGuide
|
|
69
|
+
export { default as SeamlyGeneralError } from './api/errors/seamly-general-error'
|
|
70
|
+
// Used by: StyleGuide
|
|
71
|
+
export { default as SeamlyOfflineError } from './api/errors/seamly-offline-error'
|
|
72
|
+
// Used by: Client
|
|
73
|
+
export { className } from './lib/css'
|
|
74
|
+
// Used by: StyleGuide
|
|
75
|
+
export { default as Engine } from './lib/engine'
|
|
76
|
+
// Used by: StyleGuide
|
|
77
|
+
export { default as ExternalApi } from './lib/external-api'
|
|
78
|
+
// Used by: StyleGuide
|
|
79
|
+
export { randomId } from './lib/id'
|
|
77
80
|
// Used by: Client
|
|
78
81
|
export {
|
|
79
82
|
useEvents,
|
|
@@ -85,8 +88,3 @@ export {
|
|
|
85
88
|
useSeamlyMessageContainerClassNames,
|
|
86
89
|
useSeamlyOptions,
|
|
87
90
|
} from './ui/hooks/seamly-hooks'
|
|
88
|
-
// Used by: StyleGuide
|
|
89
|
-
export { getUrlParams, getUrlSearchString } from './ui/utils/general-utils'
|
|
90
|
-
// Used by: Client
|
|
91
|
-
export { eventTypes } from './ui/utils/seamly-utils'
|
|
92
|
-
export { useSeamlyActions } from 'ui/hooks/use-seamly-actions'
|
|
@@ -1,19 +1,33 @@
|
|
|
1
1
|
import { API } from 'api'
|
|
2
|
+
import type { Config } from 'config.types'
|
|
3
|
+
import Events, { Events as EventsType } from 'minivents'
|
|
4
|
+
import { render } from 'preact'
|
|
5
|
+
import ChatApp from 'ui/components/chat-app'
|
|
6
|
+
import SeamlyCore from 'ui/components/core/seamly-core'
|
|
2
7
|
import { initializeApp } from 'domains/app/actions'
|
|
3
|
-
|
|
4
8
|
import { initializeConfig } from 'domains/config/actions'
|
|
5
9
|
import { setConfig } from 'domains/config/slice'
|
|
6
10
|
import { setLocale } from 'domains/i18n/actions'
|
|
7
|
-
|
|
8
11
|
import { createStore } from 'domains/store'
|
|
9
12
|
import { initializeVisibility } from 'domains/visibility/actions'
|
|
10
|
-
import
|
|
11
|
-
import { render } from 'preact'
|
|
12
|
-
import ChatApp from 'ui/components/chat-app'
|
|
13
|
-
import SeamlyCore from 'ui/components/core/seamly-core'
|
|
13
|
+
import type ExternalApi from 'lib/external-api'
|
|
14
14
|
|
|
15
15
|
export default class Engine {
|
|
16
|
-
|
|
16
|
+
config: Config
|
|
17
|
+
|
|
18
|
+
namespace: string
|
|
19
|
+
|
|
20
|
+
parentElement: HTMLElement
|
|
21
|
+
|
|
22
|
+
externalApi: ExternalApi
|
|
23
|
+
|
|
24
|
+
functions: {}
|
|
25
|
+
|
|
26
|
+
eventBus: EventsType
|
|
27
|
+
|
|
28
|
+
api: API
|
|
29
|
+
|
|
30
|
+
constructor(config: Config, externalApi: ExternalApi) {
|
|
17
31
|
const { namespace = '', parentElement, showFaq, ...restConfig } = config
|
|
18
32
|
|
|
19
33
|
this.config = {
|
|
@@ -32,6 +46,8 @@ export default class Engine {
|
|
|
32
46
|
context: config.context,
|
|
33
47
|
})
|
|
34
48
|
|
|
49
|
+
// Following are ignored because the types of minivents do not match the docs.
|
|
50
|
+
// @ts-ignore
|
|
35
51
|
this.eventBus = new Events()
|
|
36
52
|
this.functions = {}
|
|
37
53
|
this.registerFunctions({
|
|
@@ -39,9 +55,11 @@ export default class Engine {
|
|
|
39
55
|
off: this.eventBus.off,
|
|
40
56
|
})
|
|
41
57
|
|
|
58
|
+
// @ts-ignore
|
|
42
59
|
this.eventBus.on('function.register', (functionName, fn) =>
|
|
43
60
|
this.registerFunction(functionName, fn),
|
|
44
61
|
)
|
|
62
|
+
// @ts-ignore
|
|
45
63
|
this.eventBus.on('function.unregister', (functionName, fn) =>
|
|
46
64
|
this.unregisterFunction(functionName, fn),
|
|
47
65
|
)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
export const getUrlSearchParams = () => {
|
|
2
|
+
const params = new URLSearchParams(window.location.search)
|
|
3
|
+
|
|
4
|
+
return Array.from(params.entries()).reduce(
|
|
5
|
+
(acc, [key, val]) => ({ ...acc, [key]: val }),
|
|
6
|
+
{},
|
|
7
|
+
)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Return search parameters as a string
|
|
11
|
+
export const getUrlSearchString = (params: Record<string, string>) =>
|
|
12
|
+
new URLSearchParams(params).toString()
|
|
13
|
+
|
|
14
|
+
// Return search parameters found in URL or sessionStorage
|
|
15
|
+
export const getSearchParamsByKeys = <T extends string>(
|
|
16
|
+
...keys: T[]
|
|
17
|
+
): Record<T, string> => {
|
|
18
|
+
const url = new URL(window.location.href)
|
|
19
|
+
|
|
20
|
+
const values = keys.reduce((acc, key) => {
|
|
21
|
+
const searchParam = url.searchParams.get(key)
|
|
22
|
+
const param = searchParam || sessionStorage.getItem(key)
|
|
23
|
+
if (param) {
|
|
24
|
+
acc[key] = param
|
|
25
|
+
}
|
|
26
|
+
return acc
|
|
27
|
+
}, {} as Record<T, string>)
|
|
28
|
+
|
|
29
|
+
return values
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Adds a search parameter to the url
|
|
33
|
+
export const setSearchParam = (key: string, value: string): void => {
|
|
34
|
+
const url = new URL(window.location.href)
|
|
35
|
+
const { searchParams } = url
|
|
36
|
+
|
|
37
|
+
searchParams.set(key, value)
|
|
38
|
+
|
|
39
|
+
url.search = searchParams.toString()
|
|
40
|
+
window.location.href = url.toString()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Replace search parameters with those found in URL search parameters or sessionStorage
|
|
44
|
+
export const replaceSearchParams = <T extends string>(
|
|
45
|
+
...keys: T[]
|
|
46
|
+
): Record<T, string> => {
|
|
47
|
+
const url = new URL(window.location.href)
|
|
48
|
+
|
|
49
|
+
const params = keys.reduce<URLSearchParams>((acc, key) => {
|
|
50
|
+
const paramValue = url.searchParams.get(key)
|
|
51
|
+
|
|
52
|
+
const value = paramValue || sessionStorage.getItem(key)
|
|
53
|
+
|
|
54
|
+
// If the query parameter is present, add it to the sessionStorage
|
|
55
|
+
if (paramValue) {
|
|
56
|
+
sessionStorage.setItem(key, paramValue)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Bail if there is nothing to set
|
|
60
|
+
if (!value) return acc
|
|
61
|
+
|
|
62
|
+
acc.set(key, value)
|
|
63
|
+
return acc
|
|
64
|
+
}, new URLSearchParams())
|
|
65
|
+
|
|
66
|
+
// To keep other params in place, we merge them with the current URL parameters
|
|
67
|
+
const combinedParams = new URLSearchParams({
|
|
68
|
+
...Object.fromEntries(url.searchParams),
|
|
69
|
+
...Object.fromEntries(params),
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
if (combinedParams.toString()) {
|
|
73
|
+
window.history.replaceState(null, null, `?${combinedParams}`)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return getSearchParamsByKeys(...params.keys())
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Sets up click handlers for elements with data-attribute `data-reset-search-params`.
|
|
80
|
+
// Clicking these will remove all given keys from the sessionStorage and remove the search parameters from the url
|
|
81
|
+
|
|
82
|
+
// If you want to reset both 'apiKey' and 'locale' when the event is executed, you would use it as followed
|
|
83
|
+
// import { initResetSearchParams } from 'lib/url-helpers'
|
|
84
|
+
|
|
85
|
+
// Setup the event handlers for the search parameters you want to be reset after execution.
|
|
86
|
+
// initResetSearchParams('apiKey', 'locale')
|
|
87
|
+
|
|
88
|
+
// Somewhere in the HTML add an element with the 'data-reset-search-params' attribute.
|
|
89
|
+
// <a href="#" data-reset-search-params>Reset account and source locale</a>
|
|
90
|
+
export const initResetSearchParams = <T extends string>(...keys: T[]): void => {
|
|
91
|
+
const resetLink = document.querySelector('[data-reset-search-params]')
|
|
92
|
+
|
|
93
|
+
if (!resetLink) {
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
resetLink.addEventListener('click', (e) => {
|
|
98
|
+
e.preventDefault()
|
|
99
|
+
const url = new URL(window.location.href)
|
|
100
|
+
|
|
101
|
+
keys.forEach((key) => {
|
|
102
|
+
// Clear current session for each key
|
|
103
|
+
sessionStorage.removeItem(key)
|
|
104
|
+
|
|
105
|
+
// Delete key from url
|
|
106
|
+
url.searchParams.delete(key)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
// Reload page
|
|
110
|
+
window.location.href = url.toString()
|
|
111
|
+
})
|
|
112
|
+
}
|