@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.
- package/CHANGELOG.md +9 -0
- package/demo/index.html +1 -1
- package/dist/temba-components.js +760 -1189
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/chat/Chat.js +714 -0
- package/out-tsc/src/chat/Chat.js.map +1 -0
- package/out-tsc/src/completion/helpers.js +1 -29
- package/out-tsc/src/completion/helpers.js.map +1 -1
- package/out-tsc/src/compose/Compose.js +6 -2
- package/out-tsc/src/compose/Compose.js.map +1 -1
- package/out-tsc/src/contacts/ContactChat.js +518 -54
- package/out-tsc/src/contacts/ContactChat.js.map +1 -1
- package/out-tsc/src/contacts/events.js +1 -998
- package/out-tsc/src/contacts/events.js.map +1 -1
- package/out-tsc/src/lightbox/Lightbox.js +4 -0
- package/out-tsc/src/lightbox/Lightbox.js.map +1 -1
- package/out-tsc/src/list/TembaMenu.js +0 -1
- package/out-tsc/src/list/TembaMenu.js.map +1 -1
- package/out-tsc/src/markdown.js +33 -0
- package/out-tsc/src/markdown.js.map +1 -0
- package/out-tsc/src/select/Select.js +6 -1
- package/out-tsc/src/select/Select.js.map +1 -1
- package/out-tsc/src/textinput/TextInput.js +1 -1
- package/out-tsc/src/textinput/TextInput.js.map +1 -1
- package/out-tsc/src/thumbnail/Thumbnail.js +128 -81
- package/out-tsc/src/thumbnail/Thumbnail.js.map +1 -1
- package/out-tsc/src/utils/index.js +9 -11
- package/out-tsc/src/utils/index.js.map +1 -1
- package/out-tsc/src/webchat/WebChat.js +109 -358
- package/out-tsc/src/webchat/WebChat.js.map +1 -1
- package/out-tsc/src/webchat/index.js +17 -0
- package/out-tsc/src/webchat/index.js.map +1 -1
- package/out-tsc/temba-modules.js +2 -2
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/temba-webchat.js +2 -0
- package/out-tsc/temba-webchat.js.map +1 -1
- package/out-tsc/test/temba-contact-chat.test.js +1 -0
- package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
- package/out-tsc/test/temba-lightbox.test.js +4 -4
- package/out-tsc/test/temba-lightbox.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/contacts/compose-attachments-no-text-failure.png +0 -0
- package/screenshots/truth/contacts/compose-attachments-no-text-success.png +0 -0
- package/screenshots/truth/contacts/compose-text-and-attachments-failure-attachments.png +0 -0
- package/screenshots/truth/contacts/compose-text-and-attachments-failure-generic.png +0 -0
- package/screenshots/truth/contacts/compose-text-and-attachments-failure-text-and-attachments.png +0 -0
- package/screenshots/truth/contacts/compose-text-and-attachments-failure-text.png +0 -0
- package/screenshots/truth/contacts/compose-text-and-attachments-success.png +0 -0
- package/screenshots/truth/contacts/compose-text-no-attachments-failure.png +0 -0
- package/screenshots/truth/contacts/compose-text-no-attachments-success.png +0 -0
- package/screenshots/truth/contacts/contact-active-default.png +0 -0
- package/screenshots/truth/contacts/contact-active-show-chatbox.png +0 -0
- package/screenshots/truth/contacts/contact-archived-hide-chatbox.png +0 -0
- package/screenshots/truth/contacts/contact-blocked-hide-chatbox.png +0 -0
- package/screenshots/truth/contacts/contact-stopped-hide-chatbox.png +0 -0
- package/screenshots/truth/lightbox/img-zoomed.png +0 -0
- package/screenshots/truth/lightbox/img.png +0 -0
- package/src/chat/Chat.ts +791 -0
- package/src/completion/helpers.ts +2 -40
- package/src/compose/Compose.ts +6 -2
- package/src/contacts/ContactChat.ts +609 -59
- package/src/contacts/events.ts +1 -1068
- package/src/lightbox/Lightbox.ts +5 -0
- package/src/list/TembaMenu.ts +0 -1
- package/src/markdown.ts +41 -0
- package/src/select/Select.ts +5 -1
- package/src/textinput/TextInput.ts +1 -1
- package/src/thumbnail/Thumbnail.ts +130 -81
- package/src/utils/index.ts +12 -13
- package/src/webchat/WebChat.ts +196 -413
- package/src/webchat/index.ts +23 -1
- package/static/css/temba-components.css +2 -0
- package/temba-modules.ts +2 -2
- package/temba-webchat.ts +2 -0
- package/test/temba-contact-chat.test.ts +1 -0
- package/test/temba-lightbox.test.ts +4 -4
- package/test-assets/contacts/history.json +1 -56
- package/out-tsc/src/contacts/ContactHistory.js +0 -691
- package/out-tsc/src/contacts/ContactHistory.js.map +0 -1
- package/out-tsc/test/temba-contact-history.test.js +0 -69
- package/out-tsc/test/temba-contact-history.test.js.map +0 -1
- package/src/contacts/ContactHistory.ts +0 -875
- package/test/temba-contact-history.test.ts +0 -107
|
@@ -1,10 +1,189 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-this-alias */
|
|
2
3
|
import { css, html } from 'lit';
|
|
3
4
|
import { property } from 'lit/decorators.js';
|
|
4
5
|
import { CustomEventType } from '../interfaces';
|
|
5
|
-
import { postJSON } from '../utils';
|
|
6
|
+
import { oxford, oxfordFn, postJSON } from '../utils';
|
|
6
7
|
import { ContactStoreElement } from './ContactStoreElement';
|
|
7
|
-
|
|
8
|
+
import { fetchContactHistory, getDisplayName } from './helpers';
|
|
9
|
+
import { MessageType } from '../chat/Chat';
|
|
10
|
+
import { getUserDisplay } from '../webchat';
|
|
11
|
+
import { DEFAULT_AVATAR } from '../webchat/assets';
|
|
12
|
+
export var Events;
|
|
13
|
+
(function (Events) {
|
|
14
|
+
Events["MESSAGE_CREATED"] = "msg_created";
|
|
15
|
+
Events["MESSAGE_RECEIVED"] = "msg_received";
|
|
16
|
+
Events["BROADCAST_CREATED"] = "broadcast_created";
|
|
17
|
+
Events["IVR_CREATED"] = "ivr_created";
|
|
18
|
+
Events["FLOW_ENTERED"] = "flow_entered";
|
|
19
|
+
Events["FLOW_EXITED"] = "flow_exited";
|
|
20
|
+
Events["RUN_RESULT_CHANGED"] = "run_result_changed";
|
|
21
|
+
Events["CONTACT_FIELD_CHANGED"] = "contact_field_changed";
|
|
22
|
+
Events["CONTACT_GROUPS_CHANGED"] = "contact_groups_changed";
|
|
23
|
+
Events["CONTACT_NAME_CHANGED"] = "contact_name_changed";
|
|
24
|
+
Events["CONTACT_URNS_CHANGED"] = "contact_urns_changed";
|
|
25
|
+
Events["CAMPAIGN_FIRED"] = "campaign_fired";
|
|
26
|
+
Events["CHANNEL_EVENT"] = "channel_event";
|
|
27
|
+
Events["CONTACT_LANGUAGE_CHANGED"] = "contact_language_changed";
|
|
28
|
+
Events["WEBHOOK_CALLED"] = "webhook_called";
|
|
29
|
+
Events["AIRTIME_TRANSFERRED"] = "airtime_transferred";
|
|
30
|
+
Events["CALL_STARTED"] = "call_started";
|
|
31
|
+
Events["EMAIL_SENT"] = "email_sent";
|
|
32
|
+
Events["INPUT_LABELS_ADDED"] = "input_labels_added";
|
|
33
|
+
Events["NOTE_CREATED"] = "note_created";
|
|
34
|
+
Events["TICKET_ASSIGNED"] = "ticket_assigned";
|
|
35
|
+
Events["TICKET_NOTE_ADDED"] = "ticket_note_added";
|
|
36
|
+
Events["TICKET_CLOSED"] = "ticket_closed";
|
|
37
|
+
Events["TICKET_OPENED"] = "ticket_opened";
|
|
38
|
+
Events["TICKET_REOPENED"] = "ticket_reopened";
|
|
39
|
+
Events["OPTIN_REQUESTED"] = "optin_requested";
|
|
40
|
+
Events["ERROR"] = "error";
|
|
41
|
+
Events["FAILURE"] = "failure";
|
|
42
|
+
})(Events || (Events = {}));
|
|
43
|
+
const renderInfoList = (singular, plural, items) => {
|
|
44
|
+
if (items.length === 1) {
|
|
45
|
+
return `${singular} **${items[0].name}**`;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const list = items.map((item) => `**${item.name}**`);
|
|
49
|
+
if (list.length === 2) {
|
|
50
|
+
return `${plural} ${list.join(' and ')}`;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const last = list.pop();
|
|
54
|
+
return `${plural} ${list.join(', ')}, and ${last}`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const toTitleCase = (str) => {
|
|
59
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
60
|
+
};
|
|
61
|
+
const renderChannelEvent = (event) => {
|
|
62
|
+
var _a, _b;
|
|
63
|
+
if (event.event.type === 'mt_miss') {
|
|
64
|
+
return 'Missed outgoing call';
|
|
65
|
+
}
|
|
66
|
+
else if (event.event.type === 'mo_miss') {
|
|
67
|
+
return 'Missed incoming call';
|
|
68
|
+
}
|
|
69
|
+
else if (event.event.type === 'new_conversation') {
|
|
70
|
+
return 'Started conversation';
|
|
71
|
+
}
|
|
72
|
+
else if (event.channel_event_type === 'welcome_message') {
|
|
73
|
+
return 'Welcome Message Sent';
|
|
74
|
+
}
|
|
75
|
+
else if (event.event.type === 'referral') {
|
|
76
|
+
return 'Referred';
|
|
77
|
+
}
|
|
78
|
+
else if (event.event.type === 'follow') {
|
|
79
|
+
return 'Followed';
|
|
80
|
+
}
|
|
81
|
+
else if (event.event.type === 'stop_contact') {
|
|
82
|
+
return 'Stopped';
|
|
83
|
+
}
|
|
84
|
+
else if (event.event.type === 'mt_call') {
|
|
85
|
+
return 'Outgoing Phone Call';
|
|
86
|
+
}
|
|
87
|
+
else if (event.event.type == 'mo_call') {
|
|
88
|
+
return 'Incoming Phone call';
|
|
89
|
+
}
|
|
90
|
+
else if (event.event.type == 'optin') {
|
|
91
|
+
return `Opted in to **${(_a = event.event.optin) === null || _a === void 0 ? void 0 : _a.name}**`;
|
|
92
|
+
}
|
|
93
|
+
else if (event.event.type == 'optout') {
|
|
94
|
+
return `Opted out of **${(_b = event.event.optin) === null || _b === void 0 ? void 0 : _b.name}**`;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const renderFlowEvent = (event) => {
|
|
98
|
+
let verb = 'Interrupted';
|
|
99
|
+
if (event.status !== 'I') {
|
|
100
|
+
if (event.type === Events.FLOW_ENTERED) {
|
|
101
|
+
verb = 'Started';
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
verb = 'Completed';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return `${verb} [**${event.flow.name}**](/flow/editor/${event.flow.uuid}/)`;
|
|
108
|
+
};
|
|
109
|
+
const renderResultEvent = (event) => {
|
|
110
|
+
if (!event.name.startsWith('_') && event.value) {
|
|
111
|
+
return `Updated flow result **${event.name}** to **${event.value}**`;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const renderUpdateEvent = (event) => {
|
|
115
|
+
return event.value
|
|
116
|
+
? `Updated **${event.field.name}** to **${event.value.text}**`
|
|
117
|
+
: `Cleared **${event.field.name}**`;
|
|
118
|
+
};
|
|
119
|
+
const renderNameChanged = (event) => {
|
|
120
|
+
return `Updated **Contact Name** to **${event.name}**`;
|
|
121
|
+
};
|
|
122
|
+
const renderContactURNsChanged = (event) => {
|
|
123
|
+
return `Updated **URNs** to ${oxfordFn(event.urns, (urn) => `**${urn.split(':')[1].split('?')[0]}**`)}`;
|
|
124
|
+
};
|
|
125
|
+
const renderEmailSent = (event) => {
|
|
126
|
+
return `Email sent to **${oxford(event.to, 'and')}** with subject **${event.subject}**`;
|
|
127
|
+
};
|
|
128
|
+
const renderLabelsAdded = (event) => {
|
|
129
|
+
return `Applied ${renderInfoList('label', 'labels', event.labels)}`;
|
|
130
|
+
};
|
|
131
|
+
export const renderTicketAction = (event, action) => {
|
|
132
|
+
if (event.created_by) {
|
|
133
|
+
return `**${getUserDisplay(event.created_by)}** ${action} a **[ticket](/ticket/all/closed/${event.ticket.uuid}/)**`;
|
|
134
|
+
}
|
|
135
|
+
return `A **[ticket](/ticket/all/closed/${event.ticket.uuid}/)** was **${action}**`;
|
|
136
|
+
};
|
|
137
|
+
export const renderTicketAssigned = (event) => {
|
|
138
|
+
return event.assignee
|
|
139
|
+
? event.assignee.id === event.created_by.id
|
|
140
|
+
? `**${getDisplayName(event.created_by)}** took this ticket`
|
|
141
|
+
: `${getDisplayName(event.created_by)} assigned this ticket to **${getDisplayName(event.assignee)}**`
|
|
142
|
+
: `**${getDisplayName(event.created_by)}** unassigned this ticket`;
|
|
143
|
+
};
|
|
144
|
+
export const renderContactGroupsEvent = (event) => {
|
|
145
|
+
const groupsEvent = event;
|
|
146
|
+
if (groupsEvent.groups_added) {
|
|
147
|
+
return renderInfoList('Added to group', 'Added to groups', groupsEvent.groups_added);
|
|
148
|
+
}
|
|
149
|
+
else if (groupsEvent.groups_removed) {
|
|
150
|
+
return renderInfoList('Removed from group', 'Removed from groups', groupsEvent.groups_removed);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
export const renderCampaignFiredEvent = (event) => {
|
|
154
|
+
return `Campaign ${event.campaign.name}
|
|
155
|
+
${event.fired_result === 'S' ? 'skipped' : 'triggered'}
|
|
156
|
+
${event.campaign_event.offset_display}
|
|
157
|
+
${event.campaign_event.relative_to.name}`;
|
|
158
|
+
};
|
|
159
|
+
export const renderTicketOpened = (event) => {
|
|
160
|
+
return `${event.ticket.topic.name} ticket was opened`;
|
|
161
|
+
};
|
|
162
|
+
export const renderErrorMessage = (event) => {
|
|
163
|
+
return `${event.text} ${event.type === Events.FAILURE
|
|
164
|
+
? `Run ended prematurely, check the flow design`
|
|
165
|
+
: null}`;
|
|
166
|
+
};
|
|
167
|
+
export const renderWebhookEvent = (event) => {
|
|
168
|
+
return event.status === 'success'
|
|
169
|
+
? `Successfully called ${event.url}`
|
|
170
|
+
: `Failed to call ${event.url}`;
|
|
171
|
+
};
|
|
172
|
+
export const renderAirtimeTransferredEvent = (event) => {
|
|
173
|
+
if (parseFloat(event.actual_amount) === 0) {
|
|
174
|
+
return `Airtime transfer failed`;
|
|
175
|
+
}
|
|
176
|
+
return `Transferred **${event.actual_amount}** ${event.currency} of airtime`;
|
|
177
|
+
};
|
|
178
|
+
export const renderCallStartedEvent = () => {
|
|
179
|
+
return `Call Started`;
|
|
180
|
+
};
|
|
181
|
+
export const renderContactLanguageChangedEvent = (event) => {
|
|
182
|
+
return `Language updated to **${event.language}**`;
|
|
183
|
+
};
|
|
184
|
+
export const renderOptinRequested = (event) => {
|
|
185
|
+
return `Requested opt-in for ${event.optin.name}`;
|
|
186
|
+
};
|
|
8
187
|
export class ContactChat extends ContactStoreElement {
|
|
9
188
|
static get styles() {
|
|
10
189
|
return css `
|
|
@@ -35,7 +214,7 @@ export class ContactChat extends ContactStoreElement {
|
|
|
35
214
|
}
|
|
36
215
|
|
|
37
216
|
.chatbox {
|
|
38
|
-
|
|
217
|
+
background: #fff;
|
|
39
218
|
display: flex;
|
|
40
219
|
flex-direction: column;
|
|
41
220
|
--textarea-min-height: 1em;
|
|
@@ -43,10 +222,6 @@ export class ContactChat extends ContactStoreElement {
|
|
|
43
222
|
--widget-box-shadow-focused: none;
|
|
44
223
|
}
|
|
45
224
|
|
|
46
|
-
.chatbox:focus-within {
|
|
47
|
-
--textarea-height: 4em;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
225
|
.chatbox.full {
|
|
51
226
|
border-bottom-right-radius: 0 !important;
|
|
52
227
|
}
|
|
@@ -81,6 +256,11 @@ export class ContactChat extends ContactStoreElement {
|
|
|
81
256
|
--color-focus: transparent;
|
|
82
257
|
--color-widget-bg-focused: transparent;
|
|
83
258
|
}
|
|
259
|
+
|
|
260
|
+
.border {
|
|
261
|
+
border-top: 1px solid #f1f1f1;
|
|
262
|
+
margin: 0 1em;
|
|
263
|
+
}
|
|
84
264
|
`;
|
|
85
265
|
}
|
|
86
266
|
constructor() {
|
|
@@ -88,39 +268,27 @@ export class ContactChat extends ContactStoreElement {
|
|
|
88
268
|
this.contactsEndpoint = '/api/v2/contacts.json';
|
|
89
269
|
this.currentNote = '';
|
|
90
270
|
this.showDetails = true;
|
|
91
|
-
this.monitor = false;
|
|
92
271
|
this.currentTicket = null;
|
|
93
272
|
this.currentContact = null;
|
|
94
273
|
this.agent = '';
|
|
95
|
-
this.
|
|
274
|
+
this.blockFetching = false;
|
|
275
|
+
this.avatar = DEFAULT_AVATAR;
|
|
276
|
+
this.ticket = null;
|
|
277
|
+
this.lastEventTime = null;
|
|
278
|
+
this.newestEventTime = null;
|
|
279
|
+
this.refreshId = null;
|
|
280
|
+
this.polling = false;
|
|
281
|
+
}
|
|
282
|
+
firstUpdated(changed) {
|
|
283
|
+
super.firstUpdated(changed);
|
|
96
284
|
}
|
|
97
285
|
connectedCallback() {
|
|
98
286
|
super.connectedCallback();
|
|
99
|
-
|
|
100
|
-
this.refreshInterval = setInterval(() => {
|
|
101
|
-
if (this.currentTicket && this.currentTicket.closed_on) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
this.refresh();
|
|
105
|
-
}, DEFAULT_REFRESH);
|
|
106
|
-
}
|
|
287
|
+
this.chat = this.shadowRoot.querySelector('temba-chat');
|
|
107
288
|
}
|
|
108
289
|
disconnectedCallback() {
|
|
109
|
-
if (this.
|
|
110
|
-
clearInterval(this.
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
getContactHistory() {
|
|
114
|
-
return this.shadowRoot.querySelector('temba-contact-history');
|
|
115
|
-
}
|
|
116
|
-
refresh(scrollToBottom = false) {
|
|
117
|
-
const contactHistory = this.getContactHistory();
|
|
118
|
-
if (contactHistory) {
|
|
119
|
-
if (scrollToBottom) {
|
|
120
|
-
contactHistory.scrollToBottom();
|
|
121
|
-
}
|
|
122
|
-
contactHistory.refresh();
|
|
123
|
-
// super.refresh();
|
|
290
|
+
if (this.refreshId) {
|
|
291
|
+
clearInterval(this.refreshId);
|
|
124
292
|
}
|
|
125
293
|
}
|
|
126
294
|
updated(changedProperties) {
|
|
@@ -130,6 +298,22 @@ export class ContactChat extends ContactStoreElement {
|
|
|
130
298
|
changedProperties.has('currentContact')) {
|
|
131
299
|
this.currentContact = this.data;
|
|
132
300
|
}
|
|
301
|
+
if (changedProperties.has('currentContact')) {
|
|
302
|
+
this.chat = this.shadowRoot.querySelector('temba-chat');
|
|
303
|
+
this.reset();
|
|
304
|
+
this.fetchPreviousMessages();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
reset() {
|
|
308
|
+
this.blockFetching = false;
|
|
309
|
+
this.ticket = null;
|
|
310
|
+
this.lastEventTime = null;
|
|
311
|
+
this.newestEventTime = null;
|
|
312
|
+
this.refreshId = null;
|
|
313
|
+
this.polling = false;
|
|
314
|
+
}
|
|
315
|
+
refresh() {
|
|
316
|
+
this.checkForNewMessages();
|
|
133
317
|
}
|
|
134
318
|
handleSend(evt) {
|
|
135
319
|
const buttonName = evt.detail.name;
|
|
@@ -156,8 +340,8 @@ export class ContactChat extends ContactStoreElement {
|
|
|
156
340
|
postJSON(`/api/v2/messages.json`, payload)
|
|
157
341
|
.then((response) => {
|
|
158
342
|
if (response.status < 400) {
|
|
343
|
+
this.checkForNewMessages();
|
|
159
344
|
compose.reset();
|
|
160
|
-
this.refresh(true);
|
|
161
345
|
this.fireCustomEvent(CustomEventType.MessageSent, { msg: payload });
|
|
162
346
|
}
|
|
163
347
|
else if (response.status < 500) {
|
|
@@ -201,15 +385,290 @@ export class ContactChat extends ContactStoreElement {
|
|
|
201
385
|
`;
|
|
202
386
|
return html `${contactHistoryAndChatbox}`;
|
|
203
387
|
}
|
|
388
|
+
getEndpoint() {
|
|
389
|
+
return `/contact/history/${this.currentContact.uuid}/?_format=json`;
|
|
390
|
+
}
|
|
391
|
+
scheduleRefresh() {
|
|
392
|
+
// knock five seconds off the newest event time so we are
|
|
393
|
+
// a little more aggressive about refreshing short term
|
|
394
|
+
let window = new Date().getTime() - this.newestEventTime / 1000 - 5000;
|
|
395
|
+
if (this.refreshId) {
|
|
396
|
+
clearTimeout(this.refreshId);
|
|
397
|
+
this.refreshId = null;
|
|
398
|
+
}
|
|
399
|
+
// wait no longer than 15 seconds
|
|
400
|
+
window = Math.min(window, 15000);
|
|
401
|
+
// wait at least 2 seconds
|
|
402
|
+
window = Math.max(window, 2000);
|
|
403
|
+
this.refreshId = setTimeout(() => {
|
|
404
|
+
this.checkForNewMessages();
|
|
405
|
+
}, window);
|
|
406
|
+
}
|
|
407
|
+
getEventMessage(event) {
|
|
408
|
+
let message = null;
|
|
409
|
+
switch (event.type) {
|
|
410
|
+
case Events.ERROR:
|
|
411
|
+
case Events.FAILURE:
|
|
412
|
+
message = {
|
|
413
|
+
type: MessageType.Inline,
|
|
414
|
+
text: `Error during flow: ${toTitleCase(event.text)}`
|
|
415
|
+
};
|
|
416
|
+
break;
|
|
417
|
+
case Events.TICKET_OPENED:
|
|
418
|
+
message = {
|
|
419
|
+
type: MessageType.Inline,
|
|
420
|
+
text: renderTicketAction(event, 'opened')
|
|
421
|
+
};
|
|
422
|
+
break;
|
|
423
|
+
case Events.TICKET_ASSIGNED:
|
|
424
|
+
message = {
|
|
425
|
+
type: MessageType.Inline,
|
|
426
|
+
text: renderTicketAssigned(event)
|
|
427
|
+
};
|
|
428
|
+
break;
|
|
429
|
+
case Events.TICKET_REOPENED:
|
|
430
|
+
message = {
|
|
431
|
+
type: MessageType.Inline,
|
|
432
|
+
text: renderTicketAction(event, 'reopened')
|
|
433
|
+
};
|
|
434
|
+
break;
|
|
435
|
+
case Events.TICKET_CLOSED:
|
|
436
|
+
message = {
|
|
437
|
+
type: MessageType.Inline,
|
|
438
|
+
text: renderTicketAction(event, 'closed')
|
|
439
|
+
};
|
|
440
|
+
break;
|
|
441
|
+
case Events.FLOW_ENTERED:
|
|
442
|
+
case Events.FLOW_EXITED:
|
|
443
|
+
message = {
|
|
444
|
+
type: MessageType.Inline,
|
|
445
|
+
text: renderFlowEvent(event)
|
|
446
|
+
};
|
|
447
|
+
break;
|
|
448
|
+
case Events.RUN_RESULT_CHANGED:
|
|
449
|
+
message = {
|
|
450
|
+
type: MessageType.Inline,
|
|
451
|
+
text: renderResultEvent(event)
|
|
452
|
+
};
|
|
453
|
+
break;
|
|
454
|
+
case Events.CONTACT_FIELD_CHANGED:
|
|
455
|
+
message = {
|
|
456
|
+
type: MessageType.Inline,
|
|
457
|
+
text: renderUpdateEvent(event)
|
|
458
|
+
};
|
|
459
|
+
break;
|
|
460
|
+
case Events.CONTACT_NAME_CHANGED:
|
|
461
|
+
message = {
|
|
462
|
+
type: MessageType.Inline,
|
|
463
|
+
text: renderNameChanged(event)
|
|
464
|
+
};
|
|
465
|
+
break;
|
|
466
|
+
case Events.CONTACT_URNS_CHANGED:
|
|
467
|
+
message = {
|
|
468
|
+
type: MessageType.Inline,
|
|
469
|
+
text: renderContactURNsChanged(event)
|
|
470
|
+
};
|
|
471
|
+
break;
|
|
472
|
+
case Events.EMAIL_SENT:
|
|
473
|
+
message = {
|
|
474
|
+
type: MessageType.Inline,
|
|
475
|
+
text: renderEmailSent(event)
|
|
476
|
+
};
|
|
477
|
+
break;
|
|
478
|
+
case Events.INPUT_LABELS_ADDED:
|
|
479
|
+
message = {
|
|
480
|
+
type: MessageType.Inline,
|
|
481
|
+
text: renderLabelsAdded(event)
|
|
482
|
+
};
|
|
483
|
+
break;
|
|
484
|
+
case Events.CONTACT_GROUPS_CHANGED:
|
|
485
|
+
message = {
|
|
486
|
+
type: MessageType.Inline,
|
|
487
|
+
text: renderContactGroupsEvent(event)
|
|
488
|
+
};
|
|
489
|
+
break;
|
|
490
|
+
case Events.WEBHOOK_CALLED:
|
|
491
|
+
message = {
|
|
492
|
+
type: MessageType.Inline,
|
|
493
|
+
text: renderWebhookEvent(event)
|
|
494
|
+
};
|
|
495
|
+
break;
|
|
496
|
+
case Events.AIRTIME_TRANSFERRED:
|
|
497
|
+
message = {
|
|
498
|
+
type: MessageType.Inline,
|
|
499
|
+
text: renderAirtimeTransferredEvent(event)
|
|
500
|
+
};
|
|
501
|
+
break;
|
|
502
|
+
case Events.CALL_STARTED:
|
|
503
|
+
message = {
|
|
504
|
+
type: MessageType.Inline,
|
|
505
|
+
text: renderCallStartedEvent()
|
|
506
|
+
};
|
|
507
|
+
break;
|
|
508
|
+
case Events.CAMPAIGN_FIRED:
|
|
509
|
+
message = {
|
|
510
|
+
type: MessageType.Inline,
|
|
511
|
+
text: renderCampaignFiredEvent(event)
|
|
512
|
+
};
|
|
513
|
+
break;
|
|
514
|
+
case Events.CHANNEL_EVENT:
|
|
515
|
+
message = {
|
|
516
|
+
type: MessageType.Inline,
|
|
517
|
+
text: renderChannelEvent(event)
|
|
518
|
+
};
|
|
519
|
+
break;
|
|
520
|
+
case Events.CONTACT_LANGUAGE_CHANGED:
|
|
521
|
+
message = {
|
|
522
|
+
type: MessageType.Inline,
|
|
523
|
+
text: renderContactLanguageChangedEvent(event)
|
|
524
|
+
};
|
|
525
|
+
break;
|
|
526
|
+
case Events.OPTIN_REQUESTED:
|
|
527
|
+
message = {
|
|
528
|
+
type: MessageType.Inline,
|
|
529
|
+
text: renderOptinRequested(event)
|
|
530
|
+
};
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
message.date = new Date(event.created_on);
|
|
534
|
+
return message;
|
|
535
|
+
}
|
|
536
|
+
getUserForEvent(event) {
|
|
537
|
+
let user = null;
|
|
538
|
+
if (event.created_by) {
|
|
539
|
+
const storeUser = this.store.getUser(event.created_by.email);
|
|
540
|
+
if (storeUser) {
|
|
541
|
+
user = {
|
|
542
|
+
email: event.created_by.email,
|
|
543
|
+
name: [storeUser.first_name, storeUser.last_name].join(' '),
|
|
544
|
+
avatar: storeUser.avatar
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
else if (event.type === 'msg_received') {
|
|
549
|
+
user = {
|
|
550
|
+
name: this.currentContact.name
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
return user;
|
|
554
|
+
}
|
|
555
|
+
createMessages(page) {
|
|
556
|
+
let messages = page.events.map((event) => {
|
|
557
|
+
const ts = new Date(event.created_on).getTime() * 1000;
|
|
558
|
+
if (ts > this.newestEventTime) {
|
|
559
|
+
this.newestEventTime = ts;
|
|
560
|
+
}
|
|
561
|
+
if (event.type === 'ticket_note_added') {
|
|
562
|
+
const ticketEvent = event;
|
|
563
|
+
return {
|
|
564
|
+
type: MessageType.Note,
|
|
565
|
+
id: event.created_on + event.type,
|
|
566
|
+
user: this.getUserForEvent(ticketEvent),
|
|
567
|
+
date: new Date(ticketEvent.created_on),
|
|
568
|
+
text: ticketEvent.note
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
if (event.type === 'msg_created' || event.type === 'msg_received') {
|
|
572
|
+
const msgEvent = event;
|
|
573
|
+
return {
|
|
574
|
+
type: msgEvent.type === 'msg_created' ? 'msg_out' : 'msg_in',
|
|
575
|
+
id: msgEvent.msg.id + '',
|
|
576
|
+
user: this.getUserForEvent(msgEvent),
|
|
577
|
+
date: new Date(msgEvent.created_on),
|
|
578
|
+
attachments: msgEvent.msg.attachments,
|
|
579
|
+
text: msgEvent.msg.text,
|
|
580
|
+
sendError: msgEvent.status === 'E' || msgEvent.status === 'F',
|
|
581
|
+
popup: html `<div
|
|
582
|
+
style="display: flex; flex-direction: row; align-items:center; justify-content: space-between;font-size:0.9em;line-height:1em;min-width:10em"
|
|
583
|
+
>
|
|
584
|
+
<div style="justify-content:left;text-align:left">
|
|
585
|
+
<temba-date
|
|
586
|
+
value=${msgEvent.created_on}
|
|
587
|
+
display="duration"
|
|
588
|
+
></temba-date>
|
|
589
|
+
|
|
590
|
+
${msgEvent.failed_reason_display
|
|
591
|
+
? html `
|
|
592
|
+
<div
|
|
593
|
+
style="margin-top:0.2em;margin-right: 0.5em;min-width:10em;max-width:15em;color:var(--color-error);font-size:0.9em"
|
|
594
|
+
>
|
|
595
|
+
${msgEvent.failed_reason_display}
|
|
596
|
+
</div>
|
|
597
|
+
`
|
|
598
|
+
: null}
|
|
599
|
+
</div>
|
|
600
|
+
${msgEvent.logs_url
|
|
601
|
+
? html `<a style="margin-left:0.5em" href="${msgEvent.logs_url}"
|
|
602
|
+
><temba-icon name="log"></temba-icon
|
|
603
|
+
></a>`
|
|
604
|
+
: null}
|
|
605
|
+
</div> `
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
return this.getEventMessage(event);
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
// remove any messages we don't recognize
|
|
613
|
+
messages = messages.filter((msg) => !!msg);
|
|
614
|
+
return messages;
|
|
615
|
+
}
|
|
616
|
+
checkForNewMessages() {
|
|
617
|
+
var _a;
|
|
618
|
+
// we are already working on it
|
|
619
|
+
if (this.polling) {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
const chat = this.chat;
|
|
623
|
+
const contactChat = this;
|
|
624
|
+
if (this.currentContact && this.newestEventTime) {
|
|
625
|
+
this.polling = true;
|
|
626
|
+
const endpoint = this.getEndpoint();
|
|
627
|
+
fetchContactHistory(false, endpoint, (_a = this.currentTicket) === null || _a === void 0 ? void 0 : _a.uuid, null, this.newestEventTime).then((page) => {
|
|
628
|
+
this.lastEventTime = page.next_before;
|
|
629
|
+
const messages = this.createMessages(page);
|
|
630
|
+
if (messages.length === 0) {
|
|
631
|
+
contactChat.blockFetching = true;
|
|
632
|
+
}
|
|
633
|
+
messages.reverse();
|
|
634
|
+
chat.addMessages(messages, null, true);
|
|
635
|
+
this.polling = false;
|
|
636
|
+
this.scheduleRefresh();
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
fetchPreviousMessages() {
|
|
641
|
+
var _a;
|
|
642
|
+
const chat = this.chat;
|
|
643
|
+
const contactChat = this;
|
|
644
|
+
if (!chat || chat.fetching || contactChat.blockFetching) {
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
chat.fetching = true;
|
|
648
|
+
if (this.currentContact) {
|
|
649
|
+
const endpoint = this.getEndpoint();
|
|
650
|
+
fetchContactHistory(false, endpoint, (_a = this.currentTicket) === null || _a === void 0 ? void 0 : _a.uuid, this.lastEventTime).then((page) => {
|
|
651
|
+
this.lastEventTime = page.next_before;
|
|
652
|
+
const messages = this.createMessages(page);
|
|
653
|
+
messages.reverse();
|
|
654
|
+
if (messages.length === 0) {
|
|
655
|
+
contactChat.blockFetching = true;
|
|
656
|
+
}
|
|
657
|
+
chat.addMessages(messages);
|
|
658
|
+
this.scheduleRefresh();
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
fetchComplete() {
|
|
663
|
+
this.chat.fetching = false;
|
|
664
|
+
}
|
|
204
665
|
getTembaContactHistory() {
|
|
205
|
-
return html
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
>
|
|
212
|
-
</temba-contact-history>`;
|
|
666
|
+
return html `<temba-chat
|
|
667
|
+
@temba-scroll-threshold=${this.fetchPreviousMessages}
|
|
668
|
+
@temba-fetch-complete=${this.fetchComplete}
|
|
669
|
+
avatar=${this.avatar}
|
|
670
|
+
agent
|
|
671
|
+
></temba-chat>`;
|
|
213
672
|
}
|
|
214
673
|
getTembaChatbox() {
|
|
215
674
|
if (this.currentTicket) {
|
|
@@ -237,16 +696,18 @@ export class ContactChat extends ContactStoreElement {
|
|
|
237
696
|
}
|
|
238
697
|
}
|
|
239
698
|
getChatbox() {
|
|
240
|
-
return html `<div class="
|
|
241
|
-
<
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
699
|
+
return html `<div class="border"></div>
|
|
700
|
+
<div class="chatbox">
|
|
701
|
+
<temba-compose
|
|
702
|
+
chatbox
|
|
703
|
+
attachments
|
|
704
|
+
counter
|
|
705
|
+
button
|
|
706
|
+
autogrow
|
|
707
|
+
@temba-button-clicked=${this.handleSend.bind(this)}
|
|
708
|
+
>
|
|
709
|
+
</temba-compose>
|
|
710
|
+
</div>`;
|
|
250
711
|
}
|
|
251
712
|
}
|
|
252
713
|
__decorate([
|
|
@@ -261,9 +722,6 @@ __decorate([
|
|
|
261
722
|
__decorate([
|
|
262
723
|
property({ type: Boolean })
|
|
263
724
|
], ContactChat.prototype, "showDetails", void 0);
|
|
264
|
-
__decorate([
|
|
265
|
-
property({ type: Boolean })
|
|
266
|
-
], ContactChat.prototype, "monitor", void 0);
|
|
267
725
|
__decorate([
|
|
268
726
|
property({ type: Object })
|
|
269
727
|
], ContactChat.prototype, "currentTicket", void 0);
|
|
@@ -273,4 +731,10 @@ __decorate([
|
|
|
273
731
|
__decorate([
|
|
274
732
|
property({ type: String })
|
|
275
733
|
], ContactChat.prototype, "agent", void 0);
|
|
734
|
+
__decorate([
|
|
735
|
+
property({ type: Boolean })
|
|
736
|
+
], ContactChat.prototype, "blockFetching", void 0);
|
|
737
|
+
__decorate([
|
|
738
|
+
property({ type: String })
|
|
739
|
+
], ContactChat.prototype, "avatar", void 0);
|
|
276
740
|
//# sourceMappingURL=ContactChat.js.map
|