@seamly/web-ui 20.8.0-alpha.1 → 20.8.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/build/dist/lib/index.debug.js +46 -46
  2. package/build/dist/lib/index.debug.min.js +1 -1
  3. package/build/dist/lib/index.debug.min.js.LICENSE.txt +1 -1
  4. package/build/dist/lib/index.js +351 -260
  5. package/build/dist/lib/index.min.js +1 -1
  6. package/build/dist/lib/standalone.js +542 -252
  7. package/build/dist/lib/standalone.min.js +1 -1
  8. package/build/dist/lib/style-guide.js +156 -69
  9. package/build/dist/lib/style-guide.min.js +1 -1
  10. package/build/dist/lib/styles.css +1 -1
  11. package/package.json +1 -1
  12. package/src/javascripts/config.types.ts +1 -0
  13. package/src/javascripts/domains/config/slice.ts +2 -0
  14. package/src/javascripts/domains/i18n/slice.ts +0 -3
  15. package/src/javascripts/domains/store/slice.ts +16 -13
  16. package/src/javascripts/domains/store/store.types.ts +12 -1
  17. package/src/javascripts/domains/translations/hooks.ts +54 -48
  18. package/src/javascripts/domains/translations/selectors.ts +12 -0
  19. package/src/javascripts/domains/translations/slice.ts +70 -17
  20. package/src/javascripts/domains/translations/translations.types.ts +8 -1
  21. package/src/javascripts/schema.ts +3 -10
  22. package/src/javascripts/style-guide/components/app.js +2 -2
  23. package/src/javascripts/style-guide/states.js +61 -3
  24. package/src/javascripts/ui/components/conversation/conversation.js +7 -3
  25. package/src/javascripts/ui/components/conversation/event/card-message.js +1 -1
  26. package/src/javascripts/ui/components/conversation/event/carousel-message/index.js +1 -1
  27. package/src/javascripts/ui/components/conversation/event/choice-prompt.js +1 -1
  28. package/src/javascripts/ui/components/conversation/event/conversation-suggestions.js +9 -2
  29. package/src/javascripts/ui/components/conversation/event/cta.js +1 -1
  30. package/src/javascripts/ui/components/conversation/event/divider/variants/new-translation.js +39 -3
  31. package/src/javascripts/ui/components/conversation/event/image.js +1 -1
  32. package/src/javascripts/ui/components/conversation/event/participant.js +1 -1
  33. package/src/javascripts/ui/components/conversation/event/splash.js +1 -1
  34. package/src/javascripts/ui/components/conversation/event/text.js +1 -1
  35. package/src/javascripts/ui/components/conversation/event/translation.js +1 -1
  36. package/src/javascripts/ui/components/conversation/event/upload.js +1 -1
  37. package/src/javascripts/ui/components/conversation/event/video.js +1 -1
  38. package/src/javascripts/ui/components/conversation/message-container.js +1 -23
  39. package/src/javascripts/ui/components/core/seamly-event-subscriber.js +3 -2
  40. package/src/javascripts/ui/components/faq/faq.js +3 -1
  41. package/src/javascripts/ui/components/options/options-button.js +3 -1
  42. package/src/javascripts/ui/components/suggestions/index.js +5 -2
  43. package/src/javascripts/ui/hooks/seamly-state-hooks.js +6 -0
  44. package/src/stylesheets/5-components/_message-carousel.scss +10 -8
  45. package/CHANGELOG.md +0 -987
  46. package/src/javascripts/domains/translations/selectors.js +0 -11
