mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 09:30:31 +03:00
Added sorting to referrers bar graph
This commit is contained in:
parent
368de2b4c7
commit
05936c52b3
4 changed files with 30 additions and 19 deletions
|
@ -54,7 +54,7 @@ const SortingDropdown = ({ items, orderField, orderDir, onChange, isButton, righ
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
))}
|
))}
|
||||||
<DropdownItem divider />
|
<DropdownItem divider />
|
||||||
<DropdownItem onClick={() => onChange()}>
|
<DropdownItem disabled={!orderField} onClick={() => onChange()}>
|
||||||
<i>Clear selection</i>
|
<i>Clear selection</i>
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { Card } from 'reactstrap';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import DateInput from '../common/DateInput';
|
import DateInput from '../common/DateInput';
|
||||||
import MutedMessage from '../utils/MuttedMessage';
|
import MutedMessage from '../utils/MuttedMessage';
|
||||||
import CountriesGraph from './CountriesGraph';
|
import SortableBarGraph from './SortableBarGraph';
|
||||||
import { getShortUrlVisits, shortUrlVisitsType } from './reducers/shortUrlVisits';
|
import { getShortUrlVisits, shortUrlVisitsType } from './reducers/shortUrlVisits';
|
||||||
import {
|
import {
|
||||||
processBrowserStats,
|
processBrowserStats,
|
||||||
|
@ -96,10 +96,24 @@ export class ShortUrlsVisitsComponent extends React.Component {
|
||||||
<GraphCard title="Browsers" stats={processBrowserStats(visits)} />
|
<GraphCard title="Browsers" stats={processBrowserStats(visits)} />
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
<CountriesGraph stats={processCountriesStats(visits)} />
|
<SortableBarGraph
|
||||||
|
stats={processCountriesStats(visits)}
|
||||||
|
title="Countries"
|
||||||
|
sortingItems={{
|
||||||
|
name: 'Country name',
|
||||||
|
amount: 'Visits amount',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
<GraphCard title="Referrers" stats={processReferrersStats(visits)} isBarChart />
|
<SortableBarGraph
|
||||||
|
stats={processReferrersStats(visits)}
|
||||||
|
title="Referrers"
|
||||||
|
sortingItems={{
|
||||||
|
name: 'Referrer name',
|
||||||
|
amount: 'Visits amount',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,9 +4,11 @@ import { fromPairs, head, keys, prop, reverse, sortBy, toPairs } from 'ramda';
|
||||||
import SortingDropdown from '../utils/SortingDropdown';
|
import SortingDropdown from '../utils/SortingDropdown';
|
||||||
import GraphCard from './GraphCard';
|
import GraphCard from './GraphCard';
|
||||||
|
|
||||||
export default class CountriesGraph extends React.Component {
|
export default class SortableBarGraph extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
stats: PropTypes.any,
|
stats: PropTypes.object.isRequired,
|
||||||
|
title: PropTypes.string.isRequired,
|
||||||
|
sortingItems: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
@ -15,31 +17,27 @@ export default class CountriesGraph extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const items = {
|
const { stats, sortingItems, title } = this.props;
|
||||||
name: 'Country name',
|
|
||||||
amount: 'Visits amount',
|
|
||||||
};
|
|
||||||
const { stats } = this.props;
|
|
||||||
const sortStats = () => {
|
const sortStats = () => {
|
||||||
if (!this.state.orderField) {
|
if (!this.state.orderField) {
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortedPairs = sortBy(prop(this.state.orderField === head(keys(items)) ? 0 : 1), toPairs(stats));
|
const sortedPairs = sortBy(prop(this.state.orderField === head(keys(sortingItems)) ? 0 : 1), toPairs(stats));
|
||||||
|
|
||||||
return fromPairs(this.state.orderDir === 'ASC' ? sortedPairs : reverse(sortedPairs));
|
return fromPairs(this.state.orderDir === 'ASC' ? sortedPairs : reverse(sortedPairs));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GraphCard stats={sortStats()} isBarChart>
|
<GraphCard stats={sortStats()} isBarChart>
|
||||||
Countries
|
{title}
|
||||||
<div className="float-right">
|
<div className="float-right">
|
||||||
<SortingDropdown
|
<SortingDropdown
|
||||||
isButton={false}
|
isButton={false}
|
||||||
right
|
right
|
||||||
orderField={this.state.orderField}
|
orderField={this.state.orderField}
|
||||||
orderDir={this.state.orderDir}
|
orderDir={this.state.orderDir}
|
||||||
items={items}
|
items={sortingItems}
|
||||||
onChange={(orderField, orderDir) => this.setState({ orderField, orderDir })}
|
onChange={(orderField, orderDir) => this.setState({ orderField, orderDir })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
|
@ -7,7 +7,7 @@ import { ShortUrlsVisitsComponent as ShortUrlsVisits } from '../../src/visits/Sh
|
||||||
import MutedMessage from '../../src/utils/MuttedMessage';
|
import MutedMessage from '../../src/utils/MuttedMessage';
|
||||||
import GraphCard from '../../src/visits/GraphCard';
|
import GraphCard from '../../src/visits/GraphCard';
|
||||||
import DateInput from '../../src/common/DateInput';
|
import DateInput from '../../src/common/DateInput';
|
||||||
import CountriesGraph from '../../src/visits/CountriesGraph';
|
import SortableBarGraph from '../../src/visits/SortableBarGraph';
|
||||||
|
|
||||||
describe('<ShortUrlVisits />', () => {
|
describe('<ShortUrlVisits />', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
@ -70,11 +70,10 @@ describe('<ShortUrlVisits />', () => {
|
||||||
it('renders all graphics when visits are properly loaded', () => {
|
it('renders all graphics when visits are properly loaded', () => {
|
||||||
const wrapper = createComponent({ loading: false, error: false, visits: [{}, {}, {}] });
|
const wrapper = createComponent({ loading: false, error: false, visits: [{}, {}, {}] });
|
||||||
const graphs = wrapper.find(GraphCard);
|
const graphs = wrapper.find(GraphCard);
|
||||||
const countriesGraphs = wrapper.find(CountriesGraph);
|
const sortableBarGraphs = wrapper.find(SortableBarGraph);
|
||||||
const expectedGraphsCount = 3;
|
const expectedGraphsCount = 4;
|
||||||
|
|
||||||
expect(graphs).toHaveLength(expectedGraphsCount);
|
expect(graphs.length + sortableBarGraphs.length).toEqual(expectedGraphsCount);
|
||||||
expect(countriesGraphs).toHaveLength(1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reloads visits when selected dates change', () => {
|
it('reloads visits when selected dates change', () => {
|
||||||
|
|
Loading…
Reference in a new issue