@nyaruka/temba-components 0.78.2 → 0.80.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 (124) hide show
  1. package/.devcontainer/Dockerfile +1 -1
  2. package/CHANGELOG.md +13 -15
  3. package/dist/static/svg/index.svg +1 -1
  4. package/dist/temba-components.js +8225 -0
  5. package/dist/temba-components.js.map +1 -0
  6. package/out-tsc/src/FormElement.js.map +1 -1
  7. package/out-tsc/src/RapidElement.js.map +1 -1
  8. package/out-tsc/src/RefreshElement.js.map +1 -1
  9. package/out-tsc/src/aliaseditor/AliasEditor.js.map +1 -1
  10. package/out-tsc/src/button/Button.js.map +1 -1
  11. package/out-tsc/src/charcount/CharCount.js.map +1 -1
  12. package/out-tsc/src/charcount/helpers.js.map +1 -1
  13. package/out-tsc/src/checkbox/Checkbox.js.map +1 -1
  14. package/out-tsc/src/colorpicker/ColorPicker.js.map +1 -1
  15. package/out-tsc/src/completion/Completion.js.map +1 -1
  16. package/out-tsc/src/completion/ExcellentParser.js.map +1 -1
  17. package/out-tsc/src/completion/helpers.js.map +1 -1
  18. package/out-tsc/src/compose/Compose.js.map +1 -1
  19. package/out-tsc/src/contacts/ContactBadges.js.map +1 -1
  20. package/out-tsc/src/contacts/ContactChat.js.map +1 -1
  21. package/out-tsc/src/contacts/ContactDetails.js.map +1 -1
  22. package/out-tsc/src/contacts/ContactFieldEditor.js.map +1 -1
  23. package/out-tsc/src/contacts/ContactFields.js.map +1 -1
  24. package/out-tsc/src/contacts/ContactHistory.js.map +1 -1
  25. package/out-tsc/src/contacts/ContactNameFetch.js.map +1 -1
  26. package/out-tsc/src/contacts/ContactPending.js.map +1 -1
  27. package/out-tsc/src/contacts/ContactStoreElement.js.map +1 -1
  28. package/out-tsc/src/contacts/ContactTickets.js.map +1 -1
  29. package/out-tsc/src/contacts/events.js.map +1 -1
  30. package/out-tsc/src/contacts/helpers.js.map +1 -1
  31. package/out-tsc/src/contactsearch/ContactSearch.js.map +1 -1
  32. package/out-tsc/src/date/TembaDate.js.map +1 -1
  33. package/out-tsc/src/datepicker/DatePicker.js.map +1 -1
  34. package/out-tsc/src/dialog/Dialog.js.map +1 -1
  35. package/out-tsc/src/dialog/Modax.js.map +1 -1
  36. package/out-tsc/src/dropdown/Dropdown.js.map +1 -1
  37. package/out-tsc/src/fields/FieldManager.js.map +1 -1
  38. package/out-tsc/src/flow/FlowStoreElement.js.map +1 -1
  39. package/out-tsc/src/formfield/FormField.js.map +1 -1
  40. package/out-tsc/src/imagepicker/ImagePicker.js.map +1 -1
  41. package/out-tsc/src/label/Label.js.map +1 -1
  42. package/out-tsc/src/leafletmap/LeafletMap.js.map +1 -1
  43. package/out-tsc/src/lightbox/Lightbox.js.map +1 -1
  44. package/out-tsc/src/list/ContentMenu.js.map +1 -1
  45. package/out-tsc/src/list/NotificationList.js.map +1 -1
  46. package/out-tsc/src/list/RunList.js.map +1 -1
  47. package/out-tsc/src/list/SortableList.js.map +1 -1
  48. package/out-tsc/src/list/TembaList.js.map +1 -1
  49. package/out-tsc/src/list/TembaMenu.js.map +1 -1
  50. package/out-tsc/src/list/TicketList.js.map +1 -1
  51. package/out-tsc/src/mask/Mask.js.map +1 -1
  52. package/out-tsc/src/omnibox/Omnibox.js.map +1 -1
  53. package/out-tsc/src/options/Options.js.map +1 -1
  54. package/out-tsc/src/options/helpers.js.map +1 -1
  55. package/out-tsc/src/remote/Remote.js.map +1 -1
  56. package/out-tsc/src/resizer/Resizer.js.map +1 -1
  57. package/out-tsc/src/select/Select.js +3 -3
  58. package/out-tsc/src/select/Select.js.map +1 -1
  59. package/out-tsc/src/shadowless/Shadowless.js.map +1 -1
  60. package/out-tsc/src/slider/TembaSlider.js.map +1 -1
  61. package/out-tsc/src/sms/gsmsplitter.js.map +1 -1
  62. package/out-tsc/src/sms/gsmvalidator.js.map +1 -1
  63. package/out-tsc/src/sms/index.js.map +1 -1
  64. package/out-tsc/src/sms/unicodesplitter.js.map +1 -1
  65. package/out-tsc/src/store/Store.js +2 -2
  66. package/out-tsc/src/store/Store.js.map +1 -1
  67. package/out-tsc/src/store/StoreElement.js.map +1 -1
  68. package/out-tsc/src/store/StoreMonitorElement.js.map +1 -1
  69. package/out-tsc/src/tabpane/TabPane.js.map +1 -1
  70. package/out-tsc/src/templates/TemplateEditor.js.map +1 -1
  71. package/out-tsc/src/textinput/TextInput.js.map +1 -1
  72. package/out-tsc/src/textinput/helpers.js.map +1 -1
  73. package/out-tsc/src/thumbnail/Thumbnail.js.map +1 -1
  74. package/out-tsc/src/tip/Tip.js.map +1 -1
  75. package/out-tsc/src/user/TembaUser.js.map +1 -1
  76. package/out-tsc/src/utils/index.js.map +1 -1
  77. package/out-tsc/src/vectoricon/VectorIcon.js.map +1 -1
  78. package/out-tsc/src/vectoricon/index.js +1 -1
  79. package/out-tsc/src/vectoricon/index.js.map +1 -1
  80. package/out-tsc/src/webchat/WebChat.js +109 -40
  81. package/out-tsc/src/webchat/WebChat.js.map +1 -1
  82. package/out-tsc/temba-components.js +1 -0
  83. package/out-tsc/temba-components.js.map +1 -1
  84. package/out-tsc/temba-modules.js.map +1 -1
  85. package/out-tsc/temba-webchat.js +10 -0
  86. package/out-tsc/temba-webchat.js.map +1 -0
  87. package/out-tsc/test/temba-compose.test.js.map +1 -1
  88. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  89. package/out-tsc/test/temba-contact-history.test.js.map +1 -1
  90. package/out-tsc/test/temba-content-menu.test.js.map +1 -1
  91. package/out-tsc/test/temba-list.test.js.map +1 -1
  92. package/out-tsc/test/temba-modax.test.js.map +1 -1
  93. package/out-tsc/test/temba-select.test.js.map +1 -1
  94. package/out-tsc/test/temba-sortable-list.test.js +2 -2
  95. package/out-tsc/test/temba-sortable-list.test.js.map +1 -1
  96. package/out-tsc/test/utils.test.js.map +1 -1
  97. package/package.json +28 -21
  98. package/rollup.components.mjs +45 -0
  99. package/rollup.webchat.mjs +11 -0
  100. package/src/select/Select.ts +3 -3
  101. package/src/store/Store.ts +2 -2
  102. package/src/untyped.d.ts +5 -0
  103. package/src/vectoricon/VectorIcon.ts +0 -1
  104. package/src/vectoricon/index.ts +1 -1
  105. package/src/webchat/WebChat.ts +110 -40
  106. package/static/svg/index.svg +1 -1
  107. package/static/svg/work/traced/agent.svg +1 -1
  108. package/static/svg/work/traced/channel-facebook.svg +1 -1
  109. package/static/svg/work/traced/channel-rocketchat.svg +1 -1
  110. package/static/svg/work/traced/channel-thinq.svg +1 -1
  111. package/static/svg/work/traced/channel-vonage.svg +1 -1
  112. package/static/svg/work/traced/zendesk.svg +1 -1
  113. package/temba-components.ts +1 -0
  114. package/temba-webchat.ts +11 -0
  115. package/test/temba-sortable-list.test.ts +2 -2
  116. package/dist/49b5238f.js +0 -7999
  117. package/dist/index.js +0 -7999
  118. package/dist/sw.js +0 -2
  119. package/dist/sw.js.map +0 -1
  120. package/dist/templates/components-body.html +0 -1
  121. package/dist/templates/components-head.html +0 -1
  122. package/dist/workbox-919adfb7.js +0 -2
  123. package/dist/workbox-919adfb7.js.map +0 -1
  124. package/rollup.config.js +0 -83
