class MailingSheetView extends EICDomContent { constructor() { super() Object.assign(this, app.helpers.activeAttributes) Object.assign(this, app.helpers.basicDialogs) Object.assign(this, app.helpers.validators) } DOMContentLoaded(options) { for(let model in options.models) this[model] = options.models[model] const components = ui.eicfy(this.el) this.setupTriggers(components) this.setupRefs(components) this.currentMailing = {} this.mailingId = options.id this.workflow = new NodeMap(this.find('.workflow'), { resizable: true, allowDrag: false, orientation: 'linear', entity: { width: 120, height: 40, gap: 40 } }) this.workflow.click = this.onWorkflowSelect.bind(this) this.recipientsGrid = new DataGrid(this.find('.recipients-grid'), { headers: [ {label: 'date', type: 'date'}, {label: 'source'}, {label: 'type', type: 'markup'}, {label: ''} ], actions:[], }) this.recipientsGrid.enableFooter = true this.recipientsGrid.updateFooter = ()=>{} //We'll manage our own footer thx this.templateShadowRoot = this.outputs.templateHtmlBody.attachShadow({ mode: 'open' }) this.components['tabs'] = new Tab() this.components['tabs'].addTabs(this.findAll('.content-menu li'), this.findAll('.email-content')) ui.hide(this.components.deleteMailing.el) this.fillScheduleTime() this.loadMailingInfo(this.mailingId ) } /****************************** Loading & refresh tabs **************************************/ async loadMailingInfo(mailingId) { this.setAsyncLoading(true) this.currentMailing = await this.mailings.get(mailingId) const rawPaths = await this.mailings.getReadableFolders() const authorizedPaths = Array.isArray(rawPaths) ? rawPaths : (rawPaths?.authorizedPaths || []) if (!authorizedPaths.includes(this.currentMailing.path)) { const wrapper = document.querySelector('.massmailer.mailing-sheet section') if (wrapper) { wrapper.innerHTML = `

Access Denied

You're not authorized to access to view this mailing

` } this.setAsyncLoading(false) return } this.refresh() this.setAsyncLoading(false) } async refresh() { this.workflow.data = app.meta.collections['wf-mailings'] //Clear if(this.currentMailing.status == 'sent'){ this.components.chart = new PieChart(this.outputs.eicpiechart, { height: 120 }) this.components.chart.data = [ { severity: 'danger', value: this.currentMailing.kpis.bouncesCount }, { severity: 'success', value: this.currentMailing.kpis.readCount }, { severity: 'secondary', value: this.currentMailing.nbRecipients - this.currentMailing.kpis.bouncesCount - this.currentMailing.kpis.readCount } ] //TODO Show stats & graph tab } else { this.fillGeneralInfo() this.fillLatestActivity() this.refreshCreated() await this.refreshContent() this.fillRecipients() this.refreshMappings() this.refreshReview() this.refreshSchedule() this.refreshWorflow() } //this.setupTriggers() } fillGeneralInfo(){ this.output('name', this.currentMailing.name) this.output('created', ui.format.date(this.currentMailing.statusHistory[0].dateTime)) this.output('author', this.currentMailing.statusHistory[0].changedBy.euLoginId) this.output('status', this.mailings.getStatusLabel()[this.currentMailing.status]) this.output('infosPath', this.pathChips(this.currentMailing.path)) this.output('recipients', this.currentMailing.nbRecipients) this.output('pending', (this.currentMailing.nbRecipients>0) ? this.currentMailing.nbRecipients - this.currentMailing.kpis.bouncesCount - this.currentMailing.kpis.readCount : 'N/A') this.output('bounced', this.currentMailing.kpis.bouncesCount || 'N/A') this.output('reached', this.currentMailing.kpis.readCount || 'N/A') if(['created','draft'].includes(this.currentMailing.status)){ ui.show(this.components.deleteMailing.el) } else { ui.hide(this.components.deleteMailing.el) } } fillLatestActivity(){ this.output('history', '') let prevstatus = '' for(let historyEntry of [...this.currentMailing.statusHistory].reverse()){ let action if((historyEntry.value=='draft') && (prevstatus!= 'rejected')) { action = 'Draft saved' } else action = this.mailings.getStatusLabel()[historyEntry.value] let severity switch(historyEntry.value) { case 'rejected': severity = 'danger'; break case 'approved': severity = 'success'; break case 'submitted': severity = 'warning'; break case 'sent': severity = 'primary'; break default : severity = 'info'; break } let markup = `
  • ${action}: ${ (new Intl.DateTimeFormat("fr-FR", {timeZone: "Europe/Paris", dateStyle:'medium', timeStyle:'medium'})).format(new Date(historyEntry.dateTime))}
    by ${historyEntry.changedBy.firstname} ${historyEntry.changedBy.lastname}
  • ` prevstatus = historyEntry.value this.outputs.history.append(ui.create(markup)) } } refreshCreated(){ this.components.saveCreated.label = (this.currentMailing.status=='created') ? 'Save' : 'Change' this.components.saveCreated.severity = (this.currentMailing.status=='created') ? 'primary' : 'secondary' this.components.mailingName.value = this.currentMailing.name this.outputs.createPath.dataset.value = this.currentMailing.path this.outputs.createPath.innerHTML = this.pathChips(this.currentMailing.path) this.onNamePathChange() } async refreshContent(){ if(this.currentMailing.template.id) { this.setAsyncLoading(true, ['mainPane']) let templateInfo = await this.templates.get(this.currentMailing.template.id) this.setAsyncLoading(false, ['mainPane']) if(templateInfo) { this.currentMailing.template = templateInfo this.fillTemplate(templateInfo); } } this.components.changeTemplate.severity = (this.currentMailing.template.id) ? 'secondary' : 'primary' } refreshWorflow() { const stepActivations = this.mailings.getStepActivations(this.currentMailing, this.templates.getTokens(this.currentMailing.template)) this.workflow.data = app.meta.collections['wf-mailings'] for(const entity of this.workflow.entities){ entity.disabled = stepActivations[entity.id].disabled entity.severity = stepActivations[entity.id].severity } let entity = null if(this.currentMailing.status!='scheduled'){ entity = this.workflow.entities.find(e => e.severity == 'warning') } else { entity = this.workflow.entities.find(e => e.id == 'schedule') } this.onWorkflowSelect(entity) } fillTemplate(templateInfo){ const filterText = (text) => { let element = document.createElement('div') element.textContent = text text = element.innerHTML text = text.length > 100 ? text.slice(0, 100) + '...' : text return text } let subject = filterText(templateInfo.meta.subject ? templateInfo.meta.subject : '') this.output('templateSubject', subject.replace(this.validators.mustacheTokenRegex,'$1')) let html = atob(templateInfo.html).replace(this.validators.mustacheTokenRegex,'$1') this.templateShadowRoot.innerHTML = `\n${html}` let altText = filterText(templateInfo.meta.altText ? atob(templateInfo.meta.altText) : '') this.output('templateAlternateText', `
    ${altText.replace(this.validators.mustacheTokenRegex,'$1')}
    `) this.output('templateName', templateInfo.name.length > 60 ? templateInfo.name.slice(0, 60) + '...' : templateInfo.name) this.outputs['templateName'].setAttribute('title', templateInfo.name) } fillRecipients() { this.recipientsGrid.clear() let totalUnfilteredRecipients = 0 if(this.mailings.canImport()) { ui.show(this.components.btnImport.el, 'inline-flex') } else { ui.hide(this.components.btnImport.el) } if(this.mailings.canImportExclusion){ ui.show(this.components.btnExclusion.el, 'inline-flex') } else{ui.hide(this.components.btnExclusion.el) } if(this.mailings.canFetch()) { ui.show(this.components.btnFetch.el, 'inline-flex') } else { ui.hide(this.components.btnFetch.el) } for(const emailSource of this.currentMailing.sources){ const oneImport = this.currentMailing.imports.find(i => i.sourceId==emailSource.id) if(!emailSource.negative) totalUnfilteredRecipients += oneImport.data.length let sourceType = (emailSource.sourceType=='Excel') ? `` : `` if(emailSource.negative) sourceType = `${sourceType}` let row = this.recipientsGrid.addRow(emailSource.id, [ oneImport.importDate, // expecting source import datestamp emailSource.sourceName, sourceType, oneImport.data.length ], true) if(emailSource.sourceType!='Excel'){ // let btnEditQC = new Button(null,{ icon: 'icon-edit', severity: 'primary', size: 'xsmall', hint: 'Change the query'}) // btnEditQC.click = this.onSourceEditQC.bind(this, oneImport.id ) // row.querySelector('.cell.actions').appendChild(btnEditQC.el) let btnRefreshQC = new Button(null,{ icon: 'icon-refresh', severity: 'primary', size: 'xsmall', hint: 'Refresh data by replaying the query now'}) btnRefreshQC.click = this.onSourceRefreshQC.bind(this, oneImport.id, btnRefreshQC ) row.querySelector('.cell.actions').appendChild(btnRefreshQC.el) } let btnDel = new Button(null,{ icon: 'icon-bin', severity: 'danger', size: 'xsmall', hint: 'Remove'}) btnDel.click = this.onSourceDel.bind(this, oneImport.id ) row.querySelector('.cell.actions').appendChild(btnDel.el) } this.recipientsGrid.filter() // because skipfilter = true because potentially Big Xls... this.recipientsGrid.footer.classList.add('row') this.recipientsGrid.footer.innerHTML = `
    Total sendable recipients
    ${this.currentMailing.nbRecipients}
    ` //this.currentMailing.nbRecipients = totalRecipients const dupes = this.mailings.findDupes(this.currentMailing.imports) this.output('totalRecipients', totalUnfilteredRecipients) this.output('totalRecipientsExcluded', totalUnfilteredRecipients-this.currentMailing.nbRecipients) if(totalUnfilteredRecipients-this.currentMailing.nbRecipients>0) { this.outputs.totalRecipientsExcluded.setAttribute('warning','') this.outputs.labelExcluded.setAttribute('warning','') } else { this.outputs.totalRecipientsExcluded.removeAttribute('warning') this.outputs.labelExcluded.removeAttribute('warning') } this.output('totalFinalRecipients', this.currentMailing.nbRecipients) this.output('totalRecipientsDupes', Object.keys(dupes).length) if(Object.keys(dupes).length>0){ this.outputs.totalRecipients.parent this.outputs.totalRecipientsDupes.setAttribute('danger','') this.outputs.labelDupes.setAttribute('danger','') this.components.dupsInfo.dupes = dupes //hell yeah ui.show(this.components.dupsInfo.el, 'inline-flex') } else { this.outputs.totalRecipientsDupes.removeAttribute('danger') this.outputs.labelDupes.removeAttribute('danger') this.components.dupsInfo.dupes = null ui.hide(this.components.dupsInfo.el) } } refreshMappings() { if((!this.currentMailing.template) || (!this.currentMailing.template.id)) return const templateTokens = this.templates.getTokens(this.currentMailing.template) this.output('mappingsPanel', '') const nbMapMissingPerSrc = this.mailings.nbMapMissingPerSrc(this.currentMailing, templateTokens) for(let source of this.currentMailing.sources){ if(source.negative) continue const sourceType = (source.sourceType=='Excel') ? `` : `` let article = ui.create(`
    0 ? '': 'collapsed' }>

