@nyaruka/temba-components 0.48.0 → 0.48.2

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 (27) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/{260fc44e.js → 98c8996c.js} +155 -105
  3. package/dist/index.js +155 -105
  4. package/dist/sw.js +1 -1
  5. package/dist/sw.js.map +1 -1
  6. package/dist/templates/components-body.html +1 -1
  7. package/dist/templates/components-head.html +1 -1
  8. package/out-tsc/src/contacts/ContactChat.js +12 -8
  9. package/out-tsc/src/contacts/ContactChat.js.map +1 -1
  10. package/out-tsc/src/contacts/ContactTickets.js +157 -92
  11. package/out-tsc/src/contacts/ContactTickets.js.map +1 -1
  12. package/out-tsc/test/temba-compose.test.js +49 -48
  13. package/out-tsc/test/temba-compose.test.js.map +1 -1
  14. package/out-tsc/test/temba-contact-chat.test.js +48 -23
  15. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  16. package/package.json +1 -1
  17. package/screenshots/truth/contacts/compose-attachments-no-text-failure.png +0 -0
  18. package/screenshots/truth/contacts/compose-text-and-attachments-failure-attachments.png +0 -0
  19. package/screenshots/truth/contacts/compose-text-and-attachments-failure-text-and-attachments.png +0 -0
  20. package/screenshots/truth/contacts/compose-text-and-attachments-failure-text.png +0 -0
  21. package/screenshots/truth/contacts/compose-text-no-attachments-failure.png +0 -0
  22. package/screenshots/truth/contacts/tickets-assignment.png +0 -0
  23. package/screenshots/truth/contacts/tickets.png +0 -0
  24. package/src/contacts/ContactChat.ts +18 -8
  25. package/src/contacts/ContactTickets.ts +199 -135
  26. package/test/temba-compose.test.ts +80 -54
  27. package/test/temba-contact-chat.test.ts +60 -27
@@ -3,7 +3,6 @@ import { property } from 'lit/decorators.js';
3
3
  import { CustomEventType, Ticket, TicketStatus, User } from '../interfaces';
4
4
  import { StoreElement } from '../store/StoreElement';