@@ -406,11 +406,7 @@ export interface components {
406
406
  * @example true
407
407
  */
408
408
  persist?: boolean
409
- /**
410
- * @description Name of the attached service
411
- * @example bot
412
- */
413
- service?: string
409
+ service?: components['schemas']['Service']
414
410
  transactionId?: components['schemas']['TransactionId']
415
411
  /** @description In case a translations was active when this message originated, this object will contain the translated message in the translationLocale locale. */
416
412
  translatedBody?: {
@@ -713,11 +709,6 @@ export interface components {
713
709
  * @example image/jpeg
714
710
  */
715
711
  contentType?: string
716
- /**
717
- * @description Timestamp until when the file is available for download (in microseconds).
718
- * @example 1661165549122131
719
- */
720
- deleteAt?: number
721
712
  /**
722
713
  * @description Filename of the upload
723
714
  * @example dog.jpg
@@ -1453,3 +1444,5 @@ export interface operations {
1453
1444
  }
1454
1445
  }
1455
1446
  }
1447
+
1448
+ export interface external {}
@@ -50,8 +50,7 @@ const StyleGuideApp = ({
50
50
  const { headingText } = mainState[feature]
51
51
  setSelectedStateDescription(headingText)
52
52
  const bareState = mainState[feature][layoutMode]
53
- const { overrideMessages, showFaq } = bareState.config
54
-
53
+ const { overrideMessages, showFaq, showSuggestions } = bareState.config
55
54
  const agent = participants.find(
56
55
  (participant) => participant.id === 'agent',
57
56
  )
@@ -66,6 +65,7 @@ const StyleGuideApp = ({
66
65
  layoutMode: bareState.config.layoutMode,
67
66
  ...(overrideMessages ? { messages: overrideMessages } : {}),
68
67
  showFaq,
68
+ showSuggestions,
69
69
  },
70
70
  headerTitles: {
71
71
  ...bareState.headerTitles,
@@ -14,6 +14,7 @@ const baseState = {
14
14
  hideOnNoUserResponse: false,
15
15
  showFaq: false,
16
16
  showDisclaimer: false,
17
+ showSuggestions: true,
17
18
  },
18
19
  initialState: {},
19
20
  unreadEvents: 0,
@@ -126,6 +127,32 @@ const newTranslationDividerStart = {
126
127
  type: 'divider',
127
128
  },
128
129
  }
130
+
131
+ const newTranslationDividerStartTwo = {
132
+ type: 'info',
133
+ payload: {
134
+ body: {
135
+ language: 'Nederlands',
136
+ subtype: 'new_translation',
137
+ text: '[NL] Automatic translation to Dutch started. Please note that automatic translations may contain errors.',
138
+ translationEnabled: true,
139
+ translationLocale: 'nl',
140
+ },
141
+ fromClient: false,
142
+ fromHistory: true,
143
+ id: randomId(),
144
+ occurredAt: 1625658300534259,
145
+ participant: null,
146
+ service: {
147
+ meta: {},
148
+ name: null,
149
+ serviceSessionId: null,
150
+ },
151
+ transactionId: null,
152
+ translatedBody: null,
153
+ type: 'divider',
154
+ },
155
+ }
129
156
  const newTranslationDividerStop = {
130
157
  type: 'info',
131
158
  payload: {
@@ -736,7 +763,7 @@ const translationsSlice = {
736
763
  currentLocale: undefined,
737
764
  isAvailable: false,
738
765
  languages: [],
739
- originalPayloadIds: [],
766
+ translatedEventGroups: {},
740
767
  containerId: randomId(),
741
768
  }
742
769
 
@@ -1736,7 +1763,7 @@ const standardState = {
1736
1763
  userMessage,
1737
1764
  textMessageBoldItalicUnderline,
1738
1765
  newTopicDivider,
1739
- newTranslationDividerStart,
1766
+ newTranslationDividerStartTwo,
1740
1767
  newTranslationDividerStop,
1741
1768
  imageMessage,
1742
1769
  fileDownloadAgentMessage,
@@ -1752,13 +1779,44 @@ const standardState = {
1752
1779
  choicePromptMessage,
1753
1780
  ctaMessage,
1754
1781
  newTranslationDividerStop,
1755
- newTranslationDividerStart,
1756
1782
  ].map(addTranslationData),
1757
1783
  translations: {
1758
1784
  ...translationsSlice,
1759
1785
  currentLocale: 'nl',
1760
1786
  isActive: true,
1761
1787
  isAvailable: true,
1788
+ translatedEventGroups: {
1789
+ [newTranslationDividerStart.payload.id]: [
1790
+ infoMessage,
1791
+ shortTextMessage,
1792
+ {
1793
+ ...choicePromptMessage,
1794
+ payload: {
1795
+ ...choicePromptMessage.payload,
1796
+ id: `${choicePromptMessage.payload.id}XXX`,
1797
+ },
1798
+ },
1799
+ longTextMessage,
1800
+ userMessage,
1801
+ textMessageBoldItalicUnderline,
1802
+ newTopicDivider,
1803
+ ].map((p) => p.payload.id),
1804
+ [newTranslationDividerStartTwo.payload.id]: [
1805
+ imageMessage,
1806
+ fileDownloadAgentMessage,
1807
+ deletedFileDownloadAgentMessage,
1808
+ userMessageLong,
1809
+ videoMessage,
1810
+ textMessageWithLinks,
1811
+ textMessageWithLongLink,
1812
+ imageMessageWithLightbox,
1813
+ fileDownloadUserMessage,
1814
+ emptyUrlFileDownloadUserMessage,
1815
+ textMesageWithBullets,
1816
+ choicePromptMessage,
1817
+ ctaMessage,
1818
+ ].map((p) => p.payload.id),
1819
+ },
1762
1820
  languages: [
1763
1821
  { locale: 'nl', nativeName: 'Dutch' },
1764
1822
  { locale: 'en', nativeName: 'English' },
@@ -1,8 +1,9 @@
1
1
  import { useI18n } from 'domains/i18n/hooks'
2
2
  import { useVisibility } from 'domains/visibility/hooks'
3
3
  import { className } from 'lib/css'
4
- import { useEffect, useRef } from 'preact/hooks'
4
+ import { useLayoutEffect, useRef } from 'preact/hooks'
5
5
  import PrivacyDisclaimer from 'ui/components/layout/privacy-disclaimer'
6
+ import { timeout } from 'ui/hooks/focus-helper-hooks'
6
7
  import {
7
8
  useSeamlyIsLoading,
8
9
  useSkiplink,
@@ -51,10 +52,13 @@ const Conversation = () => {
51
52
  const focusSkiplinkTarget = useSkiplinkTargetFocusing()
52
53
  const loadedImageEventIds = useLoadedImageEventIds()
53
54
 
54
- useEffect(() => {
55
+ useLayoutEffect(() => {
55
56
  const containerElement = chatBodyContainer.current
56
57
  if (containerElement) {
57
- containerElement.scrollTop = containerElement.scrollHeight
58
+ requestAnimationFrame(async () => {
59
+ await timeout(30) // Wait for next frame tick
60
+ containerElement.scrollTop = containerElement.scrollHeight
61
+ })
58
62
  }
59
63
  }, [events, isLoading, isOpen, loadedImageEventIds])
60
64
 
@@ -4,7 +4,7 @@ import { useTranslatedEventData } from 'domains/translations/hooks'
4
4
  import CardComponent from './card-component'
5
5
 
6
6
  const CardMessage = ({ event }) => {
7
- const [body] = useTranslatedEventData(event)
7
+ const { body } = useTranslatedEventData(event)
8
8
  const descriptionId = useGeneratedId()
9
9
 
10
10
  return (
@@ -6,7 +6,7 @@ import CarouselMessageSlide from './components/slide'
6
6
  const getItemKey = (item, idx, prefix = '') => `${prefix}${item.title}:${idx}`
7
7
  const getItemLabel = (item) => item.title
8
8
  const CarouselMessage = ({ event }) => {
9
- const [body] = useTranslatedEventData(event)
9
+ const { body } = useTranslatedEventData(event)
10
10
  const slides = body.cards
11
11
 
12
12
  return (
@@ -19,7 +19,7 @@ export const useChoicePrompt = (event) => {
19
19
  const { sendAction, addMessageBubble, addDivider } = useSeamlyCommands()
20
20
  const { activeServiceSessionId } = useSeamlyServiceInfo()
21
21
  const lastEventId = useLastMessageEventId()
22
- const [body] = useTranslatedEventData(event)
22
+ const { body } = useTranslatedEventData(event)
23
23
  const { service } = payload
24
24
 
25
25
  const subEvent = useMemo(() => {
@@ -1,5 +1,6 @@
1
1
  import { useUserHasResponded } from 'domains/app/hooks'
2
2
  import { setHasResponded } from 'domains/app/slice'
3
+ import { useConfig } from 'domains/config/hooks'
3
4
  import { useI18n } from 'domains/i18n/hooks'
4
5
  import { useTranslatedEventData } from 'domains/translations/hooks'
5
6
  import { className } from 'lib/css'
@@ -12,7 +13,7 @@ import { actionTypes } from 'ui/utils/seamly-utils'
12
13
 
13
14
  export const useSuggestions = (event) => {
14
15
  const { payload } = event
15
- const [suggestions] = useTranslatedEventData(event)
16
+ const { body: suggestions } = useTranslatedEventData(event)
16
17
 
17
18
  return {
18
19
  suggestions,
@@ -26,6 +27,7 @@ const ConversationSuggestions = ({ event, ...props }) => {
26
27
  const userHasResponded = useUserHasResponded()
27
28
  const { sendAction, addMessageBubble } = useSeamlyCommands()
28
29
  const { suggestions, payload } = useSuggestions(event)
30
+ const { showSuggestions } = useConfig()
29
31
  const events = useEvents()
30
32
 
31
33
  const { t } = useI18n()
@@ -63,7 +65,12 @@ const ConversationSuggestions = ({ event, ...props }) => {
63
65
  [dispatch, sendAction, payload.id, addMessageBubble],
64
66
  )
65
67
 
66
- if (!isExpanded || userHasResponded || !hasLastTransactionEvent) {
68
+ if (
69
+ !isExpanded ||
70
+ userHasResponded ||
71
+ !hasLastTransactionEvent ||
72
+ !showSuggestions
73
+ ) {
67
74
  return null
68
75
  }
69
76
 
@@ -7,7 +7,7 @@ import { useTranslatedEventData } from 'domains/translations/hooks'
7
7
  import useEventLinkClickHandler from './hooks/use-event-link-click-handler'
8
8
 
9
9
  const Cta = ({ event }) => {
10
- const [body] = useTranslatedEventData(event)
10
+ const { body } = useTranslatedEventData(event)
11
11
  const eventClick = useEventLinkClickHandler(event.payload.id)
12
12
  const { emitEvent } = useSeamlyCommands()
13
13
 
@@ -5,17 +5,40 @@ import {
5
5
  useTranslations,
6
6
  useLocaleNativeName,
7
7
  } from 'domains/translations/hooks'
8
+ import { useDispatch, useSelector } from 'react-redux'
9
+ import {
10
+ enableEventsTranslation,
11
+ disableEventsTranslation,
12
+ } from 'domains/translations/slice'
13
+ import { useCallback } from 'preact/hooks'
14
+ import { useEvents } from 'ui/hooks/seamly-hooks'
8
15
 
9
16
  const NewTranslationDivider = ({ event }) => {
10
17
  const { t } = useI18n()
11
- const { translationEnabled, translationLocale, text } = event.payload.body
18
+ const events = useEvents()
19
+ const {
20
+ body: { translationEnabled, translationLocale, text },
21
+ id,
22
+ } = event.payload
12
23
  const { enableTranslations } = useTranslations()
13
24
  const localeNativeName = useLocaleNativeName(translationLocale)
25
+ const translatedEventGroups = useSelector(
26
+ (state) => state.translations.translatedEventGroups,
27
+ )
28
+
29
+ const dispatch = useDispatch()
30
+ const toggleTranslations = useCallback(() => {
31
+ if (!translatedEventGroups[id]) {
32
+ dispatch(disableEventsTranslation({ events, id }))
33
+ return
34
+ }
35
+
36
+ dispatch(enableEventsTranslation({ events, id }))
37
+ }, [dispatch, events, id, translatedEventGroups])
14
38
 
15
39
  const handleRestartButtonclick = () => {
16
40
  enableTranslations(translationLocale)
17
41
  }
18
-
19
42
  return (
20
43
  <EventDivider iconName="newTranslation" dividerType="newtranslation">
21
44
  <p className={className('divider__title')}>
@@ -27,10 +50,23 @@ const NewTranslationDivider = ({ event }) => {
27
50
  )}
28
51
  </p>
29
52
  {translationEnabled ? (
30
- <p>{text}</p>
53
+ <>
54
+ <p>{text}</p>
55
+ <button
56
+ className={className('button', 'button--secondary')}
57
+ onClick={toggleTranslations}
58
+ >
59
+ {t(
60
+ !translatedEventGroups[id]
61
+ ? 'translations.toggle.hideTranslationsButtonText'
62
+ : 'translations.toggle.showTranslationsButtonText',
63
+ )}
64
+ </button>
65
+ </>
31
66
  ) : (
32
67
  <button
33
68
  className={className('button', 'button--secondary')}
69
+ data-testid="restartTranslationButton"
34
70
  onClick={handleRestartButtonclick}
35
71
  >
36
72
  {t('translations.divider.restartButtonText')}
@@ -6,7 +6,7 @@ import MessageContainer from 'ui/components/conversation/message-container'
6
6
  import ImageLightbox from './image-lightbox'
7
7
 
8
8
  const Image = ({ event, descriptorId, ...props }) => {
9
- const [body] = useTranslatedEventData(event)
9
+ const { body } = useTranslatedEventData(event)
10
10
  const { description, url, isZoomable } = body
11
11
  const [showLighbox, setShowLightbox] = useState(false)
12
12
  const dispatch = useDispatch()
@@ -3,7 +3,7 @@ import { useTranslatedEventData } from 'domains/translations/hooks'
3
3
 
4
4
  const Participant = ({ event }) => {
5
5
  const { participant } = event.payload
6
- const [introduction] = useTranslatedEventData(event)
6
+ const { body: introduction } = useTranslatedEventData(event)
7
7
 
8
8
  if (!introduction) {
9
9
  return null
@@ -4,7 +4,7 @@ import MessageContainer from 'ui/components/conversation/message-container'
4
4
 
5
5
  const Splash = ({ event, ...props }) => {
6
6
  const { payload } = event
7
- const [body] = useTranslatedEventData(event)
7
+ const { body } = useTranslatedEventData(event)
8
8
  const eventClick = useEventLinkClickHandler(payload.id)
9
9
 
10
10
  return (
@@ -4,7 +4,7 @@ import { useTranslatedEventData } from 'domains/translations/hooks'
4
4
  import useEventLinkClickHandler from './hooks/use-event-link-click-handler'
5
5
 
6
6
  const Text = ({ event, ...props }) => {
7
- const [body] = useTranslatedEventData(event)
7
+ const { body } = useTranslatedEventData(event)
8
8
  const eventClick = useEventLinkClickHandler(event.payload.id)
9
9
 
10
10
  const containerProps = useMemo(() => {
@@ -4,7 +4,7 @@ import { useTranslatedEventData } from 'domains/translations/hooks'
4
4
 
5
5
  const Translation = ({ event, ...props }) => {
6
6
  const { t } = useI18n()
7
- const [body] = useTranslatedEventData(event)
7
+ const { body } = useTranslatedEventData(event)
8
8
  return (
9
9
  <MessageContainer type="text" event={event} {...props}>
10
10
  {t(body.key.join('.'), body.variables)}
@@ -21,7 +21,7 @@ const UploadContent = ({ children, url, target }) =>
21
21
 
22
22
  const Upload = ({ event, ...props }) => {
23
23
  const { t } = useI18n()
24
- const [body] = useTranslatedEventData(event)
24
+ const { body } = useTranslatedEventData(event)
25
25
  const { fromClient } = event.payload
26
26
  const { filename, url } = body
27
27
 
@@ -4,7 +4,7 @@ import { useTranslatedEventData } from 'domains/translations/hooks'
4
4
  import MessageContainer from 'ui/components/conversation/message-container'
5
5
 
6
6
  const Video = ({ event, descriptorId, ...props }) => {
7
- const [body] = useTranslatedEventData(event)
7
+ const { body } = useTranslatedEventData(event)
8
8
  const { description, url } = body
9
9
  const classNames = useSeamlyMessageContainerClassNames(event)
10
10
 
@@ -1,12 +1,10 @@
1
1
  import { className } from 'lib/css'
2
2
  import { useSeamlyMessageContainerClassNames } from 'ui/hooks/component-helper-hooks'
3
3
  import { useTranslatedEventData } from 'domains/translations/hooks'
4
- import { useI18n } from 'domains/i18n/hooks'
5
4
  import EventParticipant from './event/event-participant'
6
5
 
7
6
  function MessageContainer({
8
7
  showParticipant = true,
9
- showTranslationToggle = true,
10
8
  event,
11
9
  type,
12
10
  modifiers,
@@ -16,10 +14,8 @@ function MessageContainer({
16
14
  ...props
17
15
  }) {
18
16
  const classNames = useSeamlyMessageContainerClassNames(event)
19
- const { t } = useI18n()
20
17
 
21
- const [, { hasTranslation, isTranslated, toggleTranslation, locale }] =
22
- useTranslatedEventData(event)
18
+ const { hasTranslation, isTranslated, locale } = useTranslatedEventData(event)
23
19
 
24
20
  if (type) {
25
21
  classNames.push(`message--type-${type}`)
@@ -60,24 +56,6 @@ function MessageContainer({
60
56
  {info}
61
57
  </div>
62
58
  )}
63
- {showTranslationToggle && hasTranslation && (
64
- <div className={className('message__translation-info')}>
65
- <button
66
- className={className(
67
- 'message__translation-toggle',
68
- 'button',
69
- 'button--secondary',
70
- )}
71
- onClick={toggleTranslation}
72
- >
73
- {t(
74
- isTranslated
75
- ? 'translations.toggle.hideButtonText'
76
- : 'translations.toggle.showButtonText',
77
- )}
78
- </button>
79
- </div>
80
- )}
81
59
  </div>
82
60
  </>
83
61
  )
@@ -123,12 +123,13 @@ const SeamlyEventSubscriber = ({ eventBus }) => {
123
123
  case 'system':
124
124
  if (payload.type === 'service_changed') {
125
125
  const { serviceSettings, ...eventPayload } = payload
126
- const { uploads, entry } = serviceSettings
126
+ const { entry } = serviceSettings
127
+ const { upload } = entry.options
127
128
 
128
129
  dispatch(
129
130
  setFeatureEnabledState({
130
131
  key: featureKeys.uploads,
131
- enabled: !!(uploads && uploads.enabled),
132
+ enabled: !!(upload && upload.enabled),
132
133
  }),
133
134
  )
134
135
 
@@ -32,7 +32,9 @@ const Faq = () => {
32
32
  const { hasPrompt, continueChat } = useSeamlyResumeConversationPrompt()
33
33
 
34
34
  const lastFaqEventPayload = useSeamlyServiceData('suggestion')
35
- const [eventBody] = useTranslatedEventData({ payload: lastFaqEventPayload })
35
+ const { body: eventBody } = useTranslatedEventData({
36
+ payload: lastFaqEventPayload,
37
+ })
36
38
  const faqs = useMemo(() => {
37
39
  const newFaqs = lastFaqEventPayload && !hasInterrupt ? eventBody : []
38
40
  const itemBaseClass = `faqs__item`
@@ -43,10 +43,11 @@ const OptionsButton = () => {
43
43
  useEffect(() => {
44
44
  if (menuIsOpen && !prevMenuIsOpen.current) {
45
45
  requestAnimationFrame(async () => {
46
- await timeout(180) // Wait for next 3 frame ticks
46
+ await timeout(60) // Wait for next frame tick
47
47
  const firstActiveOptionIndex = menuOptions.findIndex(
48
48
  (option) => option.available,
49
49
  )
50
+
50
51
  const focusIndex =
51
52
  firstActiveOptionIndex === -1 ? 0 : firstActiveOptionIndex
52
53
  focusElement(menuItemButtons.current[focusIndex])
@@ -155,6 +156,7 @@ const OptionsButton = () => {
155
156
  if (!optionsLength) {
156
157
  return null
157
158
  }
159
+
158
160
  return (
159
161
  <div
160
162
  className={className('options__container')}
@@ -1,4 +1,5 @@
1
1
  import { useUserHasResponded } from 'domains/app/hooks'
2
+ import { useConfig } from 'domains/config/hooks'
2
3
  import { useI18n } from 'domains/i18n/hooks'
3
4
  import { useInterrupt } from 'domains/interrupt/hooks'
4
5
  import { useTranslatedEventData } from 'domains/translations/hooks'
@@ -29,6 +30,7 @@ const Suggestions = ({ isAside = false }) => {
29
30
  const { t } = useI18n()
30
31
  const { sendAction, addMessageBubble } = useSeamlyCommands()
31
32
  const { isOpen, setVisibility } = useVisibility()
33
+ const { showSuggestions } = useConfig()
32
34
  // a11y hooks
33
35
  const sectionId = useGeneratedId()
34
36
  const focusSkiplinkTarget = useSkiplinkTargetFocusing()
@@ -41,7 +43,7 @@ const Suggestions = ({ isAside = false }) => {
41
43
  // data hooks
42
44
  const userHasResponded = useUserHasResponded()
43
45
  const payload = useSeamlyServiceData('suggestion')
44
- const [eventBody] = useTranslatedEventData({ payload })
46
+ const { body: eventBody } = useTranslatedEventData({ payload })
45
47
  const suggestions = useMemo(
46
48
  () => (payload && !hasInterrupt ? eventBody : []),
47
49
  [payload, hasInterrupt, eventBody],
@@ -56,7 +58,8 @@ const Suggestions = ({ isAside = false }) => {
56
58
  ? (userHasResponded || isOpen) && !isAside
57
59
  : userHasResponded
58
60
  const prevHideSuggestions = useRef(hideSuggestions)
59
- const showSuggestionsContainer = hasSuggestions && !hideSuggestions
61
+ const showSuggestionsContainer =
62
+ hasSuggestions && !hideSuggestions && showSuggestions
60
63
  const renderedSuggestions = hasSuggestions
61
64
  ? suggestions
62
65
  : previousRenderedSuggestions.current
@@ -65,6 +65,12 @@ export const selectEvents = createSelector(
65
65
  )
66
66
  export const useEvents = () => useSelector(selectEvents)
67
67
 
68
+ export const selectEventIds = createSelector(selectEvents, (events) => {
69
+ return events.map((event) => event.payload.id)
70
+ })
71
+
72
+ export const useEventsIds = () => useSelector(selectEventIds)
73
+
68
74
  export const useSeamlyIsLoading = () => useSeamlyStateContext().isLoading
69
75
 
70
76
  export const useSeamlyHeaderData = () => useSeamlyStateContext().headerTitles
@@ -41,6 +41,7 @@
41
41
  .#{$n}-carousel-controls {
42
42
  display: flex;
43
43
  position: relative;
44
+ align-items: center;
44
45
  justify-content: space-between;
45
46
  width: 100%;
46
47
  height: fit-content;
@@ -51,6 +52,7 @@
51
52
  /* stylelint-disable no-descending-specificity */
52
53
  .#{$n}-carousel-controls .#{$n}-button {
53
54
  display: flex;
55
+ flex: 0 0 $buttonsize;
54
56
  align-items: center;
55
57
  justify-content: center;
56
58
  width: $buttonsize;
@@ -89,21 +91,21 @@
89
91
  padding: 0 $spacer * 0.5;
90
92
  }
91
93
 
92
- .#{$n}-carousel-pagination {
94
+ .#{$n}-carousel-pagination__wrapper {
93
95
  display: flex;
94
96
  position: relative;
95
97
  flex-direction: row;
96
98
  justify-content: center;
97
- width: 100%;
98
- margin: 0 auto;
99
- padding: 0;
100
99
  }
101
100
 
102
- .#{$n}-carousel-pagination__wrapper {
101
+ .#{$n}-carousel-pagination {
103
102
  display: flex;
104
103
  position: relative;
105
- flex-direction: row;
104
+ flex-flow: row wrap;
106
105
  justify-content: center;
106
+ width: 100%;
107
+ margin: 0 auto;
108
+ padding: 0;
107
109
  }
108
110
 
109
111
  .#{$n}-carousel-pagination__item {
@@ -114,8 +116,8 @@
114
116
  .#{$n}-carousel-pagination__button {
115
117
  display: block;
116
118
  position: relative;
117
- width: $buttonsize-small;
118
- height: $buttonsize-small;
119
+ width: $buttonsize-small * 0.75;
120
+ height: $buttonsize-small * 0.75;
119
121
  padding: 0;
120
122
  border: 0;
121
123
  border-radius: 0;