Refactor and add subscriber search and segmentation UI

This commit is contained in:
Kailash Nadh 2018-11-30 13:49:33 +05:30
parent 3867062002
commit 755d3d2630
2 changed files with 119 additions and 68 deletions

View File

@ -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 })
} }
@ -429,54 +441,93 @@ class Subscribers extends React.PureComponent {
<section className="content"> <section className="content">
<header className="header"> <header className="header">
<Row> <Row>
<Col span={ 20 }> <Col span={ 20 }>
<h1> <h1>
Subscribers Subscribers
{ this.state.queryParams.list && { this.state.queryParams.list &&
<span> &raquo; { this.state.queryParams.list.name }</span> } <span> &raquo; { this.state.queryParams.list.name }</span> }
</h1> </h1>
</Col> </Col>
<Col span={ 2 }> <Col span={ 2 }>
{ !this.state.queryFormVisible && <Button type="primary" icon="plus" onClick={ this.handleShowCreateForm }>Add subscriber</Button>
<a role="button" onClick={ this.handleToggleQueryForm }><Icon type="search" /> Advanced</a> } </Col>
</Col>
<Col span={ 2 }>
<Button type="primary" icon="plus" onClick={ this.handleShowCreateForm }>Add subscriber</Button>
</Col>
</Row> </Row>
</header> </header>
{ this.state.queryFormVisible && <div className="subscriber-query">
<div className="subscriber-query"> <Row>
<p> <Col span={10}>
Write a partial SQL expression to query the subscribers based on their <Row>
primary information or attributes. Learn more. <Col span={ 15 }>
</p> <label>Search subscribers</label>
<Input.TextArea placeholder="name LIKE '%user%'" <Input.Search
id="subscriber-query" name="name"
rows={ 10 } placeholder="Name or e-mail"
onChange={(e) => { enterButton
this.setState({ queryParams: { ...this.state.queryParams, query: e.target.value } }) onSearch={ this.handleSearch } />
}} {" "}
autosize={{ minRows: 2, maxRows: 10 }} /> </Col>
<Col span={ 8 } offset={ 1 }>
<div className="actions"> <label>&nbsp;</label><br />
<Button <a role="button" onClick={ this.handleToggleQueryForm }>
disabled={ this.state.queryParams.query === "" } <Icon type="setting" /> Advanced</a>
type="primary" </Col>
icon="search" </Row>
onClick={ () => { this.fetchRecords() } }>Query</Button> { this.state.queryFormVisible &&
{" "} <div className="advanced-query">
<Button <p>
disabled={ !this.state.queryParams.total } <label>Advanced query</label>
icon="plus" <Input.TextArea placeholder="name LIKE '%user%'"
onClick={ this.handleToggleListAdd }>Add ({this.state.queryParams.total}) to list</Button> id="subscriber-query"
{" "} rows={ 10 }
<Button icon="close" onClick={ this.handleToggleQueryForm }>Cancel</Button> onChange={(e) => {
</div> this.setState({ queryParams: { ...this.state.queryParams, query: e.target.value } })
</div> }}
} value={ this.state.queryParams.query }
autosize={{ minRows: 2, maxRows: 10 }} />
<span className="text-tiny text-small">
Write a partial SQL expression to query the subscribers based on their primary information or attributes. Learn more.
</span>
</p>
<p>
<Button
disabled={ this.state.queryParams.query === "" }
type="primary"
icon="search"
onClick={ () => { this.fetchRecords() } }>Query</Button>
{" "}
<Button
disabled={ this.state.queryParams.query === "" }
icon="refresh"
onClick={ () => { this.fetchRecords({ query: null }) } }>Reset</Button>
</p>
</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> &mdash; <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
}} }}
/> />

View File

@ -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;
} }