shlink-web-client/src/visits/ShortUrlVisits.js

150 lines
4.6 KiB
JavaScript
Raw Normal View History

import preloader from '@fortawesome/fontawesome-free-solid/faCircleNotch';
import FontAwesomeIcon from '@fortawesome/react-fontawesome';
import { isEmpty, mapObjIndexed, pick } from 'ramda';
import React from 'react';
import { connect } from 'react-redux';
import { Card } from 'reactstrap';
import PropTypes from 'prop-types';
import DateInput from '../common/DateInput';
import MutedMessage from '../utils/MuttedMessage';
2018-10-29 00:54:08 +03:00
import CountriesGraph from './CountriesGraph';
import { getShortUrlVisits, shortUrlVisitsType } from './reducers/shortUrlVisits';
import {
processBrowserStats,
processCountriesStats,
processOsStats,
processReferrersStats,
} from './services/VisitsParser';
import { VisitsHeader } from './VisitsHeader';
import GraphCard from './GraphCard';
import { getShortUrlDetail, shortUrlDetailType } from './reducers/shortUrlDetail';
import './ShortUrlVisits.scss';
2018-07-29 19:39:00 +03:00
export class ShortUrlsVisitsComponent extends React.Component {
static propTypes = {
processOsStats: PropTypes.func,
processBrowserStats: PropTypes.func,
processCountriesStats: PropTypes.func,
processReferrersStats: PropTypes.func,
2018-09-08 14:28:40 +03:00
match: PropTypes.shape({
params: PropTypes.object,
}),
getShortUrlVisits: PropTypes.func,
shortUrlVisits: shortUrlVisitsType,
getShortUrlDetail: PropTypes.func,
shortUrlDetail: shortUrlDetailType,
};
static defaultProps = {
processOsStats,
processBrowserStats,
processCountriesStats,
processReferrersStats,
};
state = { startDate: undefined, endDate: undefined };
loadVisits = () => {
const { match: { params }, getShortUrlVisits } = this.props;
getShortUrlVisits(params.shortCode, mapObjIndexed(
(value) => value && value.format ? value.format('YYYY-MM-DD') : value,
this.state
));
};
2018-07-29 20:25:22 +03:00
componentDidMount() {
const { match: { params }, getShortUrlDetail } = this.props;
this.loadVisits();
getShortUrlDetail(params.shortCode);
2018-07-29 20:25:22 +03:00
}
render() {
const {
processOsStats,
processBrowserStats,
processCountriesStats,
processReferrersStats,
shortUrlVisits,
shortUrlDetail,
} = this.props;
const renderVisitsContent = () => {
const { visits, loading, error } = shortUrlVisits;
2018-07-30 21:52:03 +03:00
if (loading) {
return <MutedMessage><FontAwesomeIcon icon={preloader} spin /> Loading...</MutedMessage>;
2018-07-30 21:52:03 +03:00
}
if (error) {
return (
<Card className="mt-4" body inverse color="danger">
An error occurred while loading visits :(
</Card>
);
}
if (isEmpty(visits)) {
return <MutedMessage>There are no visits matching current filter :(</MutedMessage>;
}
2018-07-30 21:52:03 +03:00
return (
<div className="row">
<div className="col-md-6">
<GraphCard title="Operating systems" stats={processOsStats(visits)} />
</div>
<div className="col-md-6">
<GraphCard title="Browsers" stats={processBrowserStats(visits)} />
</div>
<div className="col-md-6">
2018-10-29 00:54:08 +03:00
<CountriesGraph stats={processCountriesStats(visits)} />
</div>
<div className="col-md-6">
<GraphCard title="Referrers" stats={processReferrersStats(visits)} isBarChart />
</div>
2018-07-29 20:25:22 +03:00
</div>
2018-07-30 21:52:03 +03:00
);
};
return (
2018-08-16 19:59:00 +03:00
<div className="shlink-container">
2018-09-08 10:31:44 +03:00
<VisitsHeader shortUrlDetail={shortUrlDetail} shortUrlVisits={shortUrlVisits} />
2018-07-30 21:52:03 +03:00
2018-08-09 20:50:22 +03:00
<section className="mt-4">
<div className="row">
<div className="col-xl-3 col-lg-4 col-md-6 offset-xl-6 offset-lg-4">
<DateInput
selected={this.state.startDate}
placeholderText="Since"
2018-08-09 21:13:46 +03:00
isClearable
2018-09-05 21:17:46 +03:00
maxDate={this.state.endDate}
onChange={(date) => this.setState({ startDate: date }, () => this.loadVisits())}
2018-08-09 20:50:22 +03:00
/>
</div>
<div className="col-xl-3 col-lg-4 col-md-6">
<DateInput
2018-10-07 10:22:15 +03:00
className="short-url-visits__date-input"
2018-08-09 20:50:22 +03:00
selected={this.state.endDate}
placeholderText="Until"
2018-08-09 21:13:46 +03:00
isClearable
2018-09-05 21:17:46 +03:00
minDate={this.state.startDate}
onChange={(date) => this.setState({ endDate: date }, () => this.loadVisits())}
2018-08-09 20:50:22 +03:00
/>
</div>
</div>
</section>
<section>
{renderVisitsContent()}
</section>
2018-07-29 20:25:22 +03:00
</div>
);
2018-07-29 19:39:00 +03:00
}
}
const ShortUrlsVisits = connect(
2018-09-08 10:31:44 +03:00
pick([ 'shortUrlVisits', 'shortUrlDetail' ]),
{ getShortUrlVisits, getShortUrlDetail }
)(ShortUrlsVisitsComponent);
export default ShortUrlsVisits;