From e2f6c8abe743000a083d7e8ca87306d3929bb168 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Sun, 31 Mar 2024 20:56:03 +0300 Subject: [PATCH] ref --- .../crm/src/views/meeting/modals/detail.js | 502 ++++++++++-------- client/src/views/modal.js | 2 +- 2 files changed, 272 insertions(+), 232 deletions(-) diff --git a/client/modules/crm/src/views/meeting/modals/detail.js b/client/modules/crm/src/views/meeting/modals/detail.js index d1f9f35410..35f0d78da8 100644 --- a/client/modules/crm/src/views/meeting/modals/detail.js +++ b/client/modules/crm/src/views/meeting/modals/detail.js @@ -26,294 +26,334 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -define('crm:views/meeting/modals/detail', ['views/modals/detail', 'lib!moment'], function (Dep, moment) { +import moment from 'moment'; +import DetailModalView from 'views/modals/detail'; - return Dep.extend({ +class MeetingModalDetailView extends DetailModalView { - duplicateAction: true, + duplicateAction = true - setupAfterModelCreated: function () { - Dep.prototype.setupAfterModelCreated.call(this); + setup() { + super.setup(); - let buttonData = this.getAcceptanceButtonData(); + this.setupStatuses(); + } - this.addButton({ - name: 'setAcceptanceStatus', - html: buttonData.html, - hidden: this.hasAcceptanceStatusButton(), - style: buttonData.style, - className: 'btn-text', - pullLeft: true, - }, 'cancel'); + setupStatuses() { + if (this.notActualStatusList) { + return; + } - if ( - !~this.getAcl().getScopeForbiddenFieldList(this.model.entityType).indexOf('status') - ) { - this.addDropdownItem({ - name: 'setHeld', - text: this.translate('Set Held', 'labels', this.model.entityType), - hidden: true, - }); + this.notActualStatusList = [ + ...(this.getMetadata().get(`scopes.${this.entityType}.completedStatusList`) || []), + ...(this.getMetadata().get(`scopes.${this.entityType}.canceledStatusList`) || []), + ]; + } - this.addDropdownItem({ - name: 'setNotHeld', - text: this.translate('Set Not Held', 'labels', this.model.entityType), - hidden: true, - }); - } + setupAfterModelCreated() { + super.setupAfterModelCreated(); + + const buttonData = this.getAcceptanceButtonData(); + + this.addButton({ + name: 'setAcceptanceStatus', + html: buttonData.html, + hidden: this.hasAcceptanceStatusButton(), + style: buttonData.style, + className: 'btn-text', + pullLeft: true, + onClick: () => this.actionSetAcceptanceStatus(), + }, 'cancel'); + + if ( + !this.getAcl().getScopeForbiddenFieldList(this.model.entityType).includes('status') + ) { + this.addDropdownItem({ + name: 'setHeld', + text: this.translate('Set Held', 'labels', this.model.entityType), + hidden: true, + }); this.addDropdownItem({ - name: 'sendInvitations', - text: this.translate('Send Invitations', 'labels', 'Meeting'), - hidden: !this.isSendInvitationsToBeDisplayed(), + name: 'setNotHeld', + text: this.translate('Set Not Held', 'labels', this.model.entityType), + hidden: true, }); + } + this.addDropdownItem({ + name: 'sendInvitations', + text: this.translate('Send Invitations', 'labels', 'Meeting'), + hidden: !this.isSendInvitationsToBeDisplayed(), + onClick: () => this.actionSendInvitations(), + }); + + this.initAcceptanceStatus(); + + this.on('switch-model', (model, previousModel) => { + this.stopListening(previousModel, 'sync'); this.initAcceptanceStatus(); + }); - this.on('switch-model', (model, previousModel) => { - this.stopListening(previousModel, 'sync'); - this.initAcceptanceStatus(); - }); - - this.on('after:save', () => { - if (this.hasAcceptanceStatusButton()) { - this.showAcceptanceButton(); - } else { - this.hideAcceptanceButton(); - } - - if (this.isSendInvitationsToBeDisplayed()) { - this.showActionItem('sendInvitations'); - } else { - this.hideActionItem('sendInvitations'); - } - }); - - this.listenTo(this.model, 'sync', () => { - if (this.isSendInvitationsToBeDisplayed()) { - this.showActionItem('sendInvitations'); - - return; - } - - this.hideActionItem('sendInvitations'); - }); - - this.listenTo(this.model, 'after:save', () => { - if (this.isSendInvitationsToBeDisplayed()) { - this.showActionItem('sendInvitations'); - - return; - } - - this.hideActionItem('sendInvitations'); - }); - }, - - controlRecordButtonsVisibility: function () { - Dep.prototype.controlRecordButtonsVisibility.call(this); - - this.controlStatusActionVisibility(); - }, - - controlStatusActionVisibility: function () { - if (this.getAcl().check(this.model, 'edit') && !~['Held', 'Not Held'].indexOf(this.model.get('status'))) { - this.showActionItem('setHeld'); - this.showActionItem('setNotHeld'); - } else { - this.hideActionItem('setHeld'); - this.hideActionItem('setNotHeld'); - } - }, - - hasSetStatusButton: function () { - - }, - - initAcceptanceStatus: function () { + this.on('after:save', () => { if (this.hasAcceptanceStatusButton()) { this.showAcceptanceButton(); } else { this.hideAcceptanceButton(); } - this.listenTo(this.model, 'sync', () => { - if (this.hasAcceptanceStatusButton()) { - this.showAcceptanceButton(); - } else { - this.hideAcceptanceButton(); - } - }); - }, - - getAcceptanceButtonData: function () { - let acceptanceStatus = this.model.getLinkMultipleColumn('users', 'status', this.getUser().id); - - let text; - let style = 'default'; - - let iconHtml = null; - - if (acceptanceStatus && acceptanceStatus !== 'None') { - text = this.getLanguage().translateOption(acceptanceStatus, 'acceptanceStatus', this.model.entityType); - - style = this.getMetadata() - .get(['entityDefs', this.model.entityType, - 'fields', 'acceptanceStatus', 'style', acceptanceStatus]); - - if (style) { - let iconClass = ({ - 'success': 'fas fa-check-circle', - 'danger': 'fas fa-times-circle', - 'warning': 'fas fa-question-circle', - })[style]; - - iconHtml = $('') - .addClass(iconClass) - .addClass('text-' + style) - .get(0).outerHTML; - } + if (this.isSendInvitationsToBeDisplayed()) { + this.showActionItem('sendInvitations'); } else { - text = typeof acceptanceStatus !== 'undefined' ? - this.translate('Acceptance', 'labels', 'Meeting') : - ' '; + this.hideActionItem('sendInvitations'); } + }); - let html = this.getHelper().escapeString(text); - - if (iconHtml) { - html = iconHtml + ' ' + html; - } - - return { - style: style, - text: text, - html: html, - }; - }, - - showAcceptanceButton: function () { - this.showActionItem('setAcceptanceStatus'); - - if (!this.isRendered()) { - this.once('after:render', this.showAcceptanceButton, this); + this.listenTo(this.model, 'sync', () => { + if (this.isSendInvitationsToBeDisplayed()) { + this.showActionItem('sendInvitations'); return; } - let data = this.getAcceptanceButtonData(); + this.hideActionItem('sendInvitations'); + }); - let $button = this.$el.find('.modal-footer [data-name="setAcceptanceStatus"]'); + this.listenTo(this.model, 'after:save', () => { + if (this.isSendInvitationsToBeDisplayed()) { + this.showActionItem('sendInvitations'); - $button.html(data.html); - - $button.removeClass('btn-default'); - $button.removeClass('btn-success'); - $button.removeClass('btn-warning'); - $button.removeClass('btn-info'); - $button.removeClass('btn-primary'); - $button.removeClass('btn-danger'); - $button.addClass('btn-' + data.style); - }, - - hideAcceptanceButton: function () { - this.hideActionItem('setAcceptanceStatus'); - }, - - hasAcceptanceStatusButton: function () { - if (!this.model.has('status')) { - return false; + return; } - if (!this.model.has('usersIds')) { - return false; + this.hideActionItem('sendInvitations'); + }); + } + + controlRecordButtonsVisibility() { + super.controlRecordButtonsVisibility(); + + this.controlStatusActionVisibility(); + } + + controlStatusActionVisibility() { + this.setupStatuses(); + + if ( + this.getAcl().check(this.model, 'edit') && + !this.notActualStatusList.includes(this.model.get('status')) + ) { + this.showActionItem('setHeld'); + this.showActionItem('setNotHeld'); + + return; + } + + this.hideActionItem('setHeld'); + this.hideActionItem('setNotHeld'); + } + + initAcceptanceStatus() { + if (this.hasAcceptanceStatusButton()) { + this.showAcceptanceButton(); + } else { + this.hideAcceptanceButton(); + } + + this.listenTo(this.model, 'sync', () => { + if (this.hasAcceptanceStatusButton()) { + this.showAcceptanceButton(); + } else { + this.hideAcceptanceButton(); } + }); + } - if (~['Held', 'Not Held'].indexOf(this.model.get('status'))) { - return false; + /** + * + * @return {{ + * style: 'default'|'danger'|'success'|'warning'|'info', + * html: string, + * text: string, + * }} + */ + getAcceptanceButtonData() { + const acceptanceStatus = this.model.getLinkMultipleColumn('users', 'status', this.getUser().id); + + let text; + let style = 'default'; + + let iconHtml = null; + + if (acceptanceStatus && acceptanceStatus !== 'None') { + text = this.getLanguage().translateOption(acceptanceStatus, 'acceptanceStatus', this.model.entityType); + + style = this.getMetadata() + .get(['entityDefs', this.model.entityType, + 'fields', 'acceptanceStatus', 'style', acceptanceStatus]); + + if (style) { + const iconClass = ({ + 'success': 'fas fa-check-circle', + 'danger': 'fas fa-times-circle', + 'warning': 'fas fa-question-circle', + })[style]; + + iconHtml = $('') + .addClass(iconClass) + .addClass('text-' + style) + .get(0).outerHTML; } + } else { + text = typeof acceptanceStatus !== 'undefined' ? + this.translate('Acceptance', 'labels', 'Meeting') : + ' '; + } - if (!~this.model.getLinkMultipleIdList('users').indexOf(this.getUser().id)) { - return false; - } - return true; - }, + let html = this.getHelper().escapeString(text); - actionSetAcceptanceStatus: function () { - this.createView('dialog', 'crm:views/meeting/modals/acceptance-status', { - model: this.model, - }, (view) => { - view.render(); + if (iconHtml) { + html = iconHtml + ' ' + html; + } - this.listenTo(view, 'set-status', (status) => { - this.hideAcceptanceButton(); + return { + style: style, + text: text, + html: html, + }; + } - Espo.Ajax.postRequest(this.model.entityType + '/action/setAcceptanceStatus', { + showAcceptanceButton() { + this.showActionItem('setAcceptanceStatus'); + + if (!this.isRendered()) { + this.once('after:render', this.showAcceptanceButton, this); + + return; + } + + const data = this.getAcceptanceButtonData(); + + const $button = this.$el.find('.modal-footer [data-name="setAcceptanceStatus"]'); + + $button.html(data.html); + + $button.removeClass('btn-default'); + $button.removeClass('btn-success'); + $button.removeClass('btn-warning'); + $button.removeClass('btn-info'); + $button.removeClass('btn-primary'); + $button.removeClass('btn-danger'); + $button.addClass('btn-' + data.style); + } + + hideAcceptanceButton() { + this.hideActionItem('setAcceptanceStatus'); + } + + hasAcceptanceStatusButton() { + if (!this.model.has('status')) { + return false; + } + + if (!this.model.has('usersIds')) { + return false; + } + + if (this.notActualStatusList.includes(this.model.get('status'))) { + return false; + } + + if (!~this.model.getLinkMultipleIdList('users').indexOf(this.getUser().id)) { + return false; + } + return true; + } + + actionSetAcceptanceStatus() { + this.createView('dialog', 'crm:views/meeting/modals/acceptance-status', { + model: this.model, + }, (view) => { + view.render(); + + this.listenTo(view, 'set-status', (status) => { + this.hideAcceptanceButton(); + + Espo.Ui.notify(' ... '); + + Espo.Ajax + .postRequest(this.model.entityType + '/action/setAcceptanceStatus', { id: this.model.id, status: status, - }).then(() => { + }) + .then(() => { this.model.fetch() .then(() => { + Espo.Ui.notify(false); + setTimeout(() => { this.$el.find(`button[data-name="setAcceptanceStatus"]`).focus(); }, 50) }); }); - }); }); - }, + }); + } - actionSetHeld: function () { - this.model.save({status: 'Held'}); - this.trigger('after:save', this.model); - }, + actionSetHeld() { + this.model.save({status: 'Held'}); - actionSetNotHeld: function () { - this.model.save({status: 'Not Held'}); - this.trigger('after:save', this.model); - }, + this.trigger('after:save', this.model); + } - isSendInvitationsToBeDisplayed: function () { - if (~['Held', 'Not Held'].indexOf(this.model.get('status'))) { - return false; - } + actionSetNotHeld() { + this.model.save({status: 'Not Held'}); - let dateEnd = this.model.get('dateEnd'); + this.trigger('after:save', this.model); + } - if ( - dateEnd && - this.getDateTime().toMoment(dateEnd).isBefore(moment.now()) - ) { - return false; - } + isSendInvitationsToBeDisplayed() { + if (this.notActualStatusList.includes(this.model.get('status'))) { + return false; + } - if (!this.getAcl().checkModel(this.model, 'edit')) { - return false; - } + const dateEnd = this.model.get('dateEnd'); - let userIdList = this.model.getLinkMultipleIdList('users'); - let contactIdList = this.model.getLinkMultipleIdList('contacts'); - let leadIdList = this.model.getLinkMultipleIdList('leads'); + if ( + dateEnd && + this.getDateTime().toMoment(dateEnd).isBefore(moment.now()) + ) { + return false; + } - if (!contactIdList.length && !leadIdList.length && !userIdList.length) { - return false; - } + if (!this.getAcl().checkModel(this.model, 'edit')) { + return false; + } - return true; - }, + const userIdList = this.model.getLinkMultipleIdList('users'); + const contactIdList = this.model.getLinkMultipleIdList('contacts'); + const leadIdList = this.model.getLinkMultipleIdList('leads'); - actionSendInvitations: function () { - Espo.Ui.notify(' ... '); + if (!contactIdList.length && !leadIdList.length && !userIdList.length) { + return false; + } - this.createView('dialog', 'crm:views/meeting/modals/send-invitations', { - model: this.model, - }).then(view => { - Espo.Ui.notify(false); + return true; + } - view.render(); + actionSendInvitations() { + Espo.Ui.notify(' ... '); - this.listenToOnce(view, 'sent', () => this.model.fetch()); - }); - }, - }); -}); + this.createView('dialog', 'crm:views/meeting/modals/send-invitations', { + model: this.model, + }).then(view => { + Espo.Ui.notify(false); + + view.render(); + + this.listenToOnce(view, 'sent', () => this.model.fetch()); + }); + } +} + +export default MeetingModalDetailView; diff --git a/client/src/views/modal.js b/client/src/views/modal.js index d08fbd210e..2be70243ec 100644 --- a/client/src/views/modal.js +++ b/client/src/views/modal.js @@ -50,7 +50,7 @@ class ModalView extends View { * @property {string} [html] HTML. * @property {boolean} [pullLeft=false] Deprecated. Use the `position` property. * @property {'left'|'right'} [position='left'] A position. - * @property {'default'|'danger'|'success'|'warning'} [style='default'] A style. + * @property {'default'|'danger'|'success'|'warning'|'info'} [style='default'] A style. * @property {boolean} [hidden=false] Is hidden. * @property {boolean} [disabled=false] Disabled. * @property {function(module:ui.Dialog): void} [onClick] Called on click. If not defined, then