Added regions and cities support.

This commit is contained in:
Mike Cao 2023-04-13 22:28:29 -07:00
parent ad3ee5e953
commit f2edd0d604
58 changed files with 293 additions and 70 deletions

View file

@ -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',
},

View file

@ -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`);
}

View file

@ -113,6 +113,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({

View file

@ -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 (
<div className={locale}>
<FilterLink id="city" value={x} />
</div>
);
}
return (
<MetricsTable
{...props}
title={formatMessage(labels.cities)}
type="city"
metric={formatMessage(labels.visitors)}
websiteId={websiteId}
dataFilter={emptyFilter}
renderLabel={renderLink}
/>
);
}

View file

@ -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}
/>
);

View file

@ -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 },
);

View file

@ -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 (
<div className={locale}>
<FilterLink id="region" value={x} label={regions[x] || x} />
</div>
);
}
return (
<MetricsTable
{...props}
title={formatMessage(labels.regions)}
type="region"
metric={formatMessage(labels.visitors)}
websiteId={websiteId}
dataFilter={emptyFilter}
renderLabel={renderLink}
/>
);
}

View file

@ -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({
</WebsiteHeader>
<FilterTags
websiteId={websiteId}
params={{ url, referrer, os, browser, device, country, title }}
params={{ url, referrer, os, browser, device, country, region, city, title }}
/>
<Row
ref={ref}

View file

@ -19,7 +19,7 @@ export default function TeamDeleteForm({ teamId, teamName, onSave, onClose }) {
return (
<Form onSubmit={handleSubmit} error={error}>
<p>
<FormattedMessage {...messages.confirmDelete} values={{ name: <b>{teamName}</b> }} />
<FormattedMessage {...messages.confirmDelete} values={{ target: <b>{teamName}</b> }} />
</p>
<FormButtons flex>
<SubmitButton variant="danger" disabled={isLoading}>

View file

@ -3,6 +3,8 @@ import Link from 'next/link';
import { GridRow, GridColumn } from 'components/layout/Grid';
import BrowsersTable from 'components/metrics/BrowsersTable';
import CountriesTable from 'components/metrics/CountriesTable';
import RegionsTable from 'components/metrics/RegionsTable';
import CitiesTable from 'components/metrics/CitiesTable';
import DevicesTable from 'components/metrics/DevicesTable';
import LanguagesTable from 'components/metrics/LanguagesTable';
import OSTable from 'components/metrics/OSTable';
@ -26,6 +28,8 @@ const views = {
device: DevicesTable,
screen: ScreenTable,
country: CountriesTable,
region: RegionsTable,
city: CitiesTable,
language: LanguagesTable,
event: EventsTable,
query: QueryParametersTable,
@ -69,6 +73,16 @@ export default function WebsiteMenuView({ websiteId, websiteDomain }) {
label: formatMessage(labels.countries),
url: resolveUrl({ view: 'country' }),
},
{
key: 'region',
label: formatMessage(labels.regions),
url: resolveUrl({ view: 'region' }),
},
{
key: 'city',
label: formatMessage(labels.cities),
url: resolveUrl({ view: 'city' }),
},
{
key: 'language',
label: formatMessage(labels.languages),