@nyaruka/temba-components 0.17.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 +9 -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 +131 -138
- package/out-tsc/src/contacts/ContactHistory.js.map +1 -1
- package/out-tsc/src/contacts/events.js +55 -44
- 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 +1 -1
- 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/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 +156 -159
- package/src/contacts/events.ts +59 -44
- package/src/interfaces.ts +1 -1
- package/src/list/ContactList.ts +1 -1
- 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/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/d59a9ae2.js +0 -1
|
@@ -6,6 +6,9 @@ import { TextInput } from '../textinput/TextInput';
|
|
|
6
6
|
import { Completion } from '../completion/Completion';
|
|
7
7
|
import { ContactHistory } from './ContactHistory';
|
|
8
8
|
import { Modax } from '../dialog/Modax';
|
|
9
|
+
import { fetchContact } from './helpers';
|
|
10
|
+
|
|
11
|
+
const DEFAULT_REFRESH = 10000;
|
|
9
12
|
|
|
10
13
|
export class ContactChat extends RapidElement {
|
|
11
14
|
public static get styles() {
|
|
@@ -24,13 +27,16 @@ export class ContactChat extends RapidElement {
|
|
|
24
27
|
overflow: hidden;
|
|
25
28
|
}
|
|
26
29
|
|
|
30
|
+
.left-pane {
|
|
31
|
+
box-shadow: -13px 10px 7px 14px rgba(0, 0, 0, 0.15);
|
|
32
|
+
z-index: 100;
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
.chat-wrapper {
|
|
28
36
|
display: flex;
|
|
29
37
|
flex-direction: column;
|
|
30
38
|
height: 100%;
|
|
31
|
-
background: #fff;
|
|
32
39
|
overflow: hidden;
|
|
33
|
-
border-radius: var(--curvature);
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
.chatbox {
|
|
@@ -79,11 +85,10 @@ export class ContactChat extends RapidElement {
|
|
|
79
85
|
|
|
80
86
|
.toolbar {
|
|
81
87
|
position: relative;
|
|
82
|
-
width:
|
|
83
|
-
background: #
|
|
88
|
+
width: 2.5em;
|
|
89
|
+
background: #e6e6e6;
|
|
84
90
|
transition: all 600ms ease-in;
|
|
85
91
|
z-index: 10;
|
|
86
|
-
box-shadow: -1px 0px 6px 1px rgba(0, 0, 0, 0.1);
|
|
87
92
|
flex-shrink: 0;
|
|
88
93
|
border-top-right-radius: var(--curvature);
|
|
89
94
|
border-bottom-right-radius: var(--curvature);
|
|
@@ -100,7 +105,8 @@ export class ContactChat extends RapidElement {
|
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
.toolbar.closed {
|
|
103
|
-
box-shadow:
|
|
108
|
+
box-shadow: inset 10px 0px 10px -11px rgb(0 0 0 / 15%);
|
|
109
|
+
z-index: 1000;
|
|
104
110
|
}
|
|
105
111
|
|
|
106
112
|
temba-contact-details {
|
|
@@ -110,8 +116,6 @@ export class ContactChat extends RapidElement {
|
|
|
110
116
|
transition: margin 600ms cubic-bezier(0.68, -0.55, 0.265, 1.05),
|
|
111
117
|
opacity 600ms ease-in-out 200ms;
|
|
112
118
|
z-index: 5;
|
|
113
|
-
margin-right: -1.5em;
|
|
114
|
-
border-top-right-radius: 6px;
|
|
115
119
|
}
|
|
116
120
|
|
|
117
121
|
temba-contact-details.hidden {
|
|
@@ -149,8 +153,11 @@ export class ContactChat extends RapidElement {
|
|
|
149
153
|
`;
|
|
150
154
|
}
|
|
151
155
|
|
|
152
|
-
@property({ type:
|
|
153
|
-
|
|
156
|
+
@property({ type: String, attribute: 'contact' })
|
|
157
|
+
contactUUID: string;
|
|
158
|
+
|
|
159
|
+
@property({ type: String, attribute: 'ticket' })
|
|
160
|
+
ticketUUID: string;
|
|
154
161
|
|
|
155
162
|
@property({ type: String })
|
|
156
163
|
contactsEndpoint = '/api/v2/contacts.json';
|
|
@@ -164,9 +171,15 @@ export class ContactChat extends RapidElement {
|
|
|
164
171
|
@property({ type: Boolean })
|
|
165
172
|
showDetails = true;
|
|
166
173
|
|
|
174
|
+
@property({ type: Boolean })
|
|
175
|
+
monitor = false;
|
|
176
|
+
|
|
167
177
|
@property({ type: Object })
|
|
168
178
|
currentTicket: Ticket = null;
|
|
169
179
|
|
|
180
|
+
@property({ type: Object })
|
|
181
|
+
currentContact: Contact = null;
|
|
182
|
+
|
|
170
183
|
@property({ type: Number })
|
|
171
184
|
agent = -1;
|
|
172
185
|
|
|
@@ -175,6 +188,26 @@ export class ContactChat extends RapidElement {
|
|
|
175
188
|
this.showDetails = getCookieBoolean(COOKIE_KEYS.TICKET_SHOW_DETAILS);
|
|
176
189
|
}
|
|
177
190
|
|
|
191
|
+
refreshInterval = null;
|
|
192
|
+
|
|
193
|
+
public connectedCallback() {
|
|
194
|
+
super.connectedCallback();
|
|
195
|
+
if (this.monitor) {
|
|
196
|
+
this.refreshInterval = setInterval(() => {
|
|
197
|
+
if (this.currentTicket && this.currentTicket.closed_on) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
this.refresh();
|
|
201
|
+
}, DEFAULT_REFRESH);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
public disconnectedCallback() {
|
|
206
|
+
if (this.refreshInterval) {
|
|
207
|
+
clearInterval(this.refreshInterval);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
178
211
|
public getContactHistory(): ContactHistory {
|
|
179
212
|
return this.shadowRoot.querySelector(
|
|
180
213
|
'temba-contact-history'
|
|
@@ -194,13 +227,36 @@ export class ContactChat extends RapidElement {
|
|
|
194
227
|
public updated(changedProperties: Map<string, any>) {
|
|
195
228
|
super.updated(changedProperties);
|
|
196
229
|
|
|
230
|
+
/* if (changedProperties.has('currentTicket')) {
|
|
231
|
+
console.log('currentTicket', this.currentTicket);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (changedProperties.has('currentContact')) {
|
|
235
|
+
console.log('currentContact', this.currentContact);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (changedProperties.has('contactUUID')) {
|
|
239
|
+
console.log('contactUUID', this.contactUUID);
|
|
240
|
+
}*/
|
|
241
|
+
|
|
242
|
+
// we were provided a uuid, fetch our contact details
|
|
243
|
+
if (changedProperties.has('contactUUID')) {
|
|
244
|
+
fetchContact(this.contactsEndpoint + '?uuid=' + this.contactUUID).then(
|
|
245
|
+
contact => {
|
|
246
|
+
this.currentContact = contact;
|
|
247
|
+
}
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
197
251
|
// if we don't have an endpoint infer one
|
|
198
|
-
if (changedProperties.has('
|
|
252
|
+
if (changedProperties.has('currentContact')) {
|
|
199
253
|
// focus our completion on load
|
|
200
254
|
const prevContact = changedProperties.get('contact');
|
|
201
255
|
if (
|
|
202
256
|
!prevContact ||
|
|
203
|
-
(this.
|
|
257
|
+
(this.currentContact &&
|
|
258
|
+
this.currentContact.ticket &&
|
|
259
|
+
this.currentContact.ticket.uuid !== prevContact.ticket.uuid)
|
|
204
260
|
) {
|
|
205
261
|
const completion = this.shadowRoot.querySelector(
|
|
206
262
|
'temba-completion'
|
|
@@ -223,7 +279,7 @@ export class ContactChat extends RapidElement {
|
|
|
223
279
|
}
|
|
224
280
|
|
|
225
281
|
private handleReopen() {
|
|
226
|
-
const uuid = this.
|
|
282
|
+
const uuid = this.currentTicket.uuid;
|
|
227
283
|
postJSON(`/api/v2/tickets.json?uuid=${uuid}`, {
|
|
228
284
|
status: 'open',
|
|
229
285
|
})
|
|
@@ -239,11 +295,16 @@ export class ContactChat extends RapidElement {
|
|
|
239
295
|
}
|
|
240
296
|
|
|
241
297
|
private handleSend() {
|
|
242
|
-
|
|
243
|
-
contacts: [this.
|
|
298
|
+
const payload = {
|
|
299
|
+
contacts: [this.currentContact.uuid],
|
|
244
300
|
text: this.currentChat,
|
|
245
|
-
|
|
246
|
-
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
if (this.currentTicket) {
|
|
304
|
+
payload['ticket'] = this.currentTicket.uuid;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
postJSON(`/api/v2/broadcasts.json`, payload)
|
|
247
308
|
.then(() => {
|
|
248
309
|
this.currentChat = '';
|
|
249
310
|
this.refresh(true);
|
|
@@ -264,26 +325,26 @@ export class ContactChat extends RapidElement {
|
|
|
264
325
|
setCookie(COOKIE_KEYS.TICKET_SHOW_DETAILS, this.showDetails);
|
|
265
326
|
}
|
|
266
327
|
|
|
267
|
-
private handleCurrentTicketChanged(event: CustomEvent): void {
|
|
268
|
-
this.currentTicket = event.detail.context;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
328
|
public render(): TemplateResult {
|
|
272
329
|
return html`
|
|
273
330
|
<div style="display: flex; height: 100%;">
|
|
274
|
-
<div style="flex-grow: 1; margin-right: 0em;">
|
|
331
|
+
<div style="flex-grow: 1; margin-right: 0em;" class="left-pane">
|
|
275
332
|
<div class="chat-wrapper">
|
|
276
|
-
${this.
|
|
333
|
+
${this.currentContact
|
|
277
334
|
? html` <temba-contact-history
|
|
278
|
-
.uuid=${this.
|
|
279
|
-
.
|
|
280
|
-
.
|
|
335
|
+
.uuid=${this.currentContact.uuid}
|
|
336
|
+
.contact=${this.currentContact}
|
|
337
|
+
.ticket=${
|
|
338
|
+
this.currentTicket ? this.currentTicket.uuid : null
|
|
339
|
+
}
|
|
340
|
+
.endDate=${
|
|
341
|
+
this.currentTicket ? this.currentTicket.closed_on : null
|
|
342
|
+
}
|
|
281
343
|
.agent=${this.agent}
|
|
282
|
-
@temba-context-changed=${this.handleCurrentTicketChanged}
|
|
283
344
|
></temba-contact-history>
|
|
284
345
|
|
|
285
346
|
${
|
|
286
|
-
this.
|
|
347
|
+
this.currentTicket && this.currentTicket.closed_on
|
|
287
348
|
? html`<div class="closed-footer">
|
|
288
349
|
<temba-button
|
|
289
350
|
id="reopen-button"
|
|
@@ -320,20 +381,19 @@ export class ContactChat extends RapidElement {
|
|
|
320
381
|
: null}
|
|
321
382
|
</div>
|
|
322
383
|
</div>
|
|
323
|
-
${this.
|
|
384
|
+
${this.currentContact
|
|
324
385
|
? html`<temba-contact-details
|
|
325
386
|
style="z-index: 10"
|
|
326
387
|
class="${this.showDetails ? '' : 'hidden'}"
|
|
327
|
-
|
|
328
|
-
.name="${this.contact.name}"
|
|
388
|
+
showGroups="true"
|
|
329
389
|
.visible=${this.showDetails}
|
|
330
390
|
.ticket=${this.currentTicket}
|
|
331
|
-
|
|
391
|
+
.contact=${this.currentContact}
|
|
332
392
|
></temba-contact-details>`
|
|
333
393
|
: null}
|
|
334
394
|
|
|
335
395
|
<div class="toolbar ${this.showDetails ? '' : 'closed'}">
|
|
336
|
-
${this.
|
|
396
|
+
${this.currentContact
|
|
337
397
|
? html`
|
|
338
398
|
<temba-tip
|
|
339
399
|
style="margin-top:5px"
|
|
@@ -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>
|