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 =
- ;
-
-
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 {