- Refactoring of the mail sending part. Mail queue (table 'queued') is now used also for all test emails.
- More options how to send test emails. - Fixed problems with pausing a campaign (#593) - Started rework of transactional sender of templates (#606), however this contains functionality regression at the moment because it does not interpret templates as HBS. It needs HBS option for templates as described in https://github.com/Mailtrain-org/mailtrain/issues/611#issuecomment-502345227 TODO: - detect sending errors connected to not able to contact the mailer and pause/retry campaing and queued sending - don't mark the recipients as BOUNCED - add FAILED campaign state and fall into it if sending to campaign consistently fails (i.e. the error with sending is not temporary) - if the same happends for queued email, delete the message
This commit is contained in:
parent
ff66a6c39e
commit
30b361290b
42 changed files with 1366 additions and 786 deletions
|
@ -138,7 +138,7 @@ export default class API extends Component {
|
|||
<strong>{t('example')}</strong>
|
||||
</p>
|
||||
|
||||
<pre>curl -XPOST '{getUrl(`api/subscribe/B16uVTdW?access_token=${accessToken}`)}' \
|
||||
<pre>curl -XPOST '{getUrl(`api/subscribe/B16uVTdW?access_token=${accessToken}`)}' \<br/>
|
||||
--data 'EMAIL=test@example.com&MERGE_CHECKBOX=yes&REQUIRE_CONFIRMATION=yes'</pre>
|
||||
|
||||
<h4>POST /api/unsubscribe/:listId – {t('removeSubscription')}</h4>
|
||||
|
@ -165,7 +165,7 @@ export default class API extends Component {
|
|||
<strong>{t('example')}</strong>
|
||||
</p>
|
||||
|
||||
<pre>curl -XPOST '{getUrl(`api/unsubscribe/B16uVTdW?access_token=${accessToken}`)}' \
|
||||
<pre>curl -XPOST '{getUrl(`api/unsubscribe/B16uVTdW?access_token=${accessToken}`)}' \<br/>
|
||||
--data 'EMAIL=test@example.com'</pre>
|
||||
|
||||
<h4>POST /api/delete/:listId – {t('deleteSubscription')}</h4>
|
||||
|
@ -192,7 +192,7 @@ export default class API extends Component {
|
|||
<strong>{t('example')}</strong>
|
||||
</p>
|
||||
|
||||
<pre>curl -XPOST '{getUrl(`api/delete/B16uVTdW?access_token=${accessToken}`)}' \
|
||||
<pre>curl -XPOST '{getUrl(`api/delete/B16uVTdW?access_token=${accessToken}`)}' \<br/>
|
||||
--data 'EMAIL=test@example.com'</pre>
|
||||
|
||||
<h4>POST /api/field/:listId – {t('addNewCustomField')}</h4>
|
||||
|
@ -240,7 +240,7 @@ export default class API extends Component {
|
|||
<strong>{t('example')}</strong>
|
||||
</p>
|
||||
|
||||
<pre>curl -XPOST '{getUrl(`api/field/B16uVTdW?access_token=${accessToken}`)}' \
|
||||
<pre>curl -XPOST '{getUrl(`api/field/B16uVTdW?access_token=${accessToken}`)}' \<br/>
|
||||
--data 'NAME=Birthday&TYPE=birthday-us&VISIBLE=yes'</pre>
|
||||
|
||||
<h4>GET /api/blacklist/get – {t('getListOfBlacklistedEmails')}</h4>
|
||||
|
@ -292,7 +292,7 @@ export default class API extends Component {
|
|||
<strong>{t('example')}</strong>
|
||||
</p>
|
||||
|
||||
<pre>curl -XPOST '{getUrl(`api/blacklist/add?access_token={accessToken}`)}' \
|
||||
<pre>curl -XPOST '{getUrl(`api/blacklist/add?access_token={accessToken}`)}' \<br/>
|
||||
--data 'EMAIL=test@example.com&'</pre>
|
||||
|
||||
<h4>POST /api/blacklist/delete – {t('deleteEmailFromBlacklist')}</h4>
|
||||
|
@ -319,7 +319,7 @@ export default class API extends Component {
|
|||
<strong>{t('example')}</strong>
|
||||
</p>
|
||||
|
||||
<pre>curl -XPOST '{getUrl(`api/blacklist/delete?access_token=${accessToken}`)}' \
|
||||
<pre>curl -XPOST '{getUrl(`api/blacklist/delete?access_token=${accessToken}`)}' \<br/>
|
||||
--data 'EMAIL=test@example.com&'</pre>
|
||||
|
||||
<h4>GET /api/lists/:email – {t('getTheListsAUserHasSubscribedTo')}</h4>
|
||||
|
@ -381,15 +381,14 @@ export default class API extends Component {
|
|||
<li><strong>EMAIL</strong> – {t('emailAddress')} (<em>{t('required')}</em>)</li>
|
||||
<li><strong>SEND_CONFIGURATION_ID</strong> – {t('idOfConfigurationUsedToCreateMailer')}</li>
|
||||
<li><strong>SUBJECT</strong> – {t('subject')}</li>
|
||||
<li><strong>DATA</strong> – {t('dataPassedToTemplateWhenCompilingWith')}: <em>{'{'} "any": ["type", {'{'}"of": "data"{'}'}] {'}'}</em></li>
|
||||
<li><strong>VARIABLES</strong> – {t('mapOfTemplatesubjectVariablesToReplace')}: <em>{'{'} "FOO": "bar" {'}'}</em></li>
|
||||
<li><strong>VARIABLES</strong> – {t('mapOfTemplatesubjectVariablesToReplace')}</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
<strong>{t('example')}</strong>
|
||||
</p>
|
||||
|
||||
<pre>curl -XPOST '{getUrl(`api/templates/1/send?access_token={accessToken}`)}' \
|
||||
<pre>curl -XPOST '{getUrl(`api/templates/1/send?access_token=${accessToken}`)}' \<br/>
|
||||
--data 'EMAIL=test@example.com&SUBJECT=Test&VARIABLES[FOO]=bar&VARIABLES[TEST]=example'</pre>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -244,7 +244,7 @@ export default class CUD extends Component {
|
|||
|
||||
return filterData(data, [
|
||||
'name', 'description', 'segment', 'namespace', 'send_configuration',
|
||||
'from_name_override', 'from_email_override', 'reply_to_override', 'subject_override',
|
||||
'from_name_override', 'from_email_override', 'reply_to_override',
|
||||
'data', 'click_tracking_disabled', 'open_tracking_disabled', 'unsubscribe_url',
|
||||
'type', 'source', 'parent', 'lists'
|
||||
]);
|
||||
|
@ -284,6 +284,8 @@ export default class CUD extends Component {
|
|||
send_configuration: null,
|
||||
namespace: mailtrainConfig.user.namespace,
|
||||
|
||||
subject: '',
|
||||
|
||||
click_tracking_disabled: false,
|
||||
open_tracking_disabled: false,
|
||||
|
||||
|
@ -326,6 +328,10 @@ export default class CUD extends Component {
|
|||
state.setIn(['name', 'error'], t('nameMustNotBeEmpty'));
|
||||
}
|
||||
|
||||
if (!state.getIn(['subject', 'value'])) {
|
||||
state.setIn(['subject', 'error'], t('"Subject" line must not be empty"'));
|
||||
}
|
||||
|
||||
if (!state.getIn(['send_configuration', 'value'])) {
|
||||
state.setIn(['send_configuration', 'error'], t('sendConfigurationMustBeSelected'));
|
||||
}
|
||||
|
@ -592,7 +598,6 @@ export default class CUD extends Component {
|
|||
{ data: 2, title: t('id'), render: data => <code>{data}</code> },
|
||||
{ data: 3, title: t('description') },
|
||||
{ data: 4, title: t('type'), render: data => this.mailerTypes[data].typeName },
|
||||
{ data: 5, title: t('created'), render: data => moment(data).fromNow() },
|
||||
{ data: 6, title: t('namespace') }
|
||||
];
|
||||
|
||||
|
@ -604,10 +609,10 @@ export default class CUD extends Component {
|
|||
const addOverridable = (id, label) => {
|
||||
if(this.state.sendConfiguration[id + '_overridable']){
|
||||
if (this.getFormValue(id + '_overriden')) {
|
||||
sendSettings.push(<InputField label={t(label)} key={id + '_override'} id={id + '_override'}/>);
|
||||
sendSettings.push(<InputField label={label} key={id + '_override'} id={id + '_override'}/>);
|
||||
} else {
|
||||
sendSettings.push(
|
||||
<StaticField key={id + '_original'} label={t(label)} id={id + '_original'} className={styles.formDisabled}>
|
||||
<StaticField key={id + '_original'} label={label} id={id + '_original'} className={styles.formDisabled}>
|
||||
{this.state.sendConfiguration[id]}
|
||||
</StaticField>
|
||||
);
|
||||
|
@ -616,7 +621,7 @@ export default class CUD extends Component {
|
|||
}
|
||||
else{
|
||||
sendSettings.push(
|
||||
<StaticField key={id + '_original'} label={t(label)} id={id + '_original'} className={styles.formDisabled}>
|
||||
<StaticField key={id + '_original'} label={label} id={id + '_original'} className={styles.formDisabled}>
|
||||
{this.state.sendConfiguration[id]}
|
||||
</StaticField>
|
||||
);
|
||||
|
@ -626,7 +631,8 @@ export default class CUD extends Component {
|
|||
addOverridable('from_name', t('fromName'));
|
||||
addOverridable('from_email', t('fromEmailAddress'));
|
||||
addOverridable('reply_to', t('replytoEmailAddress'));
|
||||
addOverridable('subject', t('subjectLine'));
|
||||
|
||||
sendSettings.push(<InputField label={t('subjectLine')} key="subject" id="subject"/>);
|
||||
} else {
|
||||
sendSettings = <AlignedRow>{t('loadingSendConfiguration')}</AlignedRow>
|
||||
}
|
||||
|
@ -760,8 +766,6 @@ export default class CUD extends Component {
|
|||
</>
|
||||
}
|
||||
|
||||
|
||||
|
||||
{templateEdit}
|
||||
|
||||
<ButtonRow>
|
||||
|
|
|
@ -20,7 +20,7 @@ import {getEditForm, getTemplateTypes, getTypeForm, ResourceType} from '../templ
|
|||
import axios from '../lib/axios';
|
||||
import styles from "../lib/styles.scss";
|
||||
import {getUrl} from "../lib/urls";
|
||||
import {TestSendModalDialog} from "./TestSendModalDialog";
|
||||
import {TestSendModalDialog, TestSendModalDialogMode} from "./TestSendModalDialog";
|
||||
import {withComponentMixins} from "../lib/decorator-helpers";
|
||||
import {ContentModalDialog} from "../lib/modals";
|
||||
|
||||
|
@ -234,10 +234,11 @@ export default class CustomContent extends Component {
|
|||
return (
|
||||
<div className={this.state.elementInFullscreen ? styles.withElementInFullscreen : ''}>
|
||||
<TestSendModalDialog
|
||||
mode={TestSendModalDialogMode.CAMPAIGN_CONTENT}
|
||||
visible={this.state.showTestSendModal}
|
||||
onHide={() => this.setState({showTestSendModal: false})}
|
||||
getDataAsync={this.sendModalGetDataHandler}
|
||||
entity={this.props.entity}
|
||||
campaign={this.props.entity}
|
||||
/>
|
||||
<ContentModalDialog
|
||||
title={this.state.exportModalTitle}
|
||||
|
@ -261,7 +262,7 @@ export default class CustomContent extends Component {
|
|||
<Button type="submit" className="btn-primary" icon="check" label={t('save')}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('saveAndLeave')} onClickAsync={async () => await this.submitHandler(CustomContent.AfterSubmitAction.LEAVE)}/>
|
||||
<Button type="submit" className="btn-primary" icon="check" label={t('saveAndGoToStatus')} onClickAsync={async () => await this.submitHandler(CustomContent.AfterSubmitAction.STATUS)}/>
|
||||
<Button className="btn-success" icon="at" label={t('testSend')} onClickAsync={async () => this.setState({showTestSendModal: true})}/>
|
||||
<Button className="btn-success" icon="at" label={t('Test send')} onClickAsync={async () => this.setState({showTestSendModal: true})}/>
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
</div>
|
||||
|
|
|
@ -16,6 +16,7 @@ import {CampaignStatus, CampaignType} from "../../../shared/campaigns";
|
|||
import moment from 'moment';
|
||||
import campaignsStyles from "./styles.scss";
|
||||
import {withComponentMixins} from "../lib/decorator-helpers";
|
||||
import {TestSendModalDialog, TestSendModalDialogMode} from "./TestSendModalDialog";
|
||||
|
||||
|
||||
@withComponentMixins([
|
||||
|
@ -25,7 +26,7 @@ import {withComponentMixins} from "../lib/decorator-helpers";
|
|||
withPageHelpers,
|
||||
requiresAuthenticatedUser
|
||||
])
|
||||
class TestUser extends Component {
|
||||
class PreviewForTestUserModalDialog extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.initForm({
|
||||
|
@ -34,7 +35,9 @@ class TestUser extends Component {
|
|||
}
|
||||
|
||||
static propTypes = {
|
||||
entity: PropTypes.object.isRequired
|
||||
visible: PropTypes.bool.isRequired,
|
||||
onHide: PropTypes.func.isRequired,
|
||||
entity: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
localValidateFormValues(state) {
|
||||
|
@ -64,6 +67,10 @@ class TestUser extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
async hideModal() {
|
||||
this.props.onHide();
|
||||
}
|
||||
|
||||
render() {
|
||||
const t = this.props.t;
|
||||
|
||||
|
@ -76,12 +83,14 @@ class TestUser extends Component {
|
|||
];
|
||||
|
||||
return (
|
||||
<Form stateOwner={this}>
|
||||
<TableSelect id="testUser" label={t('previewCampaignAs')} withHeader dropdown dataUrl={`rest/campaigns-test-users-table/${this.props.entity.id}`} columns={testUsersColumns} selectionLabelIndex={1} />
|
||||
<ButtonRow>
|
||||
<Button className="btn-primary" label={t('preview')} onClickAsync={::this.previewAsync}/>
|
||||
</ButtonRow>
|
||||
</Form>
|
||||
<ModalDialog hidden={!this.props.visible} title={t('Preview Campaign')} onCloseAsync={() => this.hideModal()} buttons={[
|
||||
{ label: t('preview'), className: 'btn-primary', onClickAsync: ::this.previewAsync },
|
||||
{ label: t('close'), className: 'btn-danger', onClickAsync: ::this.hideModal }
|
||||
]}>
|
||||
<Form stateOwner={this}>
|
||||
<TableSelect id="testUser" label={t('Preview as')} withHeader dropdown dataUrl={`rest/campaigns-test-users-table/${this.props.entity.id}`} columns={testUsersColumns} selectionLabelIndex={1} />
|
||||
</Form>
|
||||
</ModalDialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -96,6 +105,12 @@ class TestUser extends Component {
|
|||
class SendControls extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
showTestSendModal: false,
|
||||
previewForTestUserVisible: false
|
||||
};
|
||||
|
||||
this.initForm({
|
||||
leaveConfirmation: false
|
||||
});
|
||||
|
@ -257,13 +272,33 @@ class SendControls extends Component {
|
|||
const t = this.props.t;
|
||||
const entity = this.props.entity;
|
||||
|
||||
const yesNoDialog = (
|
||||
<ModalDialog hidden={!this.state.modalVisible} title={this.state.modalTitle} onCloseAsync={() => this.modalAction(false)} buttons={[
|
||||
{ label: t('no'), className: 'btn-primary', onClickAsync: () => this.modalAction(false) },
|
||||
{ label: t('yes'), className: 'btn-danger', onClickAsync: () => this.modalAction(true) }
|
||||
]}>
|
||||
{this.state.modalMessage}
|
||||
</ModalDialog>
|
||||
const dialogs = (
|
||||
<>
|
||||
<TestSendModalDialog
|
||||
mode={TestSendModalDialogMode.CAMPAIGN_STATUS}
|
||||
visible={this.state.showTestSendModal}
|
||||
onHide={() => this.setState({showTestSendModal: false})}
|
||||
campaign={this.props.entity}
|
||||
/>
|
||||
<PreviewForTestUserModalDialog
|
||||
visible={this.state.previewForTestUserVisible}
|
||||
onHide={() => this.setState({previewForTestUserVisible: false})}
|
||||
entity={this.props.entity}
|
||||
/>
|
||||
<ModalDialog hidden={!this.state.modalVisible} title={this.state.modalTitle} onCloseAsync={() => this.modalAction(false)} buttons={[
|
||||
{ label: t('no'), className: 'btn-primary', onClickAsync: () => this.modalAction(false) },
|
||||
{ label: t('yes'), className: 'btn-danger', onClickAsync: () => this.modalAction(true) }
|
||||
]}>
|
||||
{this.state.modalMessage}
|
||||
</ModalDialog>
|
||||
</>
|
||||
);
|
||||
|
||||
const testButtons = (
|
||||
<>
|
||||
<Button className="btn-success" label={t('Preview')} onClickAsync={async () => this.setState({previewForTestUserVisible: true})}/>
|
||||
<Button className="btn-success" label={t('Test send')} onClickAsync={async () => this.setState({showTestSendModal: true})}/>
|
||||
</>
|
||||
);
|
||||
|
||||
if (entity.status === CampaignStatus.IDLE || entity.status === CampaignStatus.PAUSED || (entity.status === CampaignStatus.SCHEDULED && entity.scheduled)) {
|
||||
|
@ -271,7 +306,7 @@ class SendControls extends Component {
|
|||
const subscrInfo = entity.subscriptionsToSend === undefined ? '' : ` (${entity.subscriptionsToSend} ${t('subscribers-1')})`;
|
||||
|
||||
return (
|
||||
<div>{yesNoDialog}
|
||||
<div>{dialogs}
|
||||
<AlignedRow label={t('sendStatus')}>
|
||||
{entity.scheduled ? t('campaignIsScheduledForDelivery') : t('campaignIsReadyToBeSentOut')}
|
||||
</AlignedRow>
|
||||
|
@ -292,20 +327,36 @@ class SendControls extends Component {
|
|||
:
|
||||
<Button className="btn-primary" icon="send" label={t('send') + subscrInfo} onClickAsync={::this.confirmStart}/>
|
||||
}
|
||||
{entity.status === CampaignStatus.PAUSED && <Button className="btn-primary" icon="refresh" label={t('reset')} onClickAsync={::this.resetAsync}/>}
|
||||
{entity.status === CampaignStatus.PAUSED && <LinkButton className="btn-secondary" icon="signal" label={t('viewStatistics')} to={`/campaigns/${entity.id}/statistics`}/>}
|
||||
{testButtons}
|
||||
</ButtonRow>
|
||||
</div>
|
||||
);
|
||||
|
||||
} else if (entity.status === CampaignStatus.PAUSING) {
|
||||
return (
|
||||
<div>{dialogs}
|
||||
<AlignedRow label={t('sendStatus')}>
|
||||
{t('Campaign is being paused. Please wait.')}
|
||||
</AlignedRow>
|
||||
<ButtonRow>
|
||||
<LinkButton className="btn-secondary" icon="signal" label={t('viewStatistics')} to={`/campaigns/${entity.id}/statistics`}/>
|
||||
{testButtons}
|
||||
</ButtonRow>
|
||||
</div>
|
||||
);
|
||||
|
||||
} else if (entity.status === CampaignStatus.SENDING || (entity.status === CampaignStatus.SCHEDULED && !entity.scheduled)) {
|
||||
return (
|
||||
<div>{yesNoDialog}
|
||||
<div>{dialogs}
|
||||
<AlignedRow label={t('sendStatus')}>
|
||||
{t('campaignIsBeingSentOut')}
|
||||
</AlignedRow>
|
||||
<ButtonRow>
|
||||
<Button className="btn-primary" icon="stop" label={t('stop')} onClickAsync={::this.stopAsync}/>
|
||||
<LinkButton className="btn-secondary" icon="signal" label={t('viewStatistics')} to={`/campaigns/${entity.id}/statistics`}/>
|
||||
{testButtons}
|
||||
</ButtonRow>
|
||||
</div>
|
||||
);
|
||||
|
@ -314,7 +365,7 @@ class SendControls extends Component {
|
|||
const subscrInfo = entity.subscriptionsToSend === undefined ? '' : ` (${entity.subscriptionsToSend} ${t('subscribers-1')})`;
|
||||
|
||||
return (
|
||||
<div>{yesNoDialog}
|
||||
<div>{dialogs}
|
||||
<AlignedRow label={t('sendStatus')}>
|
||||
{t('allMessagesSent!HitContinueIfYouYouWant')}
|
||||
</AlignedRow>
|
||||
|
@ -322,35 +373,38 @@ class SendControls extends Component {
|
|||
<Button className="btn-primary" icon="play" label={t('continue') + subscrInfo} onClickAsync={::this.confirmStart}/>
|
||||
<Button className="btn-primary" icon="refresh" label={t('reset')} onClickAsync={::this.resetAsync}/>
|
||||
<LinkButton className="btn-secondary" icon="signal" label={t('viewStatistics')} to={`/campaigns/${entity.id}/statistics`}/>
|
||||
{testButtons}
|
||||
</ButtonRow>
|
||||
</div>
|
||||
);
|
||||
|
||||
} else if (entity.status === CampaignStatus.INACTIVE) {
|
||||
return (
|
||||
<div>{yesNoDialog}
|
||||
<div>{dialogs}
|
||||
<AlignedRow label={t('sendStatus')}>
|
||||
{t('yourCampaignIsCurrentlyDisabledClick')}
|
||||
</AlignedRow>
|
||||
<ButtonRow>
|
||||
<Button className="btn-primary" icon="play" label={t('enable')} onClickAsync={::this.enableAsync}/>
|
||||
{testButtons}
|
||||
</ButtonRow>
|
||||
</div>
|
||||
);
|
||||
|
||||
} else if (entity.status === CampaignStatus.ACTIVE) {
|
||||
return (
|
||||
<div>{yesNoDialog}
|
||||
<div>{dialogs}
|
||||
<AlignedRow label={t('sendStatus')}>
|
||||
{t('yourCampaignIsEnabledAndSendingMessages')}
|
||||
</AlignedRow>
|
||||
<ButtonRow>
|
||||
<Button className="btn-primary" icon="stop" label={t('disable')} onClickAsync={::this.disableAsync}/>
|
||||
{testButtons}
|
||||
</ButtonRow>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -441,7 +495,7 @@ export default class Status extends Component {
|
|||
addOverridable('from_name', t('fromName'));
|
||||
addOverridable('from_email', t('fromEmailAddress'));
|
||||
addOverridable('reply_to', t('replytoEmailAddress'));
|
||||
addOverridable('subject', t('subjectLine'));
|
||||
sendSettings.push(<AlignedRow key="subject" label={t('subjectLine')}>{entity.subject}</AlignedRow>);
|
||||
} else {
|
||||
sendSettings = <AlignedRow>{t('loadingSendConfiguration')}</AlignedRow>
|
||||
}
|
||||
|
@ -491,13 +545,6 @@ export default class Status extends Component {
|
|||
<Table withHeader dataUrl={`rest/lists-with-segment-by-campaign-table/${this.props.entity.id}`} columns={listsColumns} />
|
||||
</AlignedRow>
|
||||
|
||||
{(entity.type === CampaignType.REGULAR || entity.type === CampaignType.TRIGGERED) &&
|
||||
<div>
|
||||
<hr/>
|
||||
<TestUser entity={entity}/>
|
||||
</div>
|
||||
}
|
||||
|
||||
<hr/>
|
||||
<SendControls entity={entity} refreshEntity={::this.refreshEntity}/>
|
||||
|
||||
|
|
|
@ -5,13 +5,26 @@ import {withTranslation} from '../lib/i18n';
|
|||
import PropTypes from 'prop-types';
|
||||
import {ModalDialog} from "../lib/bootstrap-components";
|
||||
import {requiresAuthenticatedUser, withPageHelpers} from "../lib/page";
|
||||
import {Form, TableSelect, withForm} from "../lib/form";
|
||||
import {CheckBox, Dropdown, Form, InputField, TableSelect, withForm} from "../lib/form";
|
||||
import {withErrorHandling} from "../lib/error-handling";
|
||||
import {getMailerTypes} from "../send-configurations/helpers";
|
||||
import axios from '../lib/axios';
|
||||
import {getUrl} from '../lib/urls';
|
||||
import {withComponentMixins} from "../lib/decorator-helpers";
|
||||
import {CampaignType} from "../../../shared/campaigns";
|
||||
|
||||
const Target = {
|
||||
CAMPAIGN_ONE: 'campaign_one',
|
||||
CAMPAIGN_ALL: 'campaign_all',
|
||||
LIST_ONE: 'list_one',
|
||||
LIST_ALL: 'list_all'
|
||||
};
|
||||
|
||||
export const TestSendModalDialogMode = {
|
||||
TEMPLATE: 0,
|
||||
CAMPAIGN_CONTENT: 1,
|
||||
CAMPAIGN_STATUS: 2
|
||||
}
|
||||
|
||||
@withComponentMixins([
|
||||
withTranslation,
|
||||
|
@ -27,21 +40,39 @@ export class TestSendModalDialog extends Component {
|
|||
this.mailerTypes = getMailerTypes(props.t);
|
||||
|
||||
this.initForm({
|
||||
leaveConfirmation: false
|
||||
leaveConfirmation: false,
|
||||
onChangeBeforeValidation: {
|
||||
list: this.onListChanged
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
stateOwner: PropTypes.object,
|
||||
visible: PropTypes.bool.isRequired,
|
||||
mode: PropTypes.number.isRequired,
|
||||
onHide: PropTypes.func.isRequired,
|
||||
getDataAsync: PropTypes.func.isRequired,
|
||||
entity: PropTypes.object
|
||||
getDataAsync: PropTypes.func,
|
||||
campaign: PropTypes.object
|
||||
}
|
||||
|
||||
onListChanged(mutStateData, key, oldValue, newValue) {
|
||||
mutStateData.setIn(['segment', 'value'], null);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const t = this.props.t;
|
||||
|
||||
this.populateFormValues({
|
||||
testUser: null,
|
||||
target: Target.CAMPAIGN_ONE,
|
||||
testUserSubscriptionCid: null,
|
||||
testUserListAndSubscriptionCid: null,
|
||||
subjectPrepend: '',
|
||||
subjectAppend: t(' [Test]'),
|
||||
sendConfiguration: null,
|
||||
listCid: null,
|
||||
list: null,
|
||||
segment: null,
|
||||
useSegmentation: false
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -52,25 +83,49 @@ export class TestSendModalDialog extends Component {
|
|||
async performAction() {
|
||||
const props = this.props;
|
||||
const t = props.t;
|
||||
const mode = this.props.mode;
|
||||
|
||||
if (this.isFormWithoutErrors()) {
|
||||
|
||||
try {
|
||||
this.hideFormValidation();
|
||||
this.disableForm();
|
||||
this.setFormStatusMessage('info', t('sendingTestEmail'));
|
||||
|
||||
const data = await this.props.getDataAsync();
|
||||
const data = {};
|
||||
|
||||
const campaignCid = props.entity.cid;
|
||||
const [listCid, subscriptionCid] = this.getFormValue('testUser').split(':');
|
||||
if (mode === TestSendModalDialogMode.CAMPAIGN_CONTENT || mode === TestSendModalDialogMode.TEMPLATE) {
|
||||
const contentData = await this.props.getDataAsync();
|
||||
data.html = contentData.html;
|
||||
data.text = contentData.text;
|
||||
}
|
||||
|
||||
data.listCid = listCid;
|
||||
data.subscriptionCid = subscriptionCid;
|
||||
data.sendConfigurationId = props.entity.send_configuration;
|
||||
data.campaignId = props.entity.id;
|
||||
if (mode === TestSendModalDialogMode.TEMPLATE) {
|
||||
data.listCid = this.getFormValue('listCid');
|
||||
data.subscriptionCid = this.getFormValue('testUserSubscriptionCid');
|
||||
data.sendConfigurationId = this.getFormValue('sendConfiguration');
|
||||
|
||||
await axios.post(getUrl('rest/template-test-send'), data);
|
||||
} else if (mode === TestSendModalDialogMode.CAMPAIGN_STATUS || mode === TestSendModalDialogMode.CAMPAIGN_CONTENT) {
|
||||
data.campaignId = props.campaign.id;
|
||||
data.subjectPrepend = this.getFormValue('subjectPrepend');
|
||||
data.subjectAppend = this.getFormValue('subjectAppend');
|
||||
|
||||
const target = this.getFormValue('target');
|
||||
if (target === Target.CAMPAIGN_ONE) {
|
||||
const [listCid, subscriptionCid] = this.getFormValue('testUserListAndSubscriptionCid').split(':');
|
||||
data.listCid = listCid;
|
||||
data.subscriptionCid = subscriptionCid;
|
||||
|
||||
} else if (target === Target.LIST_ALL) {
|
||||
data.listId = this.getFormValue('list');
|
||||
data.segmentId = this.getFormValue('useSegmentation') ? this.getFormValue('segment') : null;
|
||||
|
||||
} else if (target === Target.LIST_ONE) {
|
||||
data.listCid = this.getFormValue('listCid');
|
||||
data.subscriptionCid = this.getFormValue('testUserSubscriptionCid');
|
||||
}
|
||||
}
|
||||
|
||||
await axios.post(getUrl('rest/campaign-test-send'), data);
|
||||
|
||||
this.clearFormStatusMessage();
|
||||
|
||||
|
@ -87,32 +142,204 @@ export class TestSendModalDialog extends Component {
|
|||
|
||||
localValidateFormValues(state) {
|
||||
const t = this.props.t;
|
||||
const props = this.props;
|
||||
const target = this.getFormValue('target');
|
||||
const mode = this.props.mode;
|
||||
|
||||
if (!state.getIn(['testUser', 'value'])) {
|
||||
state.setIn(['testUser', 'error'], t('subscriptionHasToBeSelected'))
|
||||
} else {
|
||||
state.setIn(['testUser', 'error'], null);
|
||||
state.setIn(['listCid', 'error'], null);
|
||||
state.setIn(['sendConfiguration', 'error'], null);
|
||||
state.setIn(['testUserSubscriptionCid', 'error'], null);
|
||||
state.setIn(['testUserListAndSubscriptionCid', 'error'], null);
|
||||
state.setIn(['list', 'error'], null);
|
||||
state.setIn(['segment', 'error'], null);
|
||||
|
||||
if (mode === TestSendModalDialogMode.TEMPLATE) {
|
||||
if (!state.getIn(['listCid', 'value'])) {
|
||||
state.setIn(['listCid', 'error'], t('listHasToBeSelected'))
|
||||
}
|
||||
|
||||
if (!state.getIn(['sendConfiguration', 'value'])) {
|
||||
state.setIn(['sendConfiguration', 'error'], t('sendConfigurationHasToBeSelected'))
|
||||
}
|
||||
|
||||
if (!state.getIn(['testUserSubscriptionCid', 'value'])) {
|
||||
state.setIn(['testUserSubscriptionCid', 'error'], t('subscriptionHasToBeSelected'))
|
||||
}
|
||||
}
|
||||
|
||||
if ((mode === TestSendModalDialogMode.CAMPAIGN_CONTENT || mode === TestSendModalDialogMode.CAMPAIGN_STATUS) && target === Target.CAMPAIGN_ONE) {
|
||||
if (!state.getIn(['testUserListAndSubscriptionCid', 'value'])) {
|
||||
state.setIn(['testUserListAndSubscriptionCid', 'error'], t('subscriptionHasToBeSelected'))
|
||||
}
|
||||
}
|
||||
|
||||
if ((mode === TestSendModalDialogMode.CAMPAIGN_CONTENT || mode === TestSendModalDialogMode.CAMPAIGN_STATUS) && target === Target.LIST_ONE) {
|
||||
if (!state.getIn(['listCid', 'value'])) {
|
||||
state.setIn(['listCid', 'error'], t('listHasToBeSelected'))
|
||||
}
|
||||
|
||||
if (!state.getIn(['testUserSubscriptionCid', 'value'])) {
|
||||
state.setIn(['testUserSubscriptionCid', 'error'], t('subscriptionHasToBeSelected'))
|
||||
}
|
||||
}
|
||||
|
||||
if ((mode === TestSendModalDialogMode.CAMPAIGN_CONTENT || mode === TestSendModalDialogMode.CAMPAIGN_STATUS) && target === Target.LIST_ALL) {
|
||||
if (!state.getIn(['list', 'value'])) {
|
||||
state.setIn(['list', 'error'], t('listMustBeSelected'));
|
||||
}
|
||||
|
||||
if (state.getIn(['useSegmentation', 'value']) && !state.getIn(['segment', 'value'])) {
|
||||
state.setIn(['segment', 'error'], t('segmentMustBeSelected'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const t = this.props.t;
|
||||
const props = this.props;
|
||||
|
||||
const testUsersColumns = [
|
||||
{ data: 1, title: t('email') },
|
||||
{ data: 2, title: t('subscriptionId'), render: data => <code>{data}</code> },
|
||||
{ data: 3, title: t('listId'), render: data => <code>{data}</code> },
|
||||
{ data: 4, title: t('list') },
|
||||
{ data: 5, title: t('listNamespace') }
|
||||
];
|
||||
const content = [];
|
||||
const target = this.getFormValue('target');
|
||||
const mode = this.props.mode;
|
||||
|
||||
if (mode === TestSendModalDialogMode.CAMPAIGN_STATUS) {
|
||||
const targetOpts = [
|
||||
{key: Target.CAMPAIGN_ONE, label: t('Single test user of the campaign')},
|
||||
{key: Target.CAMPAIGN_ALL, label: t('All test users of the campaign')},
|
||||
{key: Target.LIST_ONE, label: t('Single test user from a list')},
|
||||
{key: Target.LIST_ALL, label: t('All test users from a list/segment')}
|
||||
];
|
||||
|
||||
content.push(
|
||||
<Dropdown key="target" id="target" format="wide" label={t('Select to where you want to send the test')} options={targetOpts}/>
|
||||
);
|
||||
}
|
||||
|
||||
if (mode === TestSendModalDialogMode.TEMPLATE) {
|
||||
const listCid = this.getFormValue('listCid');
|
||||
|
||||
const testUsersColumns = [
|
||||
{ data: 1, title: t('subscriptionId'), render: data => <code>{data}</code> },
|
||||
{ data: 2, title: t('email') }
|
||||
];
|
||||
|
||||
const listsColumns = [
|
||||
{ data: 1, title: t('name') },
|
||||
{ data: 2, title: t('id'), render: data => <code>{data}</code> },
|
||||
{ data: 3, title: t('subscribers') },
|
||||
{ data: 4, title: t('description') },
|
||||
{ data: 5, title: t('namespace') }
|
||||
];
|
||||
|
||||
const sendConfigurationsColumns = [
|
||||
{ data: 1, title: t('name') },
|
||||
{ data: 2, title: t('id'), render: data => <code>{data}</code> },
|
||||
{ data: 3, title: t('description') },
|
||||
{ data: 4, title: t('type'), render: data => this.mailerTypes[data].typeName },
|
||||
{ data: 6, title: t('namespace') }
|
||||
];
|
||||
|
||||
content.push(
|
||||
<TableSelect key="sendConfiguration" id="sendConfiguration" format="wide" label={t('sendConfiguration')} withHeader dropdown dataUrl='rest/send-configurations-with-send-permission-table' columns={sendConfigurationsColumns} selectionLabelIndex={1} />
|
||||
);
|
||||
|
||||
content.push(
|
||||
<TableSelect key="listCid" id="listCid" format="wide" label={t('list')} withHeader dropdown dataUrl={`rest/lists-table`} columns={listsColumns} selectionKeyIndex={2} selectionLabelIndex={1} />
|
||||
);
|
||||
|
||||
if (listCid) {
|
||||
content.push(
|
||||
<TableSelect key="testUserSubscriptionCid" id="testUserSubscriptionCid" format="wide" label={t('subscription')} withHeader dropdown dataUrl={`rest/subscriptions-test-user-table/${listCid}`} columns={testUsersColumns} selectionKeyIndex={1} selectionLabelIndex={2} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ((mode === TestSendModalDialogMode.CAMPAIGN_CONTENT || mode === TestSendModalDialogMode.CAMPAIGN_STATUS) && target === Target.CAMPAIGN_ONE) {
|
||||
const testUsersColumns = [
|
||||
{data: 1, title: t('email')},
|
||||
{data: 2, title: t('subscriptionId'), render: data => <code>{data}</code>},
|
||||
{data: 3, title: t('listId'), render: data => <code>{data}</code>},
|
||||
{data: 4, title: t('list')},
|
||||
{data: 5, title: t('listNamespace')}
|
||||
];
|
||||
|
||||
content.push(
|
||||
<TableSelect key="testUserListAndSubscriptionCid" id="testUserListAndSubscriptionCid" format="wide" label={t('subscription')} withHeader dropdown dataUrl={`rest/campaigns-test-users-table/${this.props.campaign.id}`} columns={testUsersColumns} selectionLabelIndex={1} />
|
||||
);
|
||||
}
|
||||
|
||||
if ((mode === TestSendModalDialogMode.CAMPAIGN_CONTENT || mode === TestSendModalDialogMode.CAMPAIGN_STATUS) && target === Target.LIST_ONE) {
|
||||
const listCid = this.getFormValue('listCid');
|
||||
|
||||
const listsColumns = [
|
||||
{ data: 1, title: t('name') },
|
||||
{ data: 2, title: t('id'), render: data => <code>{data}</code> },
|
||||
{ data: 3, title: t('subscribers') },
|
||||
{ data: 4, title: t('description') },
|
||||
{ data: 5, title: t('namespace') }
|
||||
];
|
||||
|
||||
const testUsersColumns = [
|
||||
{ data: 1, title: t('subscriptionId'), render: data => <code>{data}</code> },
|
||||
{ data: 2, title: t('email') }
|
||||
];
|
||||
|
||||
content.push(
|
||||
<TableSelect key="listCid" id="listCid" format="wide" label={t('list')} withHeader dropdown dataUrl={`rest/lists-table`} columns={listsColumns} selectionKeyIndex={2} selectionLabelIndex={1} />
|
||||
);
|
||||
|
||||
if (listCid) {
|
||||
content.push(
|
||||
<TableSelect key="testUserSubscriptionCid" id="testUserSubscriptionCid" format="wide" label={t('subscription')} withHeader dropdown dataUrl={`rest/subscriptions-test-user-table/${listCid}`} columns={testUsersColumns} selectionKeyIndex={1} selectionLabelIndex={2} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ((mode === TestSendModalDialogMode.CAMPAIGN_CONTENT || mode === TestSendModalDialogMode.CAMPAIGN_STATUS) && target === Target.LIST_ALL) {
|
||||
const listsColumns = [
|
||||
{ data: 1, title: t('name') },
|
||||
{ data: 2, title: t('id'), render: data => <code>{data}</code> },
|
||||
{ data: 3, title: t('subscribers') },
|
||||
{ data: 4, title: t('description') },
|
||||
{ data: 5, title: t('namespace') }
|
||||
];
|
||||
|
||||
const segmentsColumns = [
|
||||
{ data: 1, title: t('name') }
|
||||
];
|
||||
|
||||
content.push(
|
||||
<TableSelect key="list" id="list" format="wide" label={t('list')} withHeader dropdown dataUrl='rest/lists-table' columns={listsColumns} selectionLabelIndex={1} />
|
||||
);
|
||||
|
||||
const selectedList = this.getFormValue('list');
|
||||
content.push(
|
||||
<div key="segment">
|
||||
<CheckBox id="useSegmentation" format="wide" text={t('useAParticularSegment')}/>
|
||||
{selectedList && this.getFormValue('useSegmentation') &&
|
||||
<TableSelect id="segment" format="wide" withHeader dropdown dataUrl={`rest/segments-table/${selectedList}`} columns={segmentsColumns} selectionLabelIndex={1} />
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (mode === TestSendModalDialogMode.CAMPAIGN_CONTENT || mode === TestSendModalDialogMode.CAMPAIGN_STATUS) {
|
||||
content.push(
|
||||
<InputField key="subjectPrepend" id="subjectPrepend" format="wide" label={t('Prepend to subject')}/>
|
||||
);
|
||||
|
||||
content.push(
|
||||
<InputField key="subjectAppend" id="subjectAppend" format="wide" label={t('Append to subject')}/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ModalDialog hidden={!this.props.visible} title={t('sendTestEmail')} onCloseAsync={() => this.hideModal()} buttons={[
|
||||
{ label: t('send'), className: 'btn-primary', onClickAsync: ::this.performAction },
|
||||
{ label: t('cancel'), className: 'btn-danger', onClickAsync: ::this.hideModal }
|
||||
{ label: t('close'), className: 'btn-danger', onClickAsync: ::this.hideModal }
|
||||
]}>
|
||||
<Form stateOwner={this} format="wide">
|
||||
<TableSelect id="testUser" format="wide" label={t('subscription')} withHeader dropdown dataUrl={`rest/campaigns-test-users-table/${this.props.entity.id}`} columns={testUsersColumns} selectionLabelIndex={1} />
|
||||
{content}
|
||||
</Form>
|
||||
</ModalDialog>
|
||||
);
|
||||
|
|
|
@ -18,7 +18,8 @@ export function getCampaignLabels(t) {
|
|||
[CampaignStatus.PAUSED]: t('paused'),
|
||||
[CampaignStatus.INACTIVE]: t('inactive'),
|
||||
[CampaignStatus.ACTIVE]: t('active'),
|
||||
[CampaignStatus.SENDING]: t('sending')
|
||||
[CampaignStatus.SENDING]: t('sending'),
|
||||
[CampaignStatus.PAUSING]: t('Pausing')
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -333,6 +333,13 @@ class InputField extends Component {
|
|||
|
||||
const className = owner.addFormValidationClass('form-control', id);
|
||||
|
||||
/* This is for debugging purposes when React reports that InputField is uncontrolled
|
||||
const value = owner.getFormValue(id);
|
||||
if (value === null || value === undefined) console.log(`Warning: InputField ${id} is ${value}`);
|
||||
*/
|
||||
const value = owner.getFormValue(id);
|
||||
if (value === null || value === undefined) console.log(`Warning: InputField ${id} is ${value}`);
|
||||
|
||||
return wrapInput(id, htmlId, owner, props.format, '', props.label, props.help,
|
||||
<input type={type} value={owner.getFormValue(id)} placeholder={props.placeholder} id={htmlId} className={className} aria-describedby={htmlId + '_help'} onChange={evt => owner.updateFormValue(id, evt.target.value)}/>
|
||||
);
|
||||
|
|
|
@ -85,7 +85,7 @@ export default class CUD extends Component {
|
|||
}
|
||||
|
||||
return filterData(data, ['name', 'description', 'from_email', 'from_email_overridable', 'from_name',
|
||||
'from_name_overridable', 'reply_to', 'reply_to_overridable', 'subject', 'subject_overridable', 'x_mailer',
|
||||
'from_name_overridable', 'reply_to', 'reply_to_overridable', 'x_mailer',
|
||||
'verp_hostname', 'verp_disable_sender_header', 'mailer_type', 'mailer_settings', 'namespace']);
|
||||
}
|
||||
|
||||
|
@ -103,8 +103,6 @@ export default class CUD extends Component {
|
|||
from_name_overridable: false,
|
||||
reply_to: '',
|
||||
reply_to_overridable: false,
|
||||
subject: '',
|
||||
subject_overridable: false,
|
||||
verpEnabled: false,
|
||||
verp_hostname: '',
|
||||
verp_disable_sender_header: false,
|
||||
|
@ -233,8 +231,6 @@ export default class CUD extends Component {
|
|||
<CheckBox id="from_name_overridable" text={t('overridable')} className={sendConfigurationsStyles.overridableCheckbox}/>
|
||||
<InputField id="reply_to" label={t('defaultReplytoEmail')}/>
|
||||
<CheckBox id="reply_to_overridable" text={t('overridable')} className={sendConfigurationsStyles.overridableCheckbox}/>
|
||||
<InputField id="subject" label={t('subject')}/>
|
||||
<CheckBox id="subject_overridable" text={t('overridable')} className={sendConfigurationsStyles.overridableCheckbox}/>
|
||||
<InputField id="x_mailer" label={t('xMailer')}/>
|
||||
</Fieldset>
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ export function getMailerTypes(t) {
|
|||
const initVals = mailerTypes[mailerType].initData();
|
||||
|
||||
for (const key in initVals) {
|
||||
if (!mutStateData.hasIn([key])) {
|
||||
if (!mutStateData.hasIn([key, 'value']) || mutStateData.getIn([key, 'value']) === undefined) {
|
||||
mutStateData.setIn([key, 'value'], initVals[key]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ import {getEditForm, getTemplateTypes, getTypeForm} from './helpers';
|
|||
import axios from '../lib/axios';
|
||||
import styles from "../lib/styles.scss";
|
||||
import {getUrl} from "../lib/urls";
|
||||
import {TestSendModalDialog} from "./TestSendModalDialog";
|
||||
import {TestSendModalDialog, TestSendModalDialogMode} from "../campaigns/TestSendModalDialog";
|
||||
import {withComponentMixins} from "../lib/decorator-helpers";
|
||||
import moment from 'moment';
|
||||
|
||||
|
@ -298,6 +298,7 @@ export default class CUD extends Component {
|
|||
<div className={this.state.elementInFullscreen ? styles.withElementInFullscreen : ''}>
|
||||
{isEdit &&
|
||||
<TestSendModalDialog
|
||||
mode={TestSendModalDialogMode.TEMPLATE}
|
||||
visible={this.state.showTestSendModal}
|
||||
onHide={() => this.setState({showTestSendModal: false})}
|
||||
getDataAsync={this.sendModalGetDataHandler}/>
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import {withTranslation} from '../lib/i18n';
|
||||
import PropTypes from 'prop-types';
|
||||
import {ModalDialog} from "../lib/bootstrap-components";
|
||||
import {requiresAuthenticatedUser, withPageHelpers} from "../lib/page";
|
||||
import {Form, TableSelect, withForm} from "../lib/form";
|
||||
import {withErrorHandling} from "../lib/error-handling";
|
||||
import moment from "moment";
|
||||
import {getMailerTypes} from "../send-configurations/helpers";
|
||||
import axios from '../lib/axios';
|
||||
import {getUrl} from "../lib/urls";
|
||||
import {withComponentMixins} from "../lib/decorator-helpers";
|
||||
|
||||
|
||||
@withComponentMixins([
|
||||
withTranslation,
|
||||
withForm,
|
||||
withErrorHandling,
|
||||
withPageHelpers,
|
||||
requiresAuthenticatedUser
|
||||
])
|
||||
export class TestSendModalDialog extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.mailerTypes = getMailerTypes(props.t);
|
||||
|
||||
this.initForm({
|
||||
leaveConfirmation: false
|
||||
});
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
stateOwner: PropTypes.object,
|
||||
visible: PropTypes.bool.isRequired,
|
||||
onHide: PropTypes.func.isRequired,
|
||||
getDataAsync: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.populateFormValues({
|
||||
list: null,
|
||||
testUser: null,
|
||||
sendConfiguration: null
|
||||
});
|
||||
}
|
||||
|
||||
async hideModal() {
|
||||
this.props.onHide();
|
||||
}
|
||||
|
||||
async performAction() {
|
||||
const props = this.props;
|
||||
const t = props.t;
|
||||
|
||||
if (this.isFormWithoutErrors()) {
|
||||
|
||||
try {
|
||||
this.hideFormValidation();
|
||||
this.disableForm();
|
||||
this.setFormStatusMessage('info', t('sendingTestEmail'));
|
||||
|
||||
const data = await this.props.getDataAsync();
|
||||
data.listCid = this.getFormValue('list');
|
||||
data.subscriptionCid = this.getFormValue('testUser');
|
||||
data.sendConfigurationId = this.getFormValue('sendConfiguration');
|
||||
|
||||
await axios.post(getUrl('rest/template-test-send'), data);
|
||||
|
||||
this.clearFormStatusMessage();
|
||||
|
||||
this.enableForm();
|
||||
await this.hideModal();
|
||||
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
} else {
|
||||
this.showFormValidation();
|
||||
}
|
||||
}
|
||||
|
||||
localValidateFormValues(state) {
|
||||
const t = this.props.t;
|
||||
|
||||
if (!state.getIn(['sendConfiguration', 'value'])) {
|
||||
state.setIn(['sendConfiguration', 'error'], t('sendConfigurationHasToBeSelected'))
|
||||
} else {
|
||||
state.setIn(['sendConfiguration', 'error'], null);
|
||||
}
|
||||
|
||||
if (!state.getIn(['list', 'value'])) {
|
||||
state.setIn(['list', 'error'], t('listHasToBeSelected'))
|
||||
} else {
|
||||
state.setIn(['list', 'error'], null);
|
||||
}
|
||||
|
||||
if (!state.getIn(['testUser', 'value'])) {
|
||||
state.setIn(['testUser', 'error'], t('subscriptionHasToBeSelected'))
|
||||
} else {
|
||||
state.setIn(['testUser', 'error'], null);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const t = this.props.t;
|
||||
|
||||
const listId = this.getFormValue('list');
|
||||
|
||||
const testUsersColumns = [
|
||||
{ data: 1, title: t('subscriptionId'), render: data => <code>{data}</code> },
|
||||
{ data: 2, title: t('email') }
|
||||
];
|
||||
|
||||
const listsColumns = [
|
||||
{ data: 1, title: t('name') },
|
||||
{ data: 2, title: t('id'), render: data => <code>{data}</code> },
|
||||
{ data: 3, title: t('subscribers') },
|
||||
{ data: 4, title: t('description') },
|
||||
{ data: 5, title: t('namespace') }
|
||||
];
|
||||
|
||||
const sendConfigurationsColumns = [
|
||||
{ data: 1, title: t('name') },
|
||||
{ data: 2, title: t('id'), render: data => <code>{data}</code> },
|
||||
{ data: 3, title: t('description') },
|
||||
{ data: 4, title: t('type'), render: data => this.mailerTypes[data].typeName },
|
||||
{ data: 5, title: t('created'), render: data => moment(data).fromNow() },
|
||||
{ data: 6, title: t('namespace') }
|
||||
];
|
||||
|
||||
return (
|
||||
<ModalDialog hidden={!this.props.visible} title={t('sendTestEmail')} onCloseAsync={() => this.hideModal()} buttons={[
|
||||
{ label: t('send'), className: 'btn-primary', onClickAsync: ::this.performAction },
|
||||
{ label: t('cancel'), className: 'btn-danger', onClickAsync: ::this.hideModal }
|
||||
]}>
|
||||
<Form stateOwner={this} format="wide">
|
||||
<TableSelect id="sendConfiguration" format="wide" label={t('sendConfiguration')} withHeader dropdown dataUrl='rest/send-configurations-with-send-permission-table' columns={sendConfigurationsColumns} selectionLabelIndex={1} />
|
||||
<TableSelect id="list" format="wide" label={t('list')} withHeader dropdown dataUrl={`rest/lists-table`} columns={listsColumns} selectionKeyIndex={2} selectionLabelIndex={1} />
|
||||
{ listId &&
|
||||
<TableSelect id="testUser" format="wide" label={t('subscription')} withHeader dropdown dataUrl={`rest/subscriptions-test-user-table/${listId}`} columns={testUsersColumns} selectionKeyIndex={1} selectionLabelIndex={2} />
|
||||
}
|
||||
</Form>
|
||||
</ModalDialog>
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue