diff --git a/components/common/HamburgerButton.js b/components/common/HamburgerButton.js
index a2d26779..b3e0b54f 100644
--- a/components/common/HamburgerButton.js
+++ b/components/common/HamburgerButton.js
@@ -32,9 +32,13 @@ export default function HamburgerButton() {
label: formatMessage(labels.users),
url: '/settings/users',
},
+ {
+ label: formatMessage(labels.profile),
+ url: '/settings/profile',
+ },
],
},
- {
+ cloudMode && {
label: formatMessage(labels.profile),
url: '/settings/profile',
},
diff --git a/components/common/WorldMap.js b/components/common/WorldMap.js
index b774702b..b5a40fc5 100644
--- a/components/common/WorldMap.js
+++ b/components/common/WorldMap.js
@@ -9,7 +9,8 @@ import styles from './WorldMap.module.css';
import useCountryNames from 'hooks/useCountryNames';
import useLocale from 'hooks/useLocale';
import HoverTooltip from './HoverTooltip';
-import { formatLongNumber } from '../../lib/format';
+import { formatLongNumber } from 'lib/format';
+import { percentFilter } from 'lib/filters';
function WorldMap({ data, className }) {
const { basePath } = useRouter();
@@ -26,10 +27,11 @@ function WorldMap({ data, className }) {
);
const { locale } = useLocale();
const countryNames = useCountryNames(locale);
+ const metrics = useMemo(() => percentFilter(data), [data]);
function getFillColor(code) {
if (code === 'AQ') return;
- const country = data?.find(({ x }) => x === code);
+ const country = metrics?.find(({ x }) => x === code);
if (!country) {
return colors.fillColor;
@@ -46,7 +48,7 @@ function WorldMap({ data, className }) {
function handleHover(code) {
if (code === 'AQ') return;
- const country = data?.find(({ x }) => x === code);
+ const country = metrics?.find(({ x }) => x === code);
setTooltip(`${countryNames[code]}: ${formatLongNumber(country?.y || 0)} visitors`);
}
diff --git a/components/messages.js b/components/messages.js
index de92ce8f..9de5f52b 100644
--- a/components/messages.js
+++ b/components/messages.js
@@ -114,6 +114,8 @@ export const labels = defineMessages({
editDashboard: { id: 'label.edit-dashboard', defaultMessage: 'Edit dashboard' },
title: { id: 'label.title', defaultMessage: 'Title' },
view: { id: 'label.view', defaultMessage: 'View' },
+ cities: { id: 'label.cities', defaultMessage: 'Cities' },
+ regions: { id: 'label.regions', defaultMessage: 'Regions' },
});
export const messages = defineMessages({
diff --git a/components/metrics/CitiesTable.js b/components/metrics/CitiesTable.js
new file mode 100644
index 00000000..4aa61334
--- /dev/null
+++ b/components/metrics/CitiesTable.js
@@ -0,0 +1,30 @@
+import MetricsTable from './MetricsTable';
+import { emptyFilter } from 'lib/filters';
+import FilterLink from 'components/common/FilterLink';
+import useLocale from 'hooks/useLocale';
+import useMessages from 'hooks/useMessages';
+
+export default function CitiesTable({ websiteId, ...props }) {
+ const { locale } = useLocale();
+ const { formatMessage, labels } = useMessages();
+
+ function renderLink({ x }) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+ );
+}
diff --git a/components/metrics/CountriesTable.js b/components/metrics/CountriesTable.js
index 5e7d8a8d..dcebe5e0 100644
--- a/components/metrics/CountriesTable.js
+++ b/components/metrics/CountriesTable.js
@@ -1,11 +1,10 @@
import MetricsTable from './MetricsTable';
-import { percentFilter } from 'lib/filters';
import FilterLink from 'components/common/FilterLink';
import useCountryNames from 'hooks/useCountryNames';
import useLocale from 'hooks/useLocale';
import useMessages from 'hooks/useMessages';
-export default function CountriesTable({ websiteId, onDataLoad, ...props }) {
+export default function CountriesTable({ websiteId, ...props }) {
const { locale } = useLocale();
const countryNames = useCountryNames(locale);
const { formatMessage, labels } = useMessages();
@@ -25,7 +24,6 @@ export default function CountriesTable({ websiteId, onDataLoad, ...props }) {
type="country"
metric={formatMessage(labels.visitors)}
websiteId={websiteId}
- onDataLoad={data => onDataLoad?.(percentFilter(data))}
renderLabel={renderLink}
/>
);
diff --git a/components/metrics/MetricsTable.js b/components/metrics/MetricsTable.js
index 2e20dfc6..0d83fc22 100644
--- a/components/metrics/MetricsTable.js
+++ b/components/metrics/MetricsTable.js
@@ -29,7 +29,7 @@ export default function MetricsTable({
const {
resolveUrl,
router,
- query: { url, referrer, os, browser, device, country },
+ query: { url, referrer, os, browser, device, country, region, city },
} = usePageQuery();
const { formatMessage, labels } = useMessages();
const { get, useQuery } = useApi();
@@ -37,7 +37,7 @@ export default function MetricsTable({
const { data, isLoading, isFetched, error } = useQuery(
[
'websites:metrics',
- { websiteId, type, modified, url, referrer, os, browser, device, country },
+ { websiteId, type, modified, url, referrer, os, browser, device, country, region, city },
],
() =>
get(`/websites/${websiteId}/metrics`, {
@@ -50,6 +50,8 @@ export default function MetricsTable({
browser,
device,
country,
+ region,
+ city,
}),
{ onSuccess: onDataLoad, retryDelay: delay || DEFAULT_ANIMATION_DURATION },
);
diff --git a/components/metrics/RegionsTable.js b/components/metrics/RegionsTable.js
new file mode 100644
index 00000000..87a15b40
--- /dev/null
+++ b/components/metrics/RegionsTable.js
@@ -0,0 +1,31 @@
+import MetricsTable from './MetricsTable';
+import { emptyFilter } from 'lib/filters';
+import FilterLink from 'components/common/FilterLink';
+import useLocale from 'hooks/useLocale';
+import useMessages from 'hooks/useMessages';
+import regions from 'public/iso-3166-2.json';
+
+export default function RegionsTable({ websiteId, ...props }) {
+ const { locale } = useLocale();
+ const { formatMessage, labels } = useMessages();
+
+ function renderLink({ x }) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+ );
+}
diff --git a/components/metrics/WebsiteChart.js b/components/metrics/WebsiteChart.js
index cf900f76..cc27ac25 100644
--- a/components/metrics/WebsiteChart.js
+++ b/components/metrics/WebsiteChart.js
@@ -33,13 +33,16 @@ export default function WebsiteChart({
const { startDate, endDate, unit, value, modified } = dateRange;
const [timezone] = useTimezone();
const {
- query: { url, referrer, os, browser, device, country, title },
+ query: { url, referrer, os, browser, device, country, region, city, title },
} = usePageQuery();
const { get, useQuery } = useApi();
const { ref, isSticky } = useSticky({ enabled: stickyHeader });
const { data, isLoading, error } = useQuery(
- ['websites:pageviews', { websiteId, modified, url, referrer, os, browser, device, country }],
+ [
+ 'websites:pageviews',
+ { websiteId, modified, url, referrer, os, browser, device, country, region, city, title },
+ ],
() =>
get(`/websites/${websiteId}/pageviews`, {
startAt: +startDate,
@@ -52,6 +55,9 @@ export default function WebsiteChart({
browser,
device,
country,
+ region,
+ city,
+ title,
}),
{ onSuccess: onDataLoad },
);
@@ -82,7 +88,7 @@ export default function WebsiteChart({
|