Added ordering control to short URLs list in mobile resolutions

This commit is contained in:
Alejandro Celaya 2018-08-10 22:16:50 +02:00
parent e4d5424c07
commit c80fea2877
2 changed files with 119 additions and 81 deletions

View file

@ -1,12 +1,20 @@
import caretDownIcon from '@fortawesome/fontawesome-free-solid/faCaretDown';
import caretUpIcon from '@fortawesome/fontawesome-free-solid/faCaretUp';
import FontAwesomeIcon from '@fortawesome/react-fontawesome';
import { head, isEmpty, pick } from 'ramda';
import React from 'react';
import { connect } from 'react-redux';
import { ShortUrlsRow } from './helpers/ShortUrlsRow';
import { listShortUrls } from './reducers/shortUrlsList';
import './ShortUrlsList.scss';
import caretDownIcon from '@fortawesome/fontawesome-free-solid/faCaretDown'
import caretUpIcon from '@fortawesome/fontawesome-free-solid/faCaretUp'
import FontAwesomeIcon from '@fortawesome/react-fontawesome'
import { head, isEmpty, pick, toPairs } from 'ramda'
import React from 'react'
import { connect } from 'react-redux'
import { DropdownItem, DropdownMenu, DropdownToggle, UncontrolledDropdown } from 'reactstrap'
import { ShortUrlsRow } from './helpers/ShortUrlsRow'
import { listShortUrls } from './reducers/shortUrlsList'
import './ShortUrlsList.scss'
const SORTABLE_FIELDS = {
dateCreated: 'Created at',
shortCode: 'Short URL',
originalUrl: 'Long URL',
visits: 'Visits',
};
export class ShortUrlsList extends React.Component {
refreshList = extraParams => {
@ -16,6 +24,34 @@ export class ShortUrlsList extends React.Component {
...extraParams
});
};
determineOrderDir = field => {
if (this.state.orderField !== field) {
return 'ASC';
}
const newOrderMap = {
'ASC': 'DESC',
'DESC': undefined,
};
return this.state.orderDir ? newOrderMap[this.state.orderDir] : 'ASC';
}
orderBy = field => {
const newOrderDir = this.determineOrderDir(field);
this.setState({ orderField: newOrderDir !== undefined ? field : undefined, orderDir: newOrderDir });
this.refreshList({ orderBy: { [field]: newOrderDir } })
};
renderOrderIcon = (field, className = 'short-urls-list__header-icon') => {
if (this.state.orderField !== field) {
return null;
}
return (
<FontAwesomeIcon
icon={this.state.orderDir === 'ASC' ? caretUpIcon : caretDownIcon}
className={className}
/>
);
};
constructor(props) {
super(props);
@ -32,78 +68,6 @@ export class ShortUrlsList extends React.Component {
this.refreshList({ page: params.page });
}
render() {
const determineOrderDir = field => {
if (this.state.orderField !== field) {
return 'ASC';
}
const newOrderMap = {
'ASC': 'DESC',
'DESC': undefined,
};
return this.state.orderDir ? newOrderMap[this.state.orderDir] : 'ASC';
}
const orderBy = field => {
const newOrderDir = determineOrderDir(field);
this.setState({ orderField: field, orderDir: newOrderDir });
this.refreshList({ orderBy: { [field]: newOrderDir } })
};
const renderOrderIcon = field => {
if (this.state.orderField !== field || this.state.orderDir === undefined) {
return null;
}
return (
<FontAwesomeIcon
icon={this.state.orderDir === 'ASC' ? caretUpIcon : caretDownIcon}
className="short-urls-list__header-icon"
/>
);
};
return (
<table className="table table-striped table-hover">
<thead className="short-urls-list__header">
<tr>
<th
className="short-urls-list__header-cell short-urls-list__header-cell--with-action"
onClick={() => orderBy('dateCreated')}
>
{renderOrderIcon('dateCreated')}
Created at
</th>
<th
className="short-urls-list__header-cell short-urls-list__header-cell--with-action"
onClick={() => orderBy('shortCode')}
>
{renderOrderIcon('shortCode')}
Short URL
</th>
<th
className="short-urls-list__header-cell short-urls-list__header-cell--with-action"
onClick={() => orderBy('originalUrl')}
>
{renderOrderIcon('originalUrl')}
Long URL
</th>
<th className="short-urls-list__header-cell">Tags</th>
<th
className="short-urls-list__header-cell short-urls-list__header-cell--with-action"
onClick={() => orderBy('visits')}
>
<span className="nowrap">{renderOrderIcon('visits')} Visits</span>
</th>
<th className="short-urls-list__header-cell">&nbsp;</th>
</tr>
</thead>
<tbody>
{this.renderShortUrls()}
</tbody>
</table>
);
}
renderShortUrls() {
const { shortUrlsList, selectedServer, loading, error, shortUrlsListParams } = this.props;
if (error) {
@ -128,6 +92,71 @@ export class ShortUrlsList extends React.Component {
/>
));
}
renderMobileOrderingControls() {
return (
<div className="d-block d-md-none mb-3">
<UncontrolledDropdown>
<DropdownToggle caret className="btn-block">
Order by
</DropdownToggle>
<DropdownMenu className="short-urls-list__order-dropdown">
{toPairs(SORTABLE_FIELDS).map(([key, value]) =>
<DropdownItem active={this.state.orderField === key} onClick={() => this.orderBy(key)}>
{value}
{this.renderOrderIcon(key, 'short-urls-list__header-icon--mobile')}
</DropdownItem>)}
</DropdownMenu>
</UncontrolledDropdown>
</div>
);
}
render() {
return (
<React.Fragment>
{this.renderMobileOrderingControls()}
<table className="table table-striped table-hover">
<thead className="short-urls-list__header">
<tr>
<th
className="short-urls-list__header-cell short-urls-list__header-cell--with-action"
onClick={() => this.orderBy('dateCreated')}
>
{this.renderOrderIcon('dateCreated')}
Created at
</th>
<th
className="short-urls-list__header-cell short-urls-list__header-cell--with-action"
onClick={() => this.orderBy('shortCode')}
>
{this.renderOrderIcon('shortCode')}
Short URL
</th>
<th
className="short-urls-list__header-cell short-urls-list__header-cell--with-action"
onClick={() => this.orderBy('originalUrl')}
>
{this.renderOrderIcon('originalUrl')}
Long URL
</th>
<th className="short-urls-list__header-cell">Tags</th>
<th
className="short-urls-list__header-cell short-urls-list__header-cell--with-action"
onClick={() => this.orderBy('visits')}
>
<span className="nowrap">{this.renderOrderIcon('visits')} Visits</span>
</th>
<th className="short-urls-list__header-cell">&nbsp;</th>
</tr>
</thead>
<tbody>
{this.renderShortUrls()}
</tbody>
</table>
</React.Fragment>
);
}
}
export default connect(pick(['selectedServer', 'shortUrlsListParams']), { listShortUrls })(ShortUrlsList);

View file

@ -14,6 +14,15 @@
margin-right: 5px;
}
.short-urls-list__header-icon--mobile {
margin: 3.5px 0 0;
float: right;
}
.short-urls-list__header-cell--with-action {
cursor: pointer;
}
.short-urls-list__order-dropdown {
width: 100%;
}