package/src/untyped.d.ts CHANGED
@@ -19,3 +19,8 @@ declare function mouseClick(x: number, y: number);
19
19
  declare function setViewport({}: any);
20
20
  declare function waitForNetworkIdle();
21
21
  declare module 'croppie';
22
+
23
+ declare module '*.svg' {
24
+ const content: any;
25
+ export default content;
26
+ }
@@ -1,7 +1,6 @@
1
1
  import { LitElement, TemplateResult, html, css } from 'lit';
2
2
  import { property } from 'lit/decorators.js';
3
3
  import { Icon, SVG_FINGERPRINT } from '.';
4
-
5
4
  import { getClasses } from '../utils';
6
5
 
7
6
  export class VectorIcon extends LitElement {
@@ -1,5 +1,5 @@
1
1
  // for cache busting we dynamically generate a fingerprint, use yarn svg to update
2
- export const SVG_FINGERPRINT = '821ca36a43cd96382f3aeca0de405cf3';
2
+ export const SVG_FINGERPRINT = 'e5bcaf1a10896e9b870da4b40474d67b';
3
3
 
4
4
  // only icons below are included in the sprite sheet
5
5
  export enum Icon {
@@ -10,6 +10,12 @@ interface Message {
10
10
  timestamp: number;
11
11
  }
12
12
 
13
+ enum ChatStatus {
14
+ DISCONNECTED = 'disconnected',
15
+ CONNECTING = 'connecting',
16
+ CONNECTED = 'connected',
17
+ }
18
+
13
19
  // how long of a window to show time between batches
14
20
  const BATCH_TIME_WINDOW = 30 * 60 * 1000;
15
21
 
@@ -38,6 +44,7 @@ export class WebChat extends LitElement {
38
44
  align-self: center;
39
45
  --curvature: 0.6em;
40
46
  --color-primary: hsla(208, 70%, 55%, 1);
47
+ font-family: 'Roboto', 'Helvetica Neue', sans-serif;
41
48
  }
42
49
 
43
50
  .block {
@@ -231,8 +238,8 @@ export class WebChat extends LitElement {
231
238
  }
232
239
 
233
240
  .input.inactive {
234
- //pointer-events: none;
235
- //opacity: 0.3;
241
+ // pointer-events: none;
242
+ // opacity: 0.3;
236
243
  }
237
244
 
238
245
  .active {
@@ -250,6 +257,33 @@ export class WebChat extends LitElement {
250
257
  pointer-events: initial;
251
258
  transform: rotate(0deg);
252
259
  }
260
+
261
+ .notice {
262
+ padding: 1em;
263
+ background: #f8f8f8;
264
+ color: #666;
265
+ text-align: center;
266
+ cursor: pointer;
267
+ }
268
+
269
+ .connecting .notice {
270
+ display: flex;
271
+ justify-content: center;
272
+ }
273
+
274
+ .connecting .notice temba-icon {
275
+ margin-left: 0.5em;
276
+ }
277
+
278
+ .reconnect {
279
+ color: var(--color-primary);
280
+ text-decoration: underline;
281
+ font-size: 0.9em;
282
+ }
283
+
284
+ .input:disabled {
285
+ background: transparent !important;
286
+ }
253
287
  `;
254
288
  }
255
289
 
@@ -263,8 +297,8 @@ export class WebChat extends LitElement {
263
297
  messages: Message[][] = [];
264
298
 
265
299
  // is our socket connection established
266
- @property({ type: Boolean })
267
- active: boolean;
300
+ @property({ type: String })
301
+ status: ChatStatus = ChatStatus.DISCONNECTED;
268
302
 
269
303
  // is the chat widget open
270
304
  @property({ type: Boolean })
@@ -279,37 +313,45 @@ export class WebChat extends LitElement {
279
313
  @property({ type: Boolean, attribute: false })
280
314
  hideBottomScroll = true;
281
315
 
316
+ @property({ type: String })
317
+ host: string;
318
+
282
319
  private sock: WebSocket;
283
320
 
284
321
  public constructor() {
285
322
  super();
286
323
  }
287
324
 
325
+ private handleReconnect() {
326
+ this.openSocket();
327
+ }
328
+
288
329
  private openSocket(): void {
289
- console.log('opening socket..');
330
+ if (this.status !== ChatStatus.DISCONNECTED) {
331
+ return;
332
+ }
333
+
334
+ this.status = ChatStatus.CONNECTING;
290
335
  const webChat = this;
291
- let url = `ws://localhost:8070/start?channel=${this.channel}`;
336
+ let url = `ws://localhost:8070/start/${this.channel}/`;
292
337
  if (this.urn) {
293
- url = `${url}&identifier=${this.urn}`;
338
+ url = `${url}?chat_id=${this.urn}`;
294
339
  }
295
340
  this.sock = new WebSocket(url);
296
341
  this.sock.onclose = function (event) {
297
- console.log('socket closed');
298
- webChat.active = false;
342
+ webChat.status = ChatStatus.DISCONNECTED;
299
343
  };
300
344
  this.sock.onmessage = function (event) {
301
- console.log(event.data);
345
+ webChat.status = ChatStatus.CONNECTED;
302
346
  const msg = JSON.parse(event.data) as Message;
303
347
  if (msg.type === 'chat_started') {
304
348
  if (webChat.urn !== msg.identifier) {
305
349
  webChat.messages = [];
306
350
  }
307
351
  webChat.urn = msg.identifier;
308
- webChat.active = true;
309
352
  webChat.requestUpdate('messages');
310
353
  } else if (msg.type === 'chat_resumed') {
311
354
  webChat.urn = msg.identifier;
312
- webChat.active = true;
313
355
  } else if (msg.type === 'msg_out') {
314
356
  msg['timestamp'] = new Date().getTime();
315
357
  webChat.addMessage(msg);
@@ -319,7 +361,6 @@ export class WebChat extends LitElement {
319
361
  }
320
362
 
321
363
  private restoreFromLocal(): void {
322
- console.log('Restoring from localStorage..');
323
364
  const data = JSON.parse(localStorage.getItem('temba-chat') || '{}');
324
365
  const urn = 'urn' in data ? data['urn'] : null;
325
366
  if (urn && !this.urn) {
@@ -345,7 +386,9 @@ export class WebChat extends LitElement {
345
386
 
346
387
  private focusInput() {
347
388
  const input = this.shadowRoot.querySelector('.input') as any;
348
- input.focus();
389
+ if (input) {
390
+ input.focus();
391
+ }
349
392
  }
350
393
 
351
394
  public updated(
@@ -359,13 +402,18 @@ export class WebChat extends LitElement {
359
402
  this.hideBottomScroll = true;
360
403
  this.hideTopScroll = !hasScroll;
361
404
  this.scrollToBottom();
362
- this.focusInput();
363
405
 
364
- if (!this.active) {
406
+ if (this.status === ChatStatus.DISCONNECTED) {
365
407
  this.openSocket();
366
408
  }
367
409
  }
368
410
 
411
+ if (changed.has('status')) {
412
+ if (this.status === ChatStatus.CONNECTED) {
413
+ this.focusInput();
414
+ }
415
+ }
416
+
369
417
  if (changed.has('channel')) {
370
418
  this.restoreFromLocal();
371
419
  }
@@ -404,7 +452,7 @@ export class WebChat extends LitElement {
404
452
  }
405
453
 
406
454
  private sendPendingMessage() {
407
- if (this.active) {
455
+ if (this.status === ChatStatus.CONNECTED) {
408
456
  const input = this.shadowRoot.querySelector('.input') as any;
409
457
  const text = input.value;
410
458
  input.value = '';
@@ -512,10 +560,11 @@ export class WebChat extends LitElement {
512
560
  public render(): TemplateResult {
513
561
  return html`
514
562
  <div
515
- class="chat ${this.hideTopScroll ? 'scroll-at-top' : ''} ${this
516
- .hideBottomScroll
517
- ? 'scroll-at-bottom'
518
- : ''} ${this.open ? 'open' : ''}"
563
+ class="chat ${this.status} ${this.hideTopScroll
564
+ ? 'scroll-at-top'
565
+ : ''} ${this.hideBottomScroll ? 'scroll-at-bottom' : ''} ${this.open
566
+ ? 'open'
567
+ : ''}"
519
568
  >
520
569
  <div class="messages">
521
570
  <div class="scroll" @scroll=${this.handleScroll}>
@@ -527,25 +576,46 @@ export class WebChat extends LitElement {
527
576
  : null}
528
577
  </div>
529
578
  </div>
530
- <div
531
- class="row input-panel ${this.hasPendingText ? 'pending' : ''}"
532
- @click=${this.handleClickInputPanel}
533
- >
534
- <input
535
- class="input ${this.active ? 'active' : 'inactive'}"
536
- type="text"
537
- placeholder="Message.."
538
- @keydown=${this.handleKeyUp}
539
- />
540
- <temba-icon
541
- tabindex="1"
542
- class="send-icon"
543
- name="send"
544
- size="1"
545
- clickable
546
- @click=${this.sendPendingMessage}
547
- ></temba-icon>
548
- </div>
579
+
580
+ ${this.status === ChatStatus.DISCONNECTED
581
+ ? html`<div class="notice">
582
+ <div>This chat is not currently connected.</div>
583
+ <div class="reconnect" @click=${this.handleReconnect}>
584
+ Click here to reconnect
585
+ <div></div>
586
+ </div>
587
+ </div>`
588
+ : null}
589
+ ${this.status === ChatStatus.CONNECTING
590
+ ? html`<div class="notice">
591
+ <div>Connecting</div>
592
+ <temba-icon name="progress_spinner" spin></temba-icon>
593
+ </div>`
594
+ : null}
595
+ ${this.status === ChatStatus.CONNECTED
596
+ ? html` <div
597
+ class="row input-panel ${this.hasPendingText ? 'pending' : ''}"
598
+ @click=${this.handleClickInputPanel}
599
+ >
600
+ <input
601
+ class="input ${this.status === ChatStatus.CONNECTED
602
+ ? 'active'
603
+ : 'inactive'}"
604
+ type="text"
605
+ placeholder="Message.."
606
+ ?disabled=${this.status !== ChatStatus.CONNECTED}
607
+ @keydown=${this.handleKeyUp}
608
+ />
609
+ <temba-icon
610
+ tabindex="1"
611
+ class="send-icon"
612
+ name="send"
613
+ size="1"
614
+ clickable
615
+ @click=${this.sendPendingMessage}
616
+ ></temba-icon>
617
+ </div>`
618
+ : null}
549
619
  </div>
550
620
 
551
621
  <div @click=${this.toggleChat}>