diff --git a/src/api/ShlinkApiClient.js b/src/api/ShlinkApiClient.js index e958b620..f5227652 100644 --- a/src/api/ShlinkApiClient.js +++ b/src/api/ShlinkApiClient.js @@ -39,6 +39,11 @@ export class ShlinkApiClient { .then(resp => resp.data.visits.data) .catch(e => this._handleAuthError(e, this.getShortUrlVisits, [shortCode, dates])); + getShortUrl = shortCode => + this._performRequest(`/short-codes/${shortCode}`, 'GET') + .then(resp => resp.data) + .catch(e => this._handleAuthError(e, this.getShortUrl, [shortCode])); + _performRequest = async (url, method = 'GET', params = {}, data = {}) => { if (isEmpty(this._token)) { this._token = await this._authenticate(); diff --git a/src/short-urls/ShortUrlVisits.js b/src/short-urls/ShortUrlVisits.js index e3a952ea..1ea5a4cf 100644 --- a/src/short-urls/ShortUrlVisits.js +++ b/src/short-urls/ShortUrlVisits.js @@ -1,8 +1,9 @@ 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 } from 'reactstrap'; +import { Card, CardBody, CardHeader, UncontrolledTooltip } from 'reactstrap'; import { getShortUrlVisits } from './reducers/shortUrlVisits'; import VisitsParser from '../visits/services/VisitsParser'; import preloader from '@fortawesome/fontawesome-free-solid/faCircleNotch'; @@ -17,9 +18,14 @@ export class ShortUrlsVisits extends React.Component { } render() { - const { match: { params }, selectedServer, visitsParser, shortUrlVisits: { visits, loading, error } } = this.props; + const { + match: { params }, + selectedServer, + visitsParser, + shortUrlVisits: { visits, loading, error, shortUrl } + } = this.props; const serverUrl = selectedServer ? selectedServer.url : ''; - const shortUrl = `${serverUrl}/${params.shortCode}`; + const shortLink = `${serverUrl}/${params.shortCode}`; const generateGraphData = (stats, label, isBarChart) => ({ labels: Object.keys(stats), datasets: [ @@ -72,15 +78,45 @@ export class ShortUrlsVisits extends React.Component { ); }; + const renderCreated = () => + + {shortUrl.dateCreated} + + {shortUrl.dateCreated} + + ; return (
- - -

Visit stats for {shortUrl}

-
-
+
+ + +

+ { + shortUrl.visitsCount && + Visits: {shortUrl.visitsCount} + } + Visit stats for {shortLink} +

+
+ {shortUrl.dateCreated &&
+ Created: +   + {loading && Loading...} + {!loading && renderCreated()} +
} +
+ Original URL: +   + {loading && Loading...} + {!loading && {shortUrl.longUrl}} +
+
+
+
- {renderContent()} +
+ {renderContent()} +
); } diff --git a/src/short-urls/reducers/shortUrlVisits.js b/src/short-urls/reducers/shortUrlVisits.js index df35e71a..0f9c8ed4 100644 --- a/src/short-urls/reducers/shortUrlVisits.js +++ b/src/short-urls/reducers/shortUrlVisits.js @@ -5,6 +5,7 @@ const GET_SHORT_URL_VISITS_ERROR = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_E const GET_SHORT_URL_VISITS = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS'; const initialState = { + shortUrl: {}, visits: [], loading: false, error: false @@ -25,6 +26,7 @@ export default function dispatch (state = initialState, action) { }; case GET_SHORT_URL_VISITS: return { + shortUrl: action.shortUrl, visits: action.visits, loading: false, error: false @@ -34,13 +36,13 @@ export default function dispatch (state = initialState, action) { } } -export const getShortUrlVisits = (shortCode, dates) => async dispatch => { +export const getShortUrlVisits = (shortCode, dates) => dispatch => { dispatch({ type: GET_SHORT_URL_VISITS_START }); - try { - const visits = await ShlinkApiClient.getShortUrlVisits(shortCode, dates); - dispatch({ visits, type: GET_SHORT_URL_VISITS }); - } catch (e) { - dispatch({ type: GET_SHORT_URL_VISITS_ERROR }); - } + Promise.all([ + ShlinkApiClient.getShortUrlVisits(shortCode, dates), + ShlinkApiClient.getShortUrl(shortCode) + ]) + .then(([visits, shortUrl]) => dispatch({ visits, shortUrl, type: GET_SHORT_URL_VISITS })) + .catch(() => dispatch({ type: GET_SHORT_URL_VISITS_ERROR })); };