@nyaruka/temba-components 0.132.0 → 0.133.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.
Files changed (143) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/demo/components/flow/example.html +1 -0
  3. package/demo/static/css/tailwind.css +30019 -0
  4. package/dist/temba-components.js +434 -402
  5. package/dist/temba-components.js.map +1 -1
  6. package/out-tsc/src/display/Chat.js +26 -6
  7. package/out-tsc/src/display/Chat.js.map +1 -1
  8. package/out-tsc/src/display/FloatingTab.js +4 -4
  9. package/out-tsc/src/display/FloatingTab.js.map +1 -1
  10. package/out-tsc/src/events.js.map +1 -1
  11. package/out-tsc/src/flow/CanvasNode.js +124 -58
  12. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  13. package/out-tsc/src/flow/Editor.js +66 -30
  14. package/out-tsc/src/flow/Editor.js.map +1 -1
  15. package/out-tsc/src/layout/FloatingWindow.js +1 -2
  16. package/out-tsc/src/layout/FloatingWindow.js.map +1 -1
  17. package/out-tsc/src/list/ContentMenu.js +1 -0
  18. package/out-tsc/src/list/ContentMenu.js.map +1 -1
  19. package/out-tsc/src/list/SortableList.js +3 -2
  20. package/out-tsc/src/list/SortableList.js.map +1 -1
  21. package/out-tsc/src/live/ContactChat.js +63 -35
  22. package/out-tsc/src/live/ContactChat.js.map +1 -1
  23. package/out-tsc/src/store/AppState.js +31 -0
  24. package/out-tsc/src/store/AppState.js.map +1 -1
  25. package/out-tsc/src/utils.js +3 -3
  26. package/out-tsc/src/utils.js.map +1 -1
  27. package/out-tsc/test/ActionHelper.js +6 -5
  28. package/out-tsc/test/ActionHelper.js.map +1 -1
  29. package/out-tsc/test/actions/send_broadcast.test.js +1 -1
  30. package/out-tsc/test/actions/send_broadcast.test.js.map +1 -1
  31. package/out-tsc/test/temba-contact-chat.test.js +1 -1
  32. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  33. package/out-tsc/test/temba-floating-window.test.js +0 -2
  34. package/out-tsc/test/temba-floating-window.test.js.map +1 -1
  35. package/out-tsc/test/temba-flow-editor-node.test.js +109 -0
  36. package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
  37. package/out-tsc/test/temba-utils-uuid.test.js +45 -1
  38. package/out-tsc/test/temba-utils-uuid.test.js.map +1 -1
  39. package/out-tsc/test/utils.test.js +2 -2
  40. package/out-tsc/test/utils.test.js.map +1 -1
  41. package/package.json +1 -1
  42. package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
  43. package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
  44. package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
  45. package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
  46. package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
  47. package/screenshots/truth/actions/add_contact_urn/render/expression-facebook.png +0 -0
  48. package/screenshots/truth/actions/add_contact_urn/render/expression-phone.png +0 -0
  49. package/screenshots/truth/actions/add_contact_urn/render/facebook-id.png +0 -0
  50. package/screenshots/truth/actions/add_contact_urn/render/instagram-handle.png +0 -0
  51. package/screenshots/truth/actions/add_contact_urn/render/line-id.png +0 -0
  52. package/screenshots/truth/actions/add_contact_urn/render/phone-number.png +0 -0
  53. package/screenshots/truth/actions/add_contact_urn/render/telegram-id.png +0 -0
  54. package/screenshots/truth/actions/add_contact_urn/render/viber-id.png +0 -0
  55. package/screenshots/truth/actions/add_contact_urn/render/wechat-id.png +0 -0
  56. package/screenshots/truth/actions/add_contact_urn/render/whatsapp.png +0 -0
  57. package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
  58. package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
  59. package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
  60. package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
  61. package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
  62. package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
  63. package/screenshots/truth/actions/send_broadcast/render/contacts-only.png +0 -0
  64. package/screenshots/truth/actions/send_broadcast/render/groups-and-contacts.png +0 -0
  65. package/screenshots/truth/actions/send_broadcast/render/groups-only.png +0 -0
  66. package/screenshots/truth/actions/send_broadcast/render/many-groups.png +0 -0
  67. package/screenshots/truth/actions/send_broadcast/render/multiline-text.png +0 -0
  68. package/screenshots/truth/actions/send_broadcast/render/with-attachments.png +0 -0
  69. package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
  70. package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
  71. package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
  72. package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
  73. package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
  74. package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
  75. package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
  76. package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
  77. package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
  78. package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
  79. package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
  80. package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
  81. package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
  82. package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
  83. package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
  84. package/screenshots/truth/actions/start_session/render/contact-query.png +0 -0
  85. package/screenshots/truth/actions/start_session/render/contacts-only.png +0 -0
  86. package/screenshots/truth/actions/start_session/render/create-contact.png +0 -0
  87. package/screenshots/truth/actions/start_session/render/groups-and-contacts.png +0 -0
  88. package/screenshots/truth/actions/start_session/render/groups-only.png +0 -0
  89. package/screenshots/truth/actions/start_session/render/many-recipients.png +0 -0
  90. package/screenshots/truth/contacts/chat-failure.png +0 -0
  91. package/screenshots/truth/contacts/chat-for-archived-contact.png +0 -0
  92. package/screenshots/truth/contacts/chat-for-blocked-contact.png +0 -0
  93. package/screenshots/truth/contacts/chat-for-stopped-contact.png +0 -0
  94. package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
  95. package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
  96. package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
  97. package/screenshots/truth/floating-tab/default.png +0 -0
  98. package/screenshots/truth/floating-tab/gray.png +0 -0
  99. package/screenshots/truth/floating-tab/green.png +0 -0
  100. package/screenshots/truth/floating-tab/hover.png +0 -0
  101. package/screenshots/truth/floating-tab/purple.png +0 -0
  102. package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
  103. package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
  104. package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
  105. package/screenshots/truth/nodes/split_by_llm/render/translation-task.png +0 -0
  106. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  107. package/screenshots/truth/nodes/split_by_llm_categorize/render/basic-categorization.png +0 -0
  108. package/screenshots/truth/nodes/split_by_llm_categorize/render/custom-input-and-result-name.png +0 -0
  109. package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
  110. package/screenshots/truth/nodes/split_by_llm_categorize/render/many-categories.png +0 -0
  111. package/screenshots/truth/nodes/split_by_llm_categorize/render/minimal-categories.png +0 -0
  112. package/screenshots/truth/nodes/split_by_random/render/ab-test-multiple-variants.png +0 -0
  113. package/screenshots/truth/nodes/split_by_random/render/sampling-split.png +0 -0
  114. package/screenshots/truth/nodes/split_by_random/render/three-way-split.png +0 -0
  115. package/screenshots/truth/nodes/split_by_random/render/two-bucket-split.png +0 -0
  116. package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
  117. package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
  118. package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
  119. package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
  120. package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
  121. package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
  122. package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
  123. package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
  124. package/src/display/Chat.ts +29 -7
  125. package/src/display/FloatingTab.ts +4 -4
  126. package/src/events.ts +1 -4
  127. package/src/flow/CanvasNode.ts +130 -57
  128. package/src/flow/Editor.ts +84 -30
  129. package/src/layout/FloatingWindow.ts +1 -3
  130. package/src/list/ContentMenu.ts +1 -0
  131. package/src/list/SortableList.ts +3 -2
  132. package/src/live/ContactChat.ts +68 -42
  133. package/src/store/AppState.ts +41 -0
  134. package/src/utils.ts +3 -3
  135. package/test/ActionHelper.ts +13 -5
  136. package/test/actions/send_broadcast.test.ts +2 -1
  137. package/test/temba-contact-chat.test.ts +1 -1
  138. package/test/temba-floating-window.test.ts +0 -2
  139. package/test/temba-flow-editor-node.test.ts +129 -0
  140. package/test/temba-utils-uuid.test.ts +61 -1
  141. package/test/utils.test.ts +7 -2
  142. package/test-assets/contacts/history.json +22 -9
  143. package/web-test-runner.config.mjs +3 -3
@@ -35,6 +35,8 @@ export class Chat extends RapidElement {
35
35
  this.hideBottomScroll = true;
36
36
  this.defaultAvatar = DEFAULT_AVATAR;
37
37
  this.agent = false;
38
+ this.endOfHistory = false;
39
+ this.oldestEventDate = null;
38
40
  this.msgMap = new Map();
39
41
  }
