Updated cities table.

This commit is contained in:
Mike Cao 2023-08-26 12:46:27 -07:00
parent c22fefaa2d
commit bb77c2ead6
8 changed files with 52 additions and 23 deletions

View File

@ -4,7 +4,13 @@ import { useRouter } from 'next/router';
import Link from 'next/link'; import Link from 'next/link';
import styles from './SideNav.module.css'; import styles from './SideNav.module.css';
export function SideNav({ selectedKey, items, shallow, onSelect = () => {} }) { export function SideNav({
selectedKey,
items,
shallow = true,
scroll = false,
onSelect = () => {},
}) {
const { asPath } = useRouter(); const { asPath } = useRouter();
return ( return (
<Menu items={items} selectedKey={selectedKey} className={styles.menu} onSelect={onSelect}> <Menu items={items} selectedKey={selectedKey} className={styles.menu} onSelect={onSelect}>
@ -13,7 +19,7 @@ export function SideNav({ selectedKey, items, shallow, onSelect = () => {} }) {
key={key} key={key}
className={classNames(styles.item, { [styles.selected]: asPath.startsWith(url) })} className={classNames(styles.item, { [styles.selected]: asPath.startsWith(url) })}
> >
<Link href={url} shallow={shallow}> <Link href={url} shallow={shallow} scroll={scroll}>
{label} {label}
</Link> </Link>
</Item> </Item>

View File

@ -1,20 +1,36 @@
import { useRouter } from 'next/router';
import MetricsTable from './MetricsTable'; import MetricsTable from './MetricsTable';
import { emptyFilter } from 'lib/filters'; import { emptyFilter } from 'lib/filters';
import FilterLink from 'components/common/FilterLink'; import FilterLink from 'components/common/FilterLink';
import useLocale from 'components/hooks/useLocale'; import useLocale from 'components/hooks/useLocale';
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
import useCountryNames from 'components/hooks/useCountryNames';
export function CitiesTable({ websiteId, ...props }) { export function CitiesTable({ websiteId, ...props }) {
const { locale } = useLocale(); const { locale } = useLocale();
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { basePath } = useRouter();
const countryNames = useCountryNames(locale);
function renderLink({ x }) { const renderLabel = (city, country) => {
const name = countryNames[country];
return name ? `${city}, ${name}` : city;
};
const renderLink = ({ x: city, country }) => {
return ( return (
<div className={locale}> <FilterLink id="city" value={city} label={renderLabel(city, country)}>
<FilterLink id="city" value={x} /> {country && (
</div> <img
src={`${basePath}/images/flags/${
country?.split?.('-')?.[0]?.toLowerCase() || 'xx'
}.png`}
alt={country}
/>
)}
</FilterLink>
); );
} };
return ( return (
<MetricsTable <MetricsTable

View File

@ -8,7 +8,7 @@ import { formatNumber, formatLongNumber } from 'lib/format';
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
import styles from './DataTable.module.css'; import styles from './DataTable.module.css';
export function DataTable({ export function ListTable({
data = [], data = [],
title, title,
metric, metric,
@ -94,7 +94,7 @@ const AnimatedRow = ({
<div className={styles.percent}> <div className={styles.percent}>
<animated.div className={styles.bar} style={{ width: props.width.to(n => `${n}%`) }} /> <animated.div className={styles.bar} style={{ width: props.width.to(n => `${n}%`) }} />
<animated.span className={styles.percentValue}> <animated.span className={styles.percentValue}>
{props.width.to(n => `${n.toFixed(0)}%`)} {props.width.to(n => `${n?.toFixed?.(0)}%`)}
</animated.span> </animated.span>
</div> </div>
)} )}
@ -102,4 +102,4 @@ const AnimatedRow = ({
); );
}; };
export default DataTable; export default ListTable;

View File

@ -8,7 +8,7 @@ import { percentFilter } from 'lib/filters';
import useDateRange from 'components/hooks/useDateRange'; import useDateRange from 'components/hooks/useDateRange';
import usePageQuery from 'components/hooks/usePageQuery'; import usePageQuery from 'components/hooks/usePageQuery';
import ErrorMessage from 'components/common/ErrorMessage'; import ErrorMessage from 'components/common/ErrorMessage';
import DataTable from './DataTable'; import ListTable from './ListTable';
import { DEFAULT_ANIMATION_DURATION } from 'lib/constants'; import { DEFAULT_ANIMATION_DURATION } from 'lib/constants';
import Icons from 'components/icons'; import Icons from 'components/icons';
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
@ -104,7 +104,7 @@ export function MetricsTable({
<div className={classNames(styles.container, className)}> <div className={classNames(styles.container, className)}>
{!data && isLoading && !isFetched && <Loading icon="dots" />} {!data && isLoading && !isFetched && <Loading icon="dots" />}
{error && <ErrorMessage />} {error && <ErrorMessage />}
{data && !error && <DataTable {...props} data={filteredData} className={className} />} {data && !error && <ListTable {...props} data={filteredData} className={className} />}
<div className={styles.footer}> <div className={styles.footer}>
{data && !error && limit && ( {data && !error && limit && (
<Link href={router.pathname} as={resolveUrl({ view: type })}> <Link href={router.pathname} as={resolveUrl({ view: type })}>

View File

@ -1,6 +1,6 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import DataTable from 'components/metrics/DataTable'; import ListTable from 'components/metrics/ListTable';
import useLocale from 'components/hooks/useLocale'; import useLocale from 'components/hooks/useLocale';
import useCountryNames from 'components/hooks/useCountryNames'; import useCountryNames from 'components/hooks/useCountryNames';
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
@ -24,7 +24,7 @@ export function RealtimeCountries({ data }) {
); );
return ( return (
<DataTable <ListTable
title={formatMessage(labels.countries)} title={formatMessage(labels.countries)}
metric={formatMessage(labels.visitors)} metric={formatMessage(labels.visitors)}
data={data} data={data}

View File

@ -2,7 +2,7 @@ import { useMemo, useState } from 'react';
import { ButtonGroup, Button, Flexbox } from 'react-basics'; import { ButtonGroup, Button, Flexbox } from 'react-basics';
import firstBy from 'thenby'; import firstBy from 'thenby';
import { percentFilter } from 'lib/filters'; import { percentFilter } from 'lib/filters';
import DataTable from 'components/metrics/DataTable'; import ListTable from 'components/metrics/ListTable';
import { FILTER_PAGES, FILTER_REFERRERS } from 'lib/constants'; import { FILTER_PAGES, FILTER_REFERRERS } from 'lib/constants';
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
@ -82,7 +82,7 @@ export function RealtimeUrls({ websiteDomain, data = {} }) {
</ButtonGroup> </ButtonGroup>
</Flexbox> </Flexbox>
{filter === FILTER_REFERRERS && ( {filter === FILTER_REFERRERS && (
<DataTable <ListTable
title={formatMessage(labels.referrers)} title={formatMessage(labels.referrers)}
metric={formatMessage(labels.views)} metric={formatMessage(labels.views)}
renderLabel={renderLink} renderLabel={renderLink}
@ -90,7 +90,7 @@ export function RealtimeUrls({ websiteDomain, data = {} }) {
/> />
)} )}
{filter === FILTER_PAGES && ( {filter === FILTER_PAGES && (
<DataTable <ListTable
title={formatMessage(labels.pages)} title={formatMessage(labels.pages)}
metric={formatMessage(labels.views)} metric={formatMessage(labels.views)}
renderLabel={renderLink} renderLabel={renderLink}

View File

@ -1,5 +1,5 @@
import { useContext } from 'react'; import { useContext } from 'react';
import DataTable from 'components/metrics/DataTable'; import ListTable from 'components/metrics/ListTable';
import { useMessages } from 'components/hooks'; import { useMessages } from 'components/hooks';
import { ReportContext } from '../Report'; import { ReportContext } from '../Report';
@ -7,7 +7,7 @@ export function FunnelTable() {
const { report } = useContext(ReportContext); const { report } = useContext(ReportContext);
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
return ( return (
<DataTable <ListTable
data={report?.data} data={report?.data}
title={formatMessage(labels.url)} title={formatMessage(labels.url)}
metric={formatMessage(labels.visitors)} metric={formatMessage(labels.visitors)}

View File

@ -28,14 +28,18 @@ async function relationalQuery(websiteId: string, column: string, filters: Query
return rawQuery( return rawQuery(
` `
select ${column} x, count(*) y select
${column} x,
count(*) y
${column === 'city' ? ', country' : ''}
from website_event from website_event
${joinSession} ${joinSession}
where website_event.website_id = {{websiteId::uuid}} where website_event.website_id = {{websiteId::uuid}}
and website_event.created_at between {{startDate}} and {{endDate}} and website_event.created_at between {{startDate}} and {{endDate}}
and website_event.event_type = {{eventType}} and website_event.event_type = {{eventType}}
${filterQuery} ${filterQuery}
group by 1 group by 1
${column === 'city' ? ', 3' : ''}
order by 2 desc order by 2 desc
limit 100`, limit 100`,
params, params,
@ -52,13 +56,16 @@ async function clickhouseQuery(websiteId: string, column: string, filters: Query
return rawQuery( return rawQuery(
` `
select select
${column} x, count(distinct session_id) y ${column} x,
count(distinct session_id) y
${column === 'city' ? ', country' : ''}
from website_event from website_event
where website_id = {websiteId:UUID} where website_id = {websiteId:UUID}
and created_at between {startDate:DateTime} and {endDate:DateTime} and created_at between {startDate:DateTime} and {endDate:DateTime}
and event_type = {eventType:UInt32} and event_type = {eventType:UInt32}
${filterQuery} ${filterQuery}
group by x group by x
${column === 'city' ? ', country' : ''}
order by y desc order by y desc
limit 100 limit 100
`, `,