diff --git a/CHANGELOG.md b/CHANGELOG.md index 85ef15ed..226bdd77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), #### Added -* *Nothing* +* [#54](https://github.com/shlinkio/shlink-web-client/issues/54) Added stats by city graphic in visits page. #### Changed diff --git a/src/visits/ShortUrlVisits.js b/src/visits/ShortUrlVisits.js index 36c94cd2..94e94347 100644 --- a/src/visits/ShortUrlVisits.js +++ b/src/visits/ShortUrlVisits.js @@ -17,6 +17,7 @@ const ShortUrlVisits = ({ processOsStats, processBrowserStats, processCountriesStats, + processCitiesStats, processReferrersStats, }) => class ShortUrlVisits extends React.Component { static propTypes = { @@ -70,13 +71,23 @@ const ShortUrlVisits = ({ return (
-
+
-
+
-
+
+ +
+
-
+
diff --git a/src/visits/services/VisitsParser.js b/src/visits/services/VisitsParser.js index bb801d67..39b550f3 100644 --- a/src/visits/services/VisitsParser.js +++ b/src/visits/services/VisitsParser.js @@ -76,16 +76,20 @@ export const processReferrersStats = (visits) => visits, ); -export const processCountriesStats = (visits) => +const buildLocationStatsProcessorByProperty = (propertyName) => (visits) => reduce( (stats, { visitLocation }) => { const notHasCountry = isNil(visitLocation) - || isNil(visitLocation.countryName) - || isEmpty(visitLocation.countryName); - const country = notHasCountry ? 'Unknown' : visitLocation.countryName; + || isNil(visitLocation[propertyName]) + || isEmpty(visitLocation[propertyName]); + const country = notHasCountry ? 'Unknown' : visitLocation[propertyName]; return assoc(country, (stats[country] || 0) + 1, stats); }, {}, visits, ); + +export const processCountriesStats = buildLocationStatsProcessorByProperty('countryName'); + +export const processCitiesStats = buildLocationStatsProcessorByProperty('cityName'); diff --git a/test/visits/ShortUrlVisits.test.js b/test/visits/ShortUrlVisits.test.js index 788623cb..152b4c71 100644 --- a/test/visits/ShortUrlVisits.test.js +++ b/test/visits/ShortUrlVisits.test.js @@ -23,6 +23,7 @@ describe('', () => { processCountriesStats: statsProcessor, processOsStats: statsProcessor, processReferrersStats: statsProcessor, + processCitiesStats: statsProcessor, }); wrapper = shallow( @@ -74,7 +75,7 @@ describe('', () => { const wrapper = createComponent({ loading: false, error: false, visits: [{}, {}, {}] }); const graphs = wrapper.find(GraphCard); const sortableBarGraphs = wrapper.find(SortableBarGraph); - const expectedGraphsCount = 4; + const expectedGraphsCount = 5; expect(graphs.length + sortableBarGraphs.length).toEqual(expectedGraphsCount); }); diff --git a/test/visits/services/VisitsParser.test.js b/test/visits/services/VisitsParser.test.js index f74a9476..6e62d76e 100644 --- a/test/visits/services/VisitsParser.test.js +++ b/test/visits/services/VisitsParser.test.js @@ -3,6 +3,7 @@ import { processBrowserStats, processReferrersStats, processCountriesStats, + processCitiesStats, } from '../../../src/visits/services/VisitsParser'; describe('VisitsParser', () => { @@ -12,6 +13,7 @@ describe('VisitsParser', () => { referer: 'https://google.com', visitLocation: { countryName: 'Spain', + cityName: 'Zaragoza', }, }, { @@ -19,6 +21,7 @@ describe('VisitsParser', () => { referer: 'https://google.com', visitLocation: { countryName: 'United States', + cityName: 'New York', }, }, { @@ -32,6 +35,7 @@ describe('VisitsParser', () => { referer: 'https://m.facebook.com', visitLocation: { countryName: 'Spain', + cityName: 'Zaragoza', }, }, { @@ -78,4 +82,14 @@ describe('VisitsParser', () => { }); }); }); + + describe('processCitiesStats', () => { + it('properly parses cities stats', () => { + expect(processCitiesStats(visits)).toEqual({ + 'Zaragoza': 2, + 'New York': 1, + 'Unknown': 2, + }); + }); + }); });