@nyaruka/temba-components 0.91.6 → 0.92.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 (83) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/demo/index.html +1 -1
  3. package/dist/temba-components.js +760 -1189
  4. package/dist/temba-components.js.map +1 -1
  5. package/out-tsc/src/chat/Chat.js +714 -0
  6. package/out-tsc/src/chat/Chat.js.map +1 -0
  7. package/out-tsc/src/completion/helpers.js +1 -29
  8. package/out-tsc/src/completion/helpers.js.map +1 -1
  9. package/out-tsc/src/compose/Compose.js +6 -2
  10. package/out-tsc/src/compose/Compose.js.map +1 -1
  11. package/out-tsc/src/contacts/ContactChat.js +518 -54
  12. package/out-tsc/src/contacts/ContactChat.js.map +1 -1
  13. package/out-tsc/src/contacts/events.js +1 -998
  14. package/out-tsc/src/contacts/events.js.map +1 -1
  15. package/out-tsc/src/lightbox/Lightbox.js +4 -0
  16. package/out-tsc/src/lightbox/Lightbox.js.map +1 -1
  17. package/out-tsc/src/list/TembaMenu.js +0 -1
  18. package/out-tsc/src/list/TembaMenu.js.map +1 -1
  19. package/out-tsc/src/markdown.js +33 -0
  20. package/out-tsc/src/markdown.js.map +1 -0
  21. package/out-tsc/src/select/Select.js +6 -1
  22. package/out-tsc/src/select/Select.js.map +1 -1
  23. package/out-tsc/src/textinput/TextInput.js +1 -1
  24. package/out-tsc/src/textinput/TextInput.js.map +1 -1
  25. package/out-tsc/src/thumbnail/Thumbnail.js +128 -81
  26. package/out-tsc/src/thumbnail/Thumbnail.js.map +1 -1
  27. package/out-tsc/src/utils/index.js +9 -11
  28. package/out-tsc/src/utils/index.js.map +1 -1
  29. package/out-tsc/src/webchat/WebChat.js +109 -358
  30. package/out-tsc/src/webchat/WebChat.js.map +1 -1
  31. package/out-tsc/src/webchat/index.js +17 -0
  32. package/out-tsc/src/webchat/index.js.map +1 -1
  33. package/out-tsc/temba-modules.js +2 -2
  34. package/out-tsc/temba-modules.js.map +1 -1
  35. package/out-tsc/temba-webchat.js +2 -0
  36. package/out-tsc/temba-webchat.js.map +1 -1
  37. package/out-tsc/test/temba-contact-chat.test.js +1 -0
  38. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  39. package/out-tsc/test/temba-lightbox.test.js +4 -4
  40. package/out-tsc/test/temba-lightbox.test.js.map +1 -1
  41. package/package.json +1 -1
  42. package/screenshots/truth/contacts/compose-attachments-no-text-failure.png +0 -0
  43. package/screenshots/truth/contacts/compose-attachments-no-text-success.png +0 -0
  44. package/screenshots/truth/contacts/compose-text-and-attachments-failure-attachments.png +0 -0
  45. package/screenshots/truth/contacts/compose-text-and-attachments-failure-generic.png +0 -0
  46. package/screenshots/truth/contacts/compose-text-and-attachments-failure-text-and-attachments.png +0 -0
  47. package/screenshots/truth/contacts/compose-text-and-attachments-failure-text.png +0 -0
  48. package/screenshots/truth/contacts/compose-text-and-attachments-success.png +0 -0
  49. package/screenshots/truth/contacts/compose-text-no-attachments-failure.png +0 -0
  50. package/screenshots/truth/contacts/compose-text-no-attachments-success.png +0 -0
  51. package/screenshots/truth/contacts/contact-active-default.png +0 -0
  52. package/screenshots/truth/contacts/contact-active-show-chatbox.png +0 -0
  53. package/screenshots/truth/contacts/contact-archived-hide-chatbox.png +0 -0
  54. package/screenshots/truth/contacts/contact-blocked-hide-chatbox.png +0 -0
  55. package/screenshots/truth/contacts/contact-stopped-hide-chatbox.png +0 -0
  56. package/screenshots/truth/lightbox/img-zoomed.png +0 -0
  57. package/screenshots/truth/lightbox/img.png +0 -0
  58. package/src/chat/Chat.ts +791 -0
  59. package/src/completion/helpers.ts +2 -40
  60. package/src/compose/Compose.ts +6 -2
  61. package/src/contacts/ContactChat.ts +609 -59
  62. package/src/contacts/events.ts +1 -1068
  63. package/src/lightbox/Lightbox.ts +5 -0
  64. package/src/list/TembaMenu.ts +0 -1
  65. package/src/markdown.ts +41 -0
  66. package/src/select/Select.ts +5 -1
  67. package/src/textinput/TextInput.ts +1 -1
  68. package/src/thumbnail/Thumbnail.ts +130 -81
  69. package/src/utils/index.ts +12 -13
  70. package/src/webchat/WebChat.ts +196 -413
  71. package/src/webchat/index.ts +23 -1
  72. package/static/css/temba-components.css +2 -0
  73. package/temba-modules.ts +2 -2
  74. package/temba-webchat.ts +2 -0
  75. package/test/temba-contact-chat.test.ts +1 -0
  76. package/test/temba-lightbox.test.ts +4 -4
  77. package/test-assets/contacts/history.json +1 -56
  78. package/out-tsc/src/contacts/ContactHistory.js +0 -691
  79. package/out-tsc/src/contacts/ContactHistory.js.map +0 -1
  80. package/out-tsc/test/temba-contact-history.test.js +0 -69
  81. package/out-tsc/test/temba-contact-history.test.js.map +0 -1
  82. package/src/contacts/ContactHistory.ts +0 -875
  83. package/test/temba-contact-history.test.ts +0 -107
