sync
This commit is contained in:
		@@ -1,8 +1,10 @@
 | 
				
			|||||||
import "./app/communications/style.scss";
 | 
					import "./app/communications/style.scss";
 | 
				
			||||||
import CustomerCommunication from "./app/communications/customer";
 | 
					import CustomerCommunication from "./app/communications/customer";
 | 
				
			||||||
import InternalComment from "./app/communications/internal";
 | 
					import InternalComment from "./app/communications/internal";
 | 
				
			||||||
 | 
					import CustomerRecordComment from "./app/communications/comments";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export {
 | 
					export {
 | 
				
			||||||
    CustomerCommunication,
 | 
					    CustomerCommunication,
 | 
				
			||||||
    InternalComment
 | 
					    InternalComment,
 | 
				
			||||||
 | 
					    CustomerRecordComment
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										162
									
								
								lib/app/communications/comments.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								lib/app/communications/comments.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
				
			|||||||
 | 
					import { createElement, setTooltip, createIcon } from "../../ui";
 | 
				
			||||||
 | 
					import { r as lang, nullOrEmpty, escapeHtml, escapeEmoji } from "../../utility";
 | 
				
			||||||
 | 
					import { createBox, appendMedia } from "./lib";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let r = lang;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class CustomerRecordComment {
 | 
				
			||||||
 | 
					    #container;
 | 
				
			||||||
 | 
					    #option;
 | 
				
			||||||
 | 
					    #enter;
 | 
				
			||||||
 | 
					    #message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(opt) {
 | 
				
			||||||
 | 
					        this.#option = opt ?? {};
 | 
				
			||||||
 | 
					        const getText = opt?.getText;
 | 
				
			||||||
 | 
					        if (typeof getText === 'function') {
 | 
				
			||||||
 | 
					            r = getText;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get text() { return this.#enter?.value }
 | 
				
			||||||
 | 
					    set text(s) {
 | 
				
			||||||
 | 
					        const element = this.#enter;
 | 
				
			||||||
 | 
					        if (element != null) {
 | 
				
			||||||
 | 
					            element.value = s
 | 
				
			||||||
 | 
					            s = String(nullOrEmpty(s) ? 0 : val.length) + '/' + String(this.#option.maxLength);
 | 
				
			||||||
 | 
					            this.#container.querySelector('.message-bar .prompt-count').innerText = s;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param {boolean} flag
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    set loading(flag) {
 | 
				
			||||||
 | 
					        if (this.#container == null) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.#enter.disabled = flag;
 | 
				
			||||||
 | 
					        this.#container.querySelector('.button-send-message').disabled = flag;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param {boolean} flag
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    set readonly(flag) {
 | 
				
			||||||
 | 
					        this.#option.readonly = flag;
 | 
				
			||||||
 | 
					        if (this.#container == null) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.#enter.disabled = flag === true;
 | 
				
			||||||
 | 
					        this.#container.querySelector('.button-send-message').style.display = flag === true ? 'none' : '';
 | 
				
			||||||
 | 
					        this.#container.querySelector('.message-bar .prompt-count').style.display = flag === true ? 'none' : '';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    create() {
 | 
				
			||||||
 | 
					        const readonly = this.#option.readonly;
 | 
				
			||||||
 | 
					        const container = createBox(
 | 
				
			||||||
 | 
					            createElement('div', null,
 | 
				
			||||||
 | 
					                createElement('div', div => {
 | 
				
			||||||
 | 
					                    div.className = 'title-module';
 | 
				
			||||||
 | 
					                    div.innerText = r('P_CR_COMMENTS', 'Comments');
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                createElement('button', button => {
 | 
				
			||||||
 | 
					                    button.className = 'roundbtn button-close';
 | 
				
			||||||
 | 
					                    button.style.backgroundColor = 'transparent';
 | 
				
			||||||
 | 
					                    if (this.#option.hasClose !== true) {
 | 
				
			||||||
 | 
					                        button.style.display = 'none';
 | 
				
			||||||
 | 
					                        return;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    button.appendChild(createIcon('fa-solid', 'times', {
 | 
				
			||||||
 | 
					                        fill: '#000'
 | 
				
			||||||
 | 
					                    }));
 | 
				
			||||||
 | 
					                    button.addEventListener('click', () => {
 | 
				
			||||||
 | 
					                        if (typeof this.#option.onClose === 'function') {
 | 
				
			||||||
 | 
					                            this.#option.onClose();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        // enter box
 | 
				
			||||||
 | 
					        const enter = createElement('textarea', 'ui-text');
 | 
				
			||||||
 | 
					        enter.placeholder = r('P_CU_ENTERCOMMENTHERE', 'Enter Comment Here');
 | 
				
			||||||
 | 
					        enter.maxLength = this.#option.maxLength ??= 3000;
 | 
				
			||||||
 | 
					        enter.addEventListener('input', () => {
 | 
				
			||||||
 | 
					            const val = this.text;
 | 
				
			||||||
 | 
					            const s = String(nullOrEmpty(val) ? 0 : val.length) + '/' + String(this.#option.maxLength);
 | 
				
			||||||
 | 
					            this.#container.querySelector('.message-bar .prompt-count').innerText = s;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        if (readonly === true) {
 | 
				
			||||||
 | 
					            enter.disabled = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.#enter = enter;
 | 
				
			||||||
 | 
					        container.appendChild(
 | 
				
			||||||
 | 
					            createElement('div', 'message-bar',
 | 
				
			||||||
 | 
					                enter,
 | 
				
			||||||
 | 
					                createElement('div', div => div.style.textAlign = 'right',
 | 
				
			||||||
 | 
					                    createElement('div', 'prompt-count'),
 | 
				
			||||||
 | 
					                    createElement('button', button => {
 | 
				
			||||||
 | 
					                        button.className = 'roundbtn button-send-message';
 | 
				
			||||||
 | 
					                        button.style.backgroundColor = 'rgb(19, 150, 204)';
 | 
				
			||||||
 | 
					                        if (readonly === true) {
 | 
				
			||||||
 | 
					                            button.style.display = 'none';
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        button.appendChild(createIcon('fa-solid', 'paper-plane'));
 | 
				
			||||||
 | 
					                        // setTooltip(button, r('P_M3_SENDMESSAGE', 'Send Message'));
 | 
				
			||||||
 | 
					                        setTooltip(button, r('P_CU_POSTNOTE', 'Post Note'));
 | 
				
			||||||
 | 
					                        button.addEventListener('click', () => {
 | 
				
			||||||
 | 
					                            if (typeof this.#option.onAddComment === 'function') {
 | 
				
			||||||
 | 
					                                this.#option.onAddComment(this.text);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        })
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const message = createElement('div', 'list-bar');
 | 
				
			||||||
 | 
					        this.#message = message;
 | 
				
			||||||
 | 
					        container.appendChild(message);
 | 
				
			||||||
 | 
					        return this.#container = container;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    load(data) {
 | 
				
			||||||
 | 
					        const children = [];
 | 
				
			||||||
 | 
					        if (data?.length > 0) {
 | 
				
			||||||
 | 
					            for (let comment of data) {
 | 
				
			||||||
 | 
					                const div = createElement('div', 'item-div');
 | 
				
			||||||
 | 
					                // if (sendto !== '') {
 | 
				
			||||||
 | 
					                //     sendto = r('P_CU_SENDTO_COLON', 'Send To :') + `\n${sendto}`;
 | 
				
			||||||
 | 
					                // }
 | 
				
			||||||
 | 
					                div.appendChild(createElement('div', div => {
 | 
				
			||||||
 | 
					                    div.className = 'item-poster';
 | 
				
			||||||
 | 
					                    div.innerText = comment.UserName;
 | 
				
			||||||
 | 
					                }));
 | 
				
			||||||
 | 
					                const content = createElement('div', 'item-content');
 | 
				
			||||||
 | 
					                const mmsParts = createElement('div', div => div.style.display = 'none');
 | 
				
			||||||
 | 
					                content.appendChild(createElement('span', span => span.innerHTML = escapeEmoji(escapeHtml(comment.Comment)), mmsParts));
 | 
				
			||||||
 | 
					                if (comment.IsMMS && comment.MMSParts?.length > 0) {
 | 
				
			||||||
 | 
					                    mmsParts.style.display = '';
 | 
				
			||||||
 | 
					                    for (let kv of comment.MMSParts) {
 | 
				
			||||||
 | 
					                        appendMedia(mmsParts, kv.Key, kv.Value);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                div.append(
 | 
				
			||||||
 | 
					                    content,
 | 
				
			||||||
 | 
					                    createElement('div', div => {
 | 
				
			||||||
 | 
					                        div.className = 'item-time';
 | 
				
			||||||
 | 
					                        div.innerText = comment.SubmitLocalDateStr;
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                children.push(div);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            children[0].style.marginTop = '0';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.#message.replaceChildren(...children);
 | 
				
			||||||
 | 
					        this.#message.scrollTop = this.#message.scrollHeight
 | 
				
			||||||
 | 
					        // setTimeout(() => this.#message.scrollTop = this.#message.scrollHeight, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
import { Grid, Dropdown, createElement, createCheckbox, Popup, showAlert } from "../../ui";
 | 
					import { Grid, Dropdown, createElement, createCheckbox, Popup, showAlert } from "../../ui";
 | 
				
			||||||
import { isEmail, nullOrEmpty, r } from "../../utility";
 | 
					import { isEmail, nullOrEmpty, r as lang } from "../../utility";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let r = lang;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class Contact {
 | 
					export class Contact {
 | 
				
			||||||
    #option;
 | 
					    #option;
 | 
				
			||||||
@@ -7,6 +9,10 @@ export class Contact {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    constructor(option = {}) {
 | 
					    constructor(option = {}) {
 | 
				
			||||||
        this.#option = option;
 | 
					        this.#option = option;
 | 
				
			||||||
 | 
					        const getText = option?.getText;
 | 
				
			||||||
 | 
					        if (typeof getText === 'function') {
 | 
				
			||||||
 | 
					            r = getText;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async show(parent = document.body) {
 | 
					    async show(parent = document.body) {
 | 
				
			||||||
@@ -22,9 +28,9 @@ export class Contact {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
        const preferences = new Dropdown({ tabIndex: tabIndex + 2 });
 | 
					        const preferences = new Dropdown({ tabIndex: tabIndex + 2 });
 | 
				
			||||||
        preferences.source = [
 | 
					        preferences.source = [
 | 
				
			||||||
            { value: '0', text: r('text', 'Text') },
 | 
					            { value: '0', text: r('P_CR_TEXT', 'Text') },
 | 
				
			||||||
            { value: '1', text: r('email', 'Email') },
 | 
					            { value: '1', text: r('P_CR_EMAIL', 'Email') },
 | 
				
			||||||
            { value: '2', text: r('phone', 'Phone') }
 | 
					            { value: '2', text: r('P_CR_PHONE', 'Phone') }
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
        const contactEmail = createElement('input', input => {
 | 
					        const contactEmail = createElement('input', input => {
 | 
				
			||||||
            input.type = 'email';
 | 
					            input.type = 'email';
 | 
				
			||||||
@@ -50,7 +56,7 @@ export class Contact {
 | 
				
			|||||||
        const buttons = [];
 | 
					        const buttons = [];
 | 
				
			||||||
        if (this.#option.company) {
 | 
					        if (this.#option.company) {
 | 
				
			||||||
            buttons.push({
 | 
					            buttons.push({
 | 
				
			||||||
                text: c == null ? r('addContactRecord', 'Add Contact Record') : r('editContactRecord', 'Edit Contact Record'),
 | 
					                text: c == null ? r('P_WO_ADDCONTACTRECORD', 'Add Contact Record') : r('P_WO_EDITCONTACTRECORD', 'Edit Contact Record'),
 | 
				
			||||||
                // tabIndex: tabIndex + 7,
 | 
					                // tabIndex: tabIndex + 7,
 | 
				
			||||||
                trigger: () => {
 | 
					                trigger: () => {
 | 
				
			||||||
                    const item = this.prepare();
 | 
					                    const item = this.prepare();
 | 
				
			||||||
@@ -66,7 +72,7 @@ export class Contact {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        buttons.push(
 | 
					        buttons.push(
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                text: r('workOrderOnly', 'Work Order Only'),
 | 
					                text: r('P_WO_WORKORDERONLY', 'Work Order Only'),
 | 
				
			||||||
                // tabIndex: tabIndex + 8,
 | 
					                // tabIndex: tabIndex + 8,
 | 
				
			||||||
                trigger: () => {
 | 
					                trigger: () => {
 | 
				
			||||||
                    const item = this.prepare();
 | 
					                    const item = this.prepare();
 | 
				
			||||||
@@ -81,39 +87,39 @@ export class Contact {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                text: r('cancel', 'Cancel'),
 | 
					                text: r('P_WO_CANCEL', 'Cancel'),
 | 
				
			||||||
                // tabIndex: tabIndex + 9
 | 
					                // tabIndex: tabIndex + 9
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        const popup = new Popup({
 | 
					        const popup = new Popup({
 | 
				
			||||||
            onMasking: this.#option.onMasking,
 | 
					            onMasking: this.#option.onMasking,
 | 
				
			||||||
            title: c == null ? r('addContact', 'Add Contact') : r('editContact', 'Edit Contact'),
 | 
					            title: c == null ? r('P_CR_ADDCONTACT', 'Add Contact') : r('P_CR_EDITCONTACT', 'Edit Contact'),
 | 
				
			||||||
            content: createElement('div', wrapper => {
 | 
					            content: createElement('div', wrapper => {
 | 
				
			||||||
                wrapper.className = 'setting-wrapper';
 | 
					                wrapper.className = 'setting-wrapper';
 | 
				
			||||||
                wrapper.style.width = '500px';
 | 
					                wrapper.style.width = '500px';
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
                createElement('div', 'setting-item',
 | 
					                createElement('div', 'setting-item',
 | 
				
			||||||
                    createElement('span', 'setting-label setting-required', r('contactNameColon', 'Contact Name:')),
 | 
					                    createElement('span', 'setting-label setting-required', r('P_CR_CONTACTNAME_COLON', 'Contact Name:')),
 | 
				
			||||||
                    contactName
 | 
					                    contactName
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                createElement('div', 'setting-item',
 | 
					                createElement('div', 'setting-item',
 | 
				
			||||||
                    createElement('span', 'setting-label', r('contactPreferencesColon', 'Contact Preferences:')),
 | 
					                    createElement('span', 'setting-label', r('P_CR_CONTACTPREFERENCES_COLON', 'Contact Preferences:')),
 | 
				
			||||||
                    preferences.create()
 | 
					                    preferences.create()
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                createElement('div', 'setting-item',
 | 
					                createElement('div', 'setting-item',
 | 
				
			||||||
                    createElement('span', 'setting-label', r('contactEmailColon', 'Email Address:')),
 | 
					                    createElement('span', 'setting-label', r('P_CR_EMAILADDRESS_COLON', 'Email Address:')),
 | 
				
			||||||
                    contactEmail
 | 
					                    contactEmail
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                createElement('div', 'setting-item',
 | 
					                createElement('div', 'setting-item',
 | 
				
			||||||
                    createElement('span', 'setting-label', r('contactMobileColon', 'Mobile:')),
 | 
					                    createElement('span', 'setting-label', r('P_WO_MOBILE_COLON', 'Mobile:')),
 | 
				
			||||||
                    contactMobile
 | 
					                    contactMobile
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                createElement('div', 'setting-item',
 | 
					                createElement('div', 'setting-item',
 | 
				
			||||||
                    createElement('span', 'setting-label', r('contactOptColon', 'Opt Out:')),
 | 
					                    createElement('span', 'setting-label', r('P_CR_OPTOUT_COLON', 'Opt Out:')),
 | 
				
			||||||
                    checkOpt
 | 
					                    checkOpt
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                createElement('div', 'setting-item',
 | 
					                createElement('div', 'setting-item',
 | 
				
			||||||
                    createElement('span', 'setting-label', r('contactNotesColon', 'Notes:')),
 | 
					                    createElement('span', 'setting-label', r('P_CR_NOTES_COLON', 'Notes:')),
 | 
				
			||||||
                    contactNotes
 | 
					                    contactNotes
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
@@ -149,24 +155,24 @@ export class Contact {
 | 
				
			|||||||
        const phone = this.#refs.contactMobile.value;
 | 
					        const phone = this.#refs.contactMobile.value;
 | 
				
			||||||
        const opt = this.#refs.checkOpt.querySelector('input').checked;
 | 
					        const opt = this.#refs.checkOpt.querySelector('input').checked;
 | 
				
			||||||
        const notes = this.#refs.contactNotes.value;
 | 
					        const notes = this.#refs.contactNotes.value;
 | 
				
			||||||
        const title = this.#option.contact == null ? r('addContact', 'Add Contact') : r('editContact', 'Edit Contact');
 | 
					        const title = this.#option.contact == null ? r('P_CR_ADDCONTACT', 'Add Contact') : r('P_CR_EDITCONTACT', 'Edit Contact');
 | 
				
			||||||
        if (nullOrEmpty(name)) {
 | 
					        if (nullOrEmpty(name)) {
 | 
				
			||||||
            showAlert(title, r('contactNameRequired', 'Contact Name cannot be empty.'), 'warn')
 | 
					            showAlert(title, r('P_CR_CONTACTNAMECANNOTBEEMPTY', 'Contact Name cannot be empty.'), 'warn')
 | 
				
			||||||
                .then(() => this.#refs.contactName.focus());
 | 
					                .then(() => this.#refs.contactName.focus());
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if ((pref == 0 || pref == 2) && nullOrEmpty(phone)) {
 | 
					        if ((pref == 0 || pref == 2) && nullOrEmpty(phone)) {
 | 
				
			||||||
            showAlert(title, r('contactPhoneRequired', 'Mobile cannot be empty.'), 'warn')
 | 
					            showAlert(title, r('P_CR_MOBILECANNOTBEEMPTY', 'Mobile cannot be empty.'), 'warn')
 | 
				
			||||||
                .then(() => this.#refs.contactMobile.focus());
 | 
					                .then(() => this.#refs.contactMobile.focus());
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (pref == 1 && nullOrEmpty(email)) {
 | 
					        if (pref == 1 && nullOrEmpty(email)) {
 | 
				
			||||||
            showAlert(title, r('contactEmailRequired', 'Email cannot be empty.'), 'warn')
 | 
					            showAlert(title, r('P_CU_EMAILCANNOTBEEMPTY', 'Email cannot be empty.'), 'warn')
 | 
				
			||||||
                .then(() => this.#refs.contactEmail.focus());
 | 
					                .then(() => this.#refs.contactEmail.focus());
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (!nullOrEmpty(email) && !isEmail(email)) {
 | 
					        if (!nullOrEmpty(email) && !isEmail(email)) {
 | 
				
			||||||
            showAlert(title, r('contactEmailInvalid', 'The email address is invalid.'), 'warn')
 | 
					            showAlert(title, r('P_CR_EMAILISNOTAVALIDEMAILADDRESS', 'The email address is invalid.'), 'warn')
 | 
				
			||||||
                .then(() => this.#refs.contactEmail.focus());
 | 
					                .then(() => this.#refs.contactEmail.focus());
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -197,6 +203,10 @@ export class CustomerRecordContact {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    constructor(option = {}) {
 | 
					    constructor(option = {}) {
 | 
				
			||||||
        this.#option = option;
 | 
					        this.#option = option;
 | 
				
			||||||
 | 
					        const getText = option?.getText;
 | 
				
			||||||
 | 
					        if (typeof getText === 'function') {
 | 
				
			||||||
 | 
					            r = getText;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async show(title, parent = document.body) {
 | 
					    async show(title, parent = document.body) {
 | 
				
			||||||
@@ -211,7 +221,7 @@ export class CustomerRecordContact {
 | 
				
			|||||||
            ),
 | 
					            ),
 | 
				
			||||||
            buttons: [
 | 
					            buttons: [
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    text: r('ok', 'OK'),
 | 
					                    text: r('P_WO_OK', 'OK'),
 | 
				
			||||||
                    key: 'ok',
 | 
					                    key: 'ok',
 | 
				
			||||||
                    trigger: () => {
 | 
					                    trigger: () => {
 | 
				
			||||||
                        if (typeof this.#option.onOk === 'function') {
 | 
					                        if (typeof this.#option.onOk === 'function') {
 | 
				
			||||||
@@ -219,7 +229,7 @@ export class CustomerRecordContact {
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                { text: r('cancel', 'Cancel'), key: 'cancel' }
 | 
					                { text: r('P_WO_CANCEL', 'Cancel'), key: 'cancel' }
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        const result = await popup.show(parent);
 | 
					        const result = await popup.show(parent);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								lib/app/communications/customer.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								lib/app/communications/customer.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -9,7 +9,7 @@ interface InitConfig {
 | 
				
			|||||||
    readonly?: boolean;
 | 
					    readonly?: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class CustomerCommunication {
 | 
					export default class CustomerCommunication {
 | 
				
			||||||
    constructor (opt: InitConfig);
 | 
					    constructor (opt: InitConfig);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get autoUpdatesEnabled(): boolean;
 | 
					    get autoUpdatesEnabled(): boolean;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import { Grid, GridColumn, createElement, setTooltip, createIcon, createCheckbox, createRadiobox, showAlert, showConfirm, Popup } from "../../ui";
 | 
					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 { createBox, appendMedia, fileSupported, insertFile } from "./lib";
 | 
				
			||||||
import { Contact, CustomerRecordContact } from "./contact";
 | 
					import { Contact, CustomerRecordContact } from "./contact";
 | 
				
			||||||
import Follower from "./follower";
 | 
					import Follower from "./follower";
 | 
				
			||||||
@@ -28,7 +28,9 @@ class NoteCol extends GridColumn {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CustomerCommunication {
 | 
					let r = lang;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class CustomerCommunication {
 | 
				
			||||||
    #container;
 | 
					    #container;
 | 
				
			||||||
    #option;
 | 
					    #option;
 | 
				
			||||||
    #contacts;
 | 
					    #contacts;
 | 
				
			||||||
@@ -44,6 +46,10 @@ class CustomerCommunication {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    constructor(opt) {
 | 
					    constructor(opt) {
 | 
				
			||||||
        this.#option = opt ?? {};
 | 
					        this.#option = opt ?? {};
 | 
				
			||||||
 | 
					        const getText = opt?.getText;
 | 
				
			||||||
 | 
					        if (typeof getText === 'function') {
 | 
				
			||||||
 | 
					            r = getText;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get #autoUpdates() { return this.#container.querySelector('.check-auto-update>input') }
 | 
					    get #autoUpdates() { return this.#container.querySelector('.check-auto-update>input') }
 | 
				
			||||||
@@ -191,21 +197,21 @@ class CustomerCommunication {
 | 
				
			|||||||
                let method;
 | 
					                let method;
 | 
				
			||||||
                if (c.OptOut || c.OptOut_BC || c.selected === false) {
 | 
					                if (c.OptOut || c.OptOut_BC || c.selected === false) {
 | 
				
			||||||
                    icon = 'times';
 | 
					                    icon = 'times';
 | 
				
			||||||
                    method = r('optedOut', 'Opted Out:');
 | 
					                    method = r('P_CU_OPTEDOUT_COLON', 'Opted Out:');
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else {
 | 
					                else {
 | 
				
			||||||
                    switch (pref) {
 | 
					                    switch (pref) {
 | 
				
			||||||
                        case '0':
 | 
					                        case '0':
 | 
				
			||||||
                            icon = 'comment-lines';
 | 
					                            icon = 'comment-lines';
 | 
				
			||||||
                            method = r('textsToColon', 'Texts to:');
 | 
					                            method = r('P_CU_TEXTSTO_COLON', 'Texts to:');
 | 
				
			||||||
                            break;
 | 
					                            break;
 | 
				
			||||||
                        case '2':
 | 
					                        case '2':
 | 
				
			||||||
                            icon = 'mobile';
 | 
					                            icon = 'mobile';
 | 
				
			||||||
                            method = r('callsToColon', 'Calls to:');
 | 
					                            method = r('P_CU_CALLSTO_COLON', 'Calls to:');
 | 
				
			||||||
                            break;
 | 
					                            break;
 | 
				
			||||||
                        default:
 | 
					                        default:
 | 
				
			||||||
                            icon = 'envelope';
 | 
					                            icon = 'envelope';
 | 
				
			||||||
                            method = r('emailsToColon', 'Emails to:');
 | 
					                            method = r('P_CU_EMAILSTO_COLON', 'Emails to:');
 | 
				
			||||||
                            break;
 | 
					                            break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -222,7 +228,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                this.#contacts.appendChild(item);
 | 
					                this.#contacts.appendChild(item);
 | 
				
			||||||
                let tip = `${method} ${to}`;
 | 
					                let tip = `${method} ${to}`;
 | 
				
			||||||
                if (span.scrollWidth > span.offsetWidth) {
 | 
					                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);
 | 
					                setTooltip(span, tip);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -306,7 +312,7 @@ class CustomerCommunication {
 | 
				
			|||||||
        this.#followers.replaceChildren();
 | 
					        this.#followers.replaceChildren();
 | 
				
			||||||
        if (followers?.length > 0) {
 | 
					        if (followers?.length > 0) {
 | 
				
			||||||
            this.#container.querySelector('.follower-bar').style.display = '';
 | 
					            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);
 | 
					            this.#container.querySelector('.follower-bar>.bar-list').appendChild(this.#buttonFollower);
 | 
				
			||||||
            for (let f of followers) {
 | 
					            for (let f of followers) {
 | 
				
			||||||
                if (f.OptOut) {
 | 
					                if (f.OptOut) {
 | 
				
			||||||
@@ -317,10 +323,10 @@ class CustomerCommunication {
 | 
				
			|||||||
                const email = String(f.Email).trim();
 | 
					                const email = String(f.Email).trim();
 | 
				
			||||||
                const tips = [];
 | 
					                const tips = [];
 | 
				
			||||||
                if (f.SendEmail) {
 | 
					                if (f.SendEmail) {
 | 
				
			||||||
                    tips.push(r('emailsToColon', 'Emails to:') + ` ${email}`);
 | 
					                    tips.push(r('P_CU_EMAILSTO_COLON', 'Emails to:') + ` ${email}`);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (f.SendText) {
 | 
					                if (f.SendText) {
 | 
				
			||||||
                    tips.push(r('textsToColon', 'Texts to:' + ` ${mpDisplay}`));
 | 
					                    tips.push(r('P_CU_TEXTSTO_COLON', 'Texts to:' + ` ${mpDisplay}`));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                let icon;
 | 
					                let icon;
 | 
				
			||||||
                if (f.SendText && f.SendEmail) {
 | 
					                if (f.SendText && f.SendEmail) {
 | 
				
			||||||
@@ -344,13 +350,13 @@ class CustomerCommunication {
 | 
				
			|||||||
                );
 | 
					                );
 | 
				
			||||||
                this.#followers.appendChild(item);
 | 
					                this.#followers.appendChild(item);
 | 
				
			||||||
                if (span.scrollWidth > span.offsetWidth) {
 | 
					                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'));
 | 
					                setTooltip(span, tips.join('\n'));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            this.#container.querySelector('.follower-bar').style.display = 'none';
 | 
					            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.#container.querySelector('.button-edit-contacts').insertAdjacentElement('beforebegin', this.#buttonFollower)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        this.#message.scrollTop = this.#message.scrollHeight
 | 
					        this.#message.scrollTop = this.#message.scrollHeight
 | 
				
			||||||
@@ -371,8 +377,8 @@ class CustomerCommunication {
 | 
				
			|||||||
            uncheckedNode: createIcon('fa-regular', 'ban'),
 | 
					            uncheckedNode: createIcon('fa-regular', 'ban'),
 | 
				
			||||||
            onchange: function () {
 | 
					            onchange: function () {
 | 
				
			||||||
                setTooltip(checkAutoUpdate, this.checked ?
 | 
					                setTooltip(checkAutoUpdate, this.checked ?
 | 
				
			||||||
                    r('autoUpdateEnabled', 'Auto Updates Enabled') :
 | 
					                    r('P_CU_AUTOUPDATESENABLED', 'Auto Updates Enabled') :
 | 
				
			||||||
                    r('autoUpdateDisabled', 'Auto Updates Disabled'));
 | 
					                    r('P_CU_AUTOUPDATESDISABLED', 'Auto Updates Disabled'));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        if (option.autoUpdatesVisible === false) {
 | 
					        if (option.autoUpdatesVisible === false) {
 | 
				
			||||||
@@ -387,8 +393,8 @@ class CustomerCommunication {
 | 
				
			|||||||
            uncheckedNode: createIcon('fa-regular', 'unlink'),
 | 
					            uncheckedNode: createIcon('fa-regular', 'unlink'),
 | 
				
			||||||
            onchange: function () {
 | 
					            onchange: function () {
 | 
				
			||||||
                setTooltip(checkLink, this.checked ?
 | 
					                setTooltip(checkLink, this.checked ?
 | 
				
			||||||
                    r('statusLinkIncluded', 'Status Link Included') :
 | 
					                    r('P_WO_STATUSLINKINCLUDED', 'Status Link Included') :
 | 
				
			||||||
                    r('statusLinkExcluded', 'Status Link Excluded'));
 | 
					                    r('P_WO_STATUSLINKEXCLUDED', 'Status Link Excluded'));
 | 
				
			||||||
                if (typeof option.onStatusLinkChanged === 'function') {
 | 
					                if (typeof option.onStatusLinkChanged === 'function') {
 | 
				
			||||||
                    option.onStatusLinkChanged.call(This, this.checked);
 | 
					                    option.onStatusLinkChanged.call(This, this.checked);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -401,7 +407,7 @@ class CustomerCommunication {
 | 
				
			|||||||
            createElement('div', null,
 | 
					            createElement('div', null,
 | 
				
			||||||
                createElement('div', div => {
 | 
					                createElement('div', div => {
 | 
				
			||||||
                    div.className = 'title-module';
 | 
					                    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 => {
 | 
					                createElement('div', div => {
 | 
				
			||||||
                    div.className = 'title-company';
 | 
					                    div.className = 'title-company';
 | 
				
			||||||
@@ -417,8 +423,8 @@ class CustomerCommunication {
 | 
				
			|||||||
                })
 | 
					                })
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            [
 | 
					            [
 | 
				
			||||||
                setTooltip(checkAutoUpdate, r('autoUpdateEnabled', 'Auto Updates Enabled')),
 | 
					                setTooltip(checkAutoUpdate, r('P_CU_AUTOUPDATESENABLED', 'Auto Updates Enabled')),
 | 
				
			||||||
                setTooltip(checkLink, r('statusLinkExcluded', 'Status Link Excluded'))
 | 
					                setTooltip(checkLink, r('P_WO_STATUSLINKEXCLUDED', 'Status Link Excluded'))
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        // contacts
 | 
					        // contacts
 | 
				
			||||||
@@ -427,7 +433,7 @@ class CustomerCommunication {
 | 
				
			|||||||
        this.#followers = this.#createFollowers(container, option);
 | 
					        this.#followers = this.#createFollowers(container, option);
 | 
				
			||||||
        // enter box
 | 
					        // enter box
 | 
				
			||||||
        const enter = createElement('textarea', 'ui-text');
 | 
					        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;
 | 
					        option.maxLength ??= 3000;
 | 
				
			||||||
        enter.maxLength = option.maxLength;
 | 
					        enter.maxLength = option.maxLength;
 | 
				
			||||||
        // if (readonly === true) {
 | 
					        // if (readonly === true) {
 | 
				
			||||||
@@ -442,11 +448,23 @@ class CustomerCommunication {
 | 
				
			|||||||
            if (option.customerNameVisible === true) {
 | 
					            if (option.customerNameVisible === true) {
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            const file = e.clipboardData.files[0];
 | 
					            const items = e.clipboardData.items;
 | 
				
			||||||
            if (file != null) {
 | 
					            if (items?.length > 0) {
 | 
				
			||||||
                e.preventDefault();
 | 
					                const item = items[0];
 | 
				
			||||||
                this.file = insertFile(container, file);
 | 
					                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;
 | 
					        this.#enter = enter;
 | 
				
			||||||
        container.appendChild(
 | 
					        container.appendChild(
 | 
				
			||||||
@@ -473,7 +491,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                        const file = e.dataTransfer.files[0];
 | 
					                        const file = e.dataTransfer.files[0];
 | 
				
			||||||
                        if (file != null) {
 | 
					                        if (file != null) {
 | 
				
			||||||
                            e.preventDefault();
 | 
					                            e.preventDefault();
 | 
				
			||||||
                            this.file = insertFile(container, file);
 | 
					                            this.file = insertFile(container, file, r);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
@@ -486,7 +504,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                            div.style.display = 'none';
 | 
					                            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 => {
 | 
					                        createElement('input', input => {
 | 
				
			||||||
                            input.type = 'text';
 | 
					                            input.type = 'text';
 | 
				
			||||||
                            input.className = 'ui-input';
 | 
					                            input.className = 'ui-input';
 | 
				
			||||||
@@ -506,7 +524,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                                    input.type = 'file';
 | 
					                                    input.type = 'file';
 | 
				
			||||||
                                    input.accept = fileSupported.join(',');
 | 
					                                    input.accept = fileSupported.join(',');
 | 
				
			||||||
                                    input.addEventListener('change', () => {
 | 
					                                    input.addEventListener('change', () => {
 | 
				
			||||||
                                        const file = insertFile(container, input.files?.[0]);
 | 
					                                        const file = insertFile(container, input.files?.[0], r);
 | 
				
			||||||
                                        if (file != null) {
 | 
					                                        if (file != null) {
 | 
				
			||||||
                                            this.file = file;
 | 
					                                            this.file = file;
 | 
				
			||||||
                                        }
 | 
					                                        }
 | 
				
			||||||
@@ -535,11 +553,11 @@ class CustomerCommunication {
 | 
				
			|||||||
                        //     button.style.display = 'none';
 | 
					                        //     button.style.display = 'none';
 | 
				
			||||||
                        // }
 | 
					                        // }
 | 
				
			||||||
                        button.appendChild(createIcon('fa-solid', 'paper-plane'));
 | 
					                        button.appendChild(createIcon('fa-solid', 'paper-plane'));
 | 
				
			||||||
                        setTooltip(button, r('sendMessage', 'Send Message'));
 | 
					                        setTooltip(button, r('P_M3_SENDMESSAGE', 'Send Message'));
 | 
				
			||||||
                        button.addEventListener('click', () => {
 | 
					                        button.addEventListener('click', () => {
 | 
				
			||||||
                            const val = this.text;
 | 
					                            const val = this.text;
 | 
				
			||||||
                            if (nullOrEmpty(val?.trim())) {
 | 
					                            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') {
 | 
					                                if (typeof option.onMasking === 'function') {
 | 
				
			||||||
                                    option.onMasking(true);
 | 
					                                    option.onMasking(true);
 | 
				
			||||||
                                    p.then(() => option.onMasking(false));
 | 
					                                    p.then(() => option.onMasking(false));
 | 
				
			||||||
@@ -547,6 +565,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                                return;
 | 
					                                return;
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            if (typeof option.onAddMessage === 'function') {
 | 
					                            if (typeof option.onAddMessage === 'function') {
 | 
				
			||||||
 | 
					                                this.loading = true;
 | 
				
			||||||
                                option.onAddMessage(this.text, this.file);
 | 
					                                option.onAddMessage(this.text, this.file);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        })
 | 
					                        })
 | 
				
			||||||
@@ -581,7 +600,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                            button.style.display = 'none';
 | 
					                            button.style.display = 'none';
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        button.appendChild(createIcon('fa-solid', 'user-edit'));
 | 
					                        button.appendChild(createIcon('fa-solid', 'user-edit'));
 | 
				
			||||||
                        setTooltip(button, r('editContacts', 'Edit Contacts'));
 | 
					                        setTooltip(button, r('P_CU_EDITCONTACTS', 'Edit Contacts'));
 | 
				
			||||||
                        button.addEventListener('click', () => {
 | 
					                        button.addEventListener('click', () => {
 | 
				
			||||||
                            const pop = new Popup({
 | 
					                            const pop = new Popup({
 | 
				
			||||||
                                onMasking: option.onMasking,
 | 
					                                onMasking: option.onMasking,
 | 
				
			||||||
@@ -594,7 +613,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                                            div.className = 'ui-popup-move';
 | 
					                                            div.className = 'ui-popup-move';
 | 
				
			||||||
                                            div.style.flex = '1 1 auto';
 | 
					                                            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 => {
 | 
					                                            createElement('div', div => {
 | 
				
			||||||
                                                div.className = 'title-company';
 | 
					                                                div.className = 'title-company';
 | 
				
			||||||
                                                if (nullOrEmpty(option.companyName)) {
 | 
					                                                if (nullOrEmpty(option.companyName)) {
 | 
				
			||||||
@@ -622,6 +641,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                                            }));
 | 
					                                            }));
 | 
				
			||||||
                                            button.addEventListener('click', () => {
 | 
					                                            button.addEventListener('click', () => {
 | 
				
			||||||
                                                const sel = new CustomerRecordContact({
 | 
					                                                const sel = new CustomerRecordContact({
 | 
				
			||||||
 | 
					                                                    getText: option.getText,
 | 
				
			||||||
                                                    // onMasking: option.onMasking,
 | 
					                                                    // onMasking: option.onMasking,
 | 
				
			||||||
                                                    contacts: [],
 | 
					                                                    contacts: [],
 | 
				
			||||||
                                                    onOk: list => {
 | 
					                                                    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);
 | 
					                                                sel.show(title, container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                                if (typeof option.onOpenSelectCRContacts === 'function') {
 | 
					                                                if (typeof option.onOpenSelectCRContacts === 'function') {
 | 
				
			||||||
@@ -689,7 +709,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                                                    return false;
 | 
					                                                    return false;
 | 
				
			||||||
                                                }
 | 
					                                                }
 | 
				
			||||||
                                            });
 | 
					                                            });
 | 
				
			||||||
                                            setTooltip(button, r('selectFromCustomerRecord', 'Select from Customer Record'))
 | 
					                                            setTooltip(button, r('P_CU_SELECTFROMCUSTOMERRECORD', 'Select from Customer Record'))
 | 
				
			||||||
                                        }),
 | 
					                                        }),
 | 
				
			||||||
                                        createElement('button', button => {
 | 
					                                        createElement('button', button => {
 | 
				
			||||||
                                            button.style.flex = '0 0 auto';
 | 
					                                            button.style.flex = '0 0 auto';
 | 
				
			||||||
@@ -705,12 +725,13 @@ class CustomerCommunication {
 | 
				
			|||||||
                                            }));
 | 
					                                            }));
 | 
				
			||||||
                                            button.addEventListener('click', () => {
 | 
					                                            button.addEventListener('click', () => {
 | 
				
			||||||
                                                const add = new Contact({
 | 
					                                                const add = new Contact({
 | 
				
			||||||
 | 
					                                                    getText: option.getText,
 | 
				
			||||||
                                                    // onMasking: option.onMasking,
 | 
					                                                    // onMasking: option.onMasking,
 | 
				
			||||||
                                                    company: !nullOrEmpty(option.companyName),
 | 
					                                                    company: !nullOrEmpty(option.companyName),
 | 
				
			||||||
                                                    onSave: item => {
 | 
					                                                    onSave: item => {
 | 
				
			||||||
                                                        const exists = this.#gridContact.source.some(s => s.Name === item.Name && s.MobilePhone === item.MobilePhone);
 | 
					                                                        const exists = this.#gridContact.source.some(s => s.Name === item.Name && s.MobilePhone === item.MobilePhone);
 | 
				
			||||||
                                                        if (exists) {
 | 
					                                                        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;
 | 
					                                                            return false;
 | 
				
			||||||
                                                        }
 | 
					                                                        }
 | 
				
			||||||
                                                        if (typeof option.onSave === 'function') {
 | 
					                                                        if (typeof option.onSave === 'function') {
 | 
				
			||||||
@@ -744,7 +765,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                                                });
 | 
					                                                });
 | 
				
			||||||
                                                add.show(container);
 | 
					                                                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.display = 'none';
 | 
				
			||||||
                                        }
 | 
					                                        }
 | 
				
			||||||
                                        div.style.fontWeight = 'bold';
 | 
					                                        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 => {
 | 
					                                    createElement('div', div => {
 | 
				
			||||||
                                        if (nullOrEmpty(option.companyName)) {
 | 
					                                        if (nullOrEmpty(option.companyName)) {
 | 
				
			||||||
@@ -767,7 +788,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                                    }),
 | 
					                                    }),
 | 
				
			||||||
                                    createElement('div', div => {
 | 
					                                    createElement('div', div => {
 | 
				
			||||||
                                        div.style.fontWeight = 'bold';
 | 
					                                        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 => {
 | 
					                                    createElement('div', div => {
 | 
				
			||||||
                                        div.className = 'contacts-wo';
 | 
					                                        div.className = 'contacts-wo';
 | 
				
			||||||
@@ -789,7 +810,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                                                option.onChanged([...This.#gridContact.source, ...This.#gridWo.source]);
 | 
					                                                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 = {
 | 
					                                const iconCol = {
 | 
				
			||||||
@@ -819,19 +840,20 @@ class CustomerCommunication {
 | 
				
			|||||||
                                        key: 'edit',
 | 
					                                        key: 'edit',
 | 
				
			||||||
                                        ...buttonCol,
 | 
					                                        ...buttonCol,
 | 
				
			||||||
                                        text: 'edit',
 | 
					                                        text: 'edit',
 | 
				
			||||||
                                        tooltip: r('edit', 'Edit'),
 | 
					                                        tooltip: r('P_WO_EDIT', 'Edit'),
 | 
				
			||||||
                                        events: {
 | 
					                                        events: {
 | 
				
			||||||
                                            onclick: function () {
 | 
					                                            onclick: function () {
 | 
				
			||||||
                                                const edit = new Contact({
 | 
					                                                const edit = new Contact({
 | 
				
			||||||
 | 
					                                                    getText: option.getText,
 | 
				
			||||||
                                                    // onMasking: option.onMasking,
 | 
					                                                    // onMasking: option.onMasking,
 | 
				
			||||||
                                                    contact: this,
 | 
					                                                    contact: this,
 | 
				
			||||||
                                                    company: !nullOrEmpty(This.#option.companyName),
 | 
					                                                    company: !nullOrEmpty(option.companyName),
 | 
				
			||||||
                                                    onSave: (item, _op) => {
 | 
					                                                    onSave: (item, _op) => {
 | 
				
			||||||
                                                        const exists =
 | 
					                                                        const exists =
 | 
				
			||||||
                                                            This.#gridContact.source.some(s => s !== this && s.Name === item.Name && s.MobilePhone === item.MobilePhone) ||
 | 
					                                                            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);
 | 
					                                                            This.#gridWo.source.some(s => s !== this && s.Name === item.Name && s.MobilePhone === item.MobilePhone);
 | 
				
			||||||
                                                        if (exists) {
 | 
					                                                        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;
 | 
					                                                            return false;
 | 
				
			||||||
                                                        }
 | 
					                                                        }
 | 
				
			||||||
                                                        if (typeof option.onSave === 'function') {
 | 
					                                                        if (typeof option.onSave === 'function') {
 | 
				
			||||||
@@ -884,15 +906,15 @@ class CustomerCommunication {
 | 
				
			|||||||
                                        key: 'delete',
 | 
					                                        key: 'delete',
 | 
				
			||||||
                                        ...buttonCol,
 | 
					                                        ...buttonCol,
 | 
				
			||||||
                                        text: 'times',
 | 
					                                        text: 'times',
 | 
				
			||||||
                                        tooltip: r('delete', 'Delete'),
 | 
					                                        tooltip: r('P_WO_DELETE', 'Delete'),
 | 
				
			||||||
                                        events: {
 | 
					                                        events: {
 | 
				
			||||||
                                            onclick: function () {
 | 
					                                            onclick: function () {
 | 
				
			||||||
                                                showConfirm(
 | 
					                                                showConfirm(
 | 
				
			||||||
                                                    r('remoteContact', 'Remove Contact'),
 | 
					                                                    r('P_CU_REMOVECONTACT', 'Remove Contact'),
 | 
				
			||||||
                                                    createElement('div', null,
 | 
					                                                    createElement('div', null,
 | 
				
			||||||
                                                        createElement('div', div => {
 | 
					                                                        createElement('div', div => {
 | 
				
			||||||
                                                            div.style.paddingLeft = '16px';
 | 
					                                                            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 => {
 | 
					                                                        createElement('div', div => {
 | 
				
			||||||
                                                            div.style.display = 'flex';
 | 
					                                                            div.style.display = 'flex';
 | 
				
			||||||
@@ -901,19 +923,19 @@ class CustomerCommunication {
 | 
				
			|||||||
                                                        },
 | 
					                                                        },
 | 
				
			||||||
                                                            createRadiobox({
 | 
					                                                            createRadiobox({
 | 
				
			||||||
                                                                name: 'remove-type',
 | 
					                                                                name: 'remove-type',
 | 
				
			||||||
                                                                label: r('customerRecord', 'Customer Record'),
 | 
					                                                                label: r('P_CUSTOMERRECORD', 'Customer Record'),
 | 
				
			||||||
                                                                checked: true,
 | 
					                                                                checked: true,
 | 
				
			||||||
                                                                className: 'radio-customer-record'
 | 
					                                                                className: 'radio-customer-record'
 | 
				
			||||||
                                                            }),
 | 
					                                                            }),
 | 
				
			||||||
                                                            createRadiobox({
 | 
					                                                            createRadiobox({
 | 
				
			||||||
                                                                name: 'remove-type',
 | 
					                                                                name: 'remove-type',
 | 
				
			||||||
                                                                label: r('workOrder', 'Work Order')
 | 
					                                                                label: r('P_WORKORDER', 'Work Order')
 | 
				
			||||||
                                                            })
 | 
					                                                            })
 | 
				
			||||||
                                                        )
 | 
					                                                        )
 | 
				
			||||||
                                                    ),
 | 
					                                                    ),
 | 
				
			||||||
                                                    [
 | 
					                                                    [
 | 
				
			||||||
                                                        { key: 'ok', text: r('ok', 'OK') },
 | 
					                                                        { key: 'ok', text: r('P_WO_OK', 'OK') },
 | 
				
			||||||
                                                        { key: 'cancel', text: r('cancel', 'Cancel') }
 | 
					                                                        { key: 'cancel', text: r('P_WO_CANCEL', 'Cancel') }
 | 
				
			||||||
                                                    ]
 | 
					                                                    ]
 | 
				
			||||||
                                                ).then(result => {
 | 
					                                                ).then(result => {
 | 
				
			||||||
                                                    if (result?.key === 'ok') {
 | 
					                                                    if (result?.key === 'ok') {
 | 
				
			||||||
@@ -969,12 +991,12 @@ class CustomerCommunication {
 | 
				
			|||||||
                                        key: 'delete',
 | 
					                                        key: 'delete',
 | 
				
			||||||
                                        ...buttonCol,
 | 
					                                        ...buttonCol,
 | 
				
			||||||
                                        text: 'times',
 | 
					                                        text: 'times',
 | 
				
			||||||
                                        tooltip: r('delete', 'Delete'),
 | 
					                                        tooltip: r('P_WO_DELETE', 'Delete'),
 | 
				
			||||||
                                        events: {
 | 
					                                        events: {
 | 
				
			||||||
                                            onclick: function () {
 | 
					                                            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), [
 | 
					                                                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('continue', 'Continue') },
 | 
					                                                    { key: 'continue', text: r('P_JS_CONTINUE', 'Continue') },
 | 
				
			||||||
                                                    { key: 'cancel', text: r('cancel', 'Cancel') }
 | 
					                                                    { key: 'cancel', text: r('P_WO_CANCEL', 'Cancel') }
 | 
				
			||||||
                                                ]).then(result => {
 | 
					                                                ]).then(result => {
 | 
				
			||||||
                                                    if (result?.key === 'continue') {
 | 
					                                                    if (result?.key === 'continue') {
 | 
				
			||||||
                                                        if (typeof option.onDelete === 'function') {
 | 
					                                                        if (typeof option.onDelete === 'function') {
 | 
				
			||||||
@@ -1017,7 +1039,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                ),
 | 
					                ),
 | 
				
			||||||
                createElement('div', div => {
 | 
					                createElement('div', div => {
 | 
				
			||||||
                    div.className = 'bar-info';
 | 
					                    div.className = 'bar-info';
 | 
				
			||||||
                    div.innerText = r('contactInformation', 'Contact Information');
 | 
					                    div.innerText = r('P_CR_CONTACTINFORMATION', 'Contact Information');
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
                createElement('div', div => {
 | 
					                createElement('div', div => {
 | 
				
			||||||
                    if (option.contactCollapserVisible === false) {
 | 
					                    if (option.contactCollapserVisible === false) {
 | 
				
			||||||
@@ -1061,15 +1083,16 @@ class CustomerCommunication {
 | 
				
			|||||||
                button.style.display = 'none';
 | 
					                button.style.display = 'none';
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            button.appendChild(createIcon('fa-solid', 'pen'));
 | 
					            button.appendChild(createIcon('fa-solid', 'pen'));
 | 
				
			||||||
            setTooltip(button, r('editFollower', 'Edit Followers'));
 | 
					            setTooltip(button, r('P_CU_EDITFOLLOWERS', 'Edit Followers'));
 | 
				
			||||||
            button.addEventListener('click', () => {
 | 
					            button.addEventListener('click', () => {
 | 
				
			||||||
                if (typeof option.onInitFollower === 'function') {
 | 
					                if (typeof option.onInitFollower === 'function') {
 | 
				
			||||||
                    option.onInitFollower(this.#data.followers).then(data => {
 | 
					                    option.onInitFollower(this.#data.followers).then(data => {
 | 
				
			||||||
                        if (typeof data === 'string') {
 | 
					                        if (typeof data === 'string') {
 | 
				
			||||||
                            showAlert(r('customerRecord', 'Customer Record'), data, 'warn');
 | 
					                            showAlert(r('P_CUSTOMERRECORD', 'Customer Record'), data, 'warn');
 | 
				
			||||||
                            return;
 | 
					                            return;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        const add = new Follower({
 | 
					                        const add = new Follower({
 | 
				
			||||||
 | 
					                            getText: option.getText,
 | 
				
			||||||
                            onMasking: option.onMasking,
 | 
					                            onMasking: option.onMasking,
 | 
				
			||||||
                            followers: data,
 | 
					                            followers: data,
 | 
				
			||||||
                            onOk: list => {
 | 
					                            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);
 | 
					                        add.show(title, container);
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -1105,7 +1128,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                        'border-radius': '15px',
 | 
					                        'border-radius': '15px',
 | 
				
			||||||
                        'padding': '4px'
 | 
					                        'padding': '4px'
 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
                ), r('copied', 'Copied')),
 | 
					                ), r('P_CU_COPIED', 'Copied')),
 | 
				
			||||||
                createElement('div', 'bar-list',
 | 
					                createElement('div', 'bar-list',
 | 
				
			||||||
                    followers,
 | 
					                    followers,
 | 
				
			||||||
                    buttonEditFollower
 | 
					                    buttonEditFollower
 | 
				
			||||||
@@ -1154,7 +1177,7 @@ class CustomerCommunication {
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (sendto !== '') {
 | 
					                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.appendChild(createElement('div', div => {
 | 
				
			||||||
                    div.className = 'item-poster';
 | 
					                    div.className = 'item-poster';
 | 
				
			||||||
@@ -1164,13 +1187,12 @@ class CustomerCommunication {
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }));
 | 
					                }));
 | 
				
			||||||
                const content = createElement('div', 'item-content');
 | 
					                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');
 | 
					                const mmsParts = createElement('div', div => div.style.display = 'none');
 | 
				
			||||||
                content.appendChild(createElement('span', span => {
 | 
					                content.appendChild(createElement('span', span => {
 | 
				
			||||||
                    if (/https?:\/\//i.test(comm.Message)) {
 | 
					                    if (/https?:\/\//i.test(comm.Message)) {
 | 
				
			||||||
                        span.innerHTML = emoji(formatUrl(comm.Message));
 | 
					                        span.innerHTML = escapeEmoji(formatUrl(comm.Message));
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        span.innerText = emoji(comm.Message);
 | 
					                        span.innerText = escapeEmoji(comm.Message);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    span.appendChild(mmsParts);
 | 
					                    span.appendChild(mmsParts);
 | 
				
			||||||
                }));
 | 
					                }));
 | 
				
			||||||
@@ -1189,26 +1211,26 @@ class CustomerCommunication {
 | 
				
			|||||||
                        let statustext;
 | 
					                        let statustext;
 | 
				
			||||||
                        switch (status) {
 | 
					                        switch (status) {
 | 
				
			||||||
                            case 0:
 | 
					                            case 0:
 | 
				
			||||||
                                statustext = r('pending', 'Pending');
 | 
					                                statustext = r('P_CU_PENDING', 'Pending');
 | 
				
			||||||
                                content.style.backgroundColor = '#ffc107';
 | 
					                                content.style.backgroundColor = '#ffc107';
 | 
				
			||||||
                                break;
 | 
					                                break;
 | 
				
			||||||
                            case 1:
 | 
					                            case 1:
 | 
				
			||||||
                                statustext = r('sent', 'Sent');
 | 
					                                statustext = r('P_WO_SENT', 'Sent');
 | 
				
			||||||
                                break;
 | 
					                                break;
 | 
				
			||||||
                            case 9:
 | 
					                            case 9:
 | 
				
			||||||
                                statustext = r('failed', 'Failed');
 | 
					                                statustext = r('P_MA_FAILED', 'Failed');
 | 
				
			||||||
                                content.style.backgroundColor = '#ffc107';
 | 
					                                content.style.backgroundColor = '#ffc107';
 | 
				
			||||||
                                break;
 | 
					                                break;
 | 
				
			||||||
                            case 10:
 | 
					                            case 10:
 | 
				
			||||||
                                statustext = r('optOut', 'Opt-Out');
 | 
					                                statustext = r('P_CU_OPTOUT', 'Opt-Out');
 | 
				
			||||||
                                content.style.backgroundColor = '#ffc107';
 | 
					                                content.style.backgroundColor = '#ffc107';
 | 
				
			||||||
                                break;
 | 
					                                break;
 | 
				
			||||||
                            case 412:
 | 
					                            case 412:
 | 
				
			||||||
                                statustext = r('landline', 'Landline');
 | 
					                                statustext = r('P_CU_LANDLINE', 'Landline');
 | 
				
			||||||
                                content.style.backgroundColor = '#ffc107';
 | 
					                                content.style.backgroundColor = '#ffc107';
 | 
				
			||||||
                                break;
 | 
					                                break;
 | 
				
			||||||
                            default:
 | 
					                            default:
 | 
				
			||||||
                                statustext = r('undelivered', 'Undelivered');
 | 
					                                statustext = r('P_CU_UNDELIVERED', 'Undelivered');
 | 
				
			||||||
                                content.style.backgroundColor = '#ffc107';
 | 
					                                content.style.backgroundColor = '#ffc107';
 | 
				
			||||||
                                break;
 | 
					                                break;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
@@ -1253,13 +1275,15 @@ class CustomerCommunication {
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    statusmsg += `${p.CustomerNumber}: `;
 | 
					                    statusmsg += `${p.CustomerNumber}: `;
 | 
				
			||||||
                    const st = ({
 | 
					                    const st = ({
 | 
				
			||||||
                        0: r('undelivered', 'Undelivered'),
 | 
					                        0: r('P_CU_UNDELIVERED', 'Undelivered'),
 | 
				
			||||||
                        1: r('sent', 'Sent'),
 | 
					                        1: r('P_WO_SENT', 'Sent'),
 | 
				
			||||||
                        9: r('failed', 'Failed')
 | 
					                        9: r('P_MA_FAILED', 'Failed')
 | 
				
			||||||
                    })[p.Status];
 | 
					                    })[p.Status];
 | 
				
			||||||
                    if (st != null) {
 | 
					                    if (st != null) {
 | 
				
			||||||
                        statusmsg += st;
 | 
					                        statusmsg += st;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                        statusmsg += r('P_MA_XXXXXX', 'Unknown');
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -1270,6 +1294,4 @@ class CustomerCommunication {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        return [status, statusmsg];
 | 
					        return [status, statusmsg];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
export default CustomerCommunication;
 | 
					 | 
				
			||||||
@@ -1,12 +1,18 @@
 | 
				
			|||||||
import { Grid, createElement, Popup } from "../../ui";
 | 
					import { Grid, createElement, Popup } from "../../ui";
 | 
				
			||||||
import { nullOrEmpty, r, contains } from "../../utility";
 | 
					import { nullOrEmpty, r as lang, contains } from "../../utility";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Follower {
 | 
					let r = lang;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Follower {
 | 
				
			||||||
    #option;
 | 
					    #option;
 | 
				
			||||||
    #grid;
 | 
					    #grid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(option = {}) {
 | 
					    constructor(option = {}) {
 | 
				
			||||||
        this.#option = option;
 | 
					        this.#option = option;
 | 
				
			||||||
 | 
					        const getText = option?.getText;
 | 
				
			||||||
 | 
					        if (typeof getText === 'function') {
 | 
				
			||||||
 | 
					            r = getText;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async show(title, parent = document.body) {
 | 
					    async show(title, parent = document.body) {
 | 
				
			||||||
@@ -17,7 +23,7 @@ class Follower {
 | 
				
			|||||||
            onMasking: this.#option.onMasking,
 | 
					            onMasking: this.#option.onMasking,
 | 
				
			||||||
            title,
 | 
					            title,
 | 
				
			||||||
            content: createElement('div', 'follower-wrapper',
 | 
					            content: createElement('div', 'follower-wrapper',
 | 
				
			||||||
                createElement('div', div => div.innerText = r('whoWantReceiveCustomerNotification', 'Who do you want to receive customer notifications?')),
 | 
					                createElement('div', div => div.innerText = r('P_CR_WHODOYOUWANTTORECEIVECUSTOMERNOTIFICATIONS', 'Who do you want to receive customer notifications?')),
 | 
				
			||||||
                createElement('input', search => {
 | 
					                createElement('input', search => {
 | 
				
			||||||
                    search.type = 'text';
 | 
					                    search.type = 'text';
 | 
				
			||||||
                    search.tabIndex = tabIndex + 3;
 | 
					                    search.tabIndex = tabIndex + 3;
 | 
				
			||||||
@@ -36,7 +42,7 @@ class Follower {
 | 
				
			|||||||
            ),
 | 
					            ),
 | 
				
			||||||
            buttons: [
 | 
					            buttons: [
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    text: r('ok', 'OK'),
 | 
					                    text: r('P_WO_OK', 'OK'),
 | 
				
			||||||
                    key: 'ok',
 | 
					                    key: 'ok',
 | 
				
			||||||
                    trigger: () => {
 | 
					                    trigger: () => {
 | 
				
			||||||
                        if (typeof this.#option.onOk === 'function') {
 | 
					                        if (typeof this.#option.onOk === 'function') {
 | 
				
			||||||
@@ -44,7 +50,7 @@ class Follower {
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                { text: r('cancel', 'Cancel'), key: 'cancel' }
 | 
					                { text: r('P_WO_CANCEL', 'Cancel'), key: 'cancel' }
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        const result = await popup.show(parent);
 | 
					        const result = await popup.show(parent);
 | 
				
			||||||
@@ -52,18 +58,18 @@ class Follower {
 | 
				
			|||||||
        // grid
 | 
					        // grid
 | 
				
			||||||
        const grid = new Grid(gridContainer);
 | 
					        const grid = new Grid(gridContainer);
 | 
				
			||||||
        grid.columns = [
 | 
					        grid.columns = [
 | 
				
			||||||
            { key: 'DisplayName', caption: r('contactName', 'Contact Name'), width: 240 },
 | 
					            { key: 'DisplayName', caption: r('P_WO_CONTACTNAME', 'Contact Name'), width: 240 },
 | 
				
			||||||
            { key: 'ContactTypeName', caption: r('contactType', 'Contact Type'), width: 120 },
 | 
					            { key: 'ContactTypeName', caption: r('P_WO_CONTACTTYPE', 'Contact Type'), width: 120 },
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                key: 'Text',
 | 
					                key: 'Text',
 | 
				
			||||||
                caption: r('text', 'Text'),
 | 
					                caption: r('P_CR_TEXT', 'Text'),
 | 
				
			||||||
                type: Grid.ColumnTypes.Checkbox,
 | 
					                type: Grid.ColumnTypes.Checkbox,
 | 
				
			||||||
                width: 60,
 | 
					                width: 60,
 | 
				
			||||||
                enabled: item => !nullOrEmpty(item.Mobile)
 | 
					                enabled: item => !nullOrEmpty(item.Mobile)
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                key: 'Email',
 | 
					                key: 'Email',
 | 
				
			||||||
                caption: r('email', 'Email'),
 | 
					                caption: r('P_CR_EMAIL', 'Email'),
 | 
				
			||||||
                type: Grid.ColumnTypes.Checkbox,
 | 
					                type: Grid.ColumnTypes.Checkbox,
 | 
				
			||||||
                width: 70,
 | 
					                width: 70,
 | 
				
			||||||
                // enabled: item => !nullOrEmpty(item.ID)
 | 
					                // enabled: item => !nullOrEmpty(item.ID)
 | 
				
			||||||
@@ -74,6 +80,4 @@ class Follower {
 | 
				
			|||||||
        this.#grid = grid;
 | 
					        this.#grid = grid;
 | 
				
			||||||
        return result;
 | 
					        return result;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
export default Follower;
 | 
					 | 
				
			||||||
@@ -1,8 +1,11 @@
 | 
				
			|||||||
import { createElement, setTooltip, createIcon, showAlert } from "../../ui";
 | 
					import { createElement, setTooltip, createIcon } from "../../ui";
 | 
				
			||||||
import { r, nullOrEmpty, escapeHtml } from "../../utility";
 | 
					import { r as lang, nullOrEmpty, escapeHtml, escapeEmoji } from "../../utility";
 | 
				
			||||||
import { createBox, appendMedia, fileSupported, insertFile } from "./lib";
 | 
					import { createBox, appendMedia } from "./lib";
 | 
				
			||||||
 | 
					// import { fileSupported, insertFile } from "./lib";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class InternalComment {
 | 
					let r = lang;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class InternalComment {
 | 
				
			||||||
    #container;
 | 
					    #container;
 | 
				
			||||||
    #option;
 | 
					    #option;
 | 
				
			||||||
    #enter;
 | 
					    #enter;
 | 
				
			||||||
@@ -12,6 +15,10 @@ class InternalComment {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    constructor(opt) {
 | 
					    constructor(opt) {
 | 
				
			||||||
        this.#option = opt ?? {};
 | 
					        this.#option = opt ?? {};
 | 
				
			||||||
 | 
					        const getText = opt?.getText;
 | 
				
			||||||
 | 
					        if (typeof getText === 'function') {
 | 
				
			||||||
 | 
					            r = getText;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get text() { return this.#enter?.value }
 | 
					    get text() { return this.#enter?.value }
 | 
				
			||||||
@@ -86,14 +93,14 @@ class InternalComment {
 | 
				
			|||||||
            createElement('div', null,
 | 
					            createElement('div', null,
 | 
				
			||||||
                createElement('div', div => {
 | 
					                createElement('div', div => {
 | 
				
			||||||
                    div.className = 'title-module';
 | 
					                    div.className = 'title-module';
 | 
				
			||||||
                    div.innerText = r('internalComments', 'Internal Comments');
 | 
					                    div.innerText = r('P_WO_INTERNALCOMMENTS', 'Internal Comments');
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            ), []
 | 
					            ), []
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        const readonly = this.#option.readonly;
 | 
					        const readonly = this.#option.readonly;
 | 
				
			||||||
        // enter box
 | 
					        // enter box
 | 
				
			||||||
        const enter = createElement('textarea', 'ui-text');
 | 
					        const enter = createElement('textarea', 'ui-text');
 | 
				
			||||||
        enter.placeholder = r('typeComment', 'Enter Comment Here');
 | 
					        enter.placeholder = r('P_CU_ENTERCOMMENTHERE', 'Enter Comment Here');
 | 
				
			||||||
        enter.maxLength = this.#option.maxLength ??= 3000;
 | 
					        enter.maxLength = this.#option.maxLength ??= 3000;
 | 
				
			||||||
        enter.addEventListener('input', () => {
 | 
					        enter.addEventListener('input', () => {
 | 
				
			||||||
            const val = this.text;
 | 
					            const val = this.text;
 | 
				
			||||||
@@ -107,7 +114,7 @@ class InternalComment {
 | 
				
			|||||||
        //     const file = e.clipboardData.files[0];
 | 
					        //     const file = e.clipboardData.files[0];
 | 
				
			||||||
        //     if (file != null) {
 | 
					        //     if (file != null) {
 | 
				
			||||||
        //         e.preventDefault();
 | 
					        //         e.preventDefault();
 | 
				
			||||||
        //         this.file = insertFile(container, file);
 | 
					        //         this.file = insertFile(container, file, r);
 | 
				
			||||||
        //     }
 | 
					        //     }
 | 
				
			||||||
        // });
 | 
					        // });
 | 
				
			||||||
        this.#enter = enter;
 | 
					        this.#enter = enter;
 | 
				
			||||||
@@ -132,7 +139,7 @@ class InternalComment {
 | 
				
			|||||||
                //         const file = e.dataTransfer.files[0];
 | 
					                //         const file = e.dataTransfer.files[0];
 | 
				
			||||||
                //         if (file != null) {
 | 
					                //         if (file != null) {
 | 
				
			||||||
                //             e.preventDefault();
 | 
					                //             e.preventDefault();
 | 
				
			||||||
                //             this.file = insertFile(container, file);
 | 
					                //             this.file = insertFile(container, file, r);
 | 
				
			||||||
                //         }
 | 
					                //         }
 | 
				
			||||||
                //     }
 | 
					                //     }
 | 
				
			||||||
                // });
 | 
					                // });
 | 
				
			||||||
@@ -154,7 +161,7 @@ class InternalComment {
 | 
				
			|||||||
                            //         input.type = 'file';
 | 
					                            //         input.type = 'file';
 | 
				
			||||||
                            //         input.accept = fileSupported.join(',');
 | 
					                            //         input.accept = fileSupported.join(',');
 | 
				
			||||||
                            //         input.addEventListener('change', () => {
 | 
					                            //         input.addEventListener('change', () => {
 | 
				
			||||||
                            //             const file = insertFile(container, input.files?.[0]);
 | 
					                            //             const file = insertFile(container, input.files?.[0], r);
 | 
				
			||||||
                            //             if (file != null) {
 | 
					                            //             if (file != null) {
 | 
				
			||||||
                            //                 this.file = file;
 | 
					                            //                 this.file = file;
 | 
				
			||||||
                            //             }
 | 
					                            //             }
 | 
				
			||||||
@@ -183,9 +190,14 @@ class InternalComment {
 | 
				
			|||||||
                            button.style.display = 'none';
 | 
					                            button.style.display = 'none';
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        button.appendChild(createIcon('fa-solid', 'paper-plane'));
 | 
					                        button.appendChild(createIcon('fa-solid', 'paper-plane'));
 | 
				
			||||||
                        setTooltip(button, r('sendMessage', 'Send Message'));
 | 
					                        setTooltip(button, r('P_M3_SENDMESSAGE', 'Send Message'));
 | 
				
			||||||
                        button.addEventListener('click', () => {
 | 
					                        button.addEventListener('click', () => {
 | 
				
			||||||
 | 
					                            const val = this.text;
 | 
				
			||||||
 | 
					                            if (nullOrEmpty(val?.trim())) {
 | 
				
			||||||
 | 
					                                return;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
                            if (typeof this.#option.onAddMessage === 'function') {
 | 
					                            if (typeof this.#option.onAddMessage === 'function') {
 | 
				
			||||||
 | 
					                                this.loading = true;
 | 
				
			||||||
                                this.#option.onAddMessage(this.text);
 | 
					                                this.#option.onAddMessage(this.text);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        })
 | 
					                        })
 | 
				
			||||||
@@ -198,9 +210,14 @@ class InternalComment {
 | 
				
			|||||||
                            button.style.display = 'none';
 | 
					                            button.style.display = 'none';
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        button.appendChild(createIcon('fa-solid', 'comment-alt-lines'));
 | 
					                        button.appendChild(createIcon('fa-solid', 'comment-alt-lines'));
 | 
				
			||||||
                        setTooltip(button, r('postNote', 'Post Note'));
 | 
					                        setTooltip(button, r('P_CU_POSTNOTE', 'Post Note'));
 | 
				
			||||||
                        button.addEventListener('click', () => {
 | 
					                        button.addEventListener('click', () => {
 | 
				
			||||||
 | 
					                            const val = this.text;
 | 
				
			||||||
 | 
					                            if (nullOrEmpty(val?.trim())) {
 | 
				
			||||||
 | 
					                                return;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
                            if (typeof this.#option.onAddComment === 'function') {
 | 
					                            if (typeof this.#option.onAddComment === 'function') {
 | 
				
			||||||
 | 
					                                this.loading = true;
 | 
				
			||||||
                                this.#option.onAddComment(this.text, this.file);
 | 
					                                this.#option.onAddComment(this.text, this.file);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        })
 | 
					                        })
 | 
				
			||||||
@@ -221,16 +238,15 @@ class InternalComment {
 | 
				
			|||||||
            for (let comment of data) {
 | 
					            for (let comment of data) {
 | 
				
			||||||
                const div = createElement('div', 'item-div');
 | 
					                const div = createElement('div', 'item-div');
 | 
				
			||||||
                // if (sendto !== '') {
 | 
					                // 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.appendChild(createElement('div', div => {
 | 
				
			||||||
                    div.className = 'item-poster';
 | 
					                    div.className = 'item-poster';
 | 
				
			||||||
                    div.innerText = comment.UserName;
 | 
					                    div.innerText = comment.UserName;
 | 
				
			||||||
                }));
 | 
					                }));
 | 
				
			||||||
                const content = createElement('div', 'item-content');
 | 
					                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');
 | 
					                const mmsParts = createElement('div', div => div.style.display = 'none');
 | 
				
			||||||
                content.appendChild(createElement('span', span => span.innerHTML = emoji(escapeHtml(comment.Comment)), mmsParts));
 | 
					                content.appendChild(createElement('span', span => span.innerHTML = escapeEmoji(escapeHtml(comment.Comment)), mmsParts));
 | 
				
			||||||
                if (comment.IsMMS && comment.MMSParts?.length > 0) {
 | 
					                if (comment.IsMMS && comment.MMSParts?.length > 0) {
 | 
				
			||||||
                    mmsParts.style.display = '';
 | 
					                    mmsParts.style.display = '';
 | 
				
			||||||
                    for (let kv of comment.MMSParts) {
 | 
					                    for (let kv of comment.MMSParts) {
 | 
				
			||||||
@@ -239,10 +255,10 @@ class InternalComment {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                if (comment.FollowUp?.length > 0) {
 | 
					                if (comment.FollowUp?.length > 0) {
 | 
				
			||||||
                    div.classList.add('item-sent');
 | 
					                    div.classList.add('item-sent');
 | 
				
			||||||
                    const sendto = r('sendToColon', 'Send To :') + '\r\n' + comment.FollowUp.split(';').join('\r\n');
 | 
					                    const sendto = r('P_CU_SENDTO_COLON', 'Send To :') + '\r\n' + comment.FollowUp.split(';').join('\r\n');
 | 
				
			||||||
                    content.appendChild(createElement('div', div => {
 | 
					                    content.appendChild(createElement('div', div => {
 | 
				
			||||||
                        div.className = 'item-status';
 | 
					                        div.className = 'item-status';
 | 
				
			||||||
                        div.innerText = r('sent', 'Sent');
 | 
					                        div.innerText = r('P_WO_SENT', 'Sent');
 | 
				
			||||||
                        setTooltip(div, sendto);
 | 
					                        setTooltip(div, sendto);
 | 
				
			||||||
                    }));
 | 
					                    }));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -261,6 +277,4 @@ class InternalComment {
 | 
				
			|||||||
        this.#message.scrollTop = this.#message.scrollHeight
 | 
					        this.#message.scrollTop = this.#message.scrollHeight
 | 
				
			||||||
        // setTimeout(() => this.#message.scrollTop = this.#message.scrollHeight, 0);
 | 
					        // setTimeout(() => this.#message.scrollTop = this.#message.scrollHeight, 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
export default InternalComment;
 | 
					 | 
				
			||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
import { createElement, setTooltip, showAlert, createPicture, createAudio, createVideo, createFile } from "../../ui";
 | 
					import { createElement, setTooltip, showAlert, createPicture, createAudio, createVideo, createFile } from "../../ui";
 | 
				
			||||||
import { r } from "../../utility";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function createBox(title, functions) {
 | 
					export function createBox(title, functions) {
 | 
				
			||||||
    const container = createElement('div', 'comm');
 | 
					    const container = createElement('div', 'comm');
 | 
				
			||||||
@@ -16,39 +15,51 @@ export function appendMedia(container, mimeType, url) {
 | 
				
			|||||||
        case 'application/pdf':
 | 
					        case 'application/pdf':
 | 
				
			||||||
            container.appendChild(createFile(url, 'file-pdf'));
 | 
					            container.appendChild(createFile(url, 'file-pdf'));
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					        case 'application/msword':
 | 
				
			||||||
 | 
					        case 'application/vnd.ms-word':
 | 
				
			||||||
 | 
					        case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
 | 
				
			||||||
 | 
					            container.appendChild(createFile(url, 'file-word'));
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case 'application/vnd.ms-excel':
 | 
				
			||||||
 | 
					        case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
 | 
				
			||||||
 | 
					            container.appendChild(createFile(url, 'file-excel'));
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case 'application/vnd.ms-powerpoint':
 | 
				
			||||||
 | 
					        case 'application/vnd.openxmlformats-officedocument.presentationml.presentation':
 | 
				
			||||||
 | 
					            container.appendChild(createFile(url, 'file-powerpoint'));
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
        case 'application/smil':
 | 
					        case 'application/smil':
 | 
				
			||||||
            // TODO: ignore smil files
 | 
					            // TODO: ignore smil files
 | 
				
			||||||
            // container.appendChild(createFile(url, 'smile'));
 | 
					            // container.appendChild(createFile(url, 'smile'));
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					        case 'audio/aac':
 | 
				
			||||||
        case 'audio/amr':
 | 
					        case 'audio/amr':
 | 
				
			||||||
        case 'audio/mp3':
 | 
					        case 'audio/mp3':
 | 
				
			||||||
        case 'audio/mpeg':
 | 
					        case 'audio/mpeg':
 | 
				
			||||||
        case 'audio/x-mpeg':
 | 
					        case 'audio/x-mpeg':
 | 
				
			||||||
        case 'audio/aac':
 | 
					 | 
				
			||||||
        case 'audio/ogg':
 | 
					        case 'audio/ogg':
 | 
				
			||||||
        case 'audio/opus':
 | 
					        case 'audio/opus':
 | 
				
			||||||
        case 'audio/wav':
 | 
					        case 'audio/wav':
 | 
				
			||||||
        case 'audio/webm':
 | 
					        case 'audio/webm':
 | 
				
			||||||
            container.appendChild(createAudio(mimeType, url));
 | 
					            container.appendChild(createAudio(mimeType, url));
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case 'image/gif':
 | 
					        case 'text/plain':
 | 
				
			||||||
        case 'image/jpeg':
 | 
					 | 
				
			||||||
        case 'image/png':
 | 
					 | 
				
			||||||
            container.appendChild(createPicture(url));
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        case 'text/x-vcard':
 | 
					        case 'text/x-vcard':
 | 
				
			||||||
            container.appendChild(createFile(url, 'id-card'));
 | 
					            container.appendChild(createFile(url, 'id-card'));
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					        case 'video/3gpp':
 | 
				
			||||||
 | 
					        case 'video/mp2t':
 | 
				
			||||||
        case 'video/mp4':
 | 
					        case 'video/mp4':
 | 
				
			||||||
        case 'video/mpeg':
 | 
					        case 'video/mpeg':
 | 
				
			||||||
        case 'video/x-mpeg':
 | 
					        case 'video/x-mpeg':
 | 
				
			||||||
        case 'video/mp2t':
 | 
					 | 
				
			||||||
        case 'video/webm':
 | 
					 | 
				
			||||||
        case 'video/quicktime':
 | 
					        case 'video/quicktime':
 | 
				
			||||||
 | 
					        case 'video/webm':
 | 
				
			||||||
            container.appendChild(createVideo(url));
 | 
					            container.appendChild(createVideo(url));
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            if (/^audio\//.test(mimeType)) {
 | 
					            if (/^image\//.test(mimeType)) {
 | 
				
			||||||
 | 
					                container.appendChild(createPicture(url));
 | 
				
			||||||
 | 
					            } else if (/^audio\//.test(mimeType)) {
 | 
				
			||||||
                container.appendChild(createFile(url, 'music'));
 | 
					                container.appendChild(createFile(url, 'music'));
 | 
				
			||||||
            } else if (/^video\//.test(mimeType)) {
 | 
					            } else if (/^video\//.test(mimeType)) {
 | 
				
			||||||
                container.appendChild(createFile(url, 'video'));
 | 
					                container.appendChild(createFile(url, 'video'));
 | 
				
			||||||
@@ -61,30 +72,50 @@ export function appendMedia(container, mimeType, url) {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MaxAttachmentSize = {
 | 
					const MaxAttachmentSize = {
 | 
				
			||||||
    limit: 2 * 1024 * 1024,
 | 
					    limit: 1_258_291,
 | 
				
			||||||
    text: '2MB'
 | 
					    text: '1.2MB'
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const fileSupported = [
 | 
					export const fileSupported = [
 | 
				
			||||||
 | 
					    '.amr',
 | 
				
			||||||
 | 
					    '.ogv',
 | 
				
			||||||
 | 
					    'application/msword',
 | 
				
			||||||
 | 
					    'application/vnd.ms-word',
 | 
				
			||||||
 | 
					    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
 | 
				
			||||||
 | 
					    'application/vnd.ms-excel',
 | 
				
			||||||
 | 
					    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
 | 
				
			||||||
 | 
					    'application/vnd.ms-powerpoint',
 | 
				
			||||||
 | 
					    'application/vnd.openxmlformats-officedocument.presentationml.presentation',
 | 
				
			||||||
    'application/pdf',
 | 
					    'application/pdf',
 | 
				
			||||||
 | 
					    'audio/aac',
 | 
				
			||||||
 | 
					    'audio/amr',
 | 
				
			||||||
 | 
					    'audio/mp3',
 | 
				
			||||||
    'audio/mpeg',
 | 
					    'audio/mpeg',
 | 
				
			||||||
    'audio/x-mpeg',
 | 
					    'audio/x-mpeg',
 | 
				
			||||||
    'audio/amr',
 | 
					    'audio/ogg',
 | 
				
			||||||
    '.amr',
 | 
					    'audio/opus',
 | 
				
			||||||
 | 
					    'audio/wav',
 | 
				
			||||||
 | 
					    'audio/webm',
 | 
				
			||||||
    'image/bmp',
 | 
					    'image/bmp',
 | 
				
			||||||
    'image/gif',
 | 
					    'image/gif',
 | 
				
			||||||
    'image/jpeg',
 | 
					    'image/jpeg',
 | 
				
			||||||
 | 
					    'image/jfif',
 | 
				
			||||||
    'image/png',
 | 
					    'image/png',
 | 
				
			||||||
    'image/tiff',
 | 
					    'image/tiff',
 | 
				
			||||||
 | 
					    'image/webp',
 | 
				
			||||||
    'text/plain',
 | 
					    'text/plain',
 | 
				
			||||||
 | 
					    'text/vcard',
 | 
				
			||||||
    'text/x-vcard',
 | 
					    'text/x-vcard',
 | 
				
			||||||
    'video/3gpp',
 | 
					    'video/3gpp',
 | 
				
			||||||
 | 
					    'video/mp2t',
 | 
				
			||||||
    'video/mp4',
 | 
					    'video/mp4',
 | 
				
			||||||
 | 
					    'video/mpeg',
 | 
				
			||||||
 | 
					    'video/x-mpeg',
 | 
				
			||||||
 | 
					    'video/quicktime',
 | 
				
			||||||
    'video/webm',
 | 
					    'video/webm',
 | 
				
			||||||
    'video/quicktime'
 | 
					 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function insertFile(container, file) {
 | 
					export function insertFile(container, file, r) {
 | 
				
			||||||
    const label = container.querySelector('.file-selector>.selector-name');
 | 
					    const label = container.querySelector('.file-selector>.selector-name');
 | 
				
			||||||
    if (label != null && file != null) {
 | 
					    if (label != null && file != null) {
 | 
				
			||||||
        let type = file.type;
 | 
					        let type = file.type;
 | 
				
			||||||
@@ -93,12 +124,12 @@ export function insertFile(container, file) {
 | 
				
			|||||||
            type = type.substring(type.lastIndexOf('.'));
 | 
					            type = type.substring(type.lastIndexOf('.'));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (fileSupported.indexOf(type) < 0) {
 | 
					        if (fileSupported.indexOf(type) < 0) {
 | 
				
			||||||
            showAlert(r('error', 'Error'), r('notSupported', 'File type "{type}" is now not supported.').replace('{type}', type));
 | 
					            showAlert(r('P_WO_ERROR', 'Error'), r('P_CU_TYPENOTSUPPORTED', 'File type "{type}" is now not supported.').replace('{type}', type));
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const isImage = /^image\//.test(type);
 | 
					        const isImage = /^image\//.test(type);
 | 
				
			||||||
        if (!isImage && file.size > MaxAttachmentSize.limit) {
 | 
					        if (!isImage && file.size > MaxAttachmentSize.limit) {
 | 
				
			||||||
            showAlert(r('error', 'Error'), r('fileTooLarge', `File is too large. (> ${MaxAttachmentSize.text})`), 'warn');
 | 
					            showAlert(r('P_WO_ERROR', 'Error'), r('P_WO_ATTACHMENTSIZEEXCEEDSTHEMAXIMUMTIPS', `Attachment size exceeds the maximum allowed to be sent (${MaxAttachmentSize.text})`), 'warn');
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const fn = file.name;
 | 
					        const fn = file.name;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,10 @@
 | 
				
			|||||||
    display: inline-flex;
 | 
					    display: inline-flex;
 | 
				
			||||||
    align-items: center;
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &::before {
 | 
				
			||||||
 | 
					        display: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    >svg {
 | 
					    >svg {
 | 
				
			||||||
        width: 20px;
 | 
					        width: 20px;
 | 
				
			||||||
        height: 20px;
 | 
					        height: 20px;
 | 
				
			||||||
@@ -41,6 +45,10 @@
 | 
				
			|||||||
            border: none;
 | 
					            border: none;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        &::after {
 | 
				
			||||||
 | 
					            display: none;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        >svg {
 | 
					        >svg {
 | 
				
			||||||
            width: 100%;
 | 
					            width: 100%;
 | 
				
			||||||
            height: 100%;
 | 
					            height: 100%;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import { getCookie, setCookie, deleteCookie } from "./utility/cookie";
 | 
					import { getCookie, setCookie, deleteCookie } from "./utility/cookie";
 | 
				
			||||||
import { init, r, lang } from "./utility/lgres";
 | 
					import { init, r, lang } from "./utility/lgres";
 | 
				
			||||||
import { get, post, upload } from "./utility/request";
 | 
					import { get, post, upload } from "./utility/request";
 | 
				
			||||||
import { nullOrEmpty, contains, endsWith, padStart, formatUrl, escapeHtml } from "./utility/strings";
 | 
					import { nullOrEmpty, contains, endsWith, padStart, formatUrl, escapeHtml, escapeEmoji } from "./utility/strings";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let g = typeof globalThis !== 'undefined' ? globalThis : self;
 | 
					let g = typeof globalThis !== 'undefined' ? globalThis : self;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -73,6 +73,7 @@ export {
 | 
				
			|||||||
    padStart,
 | 
					    padStart,
 | 
				
			||||||
    formatUrl,
 | 
					    formatUrl,
 | 
				
			||||||
    escapeHtml,
 | 
					    escapeHtml,
 | 
				
			||||||
 | 
					    escapeEmoji,
 | 
				
			||||||
    // variables
 | 
					    // variables
 | 
				
			||||||
    g as global,
 | 
					    g as global,
 | 
				
			||||||
    isPositive,
 | 
					    isPositive,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,8 @@ function getStorageKey(lgid) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
async function doRefreshLgres(template = '') {
 | 
					async function doRefreshLgres(template = '') {
 | 
				
			||||||
    const lgid = getCurrentLgId();
 | 
					    const lgid = getCurrentLgId();
 | 
				
			||||||
    const r = await get(`language/${lgid}${template}`);
 | 
					    const url = template.length > 0 ? template.replace('{lgid}', lgid) : `language/${lgid}`;
 | 
				
			||||||
 | 
					    const r = await get(url);
 | 
				
			||||||
    const dict = await r.json();
 | 
					    const dict = await r.json();
 | 
				
			||||||
    localStorage.setItem(getStorageKey(lgid), JSON.stringify(dict));
 | 
					    localStorage.setItem(getStorageKey(lgid), JSON.stringify(dict));
 | 
				
			||||||
    return dict;
 | 
					    return dict;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								lib/utility/strings.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								lib/utility/strings.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -3,4 +3,5 @@ export function contains(s: string, key: string | any, ignoreCase?: boolean): bo
 | 
				
			|||||||
export function endsWith(s: string, suffix: string): boolean
 | 
					export function endsWith(s: string, suffix: string): boolean
 | 
				
			||||||
export function padStart(s: string, num: Number, char: string): boolean
 | 
					export function padStart(s: string, num: Number, char: string): boolean
 | 
				
			||||||
export function formatUrl(msg: string): string
 | 
					export function formatUrl(msg: string): string
 | 
				
			||||||
export function escapeHtml(text: string): string
 | 
					export function escapeHtml(text: string): string
 | 
				
			||||||
 | 
					export function escapeEmoji(text: string): string
 | 
				
			||||||
@@ -64,4 +64,16 @@ export function escapeHtml(text) {
 | 
				
			|||||||
        .replaceAll('\r\n', '<br/>')
 | 
					        .replaceAll('\r\n', '<br/>')
 | 
				
			||||||
        .replaceAll('\n', '<br/>')
 | 
					        .replaceAll('\n', '<br/>')
 | 
				
			||||||
        .replaceAll('  ', ' ');
 | 
					        .replaceAll('  ', ' ');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function escapeEmoji(text) {
 | 
				
			||||||
 | 
					    if (text == null) {
 | 
				
			||||||
 | 
					        return '';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (typeof text !== 'string') {
 | 
				
			||||||
 | 
					        text = String(text);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return text
 | 
				
			||||||
 | 
					        .replace(/(=[A-Fa-f0-9]{2}){4}/g, s => decodeURIComponent(s.replaceAll('=', '%')))
 | 
				
			||||||
 | 
					        .replace(/&#x([0-9a-fA-F]{2,6});/g, (_, h) => String.fromCodePoint(parseInt(h, 16)));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										967
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										967
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user