Refactor campaign 'save' button and add 'start' button to campaign page

This commit is contained in:
Kailash Nadh 2018-11-28 18:35:33 +05:30
parent ca19b50126
commit ccd966a1f4
4 changed files with 89 additions and 20 deletions

View File

@ -199,8 +199,16 @@ class TheFormDef extends React.PureComponent {
} }
// Handle create / edit form submission. // Handle create / edit form submission.
handleSubmit = (e) => { handleSubmit = (cb) => {
e.preventDefault() if(this.state.loading) {
return
}
if(!cb) {
// Set a fake callback.
cb = () => {}
}
this.props.form.validateFields((err, values) => { this.props.form.validateFields((err, values) => {
if (err) { if (err) {
return return
@ -209,7 +217,7 @@ class TheFormDef extends React.PureComponent {
if(!values.tags) { if(!values.tags) {
values.tags = [] values.tags = []
} }
values.body = this.props.body values.body = this.props.body
values.content_type = this.props.contentType values.content_type = this.props.contentType
@ -222,9 +230,11 @@ class TheFormDef extends React.PureComponent {
description: `"${values["name"]}" created` }) description: `"${values["name"]}" created` })
this.props.route.history.push(cs.Routes.ViewCampaign.replace(":id", resp.data.data.id) + "#content") this.props.route.history.push(cs.Routes.ViewCampaign.replace(":id", resp.data.data.id) + "#content")
cb(true)
}).catch(e => { }).catch(e => {
notification["error"]({ placement: cs.MsgPosition, message: "Error", description: e.message }) notification["error"]({ placement: cs.MsgPosition, message: "Error", description: e.message })
this.setState({ loading: false }) this.setState({ loading: false })
cb(false)
}) })
} else { } else {
this.props.modelRequest(cs.ModelCampaigns, cs.Routes.UpdateCampaign, cs.MethodPut, { ...values, id: this.props.record.id }).then((resp) => { this.props.modelRequest(cs.ModelCampaigns, cs.Routes.UpdateCampaign, cs.MethodPut, { ...values, id: this.props.record.id }).then((resp) => {
@ -232,9 +242,11 @@ class TheFormDef extends React.PureComponent {
message: "Campaign updated", message: "Campaign updated",
description: `"${values["name"]}" updated` }) description: `"${values["name"]}" updated` })
this.setState({ loading: false }) this.setState({ loading: false })
cb(true)
}).catch(e => { }).catch(e => {
notification["error"]({ placement: cs.MsgPosition, message: "Error", description: e.message }) notification["error"]({ placement: cs.MsgPosition, message: "Error", description: e.message })
this.setState({ loading: false }) this.setState({ loading: false })
cb(false)
}) })
} }
}) })
@ -370,14 +382,6 @@ class TheFormDef extends React.PureComponent {
</Row> </Row>
</Form.Item> </Form.Item>
{ !this.props.formDisabled &&
<Form.Item {...formItemTailLayout}>
<Button htmlType="submit" type="primary">
<Icon type="save" /> { !this.props.isSingle ? "Continue" : "Save changes" }
</Button>
</Form.Item>
}
{ this.props.isSingle && { this.props.isSingle &&
<div> <div>
<hr /> <hr />
@ -405,6 +409,7 @@ class Campaign extends React.PureComponent {
state = { state = {
campaignID: this.props.route.match.params ? parseInt(this.props.route.match.params.campaignID, 10) : 0, campaignID: this.props.route.match.params ? parseInt(this.props.route.match.params.campaignID, 10) : 0,
record: {}, record: {},
formRef: null,
contentType: "richtext", contentType: "richtext",
previewRecord: null, previewRecord: null,
body: "", body: "",
@ -470,7 +475,7 @@ class Campaign extends React.PureComponent {
return ( return (
<section className="content campaign"> <section className="content campaign">
<Row> <Row>
<Col span={22}> <Col span={ 16 }>
{ !this.state.record.id && <h1>Create a campaign</h1> } { !this.state.record.id && <h1>Create a campaign</h1> }
{ this.state.record.id && { this.state.record.id &&
<h1> <h1>
@ -479,7 +484,43 @@ class Campaign extends React.PureComponent {
</h1> </h1>
} }
</Col> </Col>
<Col span={2}> <Col span={ 8 } className="right">
{ !this.state.formDisabled && !this.state.loading &&
<div>
<Button type="primary" icon="save" onClick={() => {
this.state.formRef.handleSubmit()
}}>{ !this.state.record.id ? "Continue" : "Save changes" }</Button>
{" "}
{ ( this.state.record.status === cs.CampaignStatusDraft && this.state.record.send_at) &&
<Popconfirm title="The campaign will start automatically at the scheduled date and time. Schedule now?"
onConfirm={() => {
this.state.formRef.handleSubmit(() => {
this.props.route.history.push({
pathname: cs.Routes.ViewCampaigns,
state: { campaign: this.state.record, campaignStatus: cs.CampaignStatusScheduled }
})
})
}}>
<Button icon="clock-circle" type="primary">Schedule campaign</Button>
</Popconfirm>
}
{ ( this.state.record.status === cs.CampaignStatusDraft && !this.state.record.send_at) &&
<Popconfirm title="Campaign properties cannot be changed once it starts. Save changes and start now?"
onConfirm={() => {
this.state.formRef.handleSubmit(() => {
this.props.route.history.push({
pathname: cs.Routes.ViewCampaigns,
state: { campaign: this.state.record, campaignStatus: cs.CampaignStatusRunning }
})
})
}}>
<Button icon="rocket" type="primary">Start campaign</Button>
</Popconfirm>
}
</div>
}
</Col> </Col>
</Row> </Row>
<br /> <br />
@ -492,6 +533,14 @@ class Campaign extends React.PureComponent {
<Tabs.TabPane tab="Campaign" key="form"> <Tabs.TabPane tab="Campaign" key="form">
<Spin spinning={ this.state.loading }> <Spin spinning={ this.state.loading }>
<TheForm { ...this.props } <TheForm { ...this.props }
wrappedComponentRef={ (r) => {
if(!r) {
return
}
// Take the editor's reference and save it in the state
// so that it's insertMedia() function can be passed to <Media />
this.setState({ formRef: r })
}}
record={ this.state.record } record={ this.state.record }
isSingle={ this.state.record.id ? true : false } isSingle={ this.state.record.id ? true : false }
body={ this.state.body ? this.state.body : this.state.record.body } body={ this.state.body ? this.state.body : this.state.record.body }
@ -506,10 +555,13 @@ class Campaign extends React.PureComponent {
{ this.state.record.id && { this.state.record.id &&
<div> <div>
<Editor { ...this.props } <Editor { ...this.props }
ref={ (e) => { ref={ (r) => {
if(!r) {
return
}
// Take the editor's reference and save it in the state // Take the editor's reference and save it in the state
// so that it's insertMedia() function can be passed to <Media /> // so that it's insertMedia() function can be passed to <Media />
this.setState({ editor: e }) this.setState({ editor: r })
}} }}
isSingle={ this.state.record.id ? true : false } isSingle={ this.state.record.id ? true : false }
record={ this.state.record } record={ this.state.record }
@ -517,9 +569,11 @@ class Campaign extends React.PureComponent {
toggleMedia={ this.toggleMedia } toggleMedia={ this.toggleMedia }
setContent={ this.setContent } setContent={ this.setContent }
formDisabled={ this.state.formDisabled } formDisabled={ this.state.formDisabled }
/> />
<div className="content-actions"> <div className="content-actions">
<p><Button icon="search" onClick={() => this.handlePreview(this.state.record)}>Preview</Button></p> <p>
<Button icon="search" onClick={() => this.handlePreview(this.state.record)}>Preview</Button>
</p>
</div> </div>
</div> </div>
} }
@ -535,9 +589,9 @@ class Campaign extends React.PureComponent {
onCancel={ this.toggleMedia } onCancel={ this.toggleMedia }
onOk={ this.toggleMedia }> onOk={ this.toggleMedia }>
<Media { ...{ ...this.props, <Media { ...{ ...this.props,
insertMedia: this.state.editor ? this.state.editor.insertMedia : null, insertMedia: this.state.editor ? this.state.editor.insertMedia : null,
onCancel: this.toggleMedia, onCancel: this.toggleMedia,
onOk: this.toggleMedia }} /> onOk: this.toggleMedia }} />
</Modal> </Modal>
{ this.state.previewRecord && { this.state.previewRecord &&

View File

@ -251,6 +251,16 @@ class Campaigns extends React.PureComponent {
this.props.pageTitle("Campaigns") this.props.pageTitle("Campaigns")
dayjs.extend(relativeTime) dayjs.extend(relativeTime)
this.fetchRecords() this.fetchRecords()
// Did we land here to start a campaign?
let loc = this.props.route.location
let state = loc.state
if(state && state.hasOwnProperty("campaign")) {
this.handleUpdateStatus(state.campaign, state.campaignStatus)
delete state.campaign
delete state.campaignStatus
this.props.route.history.replace({ ...loc, state })
}
} }
componentWillUnmount() { componentWillUnmount() {

View File

@ -69,6 +69,7 @@ export const Routes = {
DeleteSubscribers: "/api/subscribers", DeleteSubscribers: "/api/subscribers",
QuerySubscribersIntoLists: "/api/subscribers/lists", QuerySubscribersIntoLists: "/api/subscribers/lists",
ViewCampaigns: "/campaigns",
ViewCampaign: "/campaigns/:id", ViewCampaign: "/campaigns/:id",
GetCampaignMessengers: "/api/campaigns/messengers", GetCampaignMessengers: "/api/campaigns/messengers",
GetCampaigns: "/api/campaigns", GetCampaigns: "/api/campaigns",

View File

@ -24,6 +24,10 @@ hr {
text-align: center; text-align: center;
} }
.right {
text-align: right;
}
.text-tiny { .text-tiny {
font-size: 0.65em; font-size: 0.65em;
} }