Fixed some bugs in subscription process
Added timezone selector to campaign scheduling Fixed problems with pausing campaign.
This commit is contained in:
parent
4113cb8476
commit
e3a5a3c4eb
23 changed files with 218 additions and 99 deletions
|
@ -13,11 +13,11 @@ import axios from "../lib/axios";
|
|||
import {getPublicUrl, getUrl} from "../lib/urls";
|
||||
import interoperableErrors from '../../../shared/interoperable-errors';
|
||||
import {CampaignStatus, CampaignType} from "../../../shared/campaigns";
|
||||
import moment from 'moment';
|
||||
import moment from 'moment-timezone';
|
||||
import campaignsStyles from "./styles.scss";
|
||||
import {withComponentMixins} from "../lib/decorator-helpers";
|
||||
import {TestSendModalDialog, TestSendModalDialogMode} from "./TestSendModalDialog";
|
||||
|
||||
import styles from "../lib/styles.scss";
|
||||
|
||||
@withComponentMixins([
|
||||
withTranslation,
|
||||
|
@ -114,6 +114,8 @@ class SendControls extends Component {
|
|||
this.initForm({
|
||||
leaveConfirmation: false
|
||||
});
|
||||
|
||||
this.timezoneOptions = moment.tz.names().map(x => [x]);
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
|
@ -126,6 +128,7 @@ class SendControls extends Component {
|
|||
|
||||
state.setIn(['date', 'error'], null);
|
||||
state.setIn(['time', 'error'], null);
|
||||
state.setIn(['timezone', 'error'], null);
|
||||
|
||||
if (state.getIn(['sendLater', 'value'])) {
|
||||
const dateValue = state.getIn(['date', 'value']).trim();
|
||||
|
@ -141,36 +144,54 @@ class SendControls extends Component {
|
|||
} else if (!moment(timeValue, 'HH:mm', true).isValid()) {
|
||||
state.setIn(['time', 'error'], t('timeIsInvalid'));
|
||||
}
|
||||
|
||||
const timezone = state.getIn(['timezone', 'value']);
|
||||
if (!timezone) {
|
||||
state.setIn(['timezone', 'error'], t('Timezone must be selected'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
populateSendLater() {
|
||||
const entity = this.props.entity;
|
||||
|
||||
if (entity.scheduled) {
|
||||
const date = moment.utc(entity.scheduled);
|
||||
const timezone = entity.data.timezone || moment.tz.guess();
|
||||
const date = moment.tz(entity.scheduled, timezone);
|
||||
this.populateFormValues({
|
||||
sendLater: true,
|
||||
date: date.format('YYYY-MM-DD'),
|
||||
time: date.format('HH:mm')
|
||||
time: date.format('HH:mm'),
|
||||
timezone
|
||||
});
|
||||
|
||||
} else {
|
||||
this.populateFormValues({
|
||||
sendLater: false,
|
||||
date: '',
|
||||
time: ''
|
||||
time: '',
|
||||
timezone: moment.tz.guess()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.populateSendLater();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.entity.scheduled !== this.props.entity.scheduled) {
|
||||
this.populateSendLater();
|
||||
}
|
||||
}
|
||||
|
||||
async refreshEntity() {
|
||||
await this.props.refreshEntity();
|
||||
}
|
||||
|
||||
async postAndMaskStateError(url) {
|
||||
async postAndMaskStateError(url, data) {
|
||||
try {
|
||||
await axios.post(getUrl(url));
|
||||
await axios.post(getUrl(url), data);
|
||||
} catch (err) {
|
||||
if (err instanceof interoperableErrors.InvalidStateError) {
|
||||
// Just mask the fact that it's not possible to start anything and refresh instead.
|
||||
|
@ -183,17 +204,12 @@ class SendControls extends Component {
|
|||
async scheduleAsync() {
|
||||
if (this.isFormWithoutErrors()) {
|
||||
const data = this.getFormValues();
|
||||
const date = moment(data.date, 'YYYY-MM-DD');
|
||||
const time = moment(data.time, 'HH:mm');
|
||||
const dateTime = moment.tz(data.date + ' ' + data.time, 'YYYY-MM-DD HH:mm', data.timezone);
|
||||
|
||||
date.hour(time.hour());
|
||||
date.minute(time.minute());
|
||||
date.second(0);
|
||||
date.millisecond(0);
|
||||
date.utcOffset(0, true); // TODO, process offset from user settings
|
||||
|
||||
|
||||
await this.postAndMaskStateError(`rest/campaign-start-at/${this.props.entity.id}/${date.valueOf()}`);
|
||||
await this.postAndMaskStateError(`rest/campaign-start-at/${this.props.entity.id}`, {
|
||||
startAt: dateTime.valueOf(),
|
||||
timezone: data.timezone
|
||||
});
|
||||
|
||||
} else {
|
||||
this.showFormValidation();
|
||||
|
@ -219,7 +235,17 @@ class SendControls extends Component {
|
|||
t('doYouWantToLaunchTheCampaign?'),
|
||||
async () => {
|
||||
await this.startAsync();
|
||||
await this.refreshEntity();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async confirmSchedule() {
|
||||
const t = this.props.t;
|
||||
this.actionDialog(
|
||||
t('confirmLaunch'),
|
||||
t('Do you want to schedule the campaign for launch?'),
|
||||
async () => {
|
||||
await this.scheduleAsync();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -305,10 +331,30 @@ class SendControls extends Component {
|
|||
|
||||
const subscrInfo = entity.subscriptionsToSend === undefined ? '' : ` (${entity.subscriptionsToSend} ${t('subscribers-1')})`;
|
||||
|
||||
const timezoneColumns = [
|
||||
{ data: 0, title: t('Timezone') }
|
||||
];
|
||||
|
||||
const dateValue = (this.getFormValue('date') || '').trim();
|
||||
const timeValue = (this.getFormValue('time') || '').trim();
|
||||
const timezone = this.getFormValue('timezone');
|
||||
|
||||
let dateTimeHelp = t('Select date, time and a timezone to display the date and time with offset');
|
||||
let dateTimeAlert = null;
|
||||
if (moment(dateValue, 'YYYY-MM-DD', true).isValid() && moment(timeValue, 'HH:mm', true).isValid() && timezone) {
|
||||
const dateTime = moment.tz(dateValue + ' ' + timeValue, 'YYYY-MM-DD HH:mm', timezone);
|
||||
|
||||
dateTimeHelp = dateTime.toString();
|
||||
if (!moment().isBefore(dateTime)) {
|
||||
dateTimeAlert = <div className="alert alert-danger" role="alert">{t('Scheduled date/time seems to be in the past. If you schedule the send, campaign will be sent immediately.')}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div>{dialogs}
|
||||
<AlignedRow label={t('sendStatus')}>
|
||||
{entity.scheduled ? t('campaignIsScheduledForDelivery') : t('campaignIsReadyToBeSentOut')}
|
||||
{entity.status === CampaignStatus.SCHEDULED ? t('campaignIsScheduledForDelivery') : t('campaignIsReadyToBeSentOut')}
|
||||
</AlignedRow>
|
||||
|
||||
<Form stateOwner={this}>
|
||||
|
@ -317,16 +363,20 @@ class SendControls extends Component {
|
|||
<div>
|
||||
<DatePicker id="date" label={t('date')} />
|
||||
<InputField id="time" label={t('time')} help={t('enter24HourTimeInFormatHhmmEg1348')}/>
|
||||
{/* TODO: Timezone selector */}
|
||||
<TableSelect id="timezone" label={t('Timezone')} dropdown columns={timezoneColumns} selectionKeyIndex={0} selectionLabelIndex={0} data={this.timezoneOptions}
|
||||
help={dateTimeHelp}
|
||||
/>
|
||||
{dateTimeAlert && <AlignedRow>{dateTimeAlert}</AlignedRow>}
|
||||
</div>
|
||||
}
|
||||
</Form>
|
||||
<ButtonRow className={campaignsStyles.sendButtonRow}>
|
||||
{this.getFormValue('sendLater') ?
|
||||
<Button className="btn-primary" icon="play" label={(entity.scheduled ? t('rescheduleSend') : t('scheduleSend')) + subscrInfo} onClickAsync={::this.scheduleAsync}/>
|
||||
<Button className="btn-primary" icon="play" label={(entity.status === CampaignStatus.SCHEDULED ? t('rescheduleSend') : t('scheduleSend')) + subscrInfo} onClickAsync={::this.confirmSchedule}/>
|
||||
:
|
||||
<Button className="btn-primary" icon="play" label={t('send') + subscrInfo} onClickAsync={::this.confirmStart}/>
|
||||
}
|
||||
{entity.status === CampaignStatus.SCHEDULED && <Button className="btn-primary" icon="pause" label={t('Pause')} onClickAsync={::this.stopAsync}/>}
|
||||
{entity.status === CampaignStatus.PAUSED && <Button className="btn-primary" icon="redo" 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}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue