@seamly/web-ui 22.2.0 → 22.3.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 (47) hide show
  1. package/build/dist/lib/components.js +269 -138
  2. package/build/dist/lib/components.js.map +1 -1
  3. package/build/dist/lib/components.min.js +1 -1
  4. package/build/dist/lib/components.min.js.map +1 -1
  5. package/build/dist/lib/hooks.js +217 -41
  6. package/build/dist/lib/hooks.js.map +1 -1
  7. package/build/dist/lib/hooks.min.js +1 -1
  8. package/build/dist/lib/hooks.min.js.map +1 -1
  9. package/build/dist/lib/index.debug.js +43 -21
  10. package/build/dist/lib/index.debug.js.map +1 -1
  11. package/build/dist/lib/index.debug.min.js +1 -1
  12. package/build/dist/lib/index.debug.min.js.LICENSE.txt +12 -4
  13. package/build/dist/lib/index.debug.min.js.map +1 -1
  14. package/build/dist/lib/index.js +257 -133
  15. package/build/dist/lib/index.js.map +1 -1
  16. package/build/dist/lib/index.min.js +1 -1
  17. package/build/dist/lib/index.min.js.map +1 -1
  18. package/build/dist/lib/standalone.js +265 -133
  19. package/build/dist/lib/standalone.js.map +1 -1
  20. package/build/dist/lib/standalone.min.js +1 -1
  21. package/build/dist/lib/standalone.min.js.map +1 -1
  22. package/build/dist/lib/style-guide.js +274 -134
  23. package/build/dist/lib/style-guide.js.map +1 -1
  24. package/build/dist/lib/style-guide.min.js +1 -1
  25. package/build/dist/lib/style-guide.min.js.map +1 -1
  26. package/build/dist/lib/styles.css +1 -1
  27. package/build/dist/lib/utils.js +325 -171
  28. package/build/dist/lib/utils.js.map +1 -1
  29. package/build/dist/lib/utils.min.js +1 -1
  30. package/build/dist/lib/utils.min.js.map +1 -1
  31. package/package.json +1 -1
  32. package/src/javascripts/api/errors/seamly-api-error.ts +0 -1
  33. package/src/javascripts/api/index.ts +16 -8
  34. package/src/javascripts/domains/app/actions.ts +8 -3
  35. package/src/javascripts/domains/interrupt/selectors.ts +3 -2
  36. package/src/javascripts/domains/interrupt/slice.ts +2 -0
  37. package/src/javascripts/domains/redux/create-debounced-async-thunk.ts +109 -0
  38. package/src/javascripts/domains/redux/redux.types.ts +2 -1
  39. package/src/javascripts/domains/store/actions.ts +38 -0
  40. package/src/javascripts/domains/visibility/actions.ts +4 -1
  41. package/src/javascripts/style-guide/states.js +18 -1
  42. package/src/javascripts/ui/components/conversation/event/{card-component.js → card-component.tsx} +6 -4
  43. package/src/javascripts/ui/components/conversation/event/event-participant.js +1 -1
  44. package/src/javascripts/ui/components/core/seamly-event-subscriber.ts +14 -30
  45. package/src/javascripts/ui/components/view/window-view/window-open-button.js +8 -3
  46. package/src/javascripts/ui/hooks/use-session-expired-command.ts +31 -2
  47. package/src/stylesheets/5-components/_message-count.scss +11 -9
@@ -2269,7 +2269,8 @@ class API {
2269
2269
  });
2270
2270
  }
2271
2271
  getConversationUrl() {
2272
- return this.store.get('conversationUrl');
2272
+ const conversationUrl = this.store.get('conversationUrl');
2273
+ return conversationUrl;
2273
2274
  }
2274
2275
  hasConversation() {
2275
2276
  return !!this.getConversationUrl();
@@ -2377,7 +2378,7 @@ class API {
2377
2378
  if (error.status >= 500) {
2378
2379
  throw new SeamlyGeneralError(error);
2379
2380
  }
2380
- throw error;
2381
+ throw new ApiError(error);
2381
2382
  }
2382
2383
  });
2383
2384
  }