    ${sourceType} ${source.sourceName}

    ${nbMapMissingPerSrc[source.id] > 0 ? `${nbMapMissingPerSrc[source.id]} missing`: 'complete' }

    `) let oneMapping = this.currentMailing.mappings.find(i => i.sourceId==source.id) if(!oneMapping){ oneMapping = { "sourceName": source.sourceName, "sourceType": source.sourceType, "mappings": { }, "sourceId": source.id, } this.currentMailing.mappings.push(oneMapping) } let ul = article.querySelector('section ul') for(let variable of templateTokens) { let severity, label, title if(variable in oneMapping.mappings) { severity = 'secondary' label = oneMapping.mappings[variable].hint title = oneMapping.mappings[variable].hint } else { severity = 'primary' label = 'Select...' title = '' } let li = ui.create(`
  • ${variable}
  • `) ul.appendChild(li) } let components = ui.eicfy(article) this.setupTriggers(components) this.outputs.mappingsPanel.append(article) } } refreshReview(){ const [block2display, contents] = this.mailings.getReviewBlocks(this.currentMailing) const allBlocks = ['revieweePane','reviewerPane', 'revieweeOngoing','revieweeApproved','revieweeRejected','revieweeRequest', 'reviewerChoice','reviewerApproved','reviewerRejected'] allBlocks.forEach(blockName => ui.hide(this.outputs[blockName])) block2display.forEach(blockName => ui.show(this.outputs[blockName], 'grid')) for(let blockName in contents) this.output(blockName, contents[blockName]) } refreshSchedule(){ if(this.currentMailing.status=='scheduled'){ ui.hide(this.outputs.toSchedule) ui.show(this.outputs.scheduled) const scheduledStatus = this.mailings.getLatestStatus(this.currentMailing,'scheduled') const scheduleDate = (new Intl.DateTimeFormat("en-GB", {timeZone: "Europe/Paris", dateStyle:'medium', timeStyle:'medium'})) .format(new Date(scheduledStatus.meta.scheduleDate)) this.output('scheduledDate', scheduleDate) if(app.User.roles.includes('MAIL_Sender')) ui.show(this.outputs.unschedule, 'grid') else ui.hide(this.outputs.unschedule) } else { ui.hide(this.outputs.scheduled) ui.show(this.outputs.toSchedule) } } /**************************************** Event handlers ******************************************/ async onPathBrowse() { const button = this.find('button[data-trigger="onPathBrowse"]') this.showLoading(button) try { let result = await this.mailings.getReadableFolders() if (!result || typeof result !== 'object') { console.error("getReadableFolders returned invalid result", result) return } let { mailings, authorizedPaths, foldersWithFiles, rights } = result if (!Array.isArray(authorizedPaths)) authorizedPaths = [] if (!authorizedPaths.includes('/mailing')) authorizedPaths.unshift('/mailing') this.mailings.ffs.authorizedPaths = authorizedPaths; this.mailings.ffs.foldersWithFiles = foldersWithFiles || [] if (!mailings?.mailings) { mailings = { mailings } } const fileList = Array.isArray(mailings.mailings) ? mailings.mailings : [] this.mailings.ffs.loadStructure({ mailing: mailings.mailings || mailings }, fileList) this.mailings.ffs.currentPath = '/mailing' this.mailings.ffs.authorizedPaths = authorizedPaths this.mailings.ffs.rights = rights || [] this.createPath = this.find('div[data-output="createPath"]') this.spanPath = this.createPath ? this.createPath.querySelector('span[data-path]') : null this.currentPath = this.spanPath ? this.spanPath.getAttribute('data-path') : '/mailing' let dialogResult = await this.openDialog( await this.loadContent( 'templates/Ffs/dialogs/FileBrowserDialog', { title: `Select a path...` }, { ffs: this.mailings.ffs, editable: false, startPath: this.currentPath, canManage: true, mailings: this.mailings, context: 'mailings' } ) ) if (dialogResult) { this.currentMailing.path = dialogResult this.output('createPath', this.pathChips(this.currentMailing.path)) this.outputs.createPath.dataset.value = dialogResult this.onNamePathChange() } } catch (error) { console.error("Error on dialog PathSearch loading :", error) } finally { this.hideLoading(button); } } onNamePathChange(){ this.components.saveCreated.disabled = ((this.components.mailingName.value=='') || (this.outputs.createPath.dataset.value =='')) } async onSaveCreated(component, event){ this.currentMailing.name = this.components.mailingName.value this.currentMailing.path = this.outputs.createPath.dataset.value this.currentMailing.status = 'draft' this.components.saveCreated.loading = true try { await this.mailings.save(this.currentMailing) ui.growl.append('Mailing saved !', 'success',3000) } catch(e) {} this.components.saveCreated.loading = false this.loadMailingInfo(this.currentMailing.id) } onWorkflowSelect(entity) { if(!entity) return this.findAll('.sheet-content').forEach(el => {ui.hide(el)}) let target = entity.el.dataset.id let tab = this.find(`[data-content="${target}"]`) const stepActivations = this.mailings.getStepActivations(this.currentMailing, this.templates.getTokens(this.currentMailing.template)) if(stepActivations[target].disabled) return // Maybe this is the logical next step, brought automatically, but your role doesn't allow for it. if(tab) { ui.show(tab) switch(target){ case 'template': // todo display content corresponding to status/role break case 'recipients': // todo display content corresponding to status/role break case 'mappings': // todo display content corresponding to status/role break case 'approval': // todo display content corresponding to status/role break case 'schedule': // todo display content corresponding to status/role //if(!this.mailings.hasPrivilege('schedule')) return break default: } } else { ui.growl.append('Content unavailable', 'danger') } } async onTemplateChange() { const templateTokens = this.templates.getTokens(this.currentMailing.template) if(templateTokens && (templateTokens.length>0) && (this.currentMailing.mappings.length>0)){ let result = await this.confirmDialog({ title: `CAUTION: Existing mappings...`, message: `