40
42
  static get styles() {
@@ -92,7 +94,8 @@ export class Chat extends RapidElement {
92
94
  text-align: center;
93
95
  font-size: 0.8em;
94
96
  color: #999;
95
- margin-top: 2em;
97
+ margin-bottom: 2em;
98
+ margin-top: 1em;
96
99
  border-top: 1px solid #e9e9e9;
97
100
  padding: 1em;
98
101
  margin-left: 10%;
@@ -540,9 +543,10 @@ export class Chat extends RapidElement {
540
543
  isSameGroup(msg1, msg2) {
541
544
  var _a, _b;
542
545
  if (msg1 && msg2) {
543
- return (msg1.type === msg2.type &&
546
+ const sameGroup = msg1.type === msg2.type &&
544
547
  ((_a = msg1.user) === null || _a === void 0 ? void 0 : _a.name) === ((_b = msg2.user) === null || _b === void 0 ? void 0 : _b.name) &&
545
- Math.abs(msg1.date.getTime() - msg2.date.getTime()) < BATCH_TIME_WINDOW);
548
+ Math.abs(msg1.date.getTime() - msg2.date.getTime()) < BATCH_TIME_WINDOW;
549
+ return sameGroup;
546
550
  }
547
551
  return false;
548
552
  }
@@ -658,7 +662,7 @@ export class Chat extends RapidElement {
658
662
  this.agent) ||
659
663
  !incoming;
660
664
  return html `
661
- ${!firstGroup ? timeDisplay : null}
665
+ ${timeDisplay}
662
666
  <div
663
667
  class="block ${incoming ? 'incoming' : 'outgoing'} ${currentMsg.type}"
664
668
  >
@@ -682,7 +686,6 @@ export class Chat extends RapidElement {
682
686
  </div>`
683
687
  : null}
684
688
  </div>
685
- ${firstGroup ? timeDisplay : null}
686
689
  `;
687
690
  }
688
691
  renderMessage(event, name = null) {
@@ -706,7 +709,6 @@ export class Chat extends RapidElement {
706
709
  <div class="bubble">
707
710
  ${name ? html `<div class="name">${name}</div>` : null}
708
711
  <div class="message message-text">${message.text}</div>
709
-
710
712
  <!--div>${message.date.toLocaleDateString(undefined, VERBOSE_FORMAT)}</div-->
711
713
  </div>
712
714
  `
@@ -726,6 +728,12 @@ export class Chat extends RapidElement {
726
728
  this.messageGroups = [];
727
729
  this.hideBottomScroll = true;
728
730
  this.hideTopScroll = true;
731
+ this.endOfHistory = false;
732
+ this.oldestEventDate = null;
733
+ }
734
+ setEndOfHistory(oldestDate) {
735
+ this.endOfHistory = true;
736
+ this.oldestEventDate = oldestDate;
729
737
  }
730
738
  render() {
731
739
  return html ` <div
@@ -742,6 +750,12 @@ export class Chat extends RapidElement {
742
750
  <temba-loading
743
751
  class="${!this.fetching ? 'hidden' : ''}"
744
752
  ></temba-loading>
753
+
754
+ ${this.endOfHistory && this.oldestEventDate
755
+ ? html `<div class="time first">
756
+ ${this.oldestEventDate.toLocaleTimeString(undefined, VERBOSE_FORMAT)}
757
+ </div>`
758
+ : null}
745
759
  </div>
746
760
  <slot class="header" name="header"></slot>
747
761
  <slot class="footer" name="footer"></slot>
@@ -766,4 +780,10 @@ __decorate([
766
780
  __decorate([
767
781
  property({ type: Boolean })
768
782
  ], Chat.prototype, "agent", void 0);
783
+ __decorate([
784
+ property({ type: Boolean, attribute: false })
785
+ ], Chat.prototype, "endOfHistory", void 0);
786
+ __decorate([
787
+ property({ type: Object, attribute: false })
788
+ ], Chat.prototype, "oldestEventDate", void 0);
769
789
  //# sourceMappingURL=Chat.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Chat.js","sourceRoot":"","sources":["../../../src/display/Chat.ts"],"names":[],"mappings":"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","sourcesContent":["import { TemplateResult, html, PropertyValueMap, css } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { RapidElement } from '../RapidElement';\nimport { CustomEventType } from '../interfaces';\nimport { DEFAULT_AVATAR } from '../webchat/assets';\nimport { hashCode } from '../utils';\n\nconst BATCH_TIME_WINDOW = 60 * 60 * 1000;\nconst SCROLL_FETCH_BUFFER = 0.05;\nconst MIN_FETCH_TIME = 250;\n\nexport enum MessageType {\n Inline = 'inline',\n Error = 'error',\n Collapse = 'collapse',\n Note = 'note',\n MsgIn = 'msg_in',\n MsgOut = 'msg_out'\n}\n\ninterface User {\n avatar?: string;\n email: string;\n name: string;\n}\n\nexport interface ChatEvent {\n id?: string;\n type: MessageType;\n text: TemplateResult;\n date: Date;\n user?: User;\n popup?: TemplateResult;\n}\n\nexport interface Message extends ChatEvent {\n sendError?: boolean;\n attachments?: string[];\n}\n\nconst TIME_FORMAT = { hour: 'numeric', minute: '2-digit' } as any;\nconst VERBOSE_FORMAT = {\n weekday: undefined,\n year: undefined,\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit'\n} as any;\n\nexport class Chat extends RapidElement {\n static get styles() {\n return css`\n :host {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n position: relative;\n z-index: 1;\n }\n\n slot[name='header'] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n display: block;\n }\n\n slot[name='footer'] {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n display: block;\n }\n\n .block {\n margin-bottom: 1em;\n display: flex;\n flex-direction: row;\n }\n\n .block.outgoing {\n flex-direction: row-reverse;\n }\n\n .block.collapse {\n margin: 0;\n align-items: center;\n display: flex;\n flex-direction: column;\n margin-bottom: 0.5em;\n }\n\n .block.collapse .messsage {\n transform: scaleY(0);\n margin: 0;\n padding: 0;\n line-height: 0;\n }\n\n .time {\n text-align: center;\n font-size: 0.8em;\n color: #999;\n margin-top: 2em;\n border-top: 1px solid #e9e9e9;\n padding: 1em;\n margin-left: 10%;\n margin-right: 10%;\n }\n\n .time.first {\n border-top: none;\n margin-top: 0;\n border-bottom: 1px solid #e9e9e9;\n margin-bottom: 2em;\n }\n\n .first .time {\n margin-top: 0;\n border-top: none;\n padding-top: 0;\n }\n\n .row {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n margin-bottom: 0.25em;\n }\n\n .input-panel {\n padding: 1em;\n background: #fff;\n }\n\n temba-user {\n margin-right: 0.6em;\n margin-left: 0.6em;\n width: 2em;\n align-self: flex-end;\n }\n\n .toggle {\n flex-shrink: 0;\n width: 4em;\n height: 4em;\n overflow: hidden;\n border-radius: 100%;\n box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 1em 0.7em,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px,\n inset 0 0 0 0.25em rgba(0, 0, 0, 0.1);\n cursor: pointer;\n transition: box-shadow var(--toggle-speed, 200ms) ease-out;\n position: absolute;\n bottom: 1em;\n right: 1em;\n }\n\n .toggle:hover {\n box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 1em 0.7em,\n rgba(0, 0, 0, 0.4) 0px 1px 2px 0px,\n inset 0 0 0 0.25em rgba(0, 0, 0, 0.2);\n }\n\n .incoming .row {\n flex-direction: row-reverse;\n margin-left: 1em;\n }\n\n .bubble {\n padding: 0.75em;\n padding-bottom: 0.25em;\n background: var(--color-chat-in, #f1f1f1);\n border-radius: var(--curvature);\n border: var(--chat-border-in, none);\n }\n\n .bubble .name {\n font-size: 0.95em;\n font-weight: 400;\n color: rgba(0, 0, 0, 0.4);\n margin-bottom: 0.25em;\n }\n\n .outgoing .latest .bubble {\n border-bottom-left-radius: 0;\n }\n\n .incoming .bubble-wrap {\n align-items: flex-end;\n }\n\n .incoming .bubble {\n background: var(--color-chat-out, #3c92dd);\n border: var(--chat-border-out, none);\n color: white;\n }\n\n .incoming .latest .bubble {\n border-bottom-right-radius: 0;\n }\n\n .incoming .bubble .name {\n color: rgba(255, 255, 255, 0.7);\n }\n\n .note .bubble {\n background: #fffac3;\n color: rgba(0, 0, 0, 0.7);\n }\n\n .note .bubble .name {\n color: rgba(0, 0, 0, 0.5);\n }\n\n .message {\n margin-bottom: 0.5em;\n line-height: 1.2em;\n word-break: break-word;\n }\n\n .message-text {\n white-space: pre-line;\n }\n\n .chat {\n width: 28rem;\n border-radius: var(--curvature);\n overflow: hidden;\n box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, rgba(0, 0, 0, 0.1) 5em 5em 5em 5em;\n position: absolute;\n bottom: 3em;\n right: 1em;\n transition: all var(--toggle-speed, 200ms) ease-out;\n transform: scale(0.9);\n pointer-events: none;\n opacity: 0;\n }\n\n .chat.open {\n bottom: 6em;\n opacity: 1;\n transform: scale(1);\n pointer-events: initial;\n }\n\n .messages {\n position: relative;\n flex-grow: 1;\n overflow: hidden;\n }\n\n .scroll {\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n overflow-scrolling: touch;\n padding: 1em 1em 1em 1em;\n padding-bottom: 2.5em;\n display: flex;\n flex-direction: column-reverse;\n }\n\n .messages:before {\n content: '';\n background: radial-gradient(\n farthest-side at 50% 0,\n rgba(0, 0, 0, 0.2),\n rgba(0, 0, 0, 0)\n )\n center top;\n height: 10px;\n display: block;\n position: absolute;\n width: 100%;\n transition: opacity var(--toggle-speed, 200ms) ease-out;\n z-index: 1;\n }\n\n .messages:after {\n content: '';\n background: radial-gradient(\n farthest-side at 50% 100%,\n rgba(0, 0, 0, 0.2),\n rgba(0, 0, 0, 0)\n )\n center bottom;\n height: 10px;\n display: block;\n position: absolute;\n bottom: 0;\n margin-top: -10px;\n width: 100%;\n margin-right: 5em;\n transition: opacity var(--toggle-speed, 200ms) ease-out;\n z-index: 1;\n }\n\n .bubble-wrap {\n position: relative;\n max-width: 70%;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n margin-top: -1em;\n padding-top: 1em;\n }\n\n .scroll-at-top.messages:before {\n opacity: 0;\n }\n\n .scroll-at-bottom.messages:after {\n opacity: 0;\n }\n\n .input {\n border: none;\n flex-grow: 1;\n color: #333;\n font-size: 1em;\n }\n\n .input:focus {\n outline: none;\n }\n\n input::placeholder {\n opacity: 0.3;\n }\n\n .input.inactive {\n // pointer-events: none;\n // opacity: 0.3;\n }\n\n .active {\n }\n\n .send-icon {\n color: #eee;\n pointer-events: none;\n transform: rotate(-45deg);\n transition: transform 0.2s ease-out;\n }\n\n .pending .send-icon {\n color: var(--color-primary-dark);\n pointer-events: initial;\n transform: rotate(0deg);\n }\n\n .notice {\n padding: 1em;\n background: #f8f8f8;\n color: #666;\n text-align: center;\n cursor: pointer;\n }\n\n .connecting .notice {\n display: flex;\n justify-content: center;\n }\n\n .connecting .notice temba-icon {\n margin-left: 0.5em;\n }\n\n .reconnect {\n color: var(--color-primary-dark);\n text-decoration: underline;\n font-size: 0.9em;\n }\n\n .input:disabled {\n background: transparent !important;\n }\n\n temba-loading {\n justify-content: center;\n margin: 0.5em auto;\n margin-bottom: 2em;\n }\n\n temba-loading.hidden {\n display: none;\n }\n\n .inline {\n }\n\n .event {\n flex-grow: 1;\n align-self: center;\n display: flex;\n flex-direction: column;\n align-items: center;\n }\n\n .event p {\n margin: 0;\n padding: 0;\n }\n\n .collapse {\n }\n\n a {\n color: var(--color-primary-dark);\n }\n\n .attachments {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n align-self: flex-start;\n }\n\n .incoming .attachments {\n align-self: flex-end;\n }\n\n temba-thumbnail {\n margin: 0.4em;\n border-radius: var(--curvature);\n }\n\n .error .bubble {\n border: 1px solid var(--color-error);\n background: white;\n color: #333;\n }\n\n .error .bubble .name {\n color: #999;\n }\n\n .error temba-thumbnail {\n --thumb-background: var(--color-error);\n --thumb-icon: white;\n }\n\n .outgoing .popup {\n justify-content: left;\n }\n\n .incoming .popup {\n justify-content: right;\n }\n\n .popup {\n display: flex;\n position: absolute;\n background: #fff;\n margin: 0;\n padding: 0.5em 1em;\n border-radius: var(--curvature);\n box-shadow: rgba(0, 0, 0, 0.05) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px;\n border: 1px solid #f3f3f3;\n opacity: 0;\n transform: scale(0.7);\n transition: opacity 0.2s ease-out, transform 0.2s ease-out;\n z-index: 2;\n }\n\n .popup .arrow {\n z-index: 1;\n text-shadow: 0px 3px 3px rgba(0, 0, 0, 0.1);\n position: absolute;\n justify-content: center;\n text-align: center;\n font-size: 1.3em;\n transform: translateY(0.7em) scale(1);\n color: #fff;\n bottom: 0;\n }\n\n .bubble-wrap:hover .popup {\n transform: translateY(-120%);\n opacity: 1;\n transition-delay: 1s;\n }\n `;\n }\n\n @property({ type: Array })\n messageGroups: string[][] = [];\n\n @property({ type: Boolean })\n fetching = false;\n\n @property({ type: Boolean, attribute: false })\n hideTopScroll = true;\n\n @property({ type: Boolean, attribute: false })\n hideBottomScroll = true;\n\n @property({ type: String, attribute: 'avatar' })\n defaultAvatar = DEFAULT_AVATAR;\n\n @property({ type: Boolean })\n agent = false;\n\n private msgMap = new Map<string, ChatEvent>();\n\n public firstUpdated(\n changed: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changed);\n const scroll = this.shadowRoot.querySelector('.scroll');\n const hasScroll = scroll.scrollHeight > scroll.clientHeight;\n this.hideBottomScroll = true;\n this.hideTopScroll = !hasScroll;\n }\n\n public addMessages(\n messages: ChatEvent[],\n startTime: Date = null,\n append = false\n ) {\n // make sure our messages have ids\n messages.forEach((m) => {\n if (!m.id) {\n m.id =\n hashCode((m.text.strings || []).join('')) +\n '_' +\n m.date.toISOString();\n }\n });\n\n if (!startTime) {\n startTime = new Date();\n }\n\n const elapsed = new Date().getTime() - startTime.getTime();\n window.setTimeout(\n () => {\n this.fetching = false;\n // first add messages to the map\n const newMessages = [];\n for (const m of messages) {\n if (this.addMessage(m)) {\n newMessages.push(m.id);\n }\n }\n\n if (newMessages.length === 0) {\n return;\n }\n\n const ele = this.shadowRoot.querySelector('.scroll');\n const prevTop = ele.scrollTop;\n\n const grouped = this.groupMessages(newMessages);\n this.insertGroups(grouped, append);\n\n window.setTimeout(() => {\n ele.scrollTop = prevTop;\n\n this.fireCustomEvent(CustomEventType.FetchComplete);\n }, 100);\n },\n // if it's the first load don't wait, otherwise wait a minimum amount of time\n this.messageGroups.length === 0\n ? 0\n : Math.max(0, MIN_FETCH_TIME - elapsed)\n );\n }\n\n private addMessage(msg: ChatEvent): boolean {\n const isNew = !this.messageExists(msg);\n this.msgMap.set(msg.id, msg);\n return isNew;\n }\n\n public messageExists(msg: ChatEvent): boolean {\n return this.msgMap.has(msg.id);\n }\n\n private isSameGroup(msg1: ChatEvent, msg2: ChatEvent): boolean {\n if (msg1 && msg2) {\n return (\n msg1.type === msg2.type &&\n msg1.user?.name === msg2.user?.name &&\n Math.abs(msg1.date.getTime() - msg2.date.getTime()) < BATCH_TIME_WINDOW\n );\n }\n\n return false;\n }\n\n private insertGroups(newGroups: string[][], append = false) {\n if (!append) {\n newGroups.reverse();\n }\n\n for (const newGroup of newGroups) {\n // see if our new group belongs to the most recent group\n const group =\n this.messageGroups[append ? 0 : this.messageGroups.length - 1];\n\n if (group) {\n const lastMsgId = group[group.length - 1];\n const lastMsg = this.msgMap.get(lastMsgId);\n const newMsg = this.msgMap.get(newGroup[0]);\n // if our message belongs to the previous group, in we go\n if (this.isSameGroup(lastMsg, newMsg)) {\n group.push(...newGroup);\n } else {\n // otherwise, just add our entire group as a new one\n if (append) {\n this.messageGroups.splice(0, 0, newGroup);\n } else {\n this.messageGroups.push(newGroup);\n }\n }\n } else {\n if (append) {\n this.messageGroups.splice(0, 0, newGroup);\n } else {\n this.messageGroups.push(newGroup);\n }\n }\n }\n\n this.requestUpdate('messageGroups');\n }\n\n private groupMessages(msgIds: string[]): string[][] {\n // group our messages by origin and user\n const groups = [];\n let lastGroup = [];\n let lastMsg = null;\n for (const msgId of msgIds) {\n const msg = this.msgMap.get(msgId);\n if (!this.isSameGroup(msg, lastMsg)) {\n lastGroup = [];\n groups.push(lastGroup);\n }\n lastGroup.push(msgId);\n lastMsg = msg;\n }\n return groups;\n }\n\n private handleScroll(event: any) {\n const ele = event.target;\n const top = ele.scrollHeight - ele.clientHeight;\n const scroll = Math.round(top + ele.scrollTop);\n const scrollPct = scroll / top;\n\n this.hideTopScroll = scrollPct <= 0.01;\n this.hideBottomScroll = scrollPct >= 0.99;\n\n if (scrollPct < SCROLL_FETCH_BUFFER) {\n this.fireCustomEvent(CustomEventType.ScrollThreshold);\n }\n }\n\n private scrollToBottom() {\n const scroll = this.shadowRoot.querySelector('.scroll');\n if (scroll) {\n scroll.scrollTop = scroll.scrollHeight;\n this.hideBottomScroll = true;\n }\n }\n\n private renderMessageGroup(\n msgIds: string[],\n idx: number,\n groups: string[][]\n ): TemplateResult {\n const today = new Date();\n const firstGroup = idx === groups.length - 1;\n\n let prevMsg: ChatEvent;\n if (idx > 0) {\n const lastGroup = groups[idx - 1];\n if (lastGroup && lastGroup.length > 0) {\n prevMsg = this.msgMap.get(lastGroup[0]);\n }\n }\n\n const mostRecentId = msgIds[msgIds.length - 1];\n const currentMsg = this.msgMap.get(mostRecentId);\n let timeDisplay = null;\n if (\n prevMsg &&\n !this.isSameGroup(prevMsg, currentMsg) &&\n (Math.abs(currentMsg.date.getTime() - prevMsg.date.getTime()) >\n BATCH_TIME_WINDOW ||\n idx === groups.length - 1)\n ) {\n if (\n today.getDate() !== prevMsg.date.getDate() ||\n prevMsg.date.getDate() !== currentMsg.date.getDate()\n ) {\n timeDisplay = html`<div class=\"time ${firstGroup ? 'first' : ''}\">\n ${prevMsg.date.toLocaleTimeString(undefined, VERBOSE_FORMAT)}\n </div>`;\n } else {\n timeDisplay = html`<div class=\"time ${firstGroup ? 'first' : ''}\">\n ${prevMsg.date.toLocaleTimeString(undefined, TIME_FORMAT)}\n </div>`;\n }\n }\n\n const incoming = this.agent\n ? currentMsg.type !== 'msg_in'\n : currentMsg.type === 'msg_in';\n\n const name = currentMsg.user?.name;\n const email = currentMsg.user?.email;\n\n const showAvatar =\n ((currentMsg.type === 'note' ||\n currentMsg.type === 'msg_in' ||\n currentMsg.type === 'msg_out') &&\n this.agent) ||\n !incoming;\n\n return html`\n ${!firstGroup ? timeDisplay : null}\n <div\n class=\"block ${incoming ? 'incoming' : 'outgoing'} ${currentMsg.type}\"\n >\n <div class=\"group-messages\" style=\"flex-grow:1\">\n ${msgIds.map((msgId, index) => {\n const msg = this.msgMap.get(msgId);\n return html`<div class=\"row message\">\n ${this.renderMessage(msg, index == 0 ? name : null)}\n </div>`;\n })}\n </div>\n ${showAvatar\n ? html`<div class=\"avatar\" style=\"align-self:flex-end\">\n <temba-user\n email=${email}\n name=${name}\n avatar=${currentMsg.user?.avatar}\n ?system=${!email && !name}\n >\n </temba-user>\n </div>`\n : null}\n </div>\n ${firstGroup ? timeDisplay : null}\n `;\n }\n\n private renderMessage(event: ChatEvent, name = null): TemplateResult {\n if (\n event.type === MessageType.Error ||\n event.type === MessageType.Collapse ||\n event.type === MessageType.Inline\n ) {\n return html`<div class=\"event\">${event.text}</div>`;\n }\n\n const message = event as Message;\n return html`\n <div class=\"bubble-wrap ${message.sendError ? 'error' : ''}\">\n ${\n message.popup\n ? html`<div class=\"popup\">\n ${message.popup}\n <div class=\"arrow\">▼</div>\n </div>`\n : null\n }\n \n ${\n message.text\n ? html`\n <div class=\"bubble\">\n ${name ? html`<div class=\"name\">${name}</div>` : null}\n <div class=\"message message-text\">${message.text}</div>\n\n <!--div>${message.date.toLocaleDateString(\n undefined,\n VERBOSE_FORMAT\n )}</div-->\n </div>\n `\n : null\n }\n\n <div class=\"attachments\">\n ${(message.attachments || []).map(\n (attachment) =>\n html`<temba-thumbnail\n attachment=\"${attachment}\"\n ></temba-thumbnail>`\n )}\n </div>\n </div>\n </div>\n `;\n }\n\n public reset() {\n this.msgMap.clear();\n this.messageGroups = [];\n this.hideBottomScroll = true;\n this.hideTopScroll = true;\n }\n\n public render(): TemplateResult {\n return html` <div\n class=\"\n messages \n ${this.hideBottomScroll ? 'scroll-at-bottom' : ''}\n ${this.hideTopScroll ? 'scroll-at-top' : ''}\"\n >\n <div class=\"scroll\" @scroll=${this.handleScroll}>\n ${this.messageGroups\n ? this.messageGroups.map(\n (msgGroup, idx, groups) =>\n html`${this.renderMessageGroup(msgGroup, idx, groups)}`\n )\n : null}\n\n <temba-loading\n class=\"${!this.fetching ? 'hidden' : ''}\"\n ></temba-loading>\n </div>\n <slot class=\"header\" name=\"header\"></slot>\n <slot class=\"footer\" name=\"footer\"></slot>\n </div>`;\n }\n}\n"]}
1
+ {"version":3,"file":"Chat.js","sourceRoot":"","sources":["../../../src/display/Chat.ts"],"names":[],"mappings":"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","sourcesContent":["import { TemplateResult, html, PropertyValueMap, css } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { RapidElement } from '../RapidElement';\nimport { CustomEventType } from '../interfaces';\nimport { DEFAULT_AVATAR } from '../webchat/assets';\nimport { hashCode } from '../utils';\n\nconst BATCH_TIME_WINDOW = 60 * 60 * 1000;\nconst SCROLL_FETCH_BUFFER = 0.05;\nconst MIN_FETCH_TIME = 250;\n\nexport enum MessageType {\n Inline = 'inline',\n Error = 'error',\n Collapse = 'collapse',\n Note = 'note',\n MsgIn = 'msg_in',\n MsgOut = 'msg_out'\n}\n\ninterface User {\n avatar?: string;\n email: string;\n name: string;\n}\n\nexport interface ChatEvent {\n id?: string;\n type: MessageType;\n text: TemplateResult;\n date: Date;\n user?: User;\n popup?: TemplateResult;\n}\n\nexport interface Message extends ChatEvent {\n sendError?: boolean;\n attachments?: string[];\n}\n\nconst TIME_FORMAT = { hour: 'numeric', minute: '2-digit' } as any;\nconst VERBOSE_FORMAT = {\n weekday: undefined,\n year: undefined,\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit'\n} as any;\n\nexport class Chat extends RapidElement {\n static get styles() {\n return css`\n :host {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n position: relative;\n z-index: 1;\n }\n\n slot[name='header'] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n display: block;\n }\n\n slot[name='footer'] {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n display: block;\n }\n\n .block {\n margin-bottom: 1em;\n display: flex;\n flex-direction: row;\n }\n\n .block.outgoing {\n flex-direction: row-reverse;\n }\n\n .block.collapse {\n margin: 0;\n align-items: center;\n display: flex;\n flex-direction: column;\n margin-bottom: 0.5em;\n }\n\n .block.collapse .messsage {\n transform: scaleY(0);\n margin: 0;\n padding: 0;\n line-height: 0;\n }\n\n .time {\n text-align: center;\n font-size: 0.8em;\n color: #999;\n margin-bottom: 2em;\n margin-top: 1em;\n border-top: 1px solid #e9e9e9;\n padding: 1em;\n margin-left: 10%;\n margin-right: 10%;\n }\n\n .time.first {\n border-top: none;\n margin-top: 0;\n border-bottom: 1px solid #e9e9e9;\n margin-bottom: 2em;\n }\n\n .first .time {\n margin-top: 0;\n border-top: none;\n padding-top: 0;\n }\n\n .row {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n margin-bottom: 0.25em;\n }\n\n .input-panel {\n padding: 1em;\n background: #fff;\n }\n\n temba-user {\n margin-right: 0.6em;\n margin-left: 0.6em;\n width: 2em;\n align-self: flex-end;\n }\n\n .toggle {\n flex-shrink: 0;\n width: 4em;\n height: 4em;\n overflow: hidden;\n border-radius: 100%;\n box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 1em 0.7em,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px,\n inset 0 0 0 0.25em rgba(0, 0, 0, 0.1);\n cursor: pointer;\n transition: box-shadow var(--toggle-speed, 200ms) ease-out;\n position: absolute;\n bottom: 1em;\n right: 1em;\n }\n\n .toggle:hover {\n box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 1em 0.7em,\n rgba(0, 0, 0, 0.4) 0px 1px 2px 0px,\n inset 0 0 0 0.25em rgba(0, 0, 0, 0.2);\n }\n\n .incoming .row {\n flex-direction: row-reverse;\n margin-left: 1em;\n }\n\n .bubble {\n padding: 0.75em;\n padding-bottom: 0.25em;\n background: var(--color-chat-in, #f1f1f1);\n border-radius: var(--curvature);\n border: var(--chat-border-in, none);\n }\n\n .bubble .name {\n font-size: 0.95em;\n font-weight: 400;\n color: rgba(0, 0, 0, 0.4);\n margin-bottom: 0.25em;\n }\n\n .outgoing .latest .bubble {\n border-bottom-left-radius: 0;\n }\n\n .incoming .bubble-wrap {\n align-items: flex-end;\n }\n\n .incoming .bubble {\n background: var(--color-chat-out, #3c92dd);\n border: var(--chat-border-out, none);\n color: white;\n }\n\n .incoming .latest .bubble {\n border-bottom-right-radius: 0;\n }\n\n .incoming .bubble .name {\n color: rgba(255, 255, 255, 0.7);\n }\n\n .note .bubble {\n background: #fffac3;\n color: rgba(0, 0, 0, 0.7);\n }\n\n .note .bubble .name {\n color: rgba(0, 0, 0, 0.5);\n }\n\n .message {\n margin-bottom: 0.5em;\n line-height: 1.2em;\n word-break: break-word;\n }\n\n .message-text {\n white-space: pre-line;\n }\n\n .chat {\n width: 28rem;\n border-radius: var(--curvature);\n overflow: hidden;\n box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, rgba(0, 0, 0, 0.1) 5em 5em 5em 5em;\n position: absolute;\n bottom: 3em;\n right: 1em;\n transition: all var(--toggle-speed, 200ms) ease-out;\n transform: scale(0.9);\n pointer-events: none;\n opacity: 0;\n }\n\n .chat.open {\n bottom: 6em;\n opacity: 1;\n transform: scale(1);\n pointer-events: initial;\n }\n\n .messages {\n position: relative;\n flex-grow: 1;\n overflow: hidden;\n }\n\n .scroll {\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n overflow-scrolling: touch;\n padding: 1em 1em 1em 1em;\n padding-bottom: 2.5em;\n display: flex;\n flex-direction: column-reverse;\n }\n\n .messages:before {\n content: '';\n background: radial-gradient(\n farthest-side at 50% 0,\n rgba(0, 0, 0, 0.2),\n rgba(0, 0, 0, 0)\n )\n center top;\n height: 10px;\n display: block;\n position: absolute;\n width: 100%;\n transition: opacity var(--toggle-speed, 200ms) ease-out;\n z-index: 1;\n }\n\n .messages:after {\n content: '';\n background: radial-gradient(\n farthest-side at 50% 100%,\n rgba(0, 0, 0, 0.2),\n rgba(0, 0, 0, 0)\n )\n center bottom;\n height: 10px;\n display: block;\n position: absolute;\n bottom: 0;\n margin-top: -10px;\n width: 100%;\n margin-right: 5em;\n transition: opacity var(--toggle-speed, 200ms) ease-out;\n z-index: 1;\n }\n\n .bubble-wrap {\n position: relative;\n max-width: 70%;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n margin-top: -1em;\n padding-top: 1em;\n }\n\n .scroll-at-top.messages:before {\n opacity: 0;\n }\n\n .scroll-at-bottom.messages:after {\n opacity: 0;\n }\n\n .input {\n border: none;\n flex-grow: 1;\n color: #333;\n font-size: 1em;\n }\n\n .input:focus {\n outline: none;\n }\n\n input::placeholder {\n opacity: 0.3;\n }\n\n .input.inactive {\n // pointer-events: none;\n // opacity: 0.3;\n }\n\n .active {\n }\n\n .send-icon {\n color: #eee;\n pointer-events: none;\n transform: rotate(-45deg);\n transition: transform 0.2s ease-out;\n }\n\n .pending .send-icon {\n color: var(--color-primary-dark);\n pointer-events: initial;\n transform: rotate(0deg);\n }\n\n .notice {\n padding: 1em;\n background: #f8f8f8;\n color: #666;\n text-align: center;\n cursor: pointer;\n }\n\n .connecting .notice {\n display: flex;\n justify-content: center;\n }\n\n .connecting .notice temba-icon {\n margin-left: 0.5em;\n }\n\n .reconnect {\n color: var(--color-primary-dark);\n text-decoration: underline;\n font-size: 0.9em;\n }\n\n .input:disabled {\n background: transparent !important;\n }\n\n temba-loading {\n justify-content: center;\n margin: 0.5em auto;\n margin-bottom: 2em;\n }\n\n temba-loading.hidden {\n display: none;\n }\n\n .inline {\n }\n\n .event {\n flex-grow: 1;\n align-self: center;\n display: flex;\n flex-direction: column;\n align-items: center;\n }\n\n .event p {\n margin: 0;\n padding: 0;\n }\n\n .collapse {\n }\n\n a {\n color: var(--color-primary-dark);\n }\n\n .attachments {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n align-self: flex-start;\n }\n\n .incoming .attachments {\n align-self: flex-end;\n }\n\n temba-thumbnail {\n margin: 0.4em;\n border-radius: var(--curvature);\n }\n\n .error .bubble {\n border: 1px solid var(--color-error);\n background: white;\n color: #333;\n }\n\n .error .bubble .name {\n color: #999;\n }\n\n .error temba-thumbnail {\n --thumb-background: var(--color-error);\n --thumb-icon: white;\n }\n\n .outgoing .popup {\n justify-content: left;\n }\n\n .incoming .popup {\n justify-content: right;\n }\n\n .popup {\n display: flex;\n position: absolute;\n background: #fff;\n margin: 0;\n padding: 0.5em 1em;\n border-radius: var(--curvature);\n box-shadow: rgba(0, 0, 0, 0.05) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px;\n border: 1px solid #f3f3f3;\n opacity: 0;\n transform: scale(0.7);\n transition: opacity 0.2s ease-out, transform 0.2s ease-out;\n z-index: 2;\n }\n\n .popup .arrow {\n z-index: 1;\n text-shadow: 0px 3px 3px rgba(0, 0, 0, 0.1);\n position: absolute;\n justify-content: center;\n text-align: center;\n font-size: 1.3em;\n transform: translateY(0.7em) scale(1);\n color: #fff;\n bottom: 0;\n }\n\n .bubble-wrap:hover .popup {\n transform: translateY(-120%);\n opacity: 1;\n transition-delay: 1s;\n }\n `;\n }\n\n @property({ type: Array })\n messageGroups: string[][] = [];\n\n @property({ type: Boolean })\n fetching = false;\n\n @property({ type: Boolean, attribute: false })\n hideTopScroll = true;\n\n @property({ type: Boolean, attribute: false })\n hideBottomScroll = true;\n\n @property({ type: String, attribute: 'avatar' })\n defaultAvatar = DEFAULT_AVATAR;\n\n @property({ type: Boolean })\n agent = false;\n\n @property({ type: Boolean, attribute: false })\n endOfHistory = false;\n\n @property({ type: Object, attribute: false })\n oldestEventDate: Date = null;\n\n private msgMap = new Map<string, ChatEvent>();\n\n public firstUpdated(\n changed: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changed);\n const scroll = this.shadowRoot.querySelector('.scroll');\n const hasScroll = scroll.scrollHeight > scroll.clientHeight;\n this.hideBottomScroll = true;\n this.hideTopScroll = !hasScroll;\n }\n\n public addMessages(\n messages: ChatEvent[],\n startTime: Date = null,\n append = false\n ) {\n // make sure our messages have ids\n messages.forEach((m) => {\n if (!m.id) {\n m.id =\n hashCode((m.text.strings || []).join('')) +\n '_' +\n m.date.toISOString();\n }\n });\n\n if (!startTime) {\n startTime = new Date();\n }\n\n const elapsed = new Date().getTime() - startTime.getTime();\n window.setTimeout(\n () => {\n this.fetching = false;\n // first add messages to the map\n const newMessages = [];\n for (const m of messages) {\n if (this.addMessage(m)) {\n newMessages.push(m.id);\n }\n }\n\n if (newMessages.length === 0) {\n return;\n }\n\n const ele = this.shadowRoot.querySelector('.scroll');\n const prevTop = ele.scrollTop;\n\n const grouped = this.groupMessages(newMessages);\n this.insertGroups(grouped, append);\n\n window.setTimeout(() => {\n ele.scrollTop = prevTop;\n\n this.fireCustomEvent(CustomEventType.FetchComplete);\n }, 100);\n },\n // if it's the first load don't wait, otherwise wait a minimum amount of time\n this.messageGroups.length === 0\n ? 0\n : Math.max(0, MIN_FETCH_TIME - elapsed)\n );\n }\n\n private addMessage(msg: ChatEvent): boolean {\n const isNew = !this.messageExists(msg);\n this.msgMap.set(msg.id, msg);\n return isNew;\n }\n\n public messageExists(msg: ChatEvent): boolean {\n return this.msgMap.has(msg.id);\n }\n\n private isSameGroup(msg1: ChatEvent, msg2: ChatEvent): boolean {\n if (msg1 && msg2) {\n const sameGroup =\n msg1.type === msg2.type &&\n msg1.user?.name === msg2.user?.name &&\n Math.abs(msg1.date.getTime() - msg2.date.getTime()) < BATCH_TIME_WINDOW;\n return sameGroup;\n }\n\n return false;\n }\n\n private insertGroups(newGroups: string[][], append = false) {\n if (!append) {\n newGroups.reverse();\n }\n\n for (const newGroup of newGroups) {\n // see if our new group belongs to the most recent group\n const group =\n this.messageGroups[append ? 0 : this.messageGroups.length - 1];\n\n if (group) {\n const lastMsgId = group[group.length - 1];\n const lastMsg = this.msgMap.get(lastMsgId);\n const newMsg = this.msgMap.get(newGroup[0]);\n // if our message belongs to the previous group, in we go\n if (this.isSameGroup(lastMsg, newMsg)) {\n group.push(...newGroup);\n } else {\n // otherwise, just add our entire group as a new one\n if (append) {\n this.messageGroups.splice(0, 0, newGroup);\n } else {\n this.messageGroups.push(newGroup);\n }\n }\n } else {\n if (append) {\n this.messageGroups.splice(0, 0, newGroup);\n } else {\n this.messageGroups.push(newGroup);\n }\n }\n }\n\n this.requestUpdate('messageGroups');\n }\n\n private groupMessages(msgIds: string[]): string[][] {\n // group our messages by origin and user\n const groups = [];\n let lastGroup = [];\n let lastMsg = null;\n for (const msgId of msgIds) {\n const msg = this.msgMap.get(msgId);\n if (!this.isSameGroup(msg, lastMsg)) {\n lastGroup = [];\n groups.push(lastGroup);\n }\n lastGroup.push(msgId);\n lastMsg = msg;\n }\n return groups;\n }\n\n private handleScroll(event: any) {\n const ele = event.target;\n const top = ele.scrollHeight - ele.clientHeight;\n const scroll = Math.round(top + ele.scrollTop);\n const scrollPct = scroll / top;\n\n this.hideTopScroll = scrollPct <= 0.01;\n this.hideBottomScroll = scrollPct >= 0.99;\n\n if (scrollPct < SCROLL_FETCH_BUFFER) {\n this.fireCustomEvent(CustomEventType.ScrollThreshold);\n }\n }\n\n private scrollToBottom() {\n const scroll = this.shadowRoot.querySelector('.scroll');\n if (scroll) {\n scroll.scrollTop = scroll.scrollHeight;\n this.hideBottomScroll = true;\n }\n }\n\n private renderMessageGroup(\n msgIds: string[],\n idx: number,\n groups: string[][]\n ): TemplateResult {\n const today = new Date();\n const firstGroup = idx === groups.length - 1;\n\n let prevMsg: ChatEvent;\n if (idx > 0) {\n const lastGroup = groups[idx - 1];\n if (lastGroup && lastGroup.length > 0) {\n prevMsg = this.msgMap.get(lastGroup[0]);\n }\n }\n\n const mostRecentId = msgIds[msgIds.length - 1];\n const currentMsg = this.msgMap.get(mostRecentId);\n\n let timeDisplay = null;\n if (\n prevMsg &&\n !this.isSameGroup(prevMsg, currentMsg) &&\n (Math.abs(currentMsg.date.getTime() - prevMsg.date.getTime()) >\n BATCH_TIME_WINDOW ||\n idx === groups.length - 1)\n ) {\n if (\n today.getDate() !== prevMsg.date.getDate() ||\n prevMsg.date.getDate() !== currentMsg.date.getDate()\n ) {\n timeDisplay = html`<div class=\"time ${firstGroup ? 'first' : ''}\">\n ${prevMsg.date.toLocaleTimeString(undefined, VERBOSE_FORMAT)}\n </div>`;\n } else {\n timeDisplay = html`<div class=\"time ${firstGroup ? 'first' : ''}\">\n ${prevMsg.date.toLocaleTimeString(undefined, TIME_FORMAT)}\n </div>`;\n }\n }\n\n const incoming = this.agent\n ? currentMsg.type !== 'msg_in'\n : currentMsg.type === 'msg_in';\n\n const name = currentMsg.user?.name;\n const email = currentMsg.user?.email;\n\n const showAvatar =\n ((currentMsg.type === 'note' ||\n currentMsg.type === 'msg_in' ||\n currentMsg.type === 'msg_out') &&\n this.agent) ||\n !incoming;\n\n return html`\n ${timeDisplay}\n <div\n class=\"block ${incoming ? 'incoming' : 'outgoing'} ${currentMsg.type}\"\n >\n <div class=\"group-messages\" style=\"flex-grow:1\">\n ${msgIds.map((msgId, index) => {\n const msg = this.msgMap.get(msgId);\n return html`<div class=\"row message\">\n ${this.renderMessage(msg, index == 0 ? name : null)}\n </div>`;\n })}\n </div>\n ${showAvatar\n ? html`<div class=\"avatar\" style=\"align-self:flex-end\">\n <temba-user\n email=${email}\n name=${name}\n avatar=${currentMsg.user?.avatar}\n ?system=${!email && !name}\n >\n </temba-user>\n </div>`\n : null}\n </div>\n `;\n }\n\n private renderMessage(event: ChatEvent, name = null): TemplateResult {\n if (\n event.type === MessageType.Error ||\n event.type === MessageType.Collapse ||\n event.type === MessageType.Inline\n ) {\n return html`<div class=\"event\">${event.text}</div>`;\n }\n\n const message = event as Message;\n return html`\n <div class=\"bubble-wrap ${message.sendError ? 'error' : ''}\">\n ${\n message.popup\n ? html`<div class=\"popup\">\n ${message.popup}\n <div class=\"arrow\">▼</div>\n </div>`\n : null\n }\n \n ${\n message.text\n ? html`\n <div class=\"bubble\">\n ${name ? html`<div class=\"name\">${name}</div>` : null}\n <div class=\"message message-text\">${message.text}</div>\n <!--div>${message.date.toLocaleDateString(\n undefined,\n VERBOSE_FORMAT\n )}</div-->\n </div>\n `\n : null\n }\n\n <div class=\"attachments\">\n ${(message.attachments || []).map(\n (attachment) =>\n html`<temba-thumbnail\n attachment=\"${attachment}\"\n ></temba-thumbnail>`\n )}\n </div>\n </div>\n </div>\n `;\n }\n\n public reset() {\n this.msgMap.clear();\n this.messageGroups = [];\n this.hideBottomScroll = true;\n this.hideTopScroll = true;\n this.endOfHistory = false;\n this.oldestEventDate = null;\n }\n\n public setEndOfHistory(oldestDate: Date) {\n this.endOfHistory = true;\n this.oldestEventDate = oldestDate;\n }\n\n public render(): TemplateResult {\n return html` <div\n class=\"\n messages \n ${this.hideBottomScroll ? 'scroll-at-bottom' : ''}\n ${this.hideTopScroll ? 'scroll-at-top' : ''}\"\n >\n <div class=\"scroll\" @scroll=${this.handleScroll}>\n ${this.messageGroups\n ? this.messageGroups.map(\n (msgGroup, idx, groups) =>\n html`${this.renderMessageGroup(msgGroup, idx, groups)}`\n )\n : null}\n\n <temba-loading\n class=\"${!this.fetching ? 'hidden' : ''}\"\n ></temba-loading>\n\n ${this.endOfHistory && this.oldestEventDate\n ? html`<div class=\"time first\">\n ${this.oldestEventDate.toLocaleTimeString(\n undefined,\n VERBOSE_FORMAT\n )}\n </div>`\n : null}\n </div>\n <slot class=\"header\" name=\"header\"></slot>\n <slot class=\"footer\" name=\"footer\"></slot>\n </div>`;\n }\n}\n"]}
@@ -19,7 +19,7 @@ export class FloatingTab extends RapidElement {
19
19
  .tab {
20
20
  position: fixed;
21
21
  right: 0;
22
- z-index: 9998;
22
+ z-index: 4998;
23
23
  transition: transform var(--transition-duration, 300ms) ease-in-out;
24
24
  display: flex;
25
25
  align-items: center;
@@ -42,8 +42,8 @@ export class FloatingTab extends RapidElement {
42
42
  display: flex;
43
43
  align-items: center;
44
44
  justify-content: center;
45
- width: 32px;
46
- height: 32px;
45
+ width: 16px;
46
+ height: 16px;
47
47
  }
48
48
 
49
49
  temba-icon {
@@ -139,7 +139,7 @@ export class FloatingTab extends RapidElement {
139
139
  <div class="${classes}" style="${tabStyle}" @click=${this.handleClick}>
140
140
  <div class="icon-container">
141
141
  ${this.icon
142
- ? html `<temba-icon size="2" name="${this.icon}"></temba-icon>`
142
+ ? html `<temba-icon size="1.5" name="${this.icon}"></temba-icon>`
143
143
  : ''}
144
144
  </div>
145
145
  <div class="label">${this.label}</div>
@@ -1 +1 @@
1
- {"version":3,"file":"FloatingTab.js","sourceRoot":"","sources":["../../../src/display/FloatingTab.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, PropertyValueMap, TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { RapidElement } from '../RapidElement';\nimport { CustomEventType } from '../interfaces';\nimport { getClasses } from '../utils';\n\nexport class FloatingTab extends RapidElement {\n static get styles() {\n return css`\n .tab.hidden {\n transform: translateX(100%);\n }\n .tab {\n position: fixed;\n right: 0;\n z-index: 9998;\n transition: transform var(--transition-duration, 300ms) ease-in-out;\n display: flex;\n align-items: center;\n padding: 12px;\n border-top-left-radius: 8px;\n border-bottom-left-radius: 8px;\n cursor: pointer;\n box-shadow: -2px 2px 8px rgba(0, 0, 0, 0.2);\n transition: all calc(var(--transition-duration, 300ms) * 0.7)\n ease-in-out;\n user-select: none;\n }\n\n .tab:hover {\n padding-right: 16px;\n box-shadow: -4px 4px 12px rgba(0, 0, 0, 0.3);\n }\n\n .icon-container {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n }\n\n temba-icon {\n --icon-color: white;\n }\n\n .label {\n color: white;\n font-weight: 500;\n font-size: 16px;\n max-width: 0;\n overflow: hidden;\n white-space: nowrap;\n margin-left: 0;\n opacity: 0;\n transition: all var(--transition-duration, 300ms) ease-in-out;\n }\n\n .tab:hover .label {\n max-width: 200px;\n margin-left: 12px;\n opacity: 1;\n }\n `;\n }\n\n static TAB_HEIGHT = 56; // height of tab for auto-stacking\n static allTabs: FloatingTab[] = [];\n\n @property({ type: String })\n icon: string;\n\n @property({ type: String })\n label: string;\n\n @property({ type: String })\n color = '#6B7280';\n\n @property({ type: Number })\n top = -1; // -1 means auto-calculate position\n\n @property({ type: Boolean })\n hidden = false;\n\n connectedCallback() {\n super.connectedCallback();\n FloatingTab.allTabs.push(this);\n this.updatePosition();\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n const index = FloatingTab.allTabs.indexOf(this);\n if (index > -1) {\n FloatingTab.allTabs.splice(index, 1);\n }\n // update positions of remaining tabs\n FloatingTab.allTabs.forEach((tab) => tab.updatePosition());\n }\n\n private updatePosition() {\n // if top is manually set, use it\n if (this.top !== -1) {\n return;\n }\n\n // auto-calculate position based on index\n const index = FloatingTab.allTabs.indexOf(this);\n if (index === -1) {\n this.top = 100; // default fallback\n } else {\n // start at 100px and stack with 10px gap between tabs\n this.top = 100 + index * (FloatingTab.TAB_HEIGHT + 10);\n }\n }\n\n public updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n if (changes.has('hidden')) {\n this.classList.toggle('hidden', this.hidden);\n }\n if (changes.has('top')) {\n this.updatePosition();\n }\n }\n\n private handleClick() {\n // hide all tabs when one is clicked\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = true;\n });\n\n this.fireCustomEvent(CustomEventType.ButtonClicked, {\n action: 'toggle'\n });\n }\n\n public static showAllTabs() {\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = false;\n });\n }\n\n public static hideAllTabs() {\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = true;\n });\n }\n\n public render(): TemplateResult {\n const tabStyle = `\n background-color: ${this.color};\n top: ${this.top}px;\n `;\n\n const classes = getClasses({\n tab: true,\n hidden: this.hidden\n });\n\n return html`\n <div class=\"${classes}\" style=\"${tabStyle}\" @click=${this.handleClick}>\n <div class=\"icon-container\">\n ${this.icon\n ? html`<temba-icon size=\"2\" name=\"${this.icon}\"></temba-icon>`\n : ''}\n </div>\n <div class=\"label\">${this.label}</div>\n </div>\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"FloatingTab.js","sourceRoot":"","sources":["../../../src/display/FloatingTab.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, PropertyValueMap, TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { RapidElement } from '../RapidElement';\nimport { CustomEventType } from '../interfaces';\nimport { getClasses } from '../utils';\n\nexport class FloatingTab extends RapidElement {\n static get styles() {\n return css`\n .tab.hidden {\n transform: translateX(100%);\n }\n .tab {\n position: fixed;\n right: 0;\n z-index: 4998;\n transition: transform var(--transition-duration, 300ms) ease-in-out;\n display: flex;\n align-items: center;\n padding: 12px;\n border-top-left-radius: 8px;\n border-bottom-left-radius: 8px;\n cursor: pointer;\n box-shadow: -2px 2px 8px rgba(0, 0, 0, 0.2);\n transition: all calc(var(--transition-duration, 300ms) * 0.7)\n ease-in-out;\n user-select: none;\n }\n\n .tab:hover {\n padding-right: 16px;\n box-shadow: -4px 4px 12px rgba(0, 0, 0, 0.3);\n }\n\n .icon-container {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n }\n\n temba-icon {\n --icon-color: white;\n }\n\n .label {\n color: white;\n font-weight: 500;\n font-size: 16px;\n max-width: 0;\n overflow: hidden;\n white-space: nowrap;\n margin-left: 0;\n opacity: 0;\n transition: all var(--transition-duration, 300ms) ease-in-out;\n }\n\n .tab:hover .label {\n max-width: 200px;\n margin-left: 12px;\n opacity: 1;\n }\n `;\n }\n\n static TAB_HEIGHT = 56; // height of tab for auto-stacking\n static allTabs: FloatingTab[] = [];\n\n @property({ type: String })\n icon: string;\n\n @property({ type: String })\n label: string;\n\n @property({ type: String })\n color = '#6B7280';\n\n @property({ type: Number })\n top = -1; // -1 means auto-calculate position\n\n @property({ type: Boolean })\n hidden = false;\n\n connectedCallback() {\n super.connectedCallback();\n FloatingTab.allTabs.push(this);\n this.updatePosition();\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n const index = FloatingTab.allTabs.indexOf(this);\n if (index > -1) {\n FloatingTab.allTabs.splice(index, 1);\n }\n // update positions of remaining tabs\n FloatingTab.allTabs.forEach((tab) => tab.updatePosition());\n }\n\n private updatePosition() {\n // if top is manually set, use it\n if (this.top !== -1) {\n return;\n }\n\n // auto-calculate position based on index\n const index = FloatingTab.allTabs.indexOf(this);\n if (index === -1) {\n this.top = 100; // default fallback\n } else {\n // start at 100px and stack with 10px gap between tabs\n this.top = 100 + index * (FloatingTab.TAB_HEIGHT + 10);\n }\n }\n\n public updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n if (changes.has('hidden')) {\n this.classList.toggle('hidden', this.hidden);\n }\n if (changes.has('top')) {\n this.updatePosition();\n }\n }\n\n private handleClick() {\n // hide all tabs when one is clicked\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = true;\n });\n\n this.fireCustomEvent(CustomEventType.ButtonClicked, {\n action: 'toggle'\n });\n }\n\n public static showAllTabs() {\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = false;\n });\n }\n\n public static hideAllTabs() {\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = true;\n });\n }\n\n public render(): TemplateResult {\n const tabStyle = `\n background-color: ${this.color};\n top: ${this.top}px;\n `;\n\n const classes = getClasses({\n tab: true,\n hidden: this.hidden\n });\n\n return html`\n <div class=\"${classes}\" style=\"${tabStyle}\" @click=${this.handleClick}>\n <div class=\"icon-container\">\n ${this.icon\n ? html`<temba-icon size=\"1.5\" name=\"${this.icon}\"></temba-icon>`\n : ''}\n </div>\n <div class=\"label\">${this.label}</div>\n </div>\n `;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/events.ts"],"names":[],"mappings":"","sourcesContent":["import { Msg, ObjectReference, User } from './interfaces';\n\nexport interface EventGroup {\n type: string;\n events: ContactEvent[];\n open: boolean;\n}\n\nexport interface ContactEvent {\n uuid?: string;\n type: string;\n created_on: string;\n _user?: ObjectReference;\n}\n\nexport interface ChannelEvent extends ContactEvent {\n channel_event_type: string;\n duration: number;\n\n event: {\n type: string;\n channel: { uuid: string; name: string };\n duration?: number;\n optin?: {\n uuid: string;\n name: string;\n };\n };\n}\n\nexport interface ContactLanguageChangedEvent extends ContactEvent {\n language: string;\n}\n\nexport interface ContactStatusChangedEvent extends ContactEvent {\n status: string;\n}\n\nexport interface OptInEvent extends ContactEvent {\n optin: {\n uuid: string;\n name: string;\n };\n}\n\nexport interface CallEvent extends ContactEvent {\n call?: {\n uuid: string;\n urn: string;\n };\n}\n\nexport interface ChatStartedEvent extends ContactEvent {\n params?: object;\n}\n\nexport interface MsgEvent extends ContactEvent {\n msg: Msg;\n optin?: ObjectReference;\n _status?: { created_on: string; status: string; reason: string };\n _logs_url?: string;\n}\n\nexport interface RunEvent extends ContactEvent {\n flow: ObjectReference;\n status: string;\n}\n\nexport interface URNsChangedEvent extends ContactEvent {\n urns: string[];\n}\n\nexport interface TicketEvent extends ContactEvent {\n ticket: {\n // ticket_opened\n uuid: string;\n topic?: ObjectReference;\n };\n ticket_uuid?: string; // all other event types\n assignee?: User;\n note?: string;\n topic?: ObjectReference;\n}\n\nexport interface NameChangedEvent extends ContactEvent {\n name: string;\n}\n\nexport interface UpdateFieldEvent extends ContactEvent {\n field: { key: string; name: string };\n value: { text: string };\n}\n\nexport interface ContactGroupsEvent extends ContactEvent {\n groups_added: ObjectReference[];\n groups_removed: ObjectReference[];\n}\n\nexport interface AirtimeTransferredEvent extends ContactEvent {\n sender: string;\n recipient: string;\n currency: string;\n amount: string;\n}\n\nexport type CallStartedEvent = ContactEvent;\n\nexport interface ContactHistoryPage {\n events: ContactEvent[];\n has_older: boolean;\n recent_only: boolean;\n next_before: number;\n next_after: number;\n}\n"]}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/events.ts"],"names":[],"mappings":"","sourcesContent":["import { Msg, ObjectReference, User } from './interfaces';\n\nexport interface EventGroup {\n type: string;\n events: ContactEvent[];\n open: boolean;\n}\n\nexport interface ContactEvent {\n uuid?: string;\n type: string;\n created_on: string;\n _user?: ObjectReference;\n}\n\nexport interface ChannelEvent extends ContactEvent {\n channel_event_type: string;\n duration: number;\n\n event: {\n type: string;\n channel: { uuid: string; name: string };\n duration?: number;\n optin?: {\n uuid: string;\n name: string;\n };\n };\n}\n\nexport interface ContactLanguageChangedEvent extends ContactEvent {\n language: string;\n}\n\nexport interface ContactStatusChangedEvent extends ContactEvent {\n status: string;\n}\n\nexport interface OptInEvent extends ContactEvent {\n optin: {\n uuid: string;\n name: string;\n };\n}\n\nexport interface CallEvent extends ContactEvent {\n call?: {\n uuid: string;\n urn: string;\n };\n}\n\nexport interface ChatStartedEvent extends ContactEvent {\n params?: object;\n}\n\nexport interface MsgEvent extends ContactEvent {\n msg: Msg;\n optin?: ObjectReference;\n _status?: { created_on: string; status: string; reason: string };\n _logs_url?: string;\n}\n\nexport interface RunEvent extends ContactEvent {\n flow: ObjectReference;\n status: string;\n}\n\nexport interface URNsChangedEvent extends ContactEvent {\n urns: string[];\n}\n\nexport interface TicketEvent extends ContactEvent {\n ticket: {\n // ticket_opened\n uuid: string;\n topic?: ObjectReference;\n };\n ticket_uuid?: string; // all other event types\n assignee?: User;\n note?: string;\n topic?: ObjectReference;\n}\n\nexport interface NameChangedEvent extends ContactEvent {\n name: string;\n}\n\nexport interface UpdateFieldEvent extends ContactEvent {\n field: { key: string; name: string };\n value: { text: string };\n}\n\nexport interface ContactGroupsEvent extends ContactEvent {\n groups_added: ObjectReference[];\n groups_removed: ObjectReference[];\n}\n\nexport interface AirtimeTransferredEvent extends ContactEvent {\n sender: string;\n recipient: string;\n currency: string;\n amount: string;\n}\n\nexport type CallStartedEvent = ContactEvent;\n\nexport interface ContactHistoryPage {\n events: ContactEvent[];\n next: string | null;\n}\n"]}