This commit is contained in:
2023-08-28 15:04:23 +08:00
parent 29209a3a00
commit 84190ed9f1
14 changed files with 1004 additions and 527 deletions

View File

@ -1,5 +1,5 @@
import { Grid, GridColumn, createElement, setTooltip, createIcon, createCheckbox, createRadiobox, showAlert, showConfirm, Popup } from "../../ui";
import { r, nullOrEmpty, formatUrl, isEmail, isPhone } from "../../utility";
import { r as lang, nullOrEmpty, formatUrl, escapeEmoji, isEmail, isPhone } from "../../utility";
import { createBox, appendMedia, fileSupported, insertFile } from "./lib";
import { Contact, CustomerRecordContact } from "./contact";
import Follower from "./follower";
@ -28,7 +28,9 @@ class NoteCol extends GridColumn {
}
}
class CustomerCommunication {
let r = lang;
export default class CustomerCommunication {
#container;
#option;
#contacts;
@ -44,6 +46,10 @@ class CustomerCommunication {
constructor(opt) {
this.#option = opt ?? {};
const getText = opt?.getText;
if (typeof getText === 'function') {
r = getText;
}
}
get #autoUpdates() { return this.#container.querySelector('.check-auto-update>input') }
@ -191,21 +197,21 @@ class CustomerCommunication {
let method;
if (c.OptOut || c.OptOut_BC || c.selected === false) {
icon = 'times';
method = r('optedOut', 'Opted Out:');
method = r('P_CU_OPTEDOUT_COLON', 'Opted Out:');
}
else {
switch (pref) {
case '0':
icon = 'comment-lines';
method = r('textsToColon', 'Texts to:');
method = r('P_CU_TEXTSTO_COLON', 'Texts to:');
break;
case '2':
icon = 'mobile';
method = r('callsToColon', 'Calls to:');
method = r('P_CU_CALLSTO_COLON', 'Calls to:');
break;
default:
icon = 'envelope';
method = r('emailsToColon', 'Emails to:');
method = r('P_CU_EMAILSTO_COLON', 'Emails to:');
break;
}
}
@ -222,7 +228,7 @@ class CustomerCommunication {
this.#contacts.appendChild(item);
let tip = `${method} ${to}`;
if (span.scrollWidth > span.offsetWidth) {
tip = r('nameColon', 'Name:') + ` ${c.Name}\n${tip}`;
tip = r('P_WO_NAME_COLON', 'Name:') + ` ${c.Name}\n${tip}`;
}
setTooltip(span, tip);
}
@ -306,7 +312,7 @@ class CustomerCommunication {
this.#followers.replaceChildren();
if (followers?.length > 0) {
this.#container.querySelector('.follower-bar').style.display = '';
setTooltip(this.#buttonFollower, r('editFollower', 'Edit Followers'));
setTooltip(this.#buttonFollower, r('P_CU_EDITFOLLOWERS', 'Edit Followers'));
this.#container.querySelector('.follower-bar>.bar-list').appendChild(this.#buttonFollower);
for (let f of followers) {
if (f.OptOut) {
@ -317,10 +323,10 @@ class CustomerCommunication {
const email = String(f.Email).trim();
const tips = [];
if (f.SendEmail) {
tips.push(r('emailsToColon', 'Emails to:') + ` ${email}`);
tips.push(r('P_CU_EMAILSTO_COLON', 'Emails to:') + ` ${email}`);
}
if (f.SendText) {
tips.push(r('textsToColon', 'Texts to:' + ` ${mpDisplay}`));
tips.push(r('P_CU_TEXTSTO_COLON', 'Texts to:' + ` ${mpDisplay}`));
}
let icon;
if (f.SendText && f.SendEmail) {
@ -344,13 +350,13 @@ class CustomerCommunication {
);
this.#followers.appendChild(item);
if (span.scrollWidth > span.offsetWidth) {
tips.splice(0, 0, r('nameColon', 'Name:') + ` ${c.Name}`);
tips.splice(0, 0, r('P_WO_NAME_COLON', 'Name:') + ` ${c.Name}`);
}
setTooltip(span, tips.join('\n'));
}
} else {
this.#container.querySelector('.follower-bar').style.display = 'none';
setTooltip(this.#buttonFollower, r('addFollowers', 'Add Followers'));
setTooltip(this.#buttonFollower, r('P_CR_ADDFOLLOWERS', 'Add Followers'));
this.#container.querySelector('.button-edit-contacts').insertAdjacentElement('beforebegin', this.#buttonFollower)
}
this.#message.scrollTop = this.#message.scrollHeight
@ -371,8 +377,8 @@ class CustomerCommunication {
uncheckedNode: createIcon('fa-regular', 'ban'),
onchange: function () {
setTooltip(checkAutoUpdate, this.checked ?
r('autoUpdateEnabled', 'Auto Updates Enabled') :
r('autoUpdateDisabled', 'Auto Updates Disabled'));
r('P_CU_AUTOUPDATESENABLED', 'Auto Updates Enabled') :
r('P_CU_AUTOUPDATESDISABLED', 'Auto Updates Disabled'));
}
});
if (option.autoUpdatesVisible === false) {
@ -387,8 +393,8 @@ class CustomerCommunication {
uncheckedNode: createIcon('fa-regular', 'unlink'),
onchange: function () {
setTooltip(checkLink, this.checked ?
r('statusLinkIncluded', 'Status Link Included') :
r('statusLinkExcluded', 'Status Link Excluded'));
r('P_WO_STATUSLINKINCLUDED', 'Status Link Included') :
r('P_WO_STATUSLINKEXCLUDED', 'Status Link Excluded'));
if (typeof option.onStatusLinkChanged === 'function') {
option.onStatusLinkChanged.call(This, this.checked);
}
@ -401,7 +407,7 @@ class CustomerCommunication {
createElement('div', null,
createElement('div', div => {
div.className = 'title-module';
div.innerText = option.title ?? r('messages', 'Customer Communication');
div.innerText = option.title ?? r('P_WO_CUSTOMERCOMMUNICATION', 'Customer Communication');
}),
createElement('div', div => {
div.className = 'title-company';
@ -417,8 +423,8 @@ class CustomerCommunication {
})
),
[
setTooltip(checkAutoUpdate, r('autoUpdateEnabled', 'Auto Updates Enabled')),
setTooltip(checkLink, r('statusLinkExcluded', 'Status Link Excluded'))
setTooltip(checkAutoUpdate, r('P_CU_AUTOUPDATESENABLED', 'Auto Updates Enabled')),
setTooltip(checkLink, r('P_WO_STATUSLINKEXCLUDED', 'Status Link Excluded'))
]
);
// contacts
@ -427,7 +433,7 @@ class CustomerCommunication {
this.#followers = this.#createFollowers(container, option);
// enter box
const enter = createElement('textarea', 'ui-text');
enter.placeholder = r('typeMessage', 'Enter Message Here');
enter.placeholder = r('P_CU_ENTERMESSAGEHERE', 'Enter Message Here');
option.maxLength ??= 3000;
enter.maxLength = option.maxLength;
// if (readonly === true) {
@ -442,11 +448,23 @@ class CustomerCommunication {
if (option.customerNameVisible === true) {
return;
}
const file = e.clipboardData.files[0];
if (file != null) {
e.preventDefault();
this.file = insertFile(container, file);
const items = e.clipboardData.items;
if (items?.length > 0) {
const item = items[0];
const entry = item.webkitGetAsEntry();
if (item.kind === 'file' && (entry == null || entry.isFile)) {
const file = item.getAsFile();
if (file != null) {
e.preventDefault();
this.file = insertFile(container, file, r);
}
}
}
// const file = e.clipboardData.files[0];
// if (file != null) {
// e.preventDefault();
// this.file = insertFile(container, file, r);
// }
});
this.#enter = enter;
container.appendChild(
@ -473,7 +491,7 @@ class CustomerCommunication {
const file = e.dataTransfer.files[0];
if (file != null) {
e.preventDefault();
this.file = insertFile(container, file);
this.file = insertFile(container, file, r);
}
}
});
@ -486,7 +504,7 @@ class CustomerCommunication {
div.style.display = 'none';
}
},
createElement('span', span => span.innerText = r('nameColon', 'Name:')),
createElement('span', span => span.innerText = r('P_WO_NAME_COLON', 'Name:')),
createElement('input', input => {
input.type = 'text';
input.className = 'ui-input';
@ -506,7 +524,7 @@ class CustomerCommunication {
input.type = 'file';
input.accept = fileSupported.join(',');
input.addEventListener('change', () => {
const file = insertFile(container, input.files?.[0]);
const file = insertFile(container, input.files?.[0], r);
if (file != null) {
this.file = file;
}
@ -535,11 +553,11 @@ class CustomerCommunication {
// button.style.display = 'none';
// }
button.appendChild(createIcon('fa-solid', 'paper-plane'));
setTooltip(button, r('sendMessage', 'Send Message'));
setTooltip(button, r('P_M3_SENDMESSAGE', 'Send Message'));
button.addEventListener('click', () => {
const val = this.text;
if (nullOrEmpty(val?.trim())) {
const p = showAlert(r('error', 'Error'), r('messageRequired', 'Please input the message.'), 'warn');
const p = showAlert(r('P_WO_ERROR', 'Error'), r('P_WO_PLEASEINPUTTHEMESSAGE', 'Please input the message.'), 'warn');
if (typeof option.onMasking === 'function') {
option.onMasking(true);
p.then(() => option.onMasking(false));
@ -547,6 +565,7 @@ class CustomerCommunication {
return;
}
if (typeof option.onAddMessage === 'function') {
this.loading = true;
option.onAddMessage(this.text, this.file);
}
})
@ -581,7 +600,7 @@ class CustomerCommunication {
button.style.display = 'none';
}
button.appendChild(createIcon('fa-solid', 'user-edit'));
setTooltip(button, r('editContacts', 'Edit Contacts'));
setTooltip(button, r('P_CU_EDITCONTACTS', 'Edit Contacts'));
button.addEventListener('click', () => {
const pop = new Popup({
onMasking: option.onMasking,
@ -594,7 +613,7 @@ class CustomerCommunication {
div.className = 'ui-popup-move';
div.style.flex = '1 1 auto';
},
createElement('div', div => div.innerText = r('editContacts', 'Edit Contacts')),
createElement('div', div => div.innerText = r('P_CU_EDITCONTACTS', 'Edit Contacts')),
createElement('div', div => {
div.className = 'title-company';
if (nullOrEmpty(option.companyName)) {
@ -622,6 +641,7 @@ class CustomerCommunication {
}));
button.addEventListener('click', () => {
const sel = new CustomerRecordContact({
getText: option.getText,
// onMasking: option.onMasking,
contacts: [],
onOk: list => {
@ -653,7 +673,7 @@ class CustomerCommunication {
});
}
});
var title = r('selectFromCustomerRecord', 'Select from Customer Record');
var title = r('P_CU_SELECTFROMCUSTOMERRECORD', 'Select from Customer Record');
sel.show(title, container);
if (typeof option.onOpenSelectCRContacts === 'function') {
@ -689,7 +709,7 @@ class CustomerCommunication {
return false;
}
});
setTooltip(button, r('selectFromCustomerRecord', 'Select from Customer Record'))
setTooltip(button, r('P_CU_SELECTFROMCUSTOMERRECORD', 'Select from Customer Record'))
}),
createElement('button', button => {
button.style.flex = '0 0 auto';
@ -705,12 +725,13 @@ class CustomerCommunication {
}));
button.addEventListener('click', () => {
const add = new Contact({
getText: option.getText,
// onMasking: option.onMasking,
company: !nullOrEmpty(option.companyName),
onSave: item => {
const exists = this.#gridContact.source.some(s => s.Name === item.Name && s.MobilePhone === item.MobilePhone);
if (exists) {
showAlert(r('addContact', 'Add Contact'), r('contactUniqueRequired', 'Contact name and contact mobile must be a unique combination.'), 'warn');
showAlert(r('P_CR_ADDCONTACT', 'Add Contact'), r('P_WO_CONTACTNAMEANDMOBILEUNIQUECOMBINATION', 'Contact name and contact mobile must be a unique combination.'), 'warn');
return false;
}
if (typeof option.onSave === 'function') {
@ -744,7 +765,7 @@ class CustomerCommunication {
});
add.show(container);
});
setTooltip(button, r('addContact', 'Add Contact'))
setTooltip(button, r('P_CR_ADDCONTACT', 'Add Contact'))
})
)
}),
@ -754,7 +775,7 @@ class CustomerCommunication {
div.style.display = 'none';
}
div.style.fontWeight = 'bold';
div.innerText = r('contactFromRecord', 'Contacts from Customer Record');
div.innerText = r('P_CU_CONTACTSFROMCUSTOMERRECORD', 'Contacts from Customer Record');
}),
createElement('div', div => {
if (nullOrEmpty(option.companyName)) {
@ -767,7 +788,7 @@ class CustomerCommunication {
}),
createElement('div', div => {
div.style.fontWeight = 'bold';
div.innerText = r('contactFromWorkOrder', 'Contacts not on Customer Record');
div.innerText = r('P_CU_CONTACTSNOTCUSTOMERRECORD', 'Contacts not on Customer Record');
}),
createElement('div', div => {
div.className = 'contacts-wo';
@ -789,7 +810,7 @@ class CustomerCommunication {
option.onChanged([...This.#gridContact.source, ...This.#gridWo.source]);
}
},
tooltip: item => item.selected ? r('optedIn', 'Opted In') : r('optedOut', 'Opted Out')
tooltip: item => item.selected ? r('P_CU_OPTEDIN', 'Opted In') : r('P_CU_OPTEDOUT', 'Opted Out')
}
};
const iconCol = {
@ -819,19 +840,20 @@ class CustomerCommunication {
key: 'edit',
...buttonCol,
text: 'edit',
tooltip: r('edit', 'Edit'),
tooltip: r('P_WO_EDIT', 'Edit'),
events: {
onclick: function () {
const edit = new Contact({
getText: option.getText,
// onMasking: option.onMasking,
contact: this,
company: !nullOrEmpty(This.#option.companyName),
company: !nullOrEmpty(option.companyName),
onSave: (item, _op) => {
const exists =
This.#gridContact.source.some(s => s !== this && s.Name === item.Name && s.MobilePhone === item.MobilePhone) ||
This.#gridWo.source.some(s => s !== this && s.Name === item.Name && s.MobilePhone === item.MobilePhone);
if (exists) {
showAlert(r('editContact', 'Edit Contact'), r('contactUniqueRequired', 'Contact name and contact mobile must be a unique combination.'), 'warn');
showAlert(r('P_CR_EDITCONTACT', 'Edit Contact'), r('P_WO_CONTACTNAMEANDMOBILEUNIQUECOMBINATION', 'Contact name and contact mobile must be a unique combination.'), 'warn');
return false;
}
if (typeof option.onSave === 'function') {
@ -884,15 +906,15 @@ class CustomerCommunication {
key: 'delete',
...buttonCol,
text: 'times',
tooltip: r('delete', 'Delete'),
tooltip: r('P_WO_DELETE', 'Delete'),
events: {
onclick: function () {
showConfirm(
r('remoteContact', 'Remove Contact'),
r('P_CU_REMOVECONTACT', 'Remove Contact'),
createElement('div', null,
createElement('div', div => {
div.style.paddingLeft = '16px';
div.innerText = r('removeFrom', 'Remove {name} from').replace('{name}', this.Name);
div.innerText = r('P_CU_REMOVEFROM', 'Remove {name} from').replace('{name}', this.Name);
}),
createElement('div', div => {
div.style.display = 'flex';
@ -901,19 +923,19 @@ class CustomerCommunication {
},
createRadiobox({
name: 'remove-type',
label: r('customerRecord', 'Customer Record'),
label: r('P_CUSTOMERRECORD', 'Customer Record'),
checked: true,
className: 'radio-customer-record'
}),
createRadiobox({
name: 'remove-type',
label: r('workOrder', 'Work Order')
label: r('P_WORKORDER', 'Work Order')
})
)
),
[
{ key: 'ok', text: r('ok', 'OK') },
{ key: 'cancel', text: r('cancel', 'Cancel') }
{ key: 'ok', text: r('P_WO_OK', 'OK') },
{ key: 'cancel', text: r('P_WO_CANCEL', 'Cancel') }
]
).then(result => {
if (result?.key === 'ok') {
@ -969,12 +991,12 @@ class CustomerCommunication {
key: 'delete',
...buttonCol,
text: 'times',
tooltip: r('delete', 'Delete'),
tooltip: r('P_WO_DELETE', 'Delete'),
events: {
onclick: function () {
showConfirm(r('remoteContact', 'Remove Contact'), r('removeFromWorkorder', 'You are removing {name} from work order.\n\nDo you want to Continue?').replace('{name}', this.Name), [
{ key: 'continue', text: r('continue', 'Continue') },
{ key: 'cancel', text: r('cancel', 'Cancel') }
showConfirm(r('P_CU_REMOVECONTACT', 'Remove Contact'), r('P_CU_REMOVEFROMWORKORDER', 'You are removing {name} from work order.\n\nDo you want to Continue?').replace('{name}', this.Name), [
{ key: 'continue', text: r('P_JS_CONTINUE', 'Continue') },
{ key: 'cancel', text: r('P_WO_CANCEL', 'Cancel') }
]).then(result => {
if (result?.key === 'continue') {
if (typeof option.onDelete === 'function') {
@ -1017,7 +1039,7 @@ class CustomerCommunication {
),
createElement('div', div => {
div.className = 'bar-info';
div.innerText = r('contactInformation', 'Contact Information');
div.innerText = r('P_CR_CONTACTINFORMATION', 'Contact Information');
}),
createElement('div', div => {
if (option.contactCollapserVisible === false) {
@ -1061,15 +1083,16 @@ class CustomerCommunication {
button.style.display = 'none';
}
button.appendChild(createIcon('fa-solid', 'pen'));
setTooltip(button, r('editFollower', 'Edit Followers'));
setTooltip(button, r('P_CU_EDITFOLLOWERS', 'Edit Followers'));
button.addEventListener('click', () => {
if (typeof option.onInitFollower === 'function') {
option.onInitFollower(this.#data.followers).then(data => {
if (typeof data === 'string') {
showAlert(r('customerRecord', 'Customer Record'), data, 'warn');
showAlert(r('P_CUSTOMERRECORD', 'Customer Record'), data, 'warn');
return;
}
const add = new Follower({
getText: option.getText,
onMasking: option.onMasking,
followers: data,
onOk: list => {
@ -1085,7 +1108,7 @@ class CustomerCommunication {
}
}
});
var title = this.#data.followers?.length > 0 ? r('editFollowers', 'Edit Followers') : r('addFollowers', 'Add Followers');
var title = this.#data.followers?.length > 0 ? r('P_CU_EDITFOLLOWERS', 'Edit Followers') : r('P_CR_ADDFOLLOWERS', 'Add Followers');
add.show(title, container);
});
}
@ -1105,7 +1128,7 @@ class CustomerCommunication {
'border-radius': '15px',
'padding': '4px'
})
), r('copied', 'Copied')),
), r('P_CU_COPIED', 'Copied')),
createElement('div', 'bar-list',
followers,
buttonEditFollower
@ -1154,7 +1177,7 @@ class CustomerCommunication {
}
}
if (sendto !== '') {
sendto = r('sendToColon', 'Send To :') + `\n${sendto}`;
sendto = r('P_CU_SENDTO_COLON', 'Send To :') + `\n${sendto}`;
}
div.appendChild(createElement('div', div => {
div.className = 'item-poster';
@ -1164,13 +1187,12 @@ class CustomerCommunication {
}
}));
const content = createElement('div', 'item-content');
const emoji = s => s.replace(/(=[A-Fa-f0-9]{2}){4}/, s => decodeURIComponent(s.replaceAll('=', '%')));
const mmsParts = createElement('div', div => div.style.display = 'none');
content.appendChild(createElement('span', span => {
if (/https?:\/\//i.test(comm.Message)) {
span.innerHTML = emoji(formatUrl(comm.Message));
span.innerHTML = escapeEmoji(formatUrl(comm.Message));
} else {
span.innerText = emoji(comm.Message);
span.innerText = escapeEmoji(comm.Message);
}
span.appendChild(mmsParts);
}));
@ -1189,26 +1211,26 @@ class CustomerCommunication {
let statustext;
switch (status) {
case 0:
statustext = r('pending', 'Pending');
statustext = r('P_CU_PENDING', 'Pending');
content.style.backgroundColor = '#ffc107';
break;
case 1:
statustext = r('sent', 'Sent');
statustext = r('P_WO_SENT', 'Sent');
break;
case 9:
statustext = r('failed', 'Failed');
statustext = r('P_MA_FAILED', 'Failed');
content.style.backgroundColor = '#ffc107';
break;
case 10:
statustext = r('optOut', 'Opt-Out');
statustext = r('P_CU_OPTOUT', 'Opt-Out');
content.style.backgroundColor = '#ffc107';
break;
case 412:
statustext = r('landline', 'Landline');
statustext = r('P_CU_LANDLINE', 'Landline');
content.style.backgroundColor = '#ffc107';
break;
default:
statustext = r('undelivered', 'Undelivered');
statustext = r('P_CU_UNDELIVERED', 'Undelivered');
content.style.backgroundColor = '#ffc107';
break;
}
@ -1253,13 +1275,15 @@ class CustomerCommunication {
}
statusmsg += `${p.CustomerNumber}: `;
const st = ({
0: r('undelivered', 'Undelivered'),
1: r('sent', 'Sent'),
9: r('failed', 'Failed')
0: r('P_CU_UNDELIVERED', 'Undelivered'),
1: r('P_WO_SENT', 'Sent'),
9: r('P_MA_FAILED', 'Failed')
})[p.Status];
if (st != null) {
statusmsg += st;
}
else
statusmsg += r('P_MA_XXXXXX', 'Unknown');
}
}
}
@ -1270,6 +1294,4 @@ class CustomerCommunication {
}
return [status, statusmsg];
}
}
export default CustomerCommunication;
}