    You have existing mappings for the current Template.
    If you do select a new template (after previewing it),
    these mappings will be lost !

    `, okLabel: 'I understand', severity: 'warning', }) if(!result) return } let result = await this.openDialog( await this.loadContent( 'comms/mailings/sheet/dialogs/MailingTemplatePreviewDialog', { title: `Pick your content template` }, { status: ['prod'], currentMailing: this.currentMailing, templateModel: this.templates, mailingModel: this.mailings, } ) ) if(result) this.loadMailingInfo(this.currentMailing.id) } async onSourceDel(importId, event) { event.preventDefault() event.stopPropagation() const oneImport = this.currentMailing.imports.find(i => i.id==importId) let result = await this.confirmDialog({ title: (!oneImport.negative) ? `Remove these ${oneImport.data.length} recipients ?` : `Remove this exclusion list and re-allow ${oneImport.data.length} emails ?`, message: `

    Are you sure ?

    `, okLabel: 'Delete', severity: 'danger', okPromise: data => this.mailings.deleteImport(this.currentMailing.id, importId) }) if(result) this.loadMailingInfo(this.currentMailing.id) } async onSourceRefreshQC(importId, btn, event) { event.preventDefault() event.stopPropagation() btn.loading = true const curImport = this.currentMailing.imports.find(i => i.id==importId) const curSource = this.currentMailing.sources.find(i => i.mli_id==importId) const tmpResults = await this.contactMgr.getSample(curSource.query_id, curSource.query_params) console.log('=====>tmpResults', tmpResults) let result = await this.confirmDialog({ title: ` `, message: `

