diff --git a/client/src/Home.js b/client/src/Home.js index 1081d820..dbc3bf8f 100644 --- a/client/src/Home.js +++ b/client/src/Home.js @@ -25,7 +25,7 @@ export default class List extends Component { return (

{t('Mailtrain 2 beta')}

-
{t('Build') + ' 2020-05-28-0102'}
+
{t('Build') + ' 2020-07-17-0000'}

{this.props.configItems.shoutout}

); diff --git a/client/src/campaigns/CUD.js b/client/src/campaigns/CUD.js index 4e63ab8d..6afaf2ca 100644 --- a/client/src/campaigns/CUD.js +++ b/client/src/campaigns/CUD.js @@ -33,7 +33,7 @@ import {getUrl} from "../lib/urls"; import {campaignOverridables, CampaignSource, CampaignStatus, CampaignType} from "../../../shared/campaigns"; import moment from 'moment'; import {getMailerTypes} from "../send-configurations/helpers"; -import {getCampaignLabels} from "./helpers"; +import {getCampaignLabels, ListsSelectorHelper} from "./helpers"; import {withComponentMixins} from "../lib/decorator-helpers"; import interoperableErrors from "../../../shared/interoperable-errors"; import {Trans} from "react-i18next"; @@ -51,6 +51,8 @@ export default class CUD extends Component { const t = props.t; + this.listsSelectorHelper = new ListsSelectorHelper(this, t, 'lists'); + this.templateTypes = getTemplateTypes(props.t, 'data_sourceCustom_', ResourceType.CAMPAIGN); this.tagLanguages = getTagLanguages(props.t); @@ -79,20 +81,9 @@ export default class CUD extends Component { [CampaignSource.URL]: t('url') }; - let sourceLabelsOrder; - - if (props.createFromChannel) { - // If a campaign is created within a channel, we allow only for those source types that makes sense - sourceLabelsOrder = [ - CampaignSource.CUSTOM, CampaignSource.CUSTOM_FROM_CAMPAIGN, CampaignSource.CUSTOM_FROM_TEMPLATE - ]; - - } else { - // Regular creation or createFromCampaign - sourceLabelsOrder = [ - CampaignSource.CUSTOM, CampaignSource.CUSTOM_FROM_CAMPAIGN , CampaignSource.TEMPLATE, CampaignSource.CUSTOM_FROM_TEMPLATE, CampaignSource.URL - ]; - } + const sourceLabelsOrder = [ + CampaignSource.CUSTOM, CampaignSource.CUSTOM_FROM_CAMPAIGN , CampaignSource.TEMPLATE, CampaignSource.CUSTOM_FROM_TEMPLATE, CampaignSource.URL + ]; this.sourceOptions = []; for (const key of sourceLabelsOrder) { @@ -113,8 +104,6 @@ export default class CUD extends Component { sendConfiguration: null }; - this.nextListEntryId = 0; - this.initForm({ leaveConfirmation: !props.entity || props.entity.permissions.includes('edit'), onChange: { @@ -128,17 +117,11 @@ export default class CUD extends Component { action: PropTypes.string.isRequired, entity: PropTypes.object, createFromChannel: PropTypes.object, - createFromCampaign: PropTypes.object, + crateFromCampaign: PropTypes.object, permissions: PropTypes.object, type: PropTypes.number } - getNextListEntryId() { - const id = this.nextListEntryId; - this.nextListEntryId += 1; - return id; - } - onFormChangeBeforeValidation(mutStateData, key, oldValue, newValue) { let match; @@ -156,10 +139,7 @@ export default class CUD extends Component { } } - if (key && (match = key.match(/^(lists_[0-9]+_)list$/))) { - const prefix = match[1]; - mutStateData.setIn([prefix + 'segment', 'value'], null); - } + this.listsSelectorHelper.onFormChangeBeforeValidation(mutStateData, key, oldValue, newValue); } onSendConfigurationChanged(newState, key, oldValue, sendConfigurationId) { @@ -216,19 +196,7 @@ export default class CUD extends Component { } } - const lsts = []; - for (const lst of data.lists) { - const lstUid = this.getNextListEntryId(); - - const prefix = 'lists_' + lstUid + '_'; - - data[prefix + 'list'] = lst.list; - data[prefix + 'segment'] = lst.segment; - data[prefix + 'useSegmentation'] = !!lst.segment; - - lsts.push(lstUid); - } - data.lists = lsts; + this.listsSelectorHelper.getFormValuesMutator(data); // noinspection JSIgnoredPromiseFromCall this.fetchSendConfiguration(data.send_configuration); @@ -275,27 +243,10 @@ export default class CUD extends Component { delete data[overridable + '_overriden']; } - const lsts = []; - for (const lstUid of data.lists) { - const prefix = 'lists_' + lstUid + '_'; - - const useSegmentation = data[prefix + 'useSegmentation']; - - lsts.push({ - list: data[prefix + 'list'], - segment: useSegmentation ? data[prefix + 'segment'] : null - }); - } - data.lists = lsts; - - for (const key in data) { - if (key.startsWith('data_') || key.startsWith('lists_')) { - delete data[key]; - } - } + this.listsSelectorHelper.submitFormValuesMutator(data); return filterData(data, [ - 'name', 'description', 'segment', 'namespace', 'send_configuration', + 'name', 'description', 'channel', 'namespace', 'send_configuration', 'subject', 'from_name_override', 'from_email_override', 'reply_to_override', 'data', 'click_tracking_disabled', 'open_tracking_disabled', 'unsubscribe_url', 'type', 'source', 'parent', 'lists' @@ -314,10 +265,33 @@ export default class CUD extends Component { const data = {}; + // This is for CampaignSource.TEMPLATE and CampaignSource.CUSTOM_FROM_TEMPLATE + data.data_sourceTemplate = null; + + // This is for CampaignSource.CUSTOM_FROM_CAMPAIGN + data.data_sourceCampaign = null; + + // This is for CampaignSource.CUSTOM + data.data_sourceCustom_type = mailtrainConfig.editors[0]; + data.data_sourceCustom_tag_language = mailtrainConfig.tagLanguages[0]; + data.data_sourceCustom_data = {}; + data.data_sourceCustom_html = ''; + data.data_sourceCustom_text = ''; + + Object.assign(data, this.templateTypes[mailtrainConfig.editors[0]].initData()); + + // This is for CampaignSource.URL + data.data_sourceUrl = ''; + + // This is for CampaignType.RSS + data.data_feedUrl = ''; + if (this.props.createFromChannel) { const channel = this.props.createFromChannel; + data.channel = channel.id; + for (const overridable of campaignOverridables) { if (channel[overridable + '_override'] === null) { data[overridable + '_override'] = ''; @@ -328,19 +302,7 @@ export default class CUD extends Component { } } - const lsts = []; - for (const lst of channel.lists) { - const lstUid = this.getNextListEntryId(); - - const prefix = 'lists_' + lstUid + '_'; - - data[prefix + 'list'] = lst.list; - data[prefix + 'segment'] = lst.segment; - data[prefix + 'useSegmentation'] = !!lst.segment; - - lsts.push(lstUid); - } - data.lists = lsts; + this.listsSelectorHelper.populateFrom(data, channel.lists); data.type = CampaignType.REGULAR; @@ -366,23 +328,27 @@ export default class CUD extends Component { if (channel.source === CampaignSource.CUSTOM_FROM_TEMPLATE) { data.data_sourceTemplate = channel.sourceTemplate; - } - if (channel.source === CampaignSource.CUSTOM_FROM_CAMPAIGN) { - channel.data_sourceCampaign = channel.data.sourceCampaign; - } + } else if (channel.source === CampaignSource.CUSTOM_FROM_CAMPAIGN) { + data.data_sourceCampaign = channel.data.sourceCampaign; - if (channel.source === CampaignSource.CUSTOM) { + } else if (channel.source === CampaignSource.CUSTOM) { data.data_sourceCustom_type = channel.data.sourceCustom.type; data.data_sourceCustom_tag_language = channel.data.sourceCustom.tag_language; data.data_sourceCustom_data = channel.data.sourceCustom.data; this.templateTypes[channel.data.sourceCustom.type].afterLoad(data); + + } else if (channel.source === CampaignSource.URL) { + data.data_sourceUrl = channel.data.sourceUrl } + } else if (this.props.createFromCampaign) { const sourceCampaign = this.props.createFromCampaign; + data.channel = sourceCampaign.channel; + for (const overridable of campaignOverridables) { if (sourceCampaign[overridable + '_override'] === null) { data[overridable + '_override'] = ''; @@ -393,19 +359,7 @@ export default class CUD extends Component { } } - const lsts = []; - for (const lst of sourceCampaign.lists) { - const lstUid = this.getNextListEntryId(); - - const prefix = 'lists_' + lstUid + '_'; - - data[prefix + 'list'] = lst.list; - data[prefix + 'segment'] = lst.segment; - data[prefix + 'useSegmentation'] = !!lst.segment; - - lsts.push(lstUid); - } - data.lists = lsts; + this.listsSelectorHelper.populateFrom(data, sourceCampaign.lists); data.type = sourceCampaign.type; @@ -425,28 +379,6 @@ export default class CUD extends Component { data.unsubscribe_url = sourceCampaign.unsubscribe_url; - - // This is for CampaignSource.TEMPLATE and CampaignSource.CUSTOM_FROM_TEMPLATE - data.data_sourceTemplate = null; - - // This is for CampaignSource.CUSTOM_FROM_CAMPAIGN - data.data_sourceCampaign = null; - - // This is for CampaignSource.CUSTOM - data.data_sourceCustom_type = mailtrainConfig.editors[0]; - data.data_sourceCustom_tag_language = mailtrainConfig.tagLanguages[0]; - data.data_sourceCustom_data = {}; - data.data_sourceCustom_html = ''; - data.data_sourceCustom_text = ''; - - Object.assign(data, this.templateTypes[mailtrainConfig.editors[0]].initData()); - - // This is for CampaignSource.URL - data.data_sourceUrl = ''; - - // This is for CampaignType.RSS - data.data_feedUrl = ''; - if (sourceCampaign.source === CampaignSource.CUSTOM_FROM_TEMPLATE || sourceCampaign.source === CampaignSource.CUSTOM_FROM_CAMPAIGN || sourceCampaign.source === CampaignSource.CUSTOM) { data.source = CampaignSource.CUSTOM_FROM_CAMPAIGN; data.data_sourceCampaign = sourceCampaign.id; @@ -466,18 +398,14 @@ export default class CUD extends Component { data[overridable + '_overriden'] = false; } + data.channel = null; + data.type = this.props.type; data.name = ''; data.description = ''; - const lstUid = this.getNextListEntryId(); - const lstPrefix = 'lists_' + lstUid + '_'; - - data[lstPrefix + 'list'] = null; - data[lstPrefix + 'segment'] = null; - data[lstPrefix + 'useSegmentation'] = false; - data.lists = [lstUid]; + this.listsSelectorHelper.populateFrom(data, [{list: null, segment: null}]); data.send_configuration = null; data.namespace = getDefaultNamespace(this.props.permissions); @@ -490,27 +418,6 @@ export default class CUD extends Component { data.unsubscribe_url = ''; data.source = CampaignSource.CUSTOM; - - // This is for CampaignSource.TEMPLATE and CampaignSource.CUSTOM_FROM_TEMPLATE - data.data_sourceTemplate = null; - - // This is for CampaignSource.CUSTOM_FROM_CAMPAIGN - data.data_sourceCampaign = null; - - // This is for CampaignSource.CUSTOM - data.data_sourceCustom_type = mailtrainConfig.editors[0]; - data.data_sourceCustom_tag_language = mailtrainConfig.tagLanguages[0]; - data.data_sourceCustom_data = {}; - data.data_sourceCustom_html = ''; - data.data_sourceCustom_text = ''; - - Object.assign(data, this.templateTypes[mailtrainConfig.editors[0]].initData()); - - // This is for CampaignSource.URL - data.data_sourceUrl = ''; - - // This is for CampaignType.RSS - data.data_feedUrl = ''; } this.populateFormValues(data); @@ -583,17 +490,7 @@ export default class CUD extends Component { } } - for (const lstUid of state.getIn(['lists', 'value'])) { - const prefix = 'lists_' + lstUid + '_'; - - if (!state.getIn([prefix + 'list', 'value'])) { - state.setIn([prefix + 'list', 'error'], t('listMustBeSelected')); - } - - if (state.getIn([prefix + 'useSegmentation', 'value']) && !state.getIn([prefix + 'segment', 'value'])) { - state.setIn([prefix + 'segment', 'error'], t('segmentMustBeSelected')); - } - } + this.listsSelectorHelper.localValidateFormValues(state) validateNamespace(t, state); } @@ -627,7 +524,12 @@ export default class CUD extends Component { if (afterSubmitAction === CUD.AfterSubmitAction.STATUS) { this.navigateToWithFlashMessage(`/campaigns/${this.props.entity.id}/status`, 'success', t('campaignUpdated')); } else if (afterSubmitAction === CUD.AfterSubmitAction.LEAVE) { - this.navigateToWithFlashMessage('/campaigns', 'success', t('campaignUpdated')); + const channelId = this.getFormValue('channel'); + if (channelId) { + this.navigateToWithFlashMessage(`/channels/${channelId}/campaigns`, 'success', t('campaignUpdated')); + } else { + this.navigateToWithFlashMessage('/campaigns', 'success', t('campaignUpdated')); + } } else { await this.getFormValuesFromURL(`rest/campaigns-settings/${this.props.entity.id}`); this.enableForm(); @@ -642,7 +544,12 @@ export default class CUD extends Component { if (afterSubmitAction === CUD.AfterSubmitAction.STATUS) { this.navigateToWithFlashMessage(`/campaigns/${submitResult}/status`, 'success', t('campaignCreated')); } else if (afterSubmitAction === CUD.AfterSubmitAction.LEAVE) { - this.navigateToWithFlashMessage(`/campaigns`, 'success', t('campaignCreated')); + const channelId = this.getFormValue('channel'); + if (channelId) { + this.navigateToWithFlashMessage(`/channels/${channelId}/campaigns`, 'success', t('campaignCreated')); + } else { + this.navigateToWithFlashMessage(`/campaigns`, 'success', t('campaignCreated')); + } } else { this.navigateToWithFlashMessage(`/campaigns/${submitResult}/edit`, 'success', t('campaignCreated')); } @@ -654,46 +561,6 @@ export default class CUD extends Component { } } - onAddListEntry(orderBeforeIdx) { - this.updateForm(mutState => { - const lsts = mutState.getIn(['lists', 'value']); - let paramId = 0; - - const lstUid = this.getNextListEntryId(); - - const prefix = 'lists_' + lstUid + '_'; - - mutState.setIn([prefix + 'list', 'value'], null); - mutState.setIn([prefix + 'segment', 'value'], null); - mutState.setIn([prefix + 'useSegmentation', 'value'], false); - - mutState.setIn(['lists', 'value'], [...lsts.slice(0, orderBeforeIdx), lstUid, ...lsts.slice(orderBeforeIdx)]); - }); - } - - onRemoveListEntry(lstUid) { - this.updateForm(mutState => { - const lsts = this.getFormValue('lists'); - - const prefix = 'lists_' + lstUid + '_'; - - mutState.delete(prefix + 'list'); - mutState.delete(prefix + 'segment'); - mutState.delete(prefix + 'useSegmentation'); - - mutState.setIn(['lists', 'value'], lsts.filter(val => val !== lstUid)); - }); - } - - onListEntryMoveUp(orderIdx) { - const lsts = this.getFormValue('lists'); - this.updateFormValue('lists', [...lsts.slice(0, orderIdx - 1), lsts[orderIdx], lsts[orderIdx - 1], ...lsts.slice(orderIdx + 1)]); - } - - onListEntryMoveDown(orderIdx) { - const lsts = this.getFormValue('lists'); - this.updateFormValue('lists', [...lsts.slice(0, orderIdx), lsts[orderIdx + 1], lsts[orderIdx], ...lsts.slice(orderIdx + 2)]); - } render() { const t = this.props.t; @@ -710,90 +577,13 @@ export default class CUD extends Component { extraSettings = } - const listsColumns = [ + const channelsColumns = [ { data: 1, title: t('name') }, { data: 2, title: t('id'), render: data => {data} }, - { data: 3, title: t('subscribers') }, - { data: 4, title: t('description') }, - { data: 5, title: t('namespace') } + { data: 3, title: t('description') }, + { data: 4, title: t('namespace') } ]; - const segmentsColumns = [ - { data: 1, title: t('name') } - ]; - - const lstsEditEntries = []; - const lsts = this.getFormValue('lists') || []; - let lstOrderIdx = 0; - for (const lstUid of lsts) { - const prefix = 'lists_' + lstUid + '_'; - const lstOrderIdxClosure = lstOrderIdx; - - const selectedList = this.getFormValue(prefix + 'list'); - - lstsEditEntries.push( -
-
- {lsts.length > 1 && -
-
- -
- - {selectedList && this.getFormValue(prefix + 'useSegmentation') && - - } -
-
-
- ); - - lstOrderIdx += 1; - } - - const lstsEdit = -
- {lstsEditEntries} -
-
-
; - - const sendConfigurationsColumns = [ { data: 1, title: t('name') }, { data: 2, title: t('id'), render: data => {data} }, @@ -938,13 +728,15 @@ export default class CUD extends Component {