@@ -2486,7 +2487,7 @@ class API {
2486
2487
  if (error.status >= 500) {
2487
2488
  throw new SeamlyGeneralError(error);
2488
2489
  }
2489
- throw error;
2490
+ throw new ApiError(error);
2490
2491
  }
2491
2492
  });
2492
2493
  }
@@ -2546,15 +2547,17 @@ class API {
2546
2547
  }
2547
2548
  }
2548
2549
  _API_ready = new WeakMap(), _API_externalId = new WeakMap(), _API_conversationAuthToken = new WeakMap(), _API_layoutMode = new WeakMap(), _API_config = new WeakMap(), _API_getLocale = new WeakMap(), _API_instances = new WeakSet(), _API_getAccessToken = function _API_getAccessToken() {
2549
- return this.store.get('accessToken');
2550
+ const accessToken = this.store.get('accessToken');
2551
+ return accessToken;
2550
2552
  }, _API_setAccessToken = function _API_setAccessToken(accessToken) {
2551
2553
  this.store.set('accessToken', accessToken);
2552
2554
  }, _API_setConversationUrl = function _API_setConversationUrl(url) {
2553
2555
  this.store.set('conversationUrl', url);
2554
2556
  }, _API_getChannelTopic = function _API_getChannelTopic() {
2557
+ const channelTopic = this.store.get('channelTopic') || this.store.get('channelName');
2555
2558
  // The `channelName` fallback is needed for seamless client upgrades.
2556
2559
  // TODO: Remove when all clients have been upgraded past v20.
2557
- return this.store.get('channelTopic') || this.store.get('channelName');
2560
+ return channelTopic;
2558
2561
  }, _API_setChannelTopic = function _API_setChannelTopic(topic) {
2559
2562
  this.store.set('channelTopic', topic);
2560
2563
  }, _API_getUrlPrefix = function _API_getUrlPrefix(protocol) {
@@ -2619,7 +2622,7 @@ _API_ready = new WeakMap(), _API_externalId = new WeakMap(), _API_conversationAu
2619
2622
  return {
2620
2623
  clientName: "@seamly/web-ui",
2621
2624
  clientVariant: api_classPrivateFieldGet(this, _API_layoutMode, "f"),
2622
- clientVersion: "22.2.0",
2625
+ clientVersion: "22.3.0-beta.1",
2623
2626
  currentUrl: window.location.toString(),
2624
2627
  screenResolution: `${window.screen.width}x${window.screen.height}`,
2625
2628
  timezone: getTimeZone(),
@@ -6453,6 +6456,62 @@ const setLocale = createAsyncThunk('setLocale', (locale, {
6453
6456
  return true;
6454
6457
  }
6455
6458
  });
6459
+ ;// CONCATENATED MODULE: ./src/javascripts/domains/redux/create-debounced-async-thunk.ts
6460
+
6461
+ /**
6462
+ * A debounced analogue of the `createAsyncThunk` from `@reduxjs/toolkit`
6463
+ * @param typePrefix - a string action type value
6464
+ * @param payloadCreator - a callback function that should return a promise containing the result of some asynchronous logic
6465
+ * @param debounceOptions - the debounce options object
6466
+ */
6467
+ const createDebouncedAsyncThunk = (typePrefix, payloadCreator, debounceOptions) => {
6468
+ const {
6469
+ wait = 300,
6470
+ maxWait = 0,
6471
+ leading = false
6472
+ } = debounceOptions !== null && debounceOptions !== void 0 ? debounceOptions : {};
6473
+ let debounceTimer = null;
6474
+ let maxWaitTimer = null;
6475
+ let resolve;
6476
+ const cancel = () => {
6477
+ if (resolve) {
6478
+ resolve(false);
6479
+ resolve = undefined;
6480
+ }
6481
+ };
6482
+ const invoke = () => {
6483
+ clearTimeout(maxWaitTimer);
6484
+ maxWaitTimer = undefined;
6485
+ if (resolve) {
6486
+ resolve(true);
6487
+ resolve = undefined;
6488
+ }
6489
+ };
6490
+ const debounceExecutionCondition = () => {
6491
+ const immediate = leading && !debounceTimer;
6492
+ // Start debounced condition resolution
6493
+ clearTimeout(debounceTimer);
6494
+ debounceTimer = setTimeout(() => {
6495
+ invoke();
6496
+ debounceTimer = null;
6497
+ }, wait);
6498
+ if (immediate) {
6499
+ return true;
6500
+ }
6501
+ cancel();
6502
+ // Start max wait condition resolution
6503
+ if (maxWait && !maxWaitTimer) {
6504
+ maxWaitTimer = setTimeout(invoke, maxWait);
6505
+ }
6506
+ return new Promise(res => {
6507
+ resolve = res;
6508
+ });
6509
+ };
6510
+ return createAsyncThunk(typePrefix, payloadCreator, {
6511
+ condition: debounceExecutionCondition
6512
+ });
6513
+ };
6514
+ /* harmony default export */ const create_debounced_async_thunk = (createDebouncedAsyncThunk);
6456
6515
  ;// CONCATENATED MODULE: ./node_modules/reselect/es/defaultMemoize.js
6457
6516
  // Cache implementation based on Erik Rasmussen's `lru-memoize`:
6458
6517
  // https://github.com/erikras/lru-memoize
@@ -7009,8 +7068,9 @@ const setVisibility = createAsyncThunk('setVisibility', (requestedVisibility, {
7009
7068
  if (previousVisibility === calculatedVisibility) {
7010
7069
  return undefined;
7011
7070
  }
7071
+ const visibility = api.store.get(StoreKey);
7012
7072
  // Store the user-requested visibility in order to reinitialize after refresh
7013
- api.store.set(StoreKey, Object.assign(Object.assign({}, api.store.get(StoreKey) || {}), {
7073
+ api.store.set(StoreKey, Object.assign(Object.assign({}, visibility || {}), {
7014
7074
  [layoutMode]: requestedVisibility
7015
7075
  }));
7016
7076
  if (requestedVisibility) {
@@ -7074,6 +7134,7 @@ var app_actions_awaiter = undefined && undefined.__awaiter || function (thisArg,
7074
7134
 
7075
7135
 
7076
7136
 
7137
+
7077
7138
  const initializeApp = createAsyncThunk('initializeApp', (_, {
7078
7139
  extra: {
7079
7140
  api,
@@ -7139,14 +7200,14 @@ const initializeApp = createAsyncThunk('initializeApp', (_, {
7139
7200
  });
7140
7201
  }
7141
7202
  }));
7142
- const resetApp = createAsyncThunk('resetApp', (_, {
7203
+ const resetApp = create_debounced_async_thunk('resetApp', (_, {
7143
7204
  dispatch,
7144
7205
  extra: {
7145
7206
  api
7146
7207
  }
7147
7208
  }) => app_actions_awaiter(void 0, void 0, void 0, function* () {
7148
7209
  yield api.disconnect();
7149
- yield api.clearStore();
7210
+ api.clearStore();
7150
7211
  dispatch(resetConfig());
7151
7212
  yield dispatch(initializeConfig());
7152
7213
  try {
@@ -7154,11 +7215,14 @@ const resetApp = createAsyncThunk('resetApp', (_, {
7154
7215
  locale
7155
7216
  } = yield dispatch(initializeApp()).unwrap();
7156
7217
  yield dispatch(setLocale(locale));
7157
- } catch (rejectedValueOrSerializedError) {
7218
+ } catch (e) {
7158
7219
  // nothing to do
7159
7220
  }
7160
7221
  dispatch(initializeVisibility());
7161
- }));
7222
+ }), {
7223
+ wait: 2000,
7224
+ leading: true
7225
+ });
7162
7226
  ;// CONCATENATED MODULE: ./src/javascripts/domains/app/hooks.js
7163
7227
 
7164
7228
 
@@ -7194,12 +7258,75 @@ const {
7194
7258
  setHasResponded
7195
7259
  } = appSlice.actions;
7196
7260
  /* harmony default export */ const slice = (appSlice.reducer);
7261
+ ;// CONCATENATED MODULE: ./src/javascripts/domains/store/actions.ts
7262
+ var store_actions_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
7263
+ function adopt(value) {
7264
+ return value instanceof P ? value : new P(function (resolve) {
7265
+ resolve(value);
7266
+ });
7267
+ }
7268
+ return new (P || (P = Promise))(function (resolve, reject) {
7269
+ function fulfilled(value) {
7270
+ try {
7271
+ step(generator.next(value));
7272
+ } catch (e) {
7273
+ reject(e);
7274
+ }
7275
+ }
7276
+ function rejected(value) {
7277
+ try {
7278
+ step(generator["throw"](value));
7279
+ } catch (e) {
7280
+ reject(e);
7281
+ }
7282
+ }
7283
+ function step(result) {
7284
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
7285
+ }
7286
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
7287
+ });
7288
+ };
7289
+
7290
+ const getConversation = createAsyncThunk('getConversation', (_, {
7291
+ extra: {
7292
+ api
7293
+ },
7294
+ rejectWithValue
7295
+ }) => store_actions_awaiter(void 0, void 0, void 0, function* () {
7296
+ try {
7297
+ return api.getConversation();
7298
+ } catch (error) {
7299
+ return rejectWithValue({
7300
+ name: error === null || error === void 0 ? void 0 : error.name,
7301
+ message: error === null || error === void 0 ? void 0 : error.message,
7302
+ langKey: error === null || error === void 0 ? void 0 : error.langKey,
7303
+ action: error === null || error === void 0 ? void 0 : error.action,
7304
+ originalEvent: error === null || error === void 0 ? void 0 : error.originalEvent,
7305
+ originalError: error === null || error === void 0 ? void 0 : error.originalError
7306
+ });
7307
+ }
7308
+ }), {
7309
+ condition(payload, {
7310
+ getState
7311
+ }) {
7312
+ var _a;
7313
+ const {
7314
+ state: {
7315
+ events
7316
+ }
7317
+ } = getState();
7318
+ const lastEvent = events[events.length - 1];
7319
+ const payloadLastEventId = (_a = payload === null || payload === void 0 ? void 0 : payload.lastEvent) === null || _a === void 0 ? void 0 : _a.id;
7320
+ return lastEvent && payloadLastEventId !== lastEvent.payload.id;
7321
+ }
7322
+ });
7197
7323
  ;// CONCATENATED MODULE: ./src/javascripts/domains/interrupt/slice.ts
7198
7324
 
7199
7325
 
7200
7326
 
7201
7327
 
7202
7328
 
7329
+
7203
7330
  const slice_initialState = {
7204
7331
  error: undefined
7205
7332
  };
@@ -7213,7 +7340,7 @@ const interruptSlice = createSlice({
7213
7340
  clearInterrupt: () => slice_initialState
7214
7341
  },
7215
7342
  extraReducers: builder => {
7216
- builder.addCase(initializeConfig.pending, () => slice_initialState).addMatcher(isAnyOf(initializeApp.rejected, initializeConfig.rejected, setLocale.rejected, setVisibility.rejected, initializeVisibility.rejected), (state, {
7343
+ builder.addCase(initializeConfig.pending, () => slice_initialState).addMatcher(isAnyOf(initializeApp.rejected, initializeConfig.rejected, setLocale.rejected, setVisibility.rejected, initializeVisibility.rejected, getConversation.rejected), (state, {
7217
7344
  payload
7218
7345
  }) => {
7219
7346
  state.error = payload;
@@ -9619,6 +9746,9 @@ function useInterrupt() {
9619
9746
 
9620
9747
 
9621
9748
 
9749
+
9750
+
9751
+
9622
9752
  function useSessionExpiredCommand() {
9623
9753
  const {
9624
9754
  meta: {
@@ -9626,13 +9756,35 @@ function useSessionExpiredCommand() {
9626
9756
  action
9627
9757
  }
9628
9758
  } = useInterrupt();
9759
+ const dispatch = useAppDispatch();
9629
9760
  const seamlyCommands = use_seamly_commands();
9630
9761
  const isExpiredError = (originalError === null || originalError === void 0 ? void 0 : originalError.name) === 'SeamlySessionExpiredError';
9762
+ const limit = (0,hooks_.useRef)(0);
9763
+ const limitTimer = (0,hooks_.useRef)(null);
9631
9764
  (0,hooks_.useEffect)(() => {
9632
9765
  if (isExpiredError && seamlyCommands[action]) {
9766
+ if (limit.current >= 10) {
9767
+ limitTimer.current = setTimeout(() => {
9768
+ limit.current = 0;
9769
+ }, 10000);
9770
+ const error = new SeamlyGeneralError();
9771
+ dispatch(setInterrupt({
9772
+ name: error.name,
9773
+ message: error.message,
9774
+ langKey: error.langKey,
9775
+ originalEvent: error.originalEvent,
9776
+ originalError: error.originalError,
9777
+ action: error.action
9778
+ }));
9779
+ return () => {};
9780
+ }
9781
+ limit.current += 1;
9633
9782
  seamlyCommands[action]();
9634
9783
  }
9635
- }, [action, seamlyCommands, isExpiredError]);
9784
+ return () => {
9785
+ if (limitTimer.current) clearTimeout(limitTimer.current);
9786
+ };
9787
+ }, [action, seamlyCommands, isExpiredError, dispatch]);
9636
9788
  }
9637
9789
  ;// CONCATENATED MODULE: ./src/javascripts/ui/hooks/use-seamly-chat.ts
9638
9790
  var use_seamly_chat_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
@@ -10460,7 +10612,7 @@ const EventParticipant = ({
10460
10612
  })
10461
10613
  }));
10462
10614
  }
10463
- if (showName) {
10615
+ if (showName && participantName) {
10464
10616
  authorInfo.push((0,jsx_runtime_namespaceObject.jsx)("span", {
10465
10617
  className: css_className('message__author-name'),
10466
10618
  children: participantName
@@ -10540,108 +10692,61 @@ function MessageContainer({
10540
10692
  });
10541
10693
  }
10542
10694
  /* harmony default export */ const message_container = (MessageContainer);
10543
- ;// CONCATENATED MODULE: ./src/javascripts/ui/components/conversation/event/card-component.js
10695
+ ;// CONCATENATED MODULE: ./src/javascripts/ui/components/conversation/event/card-component.tsx
10544
10696
 
10545
10697
 
10546
10698
 
10547
10699
 
10548
10700
 
10549
-
10550
- const CardComponent = ({
10551
- id,
10552
- action,
10553
- buttonText,
10554
- description,
10555
- hasFocus,
10556
- image,
10557
- title,
10558
- isCarouselItem
10559
- }) => {
10560
- const cardRef = (0,hooks_.useRef)(null);
10561
- const {
10562
- sendMessage,
10563
- sendAction,
10564
- emitEvent
10565
- } = use_seamly_commands();
10566
- const descriptionId = useGeneratedId();
10567
- const isMounted = (0,hooks_.useRef)();
10568
- const CardActionComponent = action.type === cardTypes.navigate ? 'a' : 'button';
10569
- const emitCardEvent = (0,hooks_.useCallback)(() => emitEvent(`action.${actionTypes.clickCard}`, {
10570
- type: actionTypes.clickCta,
10571
- originMessage: id,
10572
- action
10573
- }), [emitEvent, id, action]);
10574
- const handleClick = (0,hooks_.useCallback)(() => {
10575
- emitCardEvent();
10576
- if (action.type === cardTypes.ask) {
10577
- sendMessage({
10578
- body: action.ask
10579
- });
10580
- } else if (action.type === cardTypes.topic) {
10581
- const {
10582
- topic: name,
10583
- fallbackMessage
10584
- } = action;
10585
- sendAction({
10586
- type: actionTypes.setTopic,
10587
- body: {
10588
- name,
10589
- fallbackMessage
10701
+ const CardComponent = ({ id, action, buttonText, description, hasFocus, image, title, isCarouselItem, }) => {
10702
+ const cardRef = (0,hooks_.useRef)(null);
10703
+ const { sendMessage, sendAction, emitEvent } = use_seamly_commands();
10704
+ const descriptionId = useGeneratedId();
10705
+ const isMounted = (0,hooks_.useRef)(false);
10706
+ const CardActionComponent = action.type === cardTypes.navigate ? 'a' : 'button';
10707
+ const emitCardEvent = (0,hooks_.useCallback)(() => emitEvent(`action.${actionTypes.clickCard}`, {
10708
+ type: actionTypes.clickCta,
10709
+ originMessage: id,
10710
+ action,
10711
+ }), [emitEvent, id, action]);
10712
+ const handleClick = (0,hooks_.useCallback)(() => {
10713
+ emitCardEvent();
10714
+ if (action.type === cardTypes.ask) {
10715
+ sendMessage({ body: action.ask });
10590
10716
  }
10591
- });
10592
- }
10593
- }, [sendMessage, action, sendAction, emitCardEvent]);
10594
- const actionProps = (0,hooks_.useMemo)(() => action.type === cardTypes.navigate ? {
10595
- href: action.link,
10596
- rel: 'noopener noreferrer',
10597
- target: action.newTab ? '_blank' : '_self',
10598
- onClick: emitCardEvent
10599
- } : {
10600
- onClick: handleClick
10601
- }, [action, handleClick, emitCardEvent]);
10602
- (0,hooks_.useEffect)(() => {
10603
- if (isCarouselItem) {
10604
- if (hasFocus && isMounted.current) {
10605
- window.requestAnimationFrame(() => cardRef.current.focus());
10606
- } else {
10607
- cardRef.current.blur();
10608
- }
10609
- }
10610
- isMounted.current = true;
10611
- }, [hasFocus, isCarouselItem]);
10612
- return (0,jsx_runtime_namespaceObject.jsxs)("div", {
10613
- className: css_className('card__wrapper'),
10614
- id: id,
10615
- tabIndex: "-1" // set tabIndex of -1 so card can be focussed
10616
- ,
10617
- ref: cardRef,
10618
- children: [(0,jsx_runtime_namespaceObject.jsx)("img", {
10619
- className: css_className('card__image'),
10620
- src: image,
10621
- alt: ""
10622
- }), (0,jsx_runtime_namespaceObject.jsxs)("div", {
10623
- className: css_className('card__content'),
10624
- id: id,
10625
- children: [title && (0,jsx_runtime_namespaceObject.jsx)("h2", {
10626
- className: css_className('card__title'),
10627
- children: title
10628
- }), description && (0,jsx_runtime_namespaceObject.jsx)("div", {
10629
- className: css_className('card__description'),
10630
- dangerouslySetInnerHTML: {
10631
- __html: description
10717
+ else if (action.type === cardTypes.topic) {
10718
+ const { topic: name, fallbackMessage } = action;
10719
+ sendAction({
10720
+ type: actionTypes.setTopic,
10721
+ body: { name, fallbackMessage },
10722
+ });
10632
10723
  }
10633
- }), (0,jsx_runtime_namespaceObject.jsx)(CardActionComponent, {
10634
- tabIndex: isCarouselItem && !hasFocus ? '-1' : undefined // disable to prevent tabbing through cards
10635
- ,
10636
- className: css_className('button', 'button--primary'),
10637
- "aria-describedby": descriptionId,
10638
- ...actionProps,
10639
- children: buttonText
10640
- })]
10641
- })]
10642
- });
10724
+ }, [sendMessage, action, sendAction, emitCardEvent]);
10725
+ const actionProps = (0,hooks_.useMemo)(() => action.type === cardTypes.navigate
10726
+ ? {
10727
+ href: action.link,
10728
+ rel: 'noopener noreferrer',
10729
+ target: action.newTab ? '_blank' : '_self',
10730
+ onClick: emitCardEvent,
10731
+ }
10732
+ : {
10733
+ onClick: handleClick,
10734
+ }, [action, handleClick, emitCardEvent]);
10735
+ (0,hooks_.useEffect)(() => {
10736
+ if (isCarouselItem) {
10737
+ if (hasFocus && isMounted.current) {
10738
+ window.requestAnimationFrame(() => cardRef.current.focus());
10739
+ }
10740
+ else {
10741
+ cardRef.current.blur();
10742
+ }
10743
+ }
10744
+ isMounted.current = true;
10745
+ }, [hasFocus, isCarouselItem]);
10746
+ return ((0,jsx_runtime_namespaceObject.jsxs)("div", { className: css_className('card__wrapper'), id: id, tabIndex: -1, ref: cardRef, children: [image ? ((0,jsx_runtime_namespaceObject.jsx)("img", { className: css_className('card__image'), src: image, alt: "" })) : null, (0,jsx_runtime_namespaceObject.jsxs)("div", { className: css_className('card__content'), id: id, children: [title && (0,jsx_runtime_namespaceObject.jsx)("h2", { className: css_className('card__title'), children: title }), description && ((0,jsx_runtime_namespaceObject.jsx)("div", { className: css_className('card__description'), dangerouslySetInnerHTML: { __html: description } })), (0,jsx_runtime_namespaceObject.jsx)(CardActionComponent, Object.assign({ tabIndex: isCarouselItem && !hasFocus ? -1 : undefined, className: css_className('button', 'button--primary'), "aria-describedby": descriptionId }, actionProps, { children: buttonText }))] })] }));
10643
10747
  };
10644
10748
  /* harmony default export */ const card_component = (CardComponent);
10749
+
10645
10750
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/conversation/event/card-message.js
10646
10751
 
10647
10752
 
@@ -13797,6 +13902,33 @@ const SeamlyActivityMonitor = ({ children }) => {
13797
13902
  /* harmony default export */ const seamly_activity_monitor = (SeamlyActivityMonitor);
13798
13903
 
13799
13904
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/core/seamly-event-subscriber.ts
13905
+ var seamly_event_subscriber_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
13906
+ function adopt(value) {
13907
+ return value instanceof P ? value : new P(function (resolve) {
13908
+ resolve(value);
13909
+ });
13910
+ }
13911
+ return new (P || (P = Promise))(function (resolve, reject) {
13912
+ function fulfilled(value) {
13913
+ try {
13914
+ step(generator.next(value));
13915
+ } catch (e) {
13916
+ reject(e);
13917
+ }
13918
+ }
13919
+ function rejected(value) {
13920
+ try {
13921
+ step(generator["throw"](value));
13922
+ } catch (e) {
13923
+ reject(e);
13924
+ }
13925
+ }
13926
+ function step(result) {
13927
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
13928
+ }
13929
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
13930
+ });
13931
+ };
13800
13932
  var seamly_event_subscriber_rest = undefined && undefined.__rest || function (s, e) {
13801
13933
  var t = {};
13802
13934
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
@@ -13817,13 +13949,13 @@ var seamly_event_subscriber_rest = undefined && undefined.__rest || function (s,
13817
13949
 
13818
13950
 
13819
13951
 
13952
+
13820
13953
  const EMITTABLE_MESSAGE_TYPES = ['text', 'choice_prompt', 'image', 'video'];
13821
13954
  const SeamlyEventSubscriber = () => {
13822
13955
  const api = seamly_api_hooks_useSeamlyApiContext();
13823
13956
  const syncChannelRef = (0,hooks_.useRef)();
13824
13957
  const messageChannelRef = (0,hooks_.useRef)();
13825
- const dispatch = useDispatch();
13826
- const events = useEvents();
13958
+ const dispatch = useAppDispatch();
13827
13959
  const eventBus = (0,hooks_.useContext)(SeamlyEventBusContext);
13828
13960
  const prevEmittedEventId = (0,hooks_.useRef)(null);
13829
13961
  const {
@@ -14068,31 +14200,19 @@ const SeamlyEventSubscriber = () => {
14068
14200
  if (syncChannelRef.current) {
14069
14201
  (_a = api.conversation.channel) === null || _a === void 0 ? void 0 : _a.off('sync', syncChannelRef.current);
14070
14202
  }
14071
- syncChannelRef.current = api.conversation.channel.on('sync', payload => {
14072
- var _a;
14073
- const lastEvent = events[events.length - 1];
14074
- const payloadLastEventId = (_a = payload === null || payload === void 0 ? void 0 : payload.lastEvent) === null || _a === void 0 ? void 0 : _a.id;
14075
- if (lastEvent && payloadLastEventId === lastEvent.payload.id) {
14076
- return payload;
14077
- }
14078
- return api.getConversation().then(history => {
14203
+ syncChannelRef.current = api.conversation.channel.on('sync', payload => seamly_event_subscriber_awaiter(void 0, void 0, void 0, function* () {
14204
+ try {
14205
+ const history = yield dispatch(getConversation(payload)).unwrap();
14079
14206
  if (!history) return;
14080
14207
  dispatch(setHistory(history));
14081
- }).catch(error => {
14082
- dispatch(setInterrupt({
14083
- name: error === null || error === void 0 ? void 0 : error.name,
14084
- message: error === null || error === void 0 ? void 0 : error.message,
14085
- langKey: error === null || error === void 0 ? void 0 : error.langKey,
14086
- action: error === null || error === void 0 ? void 0 : error.action,
14087
- originalEvent: error === null || error === void 0 ? void 0 : error.originalEvent,
14088
- originalError: error === null || error === void 0 ? void 0 : error.originalError
14089
- }));
14090
- });
14091
- });
14208
+ } catch (_e) {
14209
+ // nothing to do, the error is handled in the thunk
14210
+ }
14211
+ }));
14092
14212
  return true;
14093
14213
  });
14094
14214
  }
14095
- }, [api, api.connectionInfo, api.conversation.channel, events, dispatch]);
14215
+ }, [api, api.connectionInfo, api.conversation.channel, dispatch]);
14096
14216
  return null;
14097
14217
  };
14098
14218
  /* harmony default export */ const seamly_event_subscriber = (SeamlyEventSubscriber);
@@ -17675,10 +17795,14 @@ const WindowOpenButton = ({
17675
17795
  "aria-label": ariaLabel,
17676
17796
  "aria-hidden": isOpen,
17677
17797
  onClick: handleClick,
17678
- children: [(0,jsx_runtime_namespaceObject.jsx)("span", {
17679
- className: css_className('message-count'),
17680
- "aria-hidden": "true",
17681
- children: !!count && count
17798
+ children: [(0,jsx_runtime_namespaceObject.jsx)(in_out_transition, {
17799
+ isActive: !!count,
17800
+ transitionStartState: transitionStartStates.notRendered,
17801
+ children: (0,jsx_runtime_namespaceObject.jsx)("span", {
17802
+ className: css_className('message-count'),
17803
+ "aria-hidden": "true",
17804
+ children: count
17805
+ })
17682
17806
  }), (0,jsx_runtime_namespaceObject.jsx)(ButtonIcon, {})]
17683
17807
  })
17684
17808
  });
@@ -19370,6 +19494,22 @@ const cardTopic = {
19370
19494
  }
19371
19495
  }
19372
19496
  };
19497
+ const cardNoImage = {
19498
+ type: 'message',
19499
+ payload: {
19500
+ type: 'card',
19501
+ id: randomId(),
19502
+ body: {
19503
+ action: {
19504
+ ask: '',
19505
+ type: 'ask'
19506
+ },
19507
+ buttonText: 'Ask about pizzas!',
19508
+ description: 'Pizza Margherita is a <strong>typical Neapolitan pizza</strong>.\n\nIt is made with San Marzano tomatoes, mozzarella cheese, fresh basil, salt, and extra-virgin olive oil.',
19509
+ title: 'Pizza Margherita'
19510
+ }
19511
+ }
19512
+ };
19373
19513
  const standardState = {
19374
19514
  base: {
19375
19515
  category: categoryKeys.unstarted,
@@ -19607,7 +19747,7 @@ const standardState = {
19607
19747
  serviceInfo: {
19608
19748
  activeServiceSessionId: '3942159e-9878-469e-9120-f44fd6be0f35'
19609
19749
  },
19610
- events: [cardAskText, cardNavigate, cardTopic]
19750
+ events: [cardAskText, cardNavigate, cardTopic, cardNoImage]
19611
19751
  },
19612
19752
  carousel: {
19613
19753
  category: categoryKeys.messages,