Refactor and add subscriber search and segmentation UI
This commit is contained in:
parent
3867062002
commit
755d3d2630
|
@ -204,7 +204,9 @@ class Subscribers extends React.PureComponent {
|
||||||
query: null,
|
query: null,
|
||||||
targetLists: []
|
targetLists: []
|
||||||
},
|
},
|
||||||
listAddVisible: false
|
listAddVisible: false,
|
||||||
|
allRowsSelected: false,
|
||||||
|
rowsSelected: []
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pagination config.
|
// Pagination config.
|
||||||
|
@ -234,7 +236,6 @@ class Subscribers extends React.PureComponent {
|
||||||
sorter: true,
|
sorter: true,
|
||||||
width: "25%",
|
width: "25%",
|
||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
|
|
||||||
const out = [];
|
const out = [];
|
||||||
out.push(
|
out.push(
|
||||||
<div key={`sub-email-${ record.id }`} className="sub-name">
|
<div key={`sub-email-${ record.id }`} className="sub-name">
|
||||||
|
@ -244,7 +245,9 @@ class Subscribers extends React.PureComponent {
|
||||||
|
|
||||||
if(record.lists.length > 0) {
|
if(record.lists.length > 0) {
|
||||||
for (let i = 0; i < record.lists.length; i++) {
|
for (let i = 0; i < record.lists.length; i++) {
|
||||||
out.push(<Tag className="list" key={`sub-${ record.id }-list-${ record.lists[i].id }`}><Link to={ `/subscribers/lists/${ record.lists[i].id }` }>{ record.lists[i].name }</Link></Tag>)
|
out.push(<Tag className="list" key={`sub-${ record.id }-list-${ record.lists[i].id }`}>
|
||||||
|
<Link to={ `/subscribers/lists/${ record.lists[i].id }` }>{ record.lists[i].name }</Link>
|
||||||
|
</Tag>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,7 +258,7 @@ class Subscribers extends React.PureComponent {
|
||||||
title: "Name",
|
title: "Name",
|
||||||
dataIndex: "name",
|
dataIndex: "name",
|
||||||
sorter: true,
|
sorter: true,
|
||||||
width: "25%",
|
width: "15%",
|
||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
return (
|
return (
|
||||||
<a role="button" onClick={() => this.handleShowEditForm(record)}>{text}</a>
|
<a role="button" onClick={() => this.handleShowEditForm(record)}>{text}</a>
|
||||||
|
@ -398,14 +401,23 @@ class Subscribers extends React.PureComponent {
|
||||||
this.setState({ formType: cs.FormEdit, record: record })
|
this.setState({ formType: cs.FormEdit, record: record })
|
||||||
}
|
}
|
||||||
|
|
||||||
handleToggleQueryForm = () => {
|
handleSearch = (q) => {
|
||||||
// The query form is being cancelled. Reset the results.
|
q = q.trim().toLowerCase()
|
||||||
if(this.state.queryFormVisible) {
|
if(q === "") {
|
||||||
this.fetchRecords({
|
this.fetchRecords({ query: null })
|
||||||
query: null
|
return
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
q = q.replace(/'/g, "''")
|
||||||
|
const query = `(name LIKE '%${q}%' OR email LIKE '%${q}%')`
|
||||||
|
this.fetchRecords({ query: query })
|
||||||
|
}
|
||||||
|
|
||||||
|
handleRowSelection = (_, records) => {
|
||||||
|
this.setState({ allRowsSelected: false, rowsSelected: records.map(r => r.id) })
|
||||||
|
}
|
||||||
|
|
||||||
|
handleToggleQueryForm = () => {
|
||||||
this.setState({ queryFormVisible: !this.state.queryFormVisible })
|
this.setState({ queryFormVisible: !this.state.queryFormVisible })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,31 +449,48 @@ class Subscribers extends React.PureComponent {
|
||||||
|
|
||||||
</h1>
|
</h1>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={ 2 }>
|
|
||||||
{ !this.state.queryFormVisible &&
|
|
||||||
<a role="button" onClick={ this.handleToggleQueryForm }><Icon type="search" /> Advanced</a> }
|
|
||||||
</Col>
|
|
||||||
<Col span={ 2 }>
|
<Col span={ 2 }>
|
||||||
<Button type="primary" icon="plus" onClick={ this.handleShowCreateForm }>Add subscriber</Button>
|
<Button type="primary" icon="plus" onClick={ this.handleShowCreateForm }>Add subscriber</Button>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{ this.state.queryFormVisible &&
|
|
||||||
<div className="subscriber-query">
|
<div className="subscriber-query">
|
||||||
|
<Row>
|
||||||
|
<Col span={10}>
|
||||||
|
<Row>
|
||||||
|
<Col span={ 15 }>
|
||||||
|
<label>Search subscribers</label>
|
||||||
|
<Input.Search
|
||||||
|
name="name"
|
||||||
|
placeholder="Name or e-mail"
|
||||||
|
enterButton
|
||||||
|
onSearch={ this.handleSearch } />
|
||||||
|
{" "}
|
||||||
|
</Col>
|
||||||
|
<Col span={ 8 } offset={ 1 }>
|
||||||
|
<label> </label><br />
|
||||||
|
<a role="button" onClick={ this.handleToggleQueryForm }>
|
||||||
|
<Icon type="setting" /> Advanced</a>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{ this.state.queryFormVisible &&
|
||||||
|
<div className="advanced-query">
|
||||||
<p>
|
<p>
|
||||||
Write a partial SQL expression to query the subscribers based on their
|
<label>Advanced query</label>
|
||||||
primary information or attributes. Learn more.
|
|
||||||
</p>
|
|
||||||
<Input.TextArea placeholder="name LIKE '%user%'"
|
<Input.TextArea placeholder="name LIKE '%user%'"
|
||||||
id="subscriber-query"
|
id="subscriber-query"
|
||||||
rows={ 10 }
|
rows={ 10 }
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
this.setState({ queryParams: { ...this.state.queryParams, query: e.target.value } })
|
this.setState({ queryParams: { ...this.state.queryParams, query: e.target.value } })
|
||||||
}}
|
}}
|
||||||
|
value={ this.state.queryParams.query }
|
||||||
autosize={{ minRows: 2, maxRows: 10 }} />
|
autosize={{ minRows: 2, maxRows: 10 }} />
|
||||||
|
<span className="text-tiny text-small">
|
||||||
<div className="actions">
|
Write a partial SQL expression to query the subscribers based on their primary information or attributes. Learn more.
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
<Button
|
<Button
|
||||||
disabled={ this.state.queryParams.query === "" }
|
disabled={ this.state.queryParams.query === "" }
|
||||||
type="primary"
|
type="primary"
|
||||||
|
@ -469,14 +498,36 @@ class Subscribers extends React.PureComponent {
|
||||||
onClick={ () => { this.fetchRecords() } }>Query</Button>
|
onClick={ () => { this.fetchRecords() } }>Query</Button>
|
||||||
{" "}
|
{" "}
|
||||||
<Button
|
<Button
|
||||||
disabled={ !this.state.queryParams.total }
|
disabled={ this.state.queryParams.query === "" }
|
||||||
icon="plus"
|
icon="refresh"
|
||||||
onClick={ this.handleToggleListAdd }>Add ({this.state.queryParams.total}) to list</Button>
|
onClick={ () => { this.fetchRecords({ query: null }) } }>Reset</Button>
|
||||||
{" "}
|
</p>
|
||||||
<Button icon="close" onClick={ this.handleToggleQueryForm }>Cancel</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
</Col>
|
||||||
|
<Col span={14}>
|
||||||
|
{ this.state.rowsSelected.length > 0 &&
|
||||||
|
<nav className="table-options">
|
||||||
|
<p>
|
||||||
|
<strong>{ this.state.allRowsSelected ? this.state.queryParams.total : this.state.rowsSelected.length }</strong>
|
||||||
|
{" "} subscriber(s) selected
|
||||||
|
{ !this.state.allRowsSelected &&
|
||||||
|
<span> — <a role="button" onClick={ () => { this.setState({ allRowsSelected: true })
|
||||||
|
}}>Select all { this.state.queryParams.total }?</a>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a role="button"><Icon type="bars" /> Manage lists</a>
|
||||||
|
<a role="button"><Icon type="rocket" /> Send campaign</a>
|
||||||
|
<a role="button"><Icon type="delete" /> Delete</a>
|
||||||
|
<a role="button"><Icon type="close" /> Blacklist</a>
|
||||||
|
</p>
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Table
|
<Table
|
||||||
columns={ this.columns }
|
columns={ this.columns }
|
||||||
|
@ -485,7 +536,8 @@ class Subscribers extends React.PureComponent {
|
||||||
loading={ this.props.reqStates[cs.ModelSubscribers] !== cs.StateDone }
|
loading={ this.props.reqStates[cs.ModelSubscribers] !== cs.StateDone }
|
||||||
pagination={ pagination }
|
pagination={ pagination }
|
||||||
rowSelection = {{
|
rowSelection = {{
|
||||||
fixed: true
|
columnWidth: "5%",
|
||||||
|
onChange: this.handleRowSelection
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,13 @@ td .ant-tag {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* External options */
|
||||||
|
.table-options {
|
||||||
|
}
|
||||||
|
.table-options a {
|
||||||
|
margin-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Dashboard */
|
/* Dashboard */
|
||||||
.dashboard {
|
.dashboard {
|
||||||
margin: 24px;
|
margin: 24px;
|
||||||
|
@ -124,27 +131,19 @@ td .ant-tag {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Subscribers */
|
/* Subscribers */
|
||||||
.subscriber-filter {
|
|
||||||
background: #fff;
|
|
||||||
min-width: 300px;
|
|
||||||
max-width: 500px;
|
|
||||||
width: 100%;
|
|
||||||
padding: 15px;
|
|
||||||
box-shadow: 0 1px 6px rgba(0, 0, 0, .2);
|
|
||||||
}
|
|
||||||
.subscriber-filter .lists {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subscribers table .name {
|
.subscribers table .name {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subscriber-query {
|
.subscriber-query {
|
||||||
margin: 15px 0 30px 0;
|
margin: 0 0 15px 0;
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
box-shadow: 0 1px 6px #ddd;
|
box-shadow: 0 1px 6px #ddd;
|
||||||
|
min-height: 140px;
|
||||||
}
|
}
|
||||||
|
.subscriber-query .advanced-query {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
.subscriber-query textarea {
|
.subscriber-query textarea {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue