From 0b15fba640abc3430f5cf94629195ddff9f3f322 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Tue, 31 Jul 2018 22:04:20 +0200 Subject: [PATCH] Added filtering by date range to visit stats page --- src/common/DateInput.js | 2 +- src/servers/DeleteServerButton.js | 2 + src/short-urls/ShortUrlVisits.js | 93 ++++++++++++++++++++---------- src/short-urls/ShortUrlVisits.scss | 3 + 4 files changed, 70 insertions(+), 30 deletions(-) create mode 100644 src/short-urls/ShortUrlVisits.scss diff --git a/src/common/DateInput.js b/src/common/DateInput.js index 34c8afb1..148301e6 100644 --- a/src/common/DateInput.js +++ b/src/common/DateInput.js @@ -15,7 +15,7 @@ export default class DateInput extends React.Component {
this.setState({ isModalOpen: true })} + key="deleteServerBtn" > Delete this server @@ -25,6 +26,7 @@ export default class DeleteServerButton extends React.Component { toggle={() => this.setState({ isModalOpen: !this.state.isModalOpen })} history={history} server={server} + key="deleteServerModal" /> ) ]; diff --git a/src/short-urls/ShortUrlVisits.js b/src/short-urls/ShortUrlVisits.js index 6508709e..c5889e58 100644 --- a/src/short-urls/ShortUrlVisits.js +++ b/src/short-urls/ShortUrlVisits.js @@ -1,20 +1,37 @@ +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 { Doughnut, HorizontalBar } from 'react-chartjs-2'; import Moment from 'react-moment'; import { connect } from 'react-redux'; -import { pick } from 'ramda'; import { Card, CardBody, CardHeader, UncontrolledTooltip } from 'reactstrap'; -import { getShortUrlVisits } from './reducers/shortUrlVisits'; +import DateInput from '../common/DateInput'; import VisitsParser from '../visits/services/VisitsParser'; -import preloader from '@fortawesome/fontawesome-free-solid/faCircleNotch'; -import FontAwesomeIcon from '@fortawesome/react-fontawesome'; +import { getShortUrlVisits } from './reducers/shortUrlVisits'; +import './ShortUrlVisits.scss'; + +const MutedMessage = ({ children }) => +
+ +

+ {children} +

+
+
; export class ShortUrlsVisits extends React.Component { - state = { startDate: '', endDate: '' }; + state = { startDate: undefined, endDate: undefined }; + loadVisits = (dates = {}) => { + const { match: { params } } = this.props; + this.props.getShortUrlVisits(params.shortCode, mapObjIndexed( + value => value && value.format ? value.format('YYYY-MM-DD') : value, + { ...this.state, ...dates } + )) + }; componentDidMount() { - const { match: { params } } = this.props; - this.props.getShortUrlVisits(params.shortCode, this.state); + this.loadVisits(); } render() { @@ -24,15 +41,6 @@ export class ShortUrlsVisits extends React.Component { visitsParser, shortUrlVisits: { visits, loading, error, shortUrl } } = this.props; - const colors = [ - '#97BBCD', - '#DCDCDC', - '#F7464A', - '#46BFBD', - '#FDB45C', - '#949FB1', - '#4D5360' - ]; const serverUrl = selectedServer ? selectedServer.url : ''; const shortLink = `${serverUrl}/${params.shortCode}`; const generateGraphData = (stats, label, isBarChart) => ({ @@ -41,7 +49,15 @@ export class ShortUrlsVisits extends React.Component { { label, data: Object.values(stats), - backgroundColor: isBarChart ? 'rgba(70, 150, 229, 0.4)' : colors, + backgroundColor: isBarChart ? 'rgba(70, 150, 229, 0.4)' : [ + '#97BBCD', + '#DCDCDC', + '#F7464A', + '#46BFBD', + '#FDB45C', + '#949FB1', + '#4D5360' + ], borderColor: isBarChart ? 'rgba(70, 150, 229, 1)' : 'white', borderWidth: 2 } @@ -67,15 +83,7 @@ export class ShortUrlsVisits extends React.Component {
; const renderContent = () => { if (loading) { - return ( -
- -

- Loading... -

-
-
- ); + return Loading...; } if (error) { @@ -86,6 +94,10 @@ export class ShortUrlsVisits extends React.Component { ); } + if (isEmpty(visits)) { + return There have been no visits matching current filter :(; + } + return (
{renderGraphCard('Operating systems', visitsParser.processOsStats(visits), false)} @@ -132,6 +144,31 @@ export class ShortUrlsVisits extends React.Component { +
+
e.preventDefault()} className="form-inline mt-4 float-md-right"> + + { + this.setState({ startDate: date }); + this.loadVisits({ startDate: date }); + }} + className="short-url-visits__date-input" + /> + { + this.setState({ endDate: date }); + this.loadVisits({ endDate: date }); + }} + className="short-url-visits__date-input" + /> + +
+
+
{renderContent()}
@@ -144,6 +181,4 @@ ShortUrlsVisits.defaultProps = { visitsParser: VisitsParser }; -export default connect(pick(['selectedServer', 'shortUrlVisits']), { - getShortUrlVisits -})(ShortUrlsVisits); +export default connect(pick(['selectedServer', 'shortUrlVisits']), { getShortUrlVisits })(ShortUrlsVisits); diff --git a/src/short-urls/ShortUrlVisits.scss b/src/short-urls/ShortUrlVisits.scss new file mode 100644 index 00000000..4ebf855e --- /dev/null +++ b/src/short-urls/ShortUrlVisits.scss @@ -0,0 +1,3 @@ +.short-url-visits__date-input { + margin-left: 10px; +}