    You are about to re-run the query !
    Currenly you have ${curImport.data.length} recipients.
    After re-running the query, you would have ${tmpResults.nbRows} recipients.

    Update the data?

    `, okLabel: 'Yes, rerun the query !', severity: 'warning', okPromise: data => this.mailings.refreshImport(this.currentMailing.id, { sourceType: curImport.sourceType, refreshOnly: true, importId: curImport.id, }, importId).then( () => btn.loading = false, () => btn.loading = false ) }) if(result) this.loadMailingInfo(this.currentMailing.id) btn.loading = false } // async onSourceEditQC(importId, event) { // event.preventDefault() // event.stopPropagation() // const curImport = this.currentMailing.imports.find(i => i.id==importId) // console.log('=====>onSourceEditQC:', curImport.data.length) // } async onImport(){ let result = await this.openDialog( await this.loadContent( 'comms/mailings/sheet/dialogs/MailingImportDialog', { title: `Import recipients from Excel file...` }, { model: this.mailings, mid: this.currentMailing.id, } ) ) if(result) this.loadMailingInfo(this.currentMailing.id) } async onExclusion(){ let result = await this.openDialog( await this.loadContent( 'comms/mailings/sheet/dialogs/MailingExclusionDialog', { title: `Import exclusion list from Excel file...` }, { model: this.mailings, mid: this.currentMailing.id, } ) ) if(result) this.loadMailingInfo(this.currentMailing.id) } async onFetch(){ let result = await this.openDialog( await this.loadContent( 'comms/mailings/sheet/dialogs/MailingFetchDialog', { title: `Fetch recipients from MyEIC applications...` }, { models: { contacts: this.contactMgr, mailings: this.mailings, }, mid: this.currentMailing.id, } ) ) if(result) this.loadMailingInfo(this.currentMailing.id) } async onDupsInfo(component, event) { let result = await this.openDialog( await this.loadContent( 'comms/mailings/sheet/dialogs/MailingDuplicatesDialog', { title: `Duplicate emails...` }, { dupes: component.dupes, } ) ) } async onMappingChange(component, event) { let result = await this.openDialog( await this.loadContent( 'comms/mailings/sheet/dialogs/MailingMappingDialog', { title: `Link template variable to a column in the Excel file...` }, { model: this.mailings, token: component._el.dataset.token, sourceId: component._el.dataset.sourceid, currentMailing: this.currentMailing, } ) ) if(result) this.loadMailingInfo(this.currentMailing.id) } async onTestSend(){ let result = await this.openDialog( await this.loadContent( 'comms/mailings/sheet/dialogs/MailingTestDialog', { title: `Sending a test mail...` }, { tokens: this.templates.getTokens(this.currentMailing.template) } ) ) if(result){ await this.mailings.test(this.currentMailing.id, this.currentMailing.template.id, result.email, result.tokenValues) } } async onReviewRequest(){ let result = await this.confirmDialog({ title: 'Request review ?', message: `You're about to request for this mailing to be reviewed.
    During the review process, the mailing won't be editable anymore.
    `, promptsClass: 'prompts', okLabel: 'Request review', severity: 'warning', okSeverity: 'primary', okPromise: (data) => { this.currentMailing.status = 'submitted' this.currentMailing.statusMeta = { comments: data.comments } return(this.mailings.save(this.currentMailing)) } }) if(result) { this.loadMailingInfo(this.currentMailing.id) } } async onReviewApprove() { let result = await this.confirmDialog({ title: 'Approve mailing ?', message: `Approve this mailing for sending ?`, okLabel: 'Approve', severity: 'success', okSeverity: 'primary', okPromise: (data) => { this.currentMailing.status = 'approved' return(this.mailings.save(this.currentMailing)) } }) if(result) { this.loadMailingInfo(this.currentMailing.id) } } async onReviewReject(){ let result = await this.confirmDialog({ title: 'Reject mailing', message: `Reject sending of this mailing ?
    `, promptsClass: 'prompts', okLabel: 'Reject sending', severity: 'warning', okSeverity: 'primary', okPromise: (data) => { this.currentMailing.status = 'rejected' this.currentMailing.statusMeta = { reason: data.reason } return(this.mailings.save(this.currentMailing)) } }) if(result) { this.loadMailingInfo(this.currentMailing.id) } } onScheduleDateChange(){ this.components.scheduleTimeLater.value = '' this.fillScheduleTime() this.components.scheduleButton.disabled = true } onScheduleTimeChange() { this.components.scheduleButton.disabled = (this.components.scheduleTimeLater.value == '') } fillScheduleTime(){ const today = new Date().toISOString().split('T')[0] const thisHour = (new Date()).getHours() this.components.scheduleTimeLater.el.innerHTML='' if(this.components.scheduleDateLater.value==today){ if((thisHour+1) < 24) { for(let h=thisHour+1; h<24; h++) this.components.scheduleTimeLater.el.append(ui.create(``)) } } else { for(let h=0; h<24; h++) this.components.scheduleTimeLater.el.append(ui.create(``)) } } async onSendingNow(component, event) { await this.sendMailing(this.components.scheduleDateNow.value, this.components.scheduleTimeNow.value) } async onSendingLater(component, event) { await this.sendMailing(this.components.scheduleDateLater.value, this.components.scheduleTimeLater.value) } async sendMailing(scheduleDate, scheduleTime) { const getCETOffset = () => { const date = new Date() const options = { timeZone: "Europe/Paris", timeZoneName: "short" } const formatter = new Intl.DateTimeFormat("en-US", options) const parts = formatter.formatToParts(date) const timeZoneOffset = parts.find(part => part.type === "timeZoneName").value return timeZoneOffset.includes("CEST") ? 2 : 1 } const today = new Date().toISOString().split('T')[0] const [year, month, day] = scheduleDate.split("-") const europeanDate = `${day}/${month}/${year}` let when if(scheduleDate==today){ when = scheduleTime=='5min' ? 'in five minutes' : `today at ${scheduleTime.toString().padStart(2, '0')}:00 (${scheduleTime < 12 ? 'AM' : 'PM'})` } else { when = `on ${europeanDate} at ${scheduleTime.toString().padStart(2, '0')}:00 (${scheduleTime < 12 ? 'AM' : 'PM'})` } let UTCScheduleTime if(scheduleTime!='5min'){ UTCScheduleTime = (new Date(`${scheduleDate}T${scheduleTime.toString().padStart(2, '0')}:00:00+0${getCETOffset()}:00`)).toISOString() } else { UTCScheduleTime = (new Date((new Date).getTime() + 5 * 60 * 1000)).toISOString() } let result = await this.confirmDialog({ title: 'Send mailing ?', message: `You are about to schedule the sending of this mailing ${when}`, okLabel: 'Schedule sending', severity: 'secondary', okSeverity: 'danger', okPromise: (data) => { return(this.mailings.schedule(this.currentMailing.id, UTCScheduleTime)) } }) if(result) { this.loadMailingInfo(this.currentMailing.id); } } async onAbortSending(component, event) { let result = await this.confirmDialog({ title: 'Abort the sending ?', message: `You are about to abort the sending of this mailing !
    If you proceed, it will be editable again,
    and it will have to be reviewed again.
    Is this really what you want to do ?`, okLabel: 'Abort', severity: 'warning', cancelSeverity: 'primary', okSeverity: 'secondary', okPromise: (data) => { this.currentMailing.status = 'draft' return(this.mailings.save(this.currentMailing)) } }) if(result) { this.loadMailingInfo(this.currentMailing.id) } } async onUnschedule(component, event) { let result = await this.confirmDialog({ title: 'Unschedule the sending ?', message: `You are about to unschedule this mailing !
    If you proceed, it will not be sent,
    and you will be able to re-schedule or to abort it.
    Is this really what you want to do ?`, okLabel: 'Unschedule', severity: 'warning', cancelSeverity: 'primary', okSeverity: 'secondary', okPromise: (data) => { this.currentMailing.status = 'approved' return(this.mailings.save(this.currentMailing)) } }) if(result) { this.loadMailingInfo(this.currentMailing.id) } } async onMailingDelete(component, event) { let result = await this.confirmDialog({ title: 'DELETE this mailing ?', message: `You are about to DELETE this mailing !
    If you proceed, it will not be sent,
    and everything it contains will be lost.
    Is this really what you want to do ?`, okLabel: 'Delete', severity: 'danger', cancelSeverity: 'primary', okSeverity: 'secondary', okPromise: (data) => { return(this.mailings.delete(this.currentMailing.id)) } }) if(result) { app.Router.route(`/mailings`) } } pathChips(path){ const dirs = path.split('/').filter(item=>item) const markup = (dirs.length>0) ? dirs.map((dir, idx) => { const path = dirs.slice(0, idx+1).join('/') return(`${dir}`) }).join('') : '[Please select it]' return(markup) } } app.registerClass('MailingSheetView', MailingSheetView) /* TODO -> Delete Draft (add in WF, add method in MT, add here) */