@@ -1,691 +0,0 @@
1
- import { __decorate } from "tslib";
2
- import { css } from 'lit';
3
- import { property } from 'lit/decorators.js';
4
- import { html } from 'lit-html';
5
- import { CustomEventType } from '../interfaces';
6
- import { RapidElement } from '../RapidElement';
7
- import { getAssets, getClasses, postJSON, throttle } from '../utils';
8
- import { Events, getEventGroupType, getEventStyles, renderAirtimeTransferredEvent, renderCallStartedEvent, renderCampaignFiredEvent, renderChannelEvent, renderContactGroupsEvent, renderContactLanguageChangedEvent, renderContactURNsChanged, renderEmailSent, renderErrorMessage, renderFlowEvent, renderLabelsAdded, renderMsgEvent, renderNameChanged, renderNoteCreated, renderOptinRequested, renderResultEvent, renderTicketAction, renderTicketAssigned, renderUpdateEvent, renderWebhookEvent } from './events';
9
- import { fetchContactHistory, MAX_CHAT_REFRESH, MIN_CHAT_REFRESH, SCROLL_THRESHOLD } from './helpers';
10
- // when images load, make sure we are on the bottom of the scroll window if necessary
11
- export const loadHandler = function (event) {
12
- const target = event.target;
13
- const events = this.host.getEventsPane();
14
- if (target.tagName == 'IMG') {
15
- if (!this.host.showMessageAlert) {
16
- if (events.scrollTop > target.offsetTop - 1000 &&
17
- target.offsetTop > events.scrollHeight - 500) {
18
- this.host.scrollToBottom();
19
- }
20
- }
21
- }
22
- };
23
- export class ContactHistory extends RapidElement {
24
- constructor() {
25
- super();
26
- this.eventGroups = [];
27
- this.refreshing = false;
28
- this.fetching = false;
29
- this.complete = false;
30
- this.debug = false;
31
- this.showMessageAlert = false;
32
- this.ticket = null;
33
- this.endDate = null;
34
- this.tickets = null;
35
- this.ticketEvents = {};
36
- this.lastHeight = 0;
37
- this.refreshTimeout = null;
38
- this.empty = false;
39
- }
40
- connectedCallback() {
41
- super.connectedCallback();
42
- this.shadowRoot.addEventListener('load', loadHandler, true);
43
- this.store = document.querySelector('temba-store');
44
- }
45
- disconnectedCallback() {
46
- super.disconnectedCallback();
47
- this.shadowRoot.removeEventListener('load', loadHandler, true);
48
- }
49
- getTicketForEvent(event) {
50
- return this.getTicket(event.ticket.uuid);
51
- }
52
- getTicket(uuid) {
53
- return (this.tickets || []).find((ticket) => ticket.uuid === uuid);
54
- }
55
- static get styles() {
56
- return css `
57
- ${getEventStyles()}
58
-
59
- .wrapper {
60
- border: 0px solid green;
61
- display: flex;
62
- flex-direction: column;
63
- align-items: items-stretch;
64
- flex-grow: 1;
65
- min-height: 0;
66
- }
67
-
68
- .events {
69
- overflow-y: scroll;
70
- overflow-x: hidden;
71
- background: #fff;
72
- display: flex;
73
- flex-direction: column;
74
- flex-grow: 1;
75
- min-height: 0;
76
- padding-top: 3em;
77
- padding-bottom: 1em;
78
- }
79
-
80
- temba-loading {
81
- align-self: center;
82
- margin-top: 0.025em;
83
- position: absolute;
84
- z-index: 250;
85
- padding-top: 1em;
86
- }
87
-
88
- .new-messages-container {
89
- display: flex;
90
- z-index: 1;
91
- background: pink;
92
- margin-bottom: 0px;
93
- }
94
-
95
- .new-messages {
96
- pointer-events: none;
97
- margin: 0 auto;
98
- margin-top: 0em;
99
- margin-bottom: -2.5em;
100
- padding: 0.25em 1em;
101
- border-radius: var(--curvature);
102
- background: var(--color-primary-dark);
103
- color: var(--color-text-light);
104
- opacity: 0;
105
- cursor: pointer;
106
- transition: all var(--transition-speed) ease-in-out;
107
- box-shadow: rgb(0 0 0 / 15%) 0px 3px 3px 0px;
108
- }
109
-
110
- .new-messages.expanded {
111
- margin-top: -2.5em;
112
- margin-bottom: 0.5em;
113
- pointer-events: auto;
114
- opacity: 1;
115
- pointer: cursor;
116
- }
117
-
118
- .scroll-title {
119
- display: flex;
120
- flex-direction: column;
121
- z-index: 2;
122
- border-top-left-radius: var(--curvature);
123
- overflow: hidden;
124
- box-shadow: 0px 3px 3px 0px rgba(0, 0, 0, 0.15);
125
- background: rgb(240, 240, 240);
126
- padding: 1em 1.2em;
127
- font-size: 1.2em;
128
- font-weight: 400;
129
- }
130
-
131
- .attachment img {
132
- cursor: pointer;
133
- }
134
- `;
135
- }
136
- firstUpdated(changedProperties) {
137
- super.firstUpdated(changedProperties);
138
- this.handleClose = this.handleClose.bind(this);
139
- }
140
- updated(changedProperties) {
141
- super.updated(changedProperties);
142
- // fire an event if we get a new event
143
- if (changedProperties.has('mostRecentEvent') &&
144
- changedProperties.get('mostRecentEvent') &&
145
- this.mostRecentEvent) {
146
- this.fireCustomEvent(CustomEventType.Refreshed);
147
- }
148
- if (changedProperties.has('endDate')) {
149
- if (this.refreshTimeout && this.endDate) {
150
- window.clearTimeout(this.refreshTimeout);
151
- }
152
- }
153
- // if we don't have an endpoint infer one
154
- if (changedProperties.has('uuid')) {
155
- if (this.uuid == null) {
156
- this.reset();
157
- }
158
- else {
159
- const endpoint = `/contact/history/${this.uuid}/?_format=json`;
160
- if (this.endpoint !== endpoint) {
161
- this.reset();
162
- if (this.endDate) {
163
- const before = new Date(this.endDate);
164
- this.nextBefore = before.getTime() * 1000 + 1000;
165
- }
166
- this.endpoint = endpoint;
167
- this.refreshTickets();
168
- }
169
- }
170
- }
171
- if (changedProperties.has('ticket')) {
172
- this.endpoint = null;
173
- this.requestUpdate('uuid');
174
- }
175
- if (changedProperties.has('refreshing') &&
176
- this.refreshing &&
177
- this.endpoint &&
178
- !this.endDate) {
179
- const after = (this.getLastEventTime() - 1) * 1000;
180
- let forceOpen = false;
181
- fetchContactHistory(false, this.endpoint, this.ticket, null, after)
182
- .then((results) => {
183
- if (results.events && results.events.length > 0) {
184
- this.updateMostRecent(results.events[0]);
185
- }
186
- // keep track of any ticket events
187
- results.events.forEach((event) => {
188
- if (event.type === Events.TICKET_OPENED) {
189
- const ticketEvent = event;
190
- this.ticketEvents[ticketEvent.ticket.uuid] = ticketEvent;
191
- }
192
- });
193
- const fetchedEvents = results.events.reverse();
194
- // dedupe any events we get from the server
195
- // TODO: perhaps make this a little less crazy
196
- let removed = 0;
197
- this.eventGroups.forEach((g) => {
198
- const before = g.events.length;
199
- g.events = g.events.filter((prev) => !fetchedEvents.find((fetched) => {
200
- return (prev.created_on == fetched.created_on &&
201
- prev.type === fetched.type);
202
- }));
203
- removed += before - g.events.length;
204
- });
205
- this.lastRefreshAdded = fetchedEvents.length - removed;
206
- // reflow our most recent event group in case it merges with our new groups
207
- const previousGroups = [...this.eventGroups];
208
- if (this.eventGroups.length > 0) {
209
- const sliced = previousGroups.splice(previousGroups.length - 1, 1)[0];
210
- forceOpen = sliced.open;
211
- if (sliced.events.length > 0) {
212
- fetchedEvents.splice(0, 0, ...sliced.events);
213
- }
214
- }
215
- const grouped = this.getEventGroups(fetchedEvents);
216
- if (grouped.length) {
217
- if (forceOpen) {
218
- grouped[grouped.length - 1].open = forceOpen;
219
- }
220
- this.eventGroups = [...previousGroups, ...grouped].filter((group) => group.events.length > 0);
221
- }
222
- this.refreshing = false;
223
- this.scheduleRefresh();
224
- })
225
- .catch(() => {
226
- this.refreshing = false;
227
- this.scheduleRefresh();
228
- });
229
- }
230
- if (changedProperties.has('fetching') && this.fetching) {
231
- if (!this.nextBefore) {
232
- this.nextBefore = new Date().getTime() * 1000 - 1000;
233
- }
234
- this.httpComplete = fetchContactHistory(this.empty, this.endpoint, this.ticket, this.nextBefore, this.nextAfter).then((results) => {
235
- // see if we have a new event
236
- if (results.events && results.events.length > 0) {
237
- this.updateMostRecent(results.events[0]);
238
- // keep track of any ticket events
239
- results.events.forEach((event) => {
240
- if (event.type === Events.TICKET_OPENED) {
241
- const ticketEvent = event;
242
- this.ticketEvents[ticketEvent.ticket.uuid] = ticketEvent;
243
- }
244
- });
245
- }
246
- let forceOpen = false;
247
- const fetchedEvents = results.events ? results.events.reverse() : [];
248
- // reflow our last event group in case it merges with our new groups
249
- if (this.eventGroups.length > 0) {
250
- const sliced = this.eventGroups.splice(0, 1)[0];
251
- forceOpen = sliced.open;
252
- fetchedEvents.push(...sliced.events);
253
- }
254
- const grouped = this.getEventGroups(fetchedEvents);
255
- if (grouped.length) {
256
- if (forceOpen) {
257
- grouped[grouped.length - 1].open = forceOpen;
258
- }
259
- this.eventGroups = [...grouped, ...this.eventGroups];
260
- }
261
- if (results.next_before === this.nextBefore) {
262
- this.complete = true;
263
- }
264
- this.nextBefore = results.next_before;
265
- this.nextAfter = results.next_after;
266
- this.fetching = false;
267
- this.empty = false;
268
- });
269
- }
270
- if (changedProperties.has('refreshing') && !this.refreshing) {
271
- if (this.lastRefreshAdded > 0) {
272
- const events = this.getEventsPane();
273
- // if we are near the bottom, push us to the bottom to show new stuff
274
- if (this.lastHeight > 0) {
275
- const addedHeight = events.scrollHeight - this.lastHeight;
276
- const distanceFromBottom = events.scrollHeight -
277
- events.scrollTop -
278
- addedHeight -
279
- events.clientHeight;
280
- if (distanceFromBottom < 500) {
281
- this.scrollToBottom();
282
- }
283
- else {
284
- this.showMessageAlert = true;
285
- }
286
- }
287
- if (this.eventGroups.length > 0) {
288
- this.lastHeight = events.scrollHeight;
289
- }
290
- }
291
- }
292
- if (changedProperties.has('fetching') &&
293
- !this.fetching &&
294
- changedProperties.get('fetching') !== undefined) {
295
- const events = this.getEventsPane();
296
- if (this.lastHeight && events.scrollHeight > this.lastHeight) {
297
- const scrollTop = events.scrollTop + events.scrollHeight - this.lastHeight;
298
- events.scrollTop = scrollTop;
299
- }
300
- // scroll to the bottom if it's our first fetch
301
- if (!this.lastHeight) {
302
- this.scrollToBottom();
303
- }
304
- // don't record our scroll height until we have history
305
- if (this.eventGroups.length > 0) {
306
- this.lastHeight = events.scrollHeight;
307
- }
308
- }
309
- if (changedProperties.has('endpoint') && this.endpoint) {
310
- this.fetching = true;
311
- this.empty = true;
312
- }
313
- }
314
- refreshTickets() {
315
- if (this.ticket) {
316
- let url = `/api/v2/tickets.json?contact=${this.uuid}`;
317
- if (this.ticket) {
318
- url = `${url}&ticket=${this.ticket}`;
319
- }
320
- getAssets(url).then((tickets) => {
321
- this.tickets = tickets.reverse();
322
- });
323
- }
324
- }
325
- getEventsPane() {
326
- return this.getDiv('.events');
327
- }
328
- scrollToBottom(smooth = false) {
329
- const events = this.getEventsPane();
330
- events.scrollTo({
331
- top: events.scrollHeight,
332
- behavior: smooth ? 'smooth' : 'auto'
333
- });
334
- this.showMessageAlert = false;
335
- window.setTimeout(() => {
336
- events.scrollTo({
337
- top: events.scrollHeight,
338
- behavior: smooth ? 'smooth' : 'auto'
339
- });
340
- }, 0);
341
- }
342
- refresh() {
343
- this.scheduleRefresh(500);
344
- }
345
- getEventGroups(events) {
346
- const grouped = [];
347
- let eventGroup = undefined;
348
- for (const event of events) {
349
- const currentEventGroupType = getEventGroupType(event, this.ticket);
350
- // see if we need a new event group
351
- if (!eventGroup || eventGroup.type !== currentEventGroupType) {
352
- // we have a new type, save our last group
353
- if (eventGroup) {
354
- grouped.push(eventGroup);
355
- }
356
- eventGroup = {
357
- open: false,
358
- events: [event],
359
- type: currentEventGroupType
360
- };
361
- }
362
- else {
363
- // our event matches the current group, stuff it in there
364
- eventGroup.events.push(event);
365
- }
366
- }
367
- if (eventGroup && eventGroup.events.length > 0) {
368
- grouped.push(eventGroup);
369
- }
370
- return grouped;
371
- }
372
- scheduleRefresh(wait = -1) {
373
- if (this.endDate) {
374
- return;
375
- }
376
- let refreshWait = wait;
377
- if (wait === -1) {
378
- const lastEventTime = this.getLastEventTime();
379
- refreshWait = Math.max(Math.min((new Date().getTime() - lastEventTime) / 2, MAX_CHAT_REFRESH), MIN_CHAT_REFRESH);
380
- }
381
- // cancel any outstanding timeout
382
- if (wait > -1 && this.refreshTimeout) {
383
- window.clearTimeout(this.refreshTimeout);
384
- }
385
- this.refreshTimeout = window.setTimeout(() => {
386
- if (this.refreshing) {
387
- this.scheduleRefresh();
388
- this.refreshing = false;
389
- }
390
- else {
391
- this.refreshing = true;
392
- }
393
- }, refreshWait);
394
- }
395
- reset() {
396
- this.endpoint = null;
397
- this.tickets = null;
398
- this.ticketEvents = {};
399
- this.eventGroups = [];
400
- this.fetching = false;
401
- this.complete = false;
402
- this.nextBefore = null;
403
- this.nextAfter = null;
404
- this.lastHeight = 0;
405
- }
406
- handleEventGroupShow(event) {
407
- const grouping = event.currentTarget;
408
- const groupIndex = parseInt(grouping.getAttribute('data-group-index'));
409
- const eventGroup = this.eventGroups[this.eventGroups.length - groupIndex - 1];
410
- eventGroup.open = true;
411
- this.requestUpdate('eventGroups');
412
- }
413
- handleEventGroupHide(event) {
414
- event.preventDefault();
415
- event.stopPropagation();
416
- const grouping = event.currentTarget;
417
- const groupIndex = parseInt(grouping.getAttribute('data-group-index'));
418
- const eventGroup = this.eventGroups[this.eventGroups.length - groupIndex - 1];
419
- eventGroup.open = false;
420
- this.requestUpdate('eventGroups');
421
- }
422
- handleScroll() {
423
- const events = this.getEventsPane();
424
- if (events.scrollTop <= SCROLL_THRESHOLD) {
425
- if (this.eventGroups.length > 0 && !this.fetching && !this.complete) {
426
- this.fetching = true;
427
- }
428
- }
429
- }
430
- updateMostRecent(newEvent) {
431
- if (!this.mostRecentEvent ||
432
- this.mostRecentEvent.type !== newEvent.type ||
433
- this.mostRecentEvent.created_on !== newEvent.created_on) {
434
- this.mostRecentEvent = newEvent;
435
- }
436
- }
437
- getLastEventTime() {
438
- const mostRecentGroup = this.eventGroups[this.eventGroups.length - 1];
439
- if (mostRecentGroup) {
440
- const mostRecentEvent = mostRecentGroup.events[mostRecentGroup.events.length - 1];
441
- return new Date(mostRecentEvent.created_on).getTime();
442
- }
443
- return 0;
444
- }
445
- renderEvent(event) {
446
- switch (event.type) {
447
- case Events.IVR_CREATED:
448
- case Events.MESSAGE_CREATED:
449
- case Events.MESSAGE_RECEIVED:
450
- case Events.BROADCAST_CREATED:
451
- if (event.created_by) {
452
- event.created_by = this.store.getUser(event.created_by.email);
453
- }
454
- return renderMsgEvent(event);
455
- case Events.FLOW_ENTERED:
456
- case Events.FLOW_EXITED:
457
- return renderFlowEvent(event);
458
- case Events.RUN_RESULT_CHANGED:
459
- return renderResultEvent(event);
460
- case Events.CONTACT_FIELD_CHANGED:
461
- return renderUpdateEvent(event);
462
- case Events.CONTACT_NAME_CHANGED:
463
- return renderNameChanged(event);
464
- case Events.CONTACT_URNS_CHANGED:
465
- return renderContactURNsChanged(event);
466
- case Events.EMAIL_SENT:
467
- return renderEmailSent(event);
468
- case Events.INPUT_LABELS_ADDED:
469
- return renderLabelsAdded(event);
470
- case Events.TICKET_OPENED: {
471
- return renderTicketAction(event, 'opened', !this.ticket);
472
- }
473
- case Events.TICKET_NOTE_ADDED:
474
- return renderNoteCreated(event);
475
- case Events.TICKET_ASSIGNED:
476
- return renderTicketAssigned(event);
477
- case Events.TICKET_REOPENED: {
478
- return renderTicketAction(event, 'reopened', !this.ticket);
479
- }
480
- case Events.TICKET_CLOSED:
481
- return renderTicketAction(event, 'closed', !this.ticket);
482
- case Events.ERROR:
483
- case Events.FAILURE:
484
- return renderErrorMessage(event);
485
- case Events.CONTACT_GROUPS_CHANGED:
486
- return renderContactGroupsEvent(event);
487
- case Events.WEBHOOK_CALLED:
488
- return renderWebhookEvent(event);
489
- case Events.AIRTIME_TRANSFERRED:
490
- return renderAirtimeTransferredEvent(event);
491
- case Events.CALL_STARTED:
492
- return renderCallStartedEvent();
493
- case Events.CAMPAIGN_FIRED:
494
- return renderCampaignFiredEvent(event);
495
- case Events.CHANNEL_EVENT:
496
- return renderChannelEvent(event);
497
- case Events.CONTACT_LANGUAGE_CHANGED:
498
- return renderContactLanguageChangedEvent(event);
499
- case Events.OPTIN_REQUESTED:
500
- return renderOptinRequested(event);
501
- }
502
- return html `<temba-icon
503
- name="alert-triangle"
504
- style="fill:var(--color-error)"
505
- ></temba-icon>
506
- <div class="description">${event.type}</div>`;
507
- }
508
- handleClose(uuid) {
509
- this.httpComplete = postJSON(`/api/v2/ticket_actions.json`, {
510
- tickets: [uuid],
511
- action: 'close'
512
- })
513
- .then(() => {
514
- this.refreshTickets();
515
- this.refresh();
516
- this.fireCustomEvent(CustomEventType.ContentChanged, {
517
- ticket: { uuid, status: 'closed' }
518
- });
519
- })
520
- .catch((response) => {
521
- console.error(response);
522
- });
523
- }
524
- checkForAgentAssignmentEvent(agent) {
525
- this.httpComplete = getAssets(`/api/v2/tickets.json?uuid=${this.ticket}`).then((assets) => {
526
- if (assets.length === 1) {
527
- const ticket = assets[0];
528
- if (ticket.assignee && ticket.assignee.email === agent) {
529
- this.fireCustomEvent(CustomEventType.ContentChanged, {
530
- ticket: { uuid: this.ticket, assigned: 'self' }
531
- });
532
- }
533
- else {
534
- this.fireCustomEvent(CustomEventType.ContentChanged, {
535
- ticket: {
536
- uuid: this.ticket,
537
- assigned: ticket.assignee ? ticket.assignee : null
538
- }
539
- });
540
- }
541
- }
542
- });
543
- }
544
- getEventHandlers() {
545
- return [
546
- {
547
- event: 'scroll',
548
- method: throttle(this.handleScroll, 50)
549
- }
550
- ];
551
- }
552
- /** Check if a ticket event is no longer represented in a session */
553
- isPurged(ticket) {
554
- return !this.ticketEvents[ticket.uuid];
555
- }
556
- handleEventClicked(event) {
557
- const ele = event.target;
558
- if (ele.tagName == 'IMG') {
559
- // if we have one, show in our lightbox
560
- const lightbox = document.querySelector('temba-lightbox');
561
- if (lightbox) {
562
- lightbox.showElement(ele);
563
- }
564
- }
565
- }
566
- renderEventContainer(event) {
567
- const renderedEvent = html `
568
- <div
569
- @click=${this.handleEventClicked}
570
- class="${this.ticket ? 'active-ticket' : ''} event ${event.type}"
571
- >
572
- ${this.renderEvent(event)}
573
- </div>
574
- ${this.debug ? html `<pre>${JSON.stringify(event, null, 2)}</pre>` : null}
575
- `;
576
- return renderedEvent;
577
- }
578
- render() {
579
- return html `
580
- ${this.fetching
581
- ? html `<temba-loading units="5" size="10"></temba-loading>`
582
- : html `<div style="height:0em"></div>`}
583
- <div class="events" @scroll=${this.handleScroll}>
584
- ${this.eventGroups.map((eventGroup, index) => {
585
- const grouping = getEventGroupType(eventGroup.events[0], this.ticket);
586
- const groupIndex = this.eventGroups.length - index - 1;
587
- const classes = getClasses({
588
- grouping: true,
589
- [grouping]: true,
590
- expanded: eventGroup.open
591
- });
592
- return html `<div class="${classes}">
593
- ${grouping === 'verbose'
594
- ? html `<div
595
- class="event-count"
596
- @click=${this.handleEventGroupShow}
597
- data-group-index="${groupIndex}"
598
- >
599
- ${eventGroup.open
600
- ? html `<temba-icon
601
- @click=${this.handleEventGroupHide}
602
- data-group-index="${groupIndex}"
603
- name="x"
604
- clickable
605
- ></temba-icon>`
606
- : html `${eventGroup.events.length}
607
- ${eventGroup.events.length === 1
608
- ? html `event`
609
- : html `events`} `}
610
- </div>`
611
- : null}
612
-
613
- <div class="items">
614
- ${eventGroup.events.map((event) => {
615
- if (event.type === Events.TICKET_ASSIGNED &&
616
- event.note) {
617
- const noteEvent = { ...event };
618
- noteEvent.type = Events.TICKET_NOTE_ADDED;
619
- return html `${this.renderEventContainer(noteEvent)}${this.renderEventContainer(event)}`;
620
- }
621
- else {
622
- return this.renderEventContainer(event);
623
- }
624
- })}
625
- </div>
626
- </div>`;
627
- })}
628
- </div>
629
-
630
- ${this.contact && this.contact.status === 'active'
631
- ? html `<div class="new-messages-container">
632
- <div
633
- @click=${() => {
634
- this.scrollToBottom(true);
635
- }}
636
- class="new-messages ${getClasses({
637
- expanded: this.showMessageAlert
638
- })}"
639
- >
640
- New Messages
641
- </div>
642
- </div>`
643
- : null}
644
-
645
- </div>
646
- `;
647
- }
648
- }
649
- __decorate([
650
- property({ type: Object })
651
- ], ContactHistory.prototype, "contact", void 0);
652
- __decorate([
653
- property({ type: String })
654
- ], ContactHistory.prototype, "uuid", void 0);
655
- __decorate([
656
- property({ type: String })
657
- ], ContactHistory.prototype, "agent", void 0);
658
- __decorate([
659
- property({ type: Array })
660
- ], ContactHistory.prototype, "eventGroups", void 0);
661
- __decorate([
662
- property({ type: Boolean })
663
- ], ContactHistory.prototype, "refreshing", void 0);
664
- __decorate([
665
- property({ type: Boolean })
666
- ], ContactHistory.prototype, "fetching", void 0);
667
- __decorate([
668
- property({ type: Boolean })
669
- ], ContactHistory.prototype, "complete", void 0);
670
- __decorate([
671
- property({ type: String })
672
- ], ContactHistory.prototype, "endpoint", void 0);
673
- __decorate([
674
- property({ type: Boolean })
675
- ], ContactHistory.prototype, "debug", void 0);
676
- __decorate([
677
- property({ type: Boolean })
678
- ], ContactHistory.prototype, "showMessageAlert", void 0);
679
- __decorate([
680
- property({ attribute: false, type: Object })
681
- ], ContactHistory.prototype, "mostRecentEvent", void 0);
682
- __decorate([
683
- property({ type: String })
684
- ], ContactHistory.prototype, "ticket", void 0);
685
- __decorate([
686
- property({ type: String })
687
- ], ContactHistory.prototype, "endDate", void 0);
688
- __decorate([
689
- property({ type: Array })
690
- ], ContactHistory.prototype, "tickets", void 0);
691
- //# sourceMappingURL=ContactHistory.js.map