5
5
  import {
6
- getAssets,
7
6
  getClasses,
8
7
  getFullName,
9
8
  postJSON,
@@ -25,6 +24,12 @@ export class ContactTickets extends StoreElement {
25
24
  @property({ type: Boolean })
26
25
  clickable = false;
27
26
 
27
+ @property({ type: Boolean })
28
+ expandable = false;
29
+
30
+ @property({ type: Boolean })
31
+ expanded = false;
32
+
28
33
  @property({ type: Object, attribute: false })
29
34
  data: Ticket[];
30
35
 
@@ -36,6 +41,7 @@ export class ContactTickets extends StoreElement {
36
41
  :hover {
37
42
  }
38
43
 
44
+ .ticket.expandable:hover,
39
45
  .ticket.clickable:hover {
40
46
  cursor: pointer;
41
47
  box-shadow: 0 0 8px 1px rgba(0, 0, 0, 0.055),
@@ -61,27 +67,58 @@ export class ContactTickets extends StoreElement {
61
67
  align-items: center;
62
68
  box-shadow: 0 0 8px 1px rgba(0, 0, 0, 0.055),
63
69
  0 0 0px 1px rgba(0, 0, 0, 0.02);
70
+ transition: all 200ms ease-in-out;
64
71
  }
65
72
 
66
73
  .ticket .body {
74
+ flex-grow: 5;
75
+ white-space: nowrap;
76
+ overflow: hidden;
77
+ text-overflow: ellipsis;
78
+ width: 200px;
79
+ }
80
+
81
+ .ticket .topic {
67
82
  flex-grow: 1;
68
- display: -webkit-box;
69
- -webkit-line-clamp: 1;
70
- -webkit-box-orient: vertical;
83
+ white-space: nowrap;
71
84
  overflow: hidden;
72
- padding: 0.1em;
85
+ text-overflow: ellipsis;
86
+ margin: 0 0.75em;
87
+ width: 60px;
73
88
  }
74
89
 
75
- .date {
90
+ .ticket.expanded .topic {
91
+ display: none;
92
+ }
93
+
94
+ .ticket.expanded .topic-expanded {
76
95
  display: -webkit-box;
96
+ }
97
+
98
+ .topic-expanded {
99
+ flex-grow: 1;
100
+ display: none;
77
101
  -webkit-line-clamp: 1;
78
102
  -webkit-box-orient: vertical;
79
103
  overflow: hidden;
80
- padding: 0.1em;
81
104
  }
82
105
 
83
- .ticket > div {
84
- padding: 0.5em 1em;
106
+ .ticket.expanded {
107
+ flex-direction: column-reverse;
108
+ align-items: stretch;
109
+ }
110
+
111
+ .ticket.expanded .body {
112
+ display: block;
113
+ max-height: 40vh;
114
+ overflow-y: auto;
115
+ -webkit-line-clamp: none;
116
+ border-top: 1px solid #e6e6e6;
117
+ // 6px solid #f9f9f9;
118
+ margin-bottom: 0.5em;
119
+ padding: 0.5em 1em 0em 1em;
120
+ white-space: normal;
121
+ width: initial;
85
122
  }
86
123
 
87
124
  .status {
@@ -94,7 +131,6 @@ export class ContactTickets extends StoreElement {
94
131
  }
95
132
 
96
133
  .resolve {
97
- margin-right: 1em;
98
134
  color: var(--color-primary-dark);
99
135
  }
100
136
 
@@ -165,6 +201,21 @@ export class ContactTickets extends StoreElement {
165
201
  .current-user {
166
202
  font-weight: 400;
167
203
  }
204
+
205
+ .details {
206
+ display: flex;
207
+ align-items: center;
208
+ padding: 0.5em 1em;
209
+ flex-shrink: 1;
210
+ }
211
+
212
+ .details .date {
213
+ padding: 0em 0.75em;
214
+ }
215
+
216
+ .details .toggle {
217
+ padding-right: 0.75em;
218
+ }
168
219
  `;
169
220
  }
170
221
 
@@ -265,6 +316,7 @@ export class ContactTickets extends StoreElement {
265
316
  .catch((response: any) => {
266
317
  console.error(response);
267
318
  });
319
+ return true;
268
320
  }
269
321
 
270
322
  public renderTicket(ticket: Ticket) {
@@ -276,156 +328,168 @@ export class ContactTickets extends StoreElement {
276
328
  @click=${() => {
277
329
  if (this.clickable) {
278
330
  this.fireCustomEvent(CustomEventType.ButtonClicked, { ticket });
331
+ } else if (this.expandable) {
332
+ this.expanded = !this.expanded;
279
333
  }
280
334
  }}
281
335
  class="ticket ${ticket.status} ${getClasses({
282
336
  clickable: this.clickable,
337
+ expandable: this.expandable,
338
+ expanded: this.expanded,
283
339
  })}"
284
340
  >
285
341
  <div class="topic">${ticket.topic.name}</div>
286
342
  <div class="body">${ticket.body}</div>
287
343
 
288
- <div class="date">
289
- <temba-date value="${date}" display="duration"></temba-date>
290
- </div>
344
+ <div class="details">
345
+ <div class="topic-expanded">${ticket.topic.name}</div>
291
346
 
292
- ${ticket.status === TicketStatus.Closed
293
- ? html`<div class="reopen">
294
- <temba-button
295
- primary
296
- small
297
- name="Reopen"
298
- @click=${(event: MouseEvent) => {
299
- event.preventDefault();
300
- event.stopPropagation();
301
- this.handleReopen(ticket.uuid);
302
- }}
303
- ></temba-button>
304
- </div>`
305
- : html`
306
- <div>
307
- <temba-dropdown
308
- drop_align="right"
309
- arrowsize="8"
310
- arrowoffset="-44"
311
- offsety="8"
312
- offsetx=${ticket.assignee ? -42 : -28}
313
- >
314
- <div slot="toggle" class="toggle">
315
- ${ticket.assignee
316
- ? html`
317
- <div style="font-size:0.5em">
318
- ${renderAvatar({
319
- name: ticket.assignee.name,
320
- position: 'left',
321
- })}
322
- </div>
323
- `
324
- : html`
325
- <temba-button
326
- name="Assign"
327
- primary
328
- small
329
- ></temba-button>
330
- `}
331
- </div>
332
-
333
- <div
334
- slot="dropdown"
335
- class="dropdown"
336
- @click=${(event: MouseEvent) => {
337
- stopEvent(event);
338
- }}
347
+ <div class="date">
348
+ <temba-date value="${date}" display="duration"></temba-date>
349
+ </div>
350
+
351
+ ${ticket.status === TicketStatus.Closed
352
+ ? html`<div class="reopen">
353
+ <temba-button
354
+ primary
355
+ small
356
+ name="Reopen"
357
+ @click=${(event: MouseEvent) => {
358
+ event.preventDefault();
359
+ event.stopPropagation();
360
+ this.handleReopen(ticket.uuid);
361
+ }}
362
+ ></temba-button>
363
+ </div>`
364
+ : html`
365
+ <div>
366
+ <temba-dropdown
367
+ drop_align="right"
368
+ arrowsize="8"
369
+ arrowoffset="-44"
370
+ offsety="8"
371
+ offsetx=${ticket.assignee ? -42 : -28}
339
372
  >
340
- ${ticket.assignee
341
- ? html`
342
- <div
343
- class="assigned option-group ${agent &&
344
- ticket.assignee.email == agent.email
345
- ? 'current-user'
346
- : ''}"
347
- >
348
- ${this.renderUser(
349
- users.find(
350
- user => user.email === ticket.assignee.email
351
- )
352
- )}
373
+ <div slot="toggle" class="toggle">
374
+ ${ticket.assignee
375
+ ? html`
376
+ <div style="font-size:0.5em">
377
+ ${renderAvatar({
378
+ name: ticket.assignee.name,
379
+ position: 'left',
380
+ })}
381
+ </div>
382
+ `
383
+ : html`
353
384
  <temba-button
354
- name="Unassign"
385
+ name="Assign"
355
386
  primary
356
387
  small
388
+ ></temba-button>
389
+ `}
390
+ </div>
391
+
392
+ <div
393
+ slot="dropdown"
394
+ class="dropdown"
395
+ @click=${(event: MouseEvent) => {
396
+ stopEvent(event);
397
+ }}
398
+ >
399
+ ${ticket.assignee
400
+ ? html`
401
+ <div
402
+ class="assigned option-group ${agent &&
403
+ ticket.assignee.email == agent.email
404
+ ? 'current-user'
405
+ : ''}"
406
+ >
407
+ ${this.renderUser(
408
+ users.find(
409
+ user => user.email === ticket.assignee.email
410
+ )
411
+ )}
412
+ <temba-button
413
+ name="Unassign"
414
+ primary
415
+ small
416
+ @click=${(event: MouseEvent) => {
417
+ stopEvent(event);
418
+ this.handleTicketAssignment(
419
+ ticket.uuid,
420
+ null
421
+ );
422
+ }}
423
+ ></temba-button>
424
+ </div>
425
+ `
426
+ : null}
427
+ ${agent &&
428
+ (!ticket.assignee ||
429
+ agent.email !== ticket.assignee.email)
430
+ ? html`
431
+ <div
432
+ class="current-user option-group"
357
433
  @click=${(event: MouseEvent) => {
358
434
  stopEvent(event);
359
- this.handleTicketAssignment(ticket.uuid, null);
435
+ this.handleTicketAssignment(
436
+ ticket.uuid,
437
+ agent.email
438
+ );
360
439
  }}
361
- ></temba-button>
362
- </div>
363
- `
364
- : null}
365
- ${agent &&
366
- (!ticket.assignee || agent.email !== ticket.assignee.email)
367
- ? html`
368
- <div
369
- class="current-user option-group"
440
+ >
441
+ ${this.renderUser(agent)}
442
+ </div>
443
+ `
444
+ : null}
445
+
446
+ <div class="options option-group">
447
+ ${this.store.getAssignableUsers().map(user => {
448
+ if (
449
+ ticket.assignee &&
450
+ user.email === ticket.assignee.email
451
+ ) {
452
+ return null;
453
+ }
454
+
455
+ if (user.email === this.agent) {
456
+ return null;
457
+ }
458
+ return html`<div
370
459
  @click=${(event: MouseEvent) => {
371
460
  stopEvent(event);
372
461
  this.handleTicketAssignment(
373
462
  ticket.uuid,
374
- agent.email
463
+ user.email
375
464
  );
376
465
  }}
377
466
  >
378
- ${this.renderUser(agent)}
379
- </div>
380
- `
381
- : null}
382
-
383
- <div class="options option-group">
384
- ${this.store.getAssignableUsers().map(user => {
385
- if (
386
- ticket.assignee &&
387
- user.email === ticket.assignee.email
388
- ) {
389
- return null;
390
- }
391
-
392
- if (user.email === this.agent) {
393
- return null;
394
- }
395
- return html`<div
396
- @click=${(event: MouseEvent) => {
397
- stopEvent(event);
398
- this.handleTicketAssignment(
399
- ticket.uuid,
400
- user.email
401
- );
402
- }}
403
- >
404
- ${this.renderUser(user)}
405
- </div>`;
406
- })}
467
+ ${this.renderUser(user)}
468
+ </div>`;
469
+ })}
470
+ </div>
407
471
  </div>
408
- </div>
409
- </temba-dropdown>
410
- </div>
411
- <temba-tip
412
- text="Resolve"
413
- position="left"
414
- style="width:1.5em"
415
- class="resolve"
416
- >
417
- <temba-icon
418
- size="1.25"
419
- name="${Icon.check}"
420
- @click=${(event: MouseEvent) => {
421
- event.preventDefault();
422
- event.stopPropagation();
423
- this.handleClose(ticket.uuid);
424
- }}
425
- ?clickable=${open}
426
- />
427
- </temba-tip>
428
- `}
472
+ </temba-dropdown>
473
+ </div>
474
+ <temba-tip
475
+ text="Resolve"
476
+ position="left"
477
+ style="width:1.5em"
478
+ class="resolve"
479
+ >
480
+ <temba-icon
481
+ size="1.25"
482
+ name="${Icon.check}"
483
+ @click=${(event: MouseEvent) => {
484
+ event.preventDefault();
485
+ event.stopPropagation();
486
+ this.handleClose(ticket.uuid);
487
+ }}
488
+ ?clickable=${open}
489
+ />
490
+ </temba-tip>
491
+ `}
492
+ </div>
429
493
  </div>
430
494
  `;
431
495
  }