@nyaruka/temba-components 0.16.0 → 0.18.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.
- package/CHANGELOG.md +29 -0
- package/dist/a525ddb7.js +1 -0
- package/dist/index.js +1 -1
- package/dist/sw.js +1 -1
- package/dist/sw.js.map +1 -1
- package/dist/templates/components-body.html +1 -1
- package/dist/templates/components-head.html +1 -1
- package/out-tsc/src/button/Button.js +1 -0
- package/out-tsc/src/button/Button.js.map +1 -1
- package/out-tsc/src/contacts/ContactChat.js +81 -33
- package/out-tsc/src/contacts/ContactChat.js.map +1 -1
- package/out-tsc/src/contacts/ContactDetails.js +22 -22
- package/out-tsc/src/contacts/ContactDetails.js.map +1 -1
- package/out-tsc/src/contacts/ContactHistory.js +132 -139
- package/out-tsc/src/contacts/ContactHistory.js.map +1 -1
- package/out-tsc/src/contacts/events.js +110 -47
- package/out-tsc/src/contacts/events.js.map +1 -1
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/list/ContactList.js +32 -17
- package/out-tsc/src/list/ContactList.js.map +1 -1
- package/out-tsc/src/list/TembaList.js +10 -3
- package/out-tsc/src/list/TembaList.js.map +1 -1
- package/out-tsc/src/list/TembaMenu.js +7 -2
- package/out-tsc/src/list/TembaMenu.js.map +1 -1
- package/out-tsc/src/loading/Loading.js +9 -1
- package/out-tsc/src/loading/Loading.js.map +1 -1
- package/out-tsc/src/options/Options.js +14 -2
- package/out-tsc/src/options/Options.js.map +1 -1
- package/out-tsc/src/select/Select.js +23 -5
- package/out-tsc/src/select/Select.js.map +1 -1
- package/out-tsc/src/tip/Tip.js +6 -0
- package/out-tsc/src/tip/Tip.js.map +1 -1
- package/out-tsc/src/vectoricon/VectorIcon.js +17 -5
- package/out-tsc/src/vectoricon/VectorIcon.js.map +1 -1
- package/out-tsc/test/temba-contact-history.test.js +2 -2
- package/out-tsc/test/temba-contact-history.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/contacts/history-expanded.png +0 -0
- package/screenshots/truth/contacts/history.png +0 -0
- package/screenshots/truth/list/items-selected.png +0 -0
- package/screenshots/truth/list/items-updated.png +0 -0
- package/screenshots/truth/list/items.png +0 -0
- package/screenshots/truth/modax/simple.png +0 -0
- package/screenshots/truth/options/block.png +0 -0
- package/screenshots/truth/select/disabled-multi-selection.png +0 -0
- package/screenshots/truth/select/disabled-selection.png +0 -0
- package/screenshots/truth/select/disabled.png +0 -0
- package/screenshots/truth/select/embedded.png +0 -0
- package/screenshots/truth/select/expression-selected.png +0 -0
- package/screenshots/truth/select/expressions.png +0 -0
- package/screenshots/truth/select/functions.png +0 -0
- package/screenshots/truth/select/local-options.png +0 -0
- package/screenshots/truth/select/remote-options.png +0 -0
- package/screenshots/truth/select/search-enabled.png +0 -0
- package/screenshots/truth/select/search-multi-no-matches.png +0 -0
- package/screenshots/truth/select/search-selected-focus.png +0 -0
- package/screenshots/truth/select/search-selected.png +0 -0
- package/screenshots/truth/select/search-with-selected.png +0 -0
- package/screenshots/truth/select/searching.png +0 -0
- package/screenshots/truth/select/selected-multi.png +0 -0
- package/screenshots/truth/select/selected-single.png +0 -0
- package/screenshots/truth/select/with-placeholder.png +0 -0
- package/screenshots/truth/select/without-placeholder.png +0 -0
- package/screenshots/truth/textinput/date-form.png +0 -0
- package/screenshots/truth/textinput/input-disabled.png +0 -0
- package/screenshots/truth/textinput/input-form.png +0 -0
- package/screenshots/truth/textinput/input-placeholder.png +0 -0
- package/screenshots/truth/textinput/input-updated.png +0 -0
- package/screenshots/truth/textinput/input.png +0 -0
- package/screenshots/truth/textinput/textarea.png +0 -0
- package/screenshots/truth/tip/bottom.png +0 -0
- package/screenshots/truth/tip/left.png +0 -0
- package/screenshots/truth/tip/right.png +0 -0
- package/screenshots/truth/tip/top.png +0 -0
- package/src/button/Button.ts +1 -0
- package/src/contacts/ContactChat.ts +93 -33
- package/src/contacts/ContactDetails.ts +23 -23
- package/src/contacts/ContactHistory.ts +157 -160
- package/src/contacts/events.ts +117 -48
- package/src/interfaces.ts +3 -0
- package/src/list/ContactList.ts +39 -20
- package/src/list/TembaList.ts +13 -4
- package/src/list/TembaMenu.ts +7 -2
- package/src/loading/Loading.ts +8 -1
- package/src/options/Options.ts +14 -2
- package/src/select/Select.ts +28 -6
- package/src/tip/Tip.ts +6 -0
- package/src/vectoricon/VectorIcon.ts +17 -5
- package/test/temba-contact-history.test.ts +2 -2
- package/test-assets/style.css +4 -1
- package/dist/228cf25e.js +0 -1
|
@@ -10,18 +10,16 @@ export class ContactDetails extends RapidElement {
|
|
|
10
10
|
static get styles() {
|
|
11
11
|
return css`
|
|
12
12
|
:host {
|
|
13
|
-
box-shadow: inset 14px 0 7px -14px rgba(0, 0, 0, 0.15);
|
|
14
13
|
background: #f9f9f9;
|
|
15
14
|
display: block;
|
|
16
15
|
height: 100%;
|
|
17
16
|
position: relative;
|
|
18
|
-
border-bottom-right-radius: var(--curvature);
|
|
19
17
|
overflow: hidden;
|
|
18
|
+
-webkit-mask-image: -webkit-radial-gradient(white, black);
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
.wrapper {
|
|
23
|
-
padding
|
|
24
|
-
padding-left: 1em;
|
|
22
|
+
padding: 0em 1em;
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
a {
|
|
@@ -33,9 +31,9 @@ export class ContactDetails extends RapidElement {
|
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
.contact > .name {
|
|
36
|
-
font-size:
|
|
34
|
+
font-size: 1.2em;
|
|
37
35
|
font-weight: 400;
|
|
38
|
-
padding: 0.75em;
|
|
36
|
+
padding: 0.5em 0.75em;
|
|
39
37
|
padding-right: 1em;
|
|
40
38
|
}
|
|
41
39
|
|
|
@@ -82,12 +80,9 @@ export class ContactDetails extends RapidElement {
|
|
|
82
80
|
}
|
|
83
81
|
|
|
84
82
|
.fields-wrapper {
|
|
85
|
-
margin-top: 1em;
|
|
86
83
|
background: #fff;
|
|
87
|
-
border-radius: var(--curvature);
|
|
88
84
|
overflow: hidden;
|
|
89
|
-
|
|
90
|
-
0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
|
85
|
+
margin: 0em -1em;
|
|
91
86
|
}
|
|
92
87
|
|
|
93
88
|
.body-wrapper {
|
|
@@ -102,9 +97,7 @@ export class ContactDetails extends RapidElement {
|
|
|
102
97
|
.fields {
|
|
103
98
|
padding: 1em;
|
|
104
99
|
max-height: 200px;
|
|
105
|
-
border-radius: var(--curvature);
|
|
106
100
|
overflow-y: auto;
|
|
107
|
-
-webkit-mask-image: -webkit-radial-gradient(white, black);
|
|
108
101
|
}
|
|
109
102
|
|
|
110
103
|
.field {
|
|
@@ -142,7 +135,7 @@ export class ContactDetails extends RapidElement {
|
|
|
142
135
|
@property({ type: String })
|
|
143
136
|
uuid: string;
|
|
144
137
|
|
|
145
|
-
@property({
|
|
138
|
+
@property({ type: Object })
|
|
146
139
|
contact: Contact;
|
|
147
140
|
|
|
148
141
|
@property({ attribute: false })
|
|
@@ -172,14 +165,10 @@ export class ContactDetails extends RapidElement {
|
|
|
172
165
|
|
|
173
166
|
public updated(changes: Map<string, any>) {
|
|
174
167
|
super.updated(changes);
|
|
175
|
-
if (changes.has('endpoint')) {
|
|
176
|
-
this.flow = null;
|
|
177
|
-
this.expandFields = false;
|
|
178
168
|
|
|
169
|
+
if (changes.has('contact')) {
|
|
179
170
|
const store: Store = document.querySelector('temba-store');
|
|
180
|
-
|
|
181
|
-
fetchContact(this.endpoint).then((contact: Contact) => {
|
|
182
|
-
this.contact = contact;
|
|
171
|
+
if (this.contact && this.contact.fields) {
|
|
183
172
|
this.fields = Object.keys(this.contact.fields).filter((key: string) => {
|
|
184
173
|
const hasField = !!this.contact.fields[key];
|
|
185
174
|
return hasField && store.getContactField(key).pinned;
|
|
@@ -198,6 +187,14 @@ export class ContactDetails extends RapidElement {
|
|
|
198
187
|
}
|
|
199
188
|
return a.name.localeCompare(b.name);
|
|
200
189
|
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (changes.has('endpoint')) {
|
|
194
|
+
this.flow = null;
|
|
195
|
+
this.expandFields = false;
|
|
196
|
+
fetchContact(this.endpoint).then((contact: Contact) => {
|
|
197
|
+
this.contact = contact;
|
|
201
198
|
});
|
|
202
199
|
}
|
|
203
200
|
}
|
|
@@ -237,9 +234,9 @@ export class ContactDetails extends RapidElement {
|
|
|
237
234
|
|
|
238
235
|
if (this.contact) {
|
|
239
236
|
return html`<div class="contact">
|
|
240
|
-
<div class="name"
|
|
241
|
-
|
|
242
|
-
${this.showGroups
|
|
237
|
+
<div class="name">
|
|
238
|
+
${this.name || this.contact.name}
|
|
239
|
+
${this.showGroups && !this.ticket
|
|
243
240
|
? html`<div>
|
|
244
241
|
${this.contact.groups.map((group: Group) => {
|
|
245
242
|
return html`<a
|
|
@@ -254,6 +251,8 @@ export class ContactDetails extends RapidElement {
|
|
|
254
251
|
})}
|
|
255
252
|
</div>`
|
|
256
253
|
: html``}
|
|
254
|
+
</div>
|
|
255
|
+
<div class="wrapper">
|
|
257
256
|
${body
|
|
258
257
|
? html`<div class="body-wrapper">
|
|
259
258
|
<div class="body">${body}</div>
|
|
@@ -306,13 +305,14 @@ export class ContactDetails extends RapidElement {
|
|
|
306
305
|
: null}
|
|
307
306
|
|
|
308
307
|
<div class="actions">
|
|
309
|
-
${this.showGroups
|
|
308
|
+
${this.showGroups && !this.ticket
|
|
310
309
|
? html`
|
|
311
310
|
<div class="start-flow">
|
|
312
311
|
<temba-select
|
|
313
312
|
endpoint="/api/v2/flows.json?archived=false"
|
|
314
313
|
placeholder="Start Flow"
|
|
315
314
|
flavor="small"
|
|
315
|
+
searchable="true"
|
|
316
316
|
.values=${this.flow ? [this.flow] : []}
|
|
317
317
|
@temba-selection=${this.handleFlowChanged}
|
|
318
318
|
></temba-select>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/camelcase */
|
|
2
2
|
import { css, property } from 'lit-element';
|
|
3
3
|
import { html, TemplateResult } from 'lit-html';
|
|
4
|
-
import { CustomEventType, Ticket } from '../interfaces';
|
|
4
|
+
import { Contact, CustomEventType, Ticket } from '../interfaces';
|
|
5
5
|
import { RapidElement } from '../RapidElement';
|
|
6
6
|
import { Asset, getAssets, getClasses, postJSON, throttle } from '../utils';
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
import {
|
|
9
9
|
AirtimeTransferredEvent,
|
|
10
10
|
CampaignFiredEvent,
|
|
@@ -56,9 +56,39 @@ import {
|
|
|
56
56
|
SCROLL_THRESHOLD,
|
|
57
57
|
} from './helpers';
|
|
58
58
|
|
|
59
|
+
// when images load, make sure we are on the bottom of the scroll window if necessary
|
|
60
|
+
export const loadHandler = function (event) {
|
|
61
|
+
const target = event.target as HTMLElement;
|
|
62
|
+
const events = this.host.getEventsPane();
|
|
63
|
+
if (target.tagName == 'IMG') {
|
|
64
|
+
if (!this.host.showMessageAlert) {
|
|
65
|
+
if (
|
|
66
|
+
events.scrollTop > target.offsetTop - 1000 &&
|
|
67
|
+
target.offsetTop > events.scrollHeight - 500
|
|
68
|
+
) {
|
|
69
|
+
this.host.scrollToBottom();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
59
75
|
export class ContactHistory extends RapidElement {
|
|
60
76
|
public httpComplete: Promise<void | ContactHistoryPage>;
|
|
61
77
|
|
|
78
|
+
public constructor() {
|
|
79
|
+
super();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
connectedCallback() {
|
|
83
|
+
super.connectedCallback();
|
|
84
|
+
this.shadowRoot.addEventListener('load', loadHandler, true);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
disconnectedCallback() {
|
|
88
|
+
super.disconnectedCallback();
|
|
89
|
+
this.shadowRoot.removeEventListener('load', loadHandler, true);
|
|
90
|
+
}
|
|
91
|
+
|
|
62
92
|
private getStickyId = (event: ContactEvent) => {
|
|
63
93
|
if (event.type === Events.TICKET_OPENED) {
|
|
64
94
|
const ticket = this.getTicketForEvent(event as TicketEvent);
|
|
@@ -95,6 +125,7 @@ export class ContactHistory extends RapidElement {
|
|
|
95
125
|
flex-grow: 1;
|
|
96
126
|
border-top-left-radius: var(--curvature);
|
|
97
127
|
padding-top: 1em;
|
|
128
|
+
background: #fff;
|
|
98
129
|
}
|
|
99
130
|
|
|
100
131
|
temba-loading {
|
|
@@ -135,15 +166,27 @@ export class ContactHistory extends RapidElement {
|
|
|
135
166
|
pointer: cursor;
|
|
136
167
|
}
|
|
137
168
|
|
|
169
|
+
.scroll-title {
|
|
170
|
+
display: flex;
|
|
171
|
+
flex-direction: column;
|
|
172
|
+
z-index: 2;
|
|
173
|
+
border-top-left-radius: var(--curvature);
|
|
174
|
+
overflow: hidden;
|
|
175
|
+
box-shadow: 0px 3px 3px 0px rgba(0, 0, 0, 0.15);
|
|
176
|
+
background: rgb(240, 240, 240);
|
|
177
|
+
padding: 1em 1.2em;
|
|
178
|
+
font-size: 1.2em;
|
|
179
|
+
font-weight: 400;
|
|
180
|
+
}
|
|
181
|
+
|
|
138
182
|
.sticky-bin {
|
|
139
183
|
display: flex;
|
|
140
184
|
flex-direction: column;
|
|
141
|
-
position: fixed;
|
|
142
185
|
z-index: 2;
|
|
143
186
|
border-top-left-radius: var(--curvature);
|
|
144
187
|
overflow: hidden;
|
|
145
|
-
background: rgba(240, 240, 240, 0.95);
|
|
146
188
|
box-shadow: 0px 3px 3px 0px rgba(0, 0, 0, 0.15);
|
|
189
|
+
background: rgb(240, 240, 240);
|
|
147
190
|
}
|
|
148
191
|
|
|
149
192
|
.sticky-bin temba-icon {
|
|
@@ -183,6 +226,9 @@ export class ContactHistory extends RapidElement {
|
|
|
183
226
|
`;
|
|
184
227
|
}
|
|
185
228
|
|
|
229
|
+
@property({ type: Object })
|
|
230
|
+
contact: Contact;
|
|
231
|
+
|
|
186
232
|
@property({ type: String })
|
|
187
233
|
uuid: string;
|
|
188
234
|
|
|
@@ -222,9 +268,6 @@ export class ContactHistory extends RapidElement {
|
|
|
222
268
|
@property({ type: Array })
|
|
223
269
|
tickets: Ticket[] = null;
|
|
224
270
|
|
|
225
|
-
@property({ type: Object })
|
|
226
|
-
currentTicket: Ticket = null;
|
|
227
|
-
|
|
228
271
|
ticketEvents: { [uuid: string]: TicketEvent } = {};
|
|
229
272
|
|
|
230
273
|
nextBefore: number;
|
|
@@ -236,35 +279,23 @@ export class ContactHistory extends RapidElement {
|
|
|
236
279
|
|
|
237
280
|
public firstUpdated(changedProperties: Map<string, any>) {
|
|
238
281
|
super.firstUpdated(changedProperties);
|
|
239
|
-
|
|
240
282
|
this.handleClose = this.handleClose.bind(this);
|
|
241
|
-
|
|
242
|
-
const stickyBin = this.getDiv('.sticky-bin');
|
|
243
|
-
const resizer = new ResizeObserver(entries => {
|
|
244
|
-
for (const entry of entries) {
|
|
245
|
-
const eventContainer = entry.contentRect;
|
|
246
|
-
stickyBin.style.width =
|
|
247
|
-
eventContainer.width + eventContainer.left - 16 + 'px';
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
resizer.observe(this);
|
|
251
283
|
}
|
|
252
284
|
|
|
253
285
|
public updated(changedProperties: Map<string, any>) {
|
|
254
286
|
super.updated(changedProperties);
|
|
255
287
|
|
|
256
|
-
// fire an event when our current ticket changes
|
|
257
|
-
if (changedProperties.has('currentTicket')) {
|
|
258
|
-
this.fireCustomEvent(CustomEventType.ContextChanged, {
|
|
259
|
-
context: this.currentTicket,
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
|
|
263
288
|
// fire an event if we get a new event
|
|
264
289
|
if (changedProperties.has('mostRecentEvent')) {
|
|
265
290
|
this.fireCustomEvent(CustomEventType.Refreshed);
|
|
266
291
|
}
|
|
267
292
|
|
|
293
|
+
if (changedProperties.has('endDate')) {
|
|
294
|
+
if (this.refreshTimeout && this.endDate) {
|
|
295
|
+
window.clearTimeout(this.refreshTimeout);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
268
299
|
// if we don't have an endpoint infer one
|
|
269
300
|
if (changedProperties.has('uuid')) {
|
|
270
301
|
if (this.uuid == null) {
|
|
@@ -294,7 +325,8 @@ export class ContactHistory extends RapidElement {
|
|
|
294
325
|
if (
|
|
295
326
|
changedProperties.has('refreshing') &&
|
|
296
327
|
this.refreshing &&
|
|
297
|
-
this.endpoint
|
|
328
|
+
this.endpoint &&
|
|
329
|
+
!this.endDate
|
|
298
330
|
) {
|
|
299
331
|
const after = (this.getLastEventTime() - 1) * 1000;
|
|
300
332
|
let forceOpen = false;
|
|
@@ -488,30 +520,20 @@ export class ContactHistory extends RapidElement {
|
|
|
488
520
|
stickyBin.removeChild(child);
|
|
489
521
|
}
|
|
490
522
|
}
|
|
491
|
-
if (!this.currentTicket) {
|
|
492
|
-
this.updateCurrentTicket();
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
private updateCurrentTicket() {
|
|
498
|
-
const openTickets = (this.tickets || []).filter(
|
|
499
|
-
ticket => ticket && ticket.status === 'open'
|
|
500
|
-
);
|
|
501
|
-
if (openTickets.length > 0) {
|
|
502
|
-
this.currentTicket = openTickets[openTickets.length - 1];
|
|
503
523
|
}
|
|
504
524
|
}
|
|
505
525
|
|
|
506
526
|
private refreshTickets() {
|
|
507
|
-
let url = `/api/v2/tickets.json?contact=${this.uuid}`;
|
|
508
527
|
if (this.ticket) {
|
|
509
|
-
url =
|
|
510
|
-
|
|
528
|
+
let url = `/api/v2/tickets.json?contact=${this.uuid}`;
|
|
529
|
+
if (this.ticket) {
|
|
530
|
+
url = `${url}&ticket=${this.ticket}`;
|
|
531
|
+
}
|
|
511
532
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
533
|
+
getAssets(url).then((tickets: Ticket[]) => {
|
|
534
|
+
this.tickets = tickets.reverse();
|
|
535
|
+
});
|
|
536
|
+
}
|
|
515
537
|
}
|
|
516
538
|
|
|
517
539
|
public getEventsPane() {
|
|
@@ -568,6 +590,10 @@ export class ContactHistory extends RapidElement {
|
|
|
568
590
|
}
|
|
569
591
|
|
|
570
592
|
private scheduleRefresh(wait = -1) {
|
|
593
|
+
if (this.endDate) {
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
|
|
571
597
|
let refreshWait = wait;
|
|
572
598
|
|
|
573
599
|
if (wait === -1) {
|
|
@@ -596,11 +622,12 @@ export class ContactHistory extends RapidElement {
|
|
|
596
622
|
private reset() {
|
|
597
623
|
// clear out our sticky bin which we manipulated manually
|
|
598
624
|
const stickyBin = this.getDiv('.sticky-bin');
|
|
599
|
-
|
|
600
|
-
|
|
625
|
+
if (stickyBin) {
|
|
626
|
+
while (stickyBin.childElementCount > 0) {
|
|
627
|
+
stickyBin.removeChild(stickyBin.firstElementChild);
|
|
628
|
+
}
|
|
601
629
|
}
|
|
602
630
|
|
|
603
|
-
this.currentTicket = null;
|
|
604
631
|
this.endpoint = null;
|
|
605
632
|
this.tickets = null;
|
|
606
633
|
this.ticketEvents = {};
|
|
@@ -657,43 +684,12 @@ export class ContactHistory extends RapidElement {
|
|
|
657
684
|
sticky.classList.add('pinned');
|
|
658
685
|
(sticky as any).eventElement = eventElement;
|
|
659
686
|
stickyBin.appendChild(eventElement);
|
|
660
|
-
const uuid = eventElement.getAttribute('data-sticky-id');
|
|
661
|
-
const ticket = this.getTicket(uuid);
|
|
662
|
-
if (ticket) {
|
|
663
|
-
if (
|
|
664
|
-
!this.currentTicket ||
|
|
665
|
-
this.currentTicket.uuid !== ticket.uuid
|
|
666
|
-
) {
|
|
667
|
-
this.currentTicket = ticket;
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
687
|
}
|
|
671
688
|
} else {
|
|
672
689
|
const eventElement = (sticky as any).eventElement;
|
|
673
690
|
if (scrollBoundary < sticky.offsetTop + sticky.offsetHeight) {
|
|
674
691
|
sticky.appendChild(eventElement);
|
|
675
692
|
sticky.classList.remove('pinned');
|
|
676
|
-
|
|
677
|
-
const uuid = eventElement.getAttribute('data-sticky-id');
|
|
678
|
-
let previousTicket: Ticket = null;
|
|
679
|
-
for (const ticket of this.tickets) {
|
|
680
|
-
if (ticket.uuid === uuid) {
|
|
681
|
-
break;
|
|
682
|
-
}
|
|
683
|
-
previousTicket = ticket;
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
if (
|
|
687
|
-
previousTicket &&
|
|
688
|
-
(!this.currentTicket ||
|
|
689
|
-
this.currentTicket.uuid !== previousTicket.uuid)
|
|
690
|
-
) {
|
|
691
|
-
if (previousTicket.status === 'open') {
|
|
692
|
-
this.currentTicket = previousTicket;
|
|
693
|
-
} else {
|
|
694
|
-
this.currentTicket = null;
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
693
|
}
|
|
698
694
|
}
|
|
699
695
|
});
|
|
@@ -765,7 +761,7 @@ export class ContactHistory extends RapidElement {
|
|
|
765
761
|
if (activeTicket && ticket && ticket.status === 'open') {
|
|
766
762
|
closeHandler = this.handleClose;
|
|
767
763
|
}
|
|
768
|
-
return renderTicketOpened(ticketEvent, closeHandler);
|
|
764
|
+
return renderTicketOpened(ticketEvent, closeHandler, !this.ticket);
|
|
769
765
|
}
|
|
770
766
|
case Events.TICKET_NOTE_ADDED:
|
|
771
767
|
return renderNoteCreated(event as TicketEvent, this.agent);
|
|
@@ -773,10 +769,14 @@ export class ContactHistory extends RapidElement {
|
|
|
773
769
|
case Events.TICKET_ASSIGNED:
|
|
774
770
|
return renderTicketAssigned(event as TicketEvent);
|
|
775
771
|
case Events.TICKET_REOPENED: {
|
|
776
|
-
return renderTicketAction(
|
|
772
|
+
return renderTicketAction(
|
|
773
|
+
event as TicketEvent,
|
|
774
|
+
'reopened',
|
|
775
|
+
!this.ticket
|
|
776
|
+
);
|
|
777
777
|
}
|
|
778
778
|
case Events.TICKET_CLOSED:
|
|
779
|
-
return renderTicketAction(event as TicketEvent, 'closed');
|
|
779
|
+
return renderTicketAction(event as TicketEvent, 'closed', !this.ticket);
|
|
780
780
|
|
|
781
781
|
case Events.ERROR:
|
|
782
782
|
case Events.FAILURE:
|
|
@@ -816,7 +816,6 @@ export class ContactHistory extends RapidElement {
|
|
|
816
816
|
this.fireCustomEvent(CustomEventType.ContentChanged, {
|
|
817
817
|
ticket: { uuid, status: 'closed' },
|
|
818
818
|
});
|
|
819
|
-
this.updateCurrentTicket();
|
|
820
819
|
})
|
|
821
820
|
.catch((response: any) => {
|
|
822
821
|
console.error(response);
|
|
@@ -824,24 +823,22 @@ export class ContactHistory extends RapidElement {
|
|
|
824
823
|
}
|
|
825
824
|
|
|
826
825
|
public checkForAgentAssignmentEvent(agent: number) {
|
|
827
|
-
|
|
828
|
-
this.
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
this.
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
this.
|
|
839
|
-
|
|
840
|
-
});
|
|
841
|
-
}
|
|
826
|
+
this.httpComplete = getAssets(
|
|
827
|
+
`/api/v2/tickets.json?ticket=${this.ticket}`
|
|
828
|
+
).then((assets: Asset[]) => {
|
|
829
|
+
if (assets.length === 1) {
|
|
830
|
+
const ticket = assets[0] as Ticket;
|
|
831
|
+
if (ticket.assignee && ticket.assignee.id === agent) {
|
|
832
|
+
this.fireCustomEvent(CustomEventType.ContentChanged, {
|
|
833
|
+
ticket: { uuid: this.ticket, assigned: 'self' },
|
|
834
|
+
});
|
|
835
|
+
} else {
|
|
836
|
+
this.fireCustomEvent(CustomEventType.ContentChanged, {
|
|
837
|
+
ticket: { uuid: this.ticket, assigned: 'other' },
|
|
838
|
+
});
|
|
842
839
|
}
|
|
843
|
-
}
|
|
844
|
-
}
|
|
840
|
+
}
|
|
841
|
+
});
|
|
845
842
|
}
|
|
846
843
|
|
|
847
844
|
public getEventHandlers() {
|
|
@@ -864,7 +861,9 @@ export class ContactHistory extends RapidElement {
|
|
|
864
861
|
|
|
865
862
|
const renderedEvent = html`
|
|
866
863
|
<div
|
|
867
|
-
class="
|
|
864
|
+
class="${this.ticket
|
|
865
|
+
? 'active-ticket'
|
|
866
|
+
: ''} event ${event.type} ${isSticky ? 'has-sticky' : ''}"
|
|
868
867
|
data-sticky-id="${stickyId}"
|
|
869
868
|
>
|
|
870
869
|
${this.renderEvent(event)}
|
|
@@ -891,7 +890,7 @@ export class ContactHistory extends RapidElement {
|
|
|
891
890
|
type: Events.TICKET_OPENED,
|
|
892
891
|
ticket: {
|
|
893
892
|
uuid: ticket.uuid,
|
|
894
|
-
|
|
893
|
+
topic: ticket.topic,
|
|
895
894
|
body: ticket.body,
|
|
896
895
|
ticketer: ticket.ticketer,
|
|
897
896
|
},
|
|
@@ -901,7 +900,8 @@ export class ContactHistory extends RapidElement {
|
|
|
901
900
|
|
|
902
901
|
const renderedEvent = renderTicketOpened(
|
|
903
902
|
ticketOpenedEvent,
|
|
904
|
-
this.handleClose
|
|
903
|
+
this.handleClose,
|
|
904
|
+
!this.ticket
|
|
905
905
|
);
|
|
906
906
|
return html`<div class="event ticket_opened">
|
|
907
907
|
${renderedEvent}
|
|
@@ -912,68 +912,65 @@ export class ContactHistory extends RapidElement {
|
|
|
912
912
|
: null;
|
|
913
913
|
|
|
914
914
|
return html`
|
|
915
|
-
|
|
915
|
+
${this.ticket
|
|
916
|
+
? html`<div class="sticky-bin">${unfetchedTickets}</div>`
|
|
917
|
+
: this.contact
|
|
918
|
+
? html`<div class="scroll-title">${this.contact.name}</div>`
|
|
919
|
+
: null}
|
|
916
920
|
${this.fetching
|
|
917
921
|
? html`<temba-loading units="5" size="10"></temba-loading>`
|
|
918
922
|
: html`<div style="height:0em"></div>`}
|
|
919
923
|
<div class="events" @scroll=${this.handleScroll}>
|
|
920
|
-
${this.
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
} else {
|
|
971
|
-
return this.renderEventContainer(event);
|
|
972
|
-
}
|
|
973
|
-
})}
|
|
974
|
-
</div>`;
|
|
975
|
-
})
|
|
976
|
-
: null}
|
|
924
|
+
${this.eventGroups.map((eventGroup: EventGroup, index: number) => {
|
|
925
|
+
const grouping = getEventGroupType(eventGroup.events[0], this.ticket);
|
|
926
|
+
const groupIndex = this.eventGroups.length - index - 1;
|
|
927
|
+
|
|
928
|
+
const classes = getClasses({
|
|
929
|
+
grouping: true,
|
|
930
|
+
[grouping]: true,
|
|
931
|
+
expanded: eventGroup.open,
|
|
932
|
+
closing: eventGroup.closing,
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
return html`<div class="${classes}">
|
|
936
|
+
${grouping === 'verbose'
|
|
937
|
+
? html`<div
|
|
938
|
+
class="event-count"
|
|
939
|
+
@click=${this.handleEventGroupShow}
|
|
940
|
+
data-group-index="${groupIndex}"
|
|
941
|
+
>
|
|
942
|
+
${eventGroup.events.length}
|
|
943
|
+
${eventGroup.events.length === 1 ? html`event` : html`events`}
|
|
944
|
+
</div>`
|
|
945
|
+
: null}
|
|
946
|
+
${grouping === 'verbose'
|
|
947
|
+
? html`
|
|
948
|
+
<temba-icon
|
|
949
|
+
@click=${this.handleEventGroupHide}
|
|
950
|
+
data-group-index="${groupIndex}"
|
|
951
|
+
class="grouping-close-button"
|
|
952
|
+
name="x"
|
|
953
|
+
clickable
|
|
954
|
+
></temba-icon>
|
|
955
|
+
`
|
|
956
|
+
: null}
|
|
957
|
+
${eventGroup.events.map((event: ContactEvent) => {
|
|
958
|
+
if (
|
|
959
|
+
event.type === Events.TICKET_ASSIGNED &&
|
|
960
|
+
(event as TicketEvent).note
|
|
961
|
+
) {
|
|
962
|
+
const noteEvent = { ...event };
|
|
963
|
+
noteEvent.type = Events.TICKET_NOTE_ADDED;
|
|
964
|
+
|
|
965
|
+
return html`${this.renderEventContainer(
|
|
966
|
+
noteEvent
|
|
967
|
+
)}${this.renderEventContainer(event)}`;
|
|
968
|
+
} else {
|
|
969
|
+
return this.renderEventContainer(event);
|
|
970
|
+
}
|
|
971
|
+
})}
|
|
972
|
+
</div>`;
|
|
973
|
+
})}
|
|
977
974
|
</div>
|
|
978
975
|
|
|
979
976
|
<div class="new-messages-container">
|