Added grid layout components.

This commit is contained in:
Mike Cao 2020-10-09 20:37:24 -07:00
parent e30f2dfb44
commit 910481e629
9 changed files with 154 additions and 72 deletions

View File

@ -0,0 +1,31 @@
import React from 'react';
import classNames from 'classnames';
import styles from './GridLayout.module.css';
export default function GridLayout({ className, children }) {
return <div className={classNames(styles.grid, className)}>{children}</div>;
}
export const GridRow = ({ className, children }) => {
return <div className={classNames(styles.row, className, 'row')}>{children}</div>;
};
export const GridColumn = ({ xs, sm, md, lg, xl, className, children }) => {
const classes = [];
classes.push(xs ? `col-${xs}` : 'col');
if (sm) {
classes.push(`col-sm-${sm}`);
}
if (md) {
classes.push(`col-md-${md}`);
}
if (lg) {
classes.push(`col-lg-${lg}`);
}
if (xl) {
classes.push(`col-lg-${xl}`);
}
return <div className={classNames(styles.col, classes, className)}>{children}</div>;
};

View File

@ -0,0 +1,40 @@
.grid {
display: flex;
flex-direction: column;
}
.col {
display: flex;
flex-direction: column;
}
.row {
border-top: 1px solid var(--gray300);
min-height: 430px;
}
.row > .col {
border-left: 1px solid var(--gray300);
padding: 20px;
}
.row > .col:first-child {
border-left: 0;
padding-left: 0;
}
.row > .col:last-child {
padding-right: 0;
}
@media only screen and (max-width: 992px) {
.row {
border: 0;
}
.row > .col {
border-top: 1px solid var(--gray300);
border-left: 0;
padding: 0;
}
}

View File

@ -8,7 +8,7 @@ import useTimezone from 'hooks/useTimezone';
import usePageQuery from 'hooks/usePageQuery'; import usePageQuery from 'hooks/usePageQuery';
import { EVENT_COLORS } from 'lib/constants'; import { EVENT_COLORS } from 'lib/constants';
export default function EventsChart({ websiteId, token }) { export default function EventsChart({ websiteId, className, token }) {
const [dateRange] = useDateRange(websiteId); const [dateRange] = useDateRange(websiteId);
const { startDate, endDate, unit, modified } = dateRange; const { startDate, endDate, unit, modified } = dateRange;
const [timezone] = useTimezone(); const [timezone] = useTimezone();
@ -79,6 +79,7 @@ export default function EventsChart({ websiteId, token }) {
return ( return (
<BarChart <BarChart
chartId={`events-${websiteId}`} chartId={`events-${websiteId}`}
className={className}
datasets={datasets} datasets={datasets}
unit={unit} unit={unit}
records={getDateLength(startDate, endDate, unit)} records={getDateLength(startDate, endDate, unit)}

View File

@ -119,6 +119,9 @@ export default function RealtimeLog({ data, websites }) {
return ( return (
<div className={styles.log}> <div className={styles.log}>
<div className={styles.header}>
<FormattedMessage id="label.realtime-logs" defaultMessage="Realtime logs" />
</div>
<Table <Table
className={styles.table} className={styles.table}
bodyClassName={styles.body} bodyClassName={styles.body}
@ -126,7 +129,7 @@ export default function RealtimeLog({ data, websites }) {
rows={logs} rows={logs}
showHeader={false} showHeader={false}
> >
<FixedSizeList height={300} itemCount={logs.length} itemSize={46}> <FixedSizeList height={400} itemCount={logs.length} itemSize={46}>
{Row} {Row}
</FixedSizeList> </FixedSizeList>
</Table> </Table>

View File

@ -2,13 +2,20 @@
font-size: var(--font-size-xsmall); font-size: var(--font-size-xsmall);
} }
.header {
display: flex;
align-items: center;
justify-content: space-between;
line-height: 40px;
font-weight: 600;
}
.row { .row {
display: flex; display: flex;
border-bottom: 1px solid var(--gray300); border-bottom: 1px solid var(--gray300);
} }
.body { .body {
height: 600px;
overflow: auto; overflow: auto;
} }

View File

@ -1,12 +1,12 @@
import React, { useState, useEffect, useMemo } from 'react'; import React, { useState, useEffect, useMemo } from 'react';
import classNames from 'classnames';
import { subMinutes, startOfMinute } from 'date-fns'; import { subMinutes, startOfMinute } from 'date-fns';
import Page from 'components/layout/Page'; import Page from 'components/layout/Page';
import useFetch from 'hooks/useFetch'; import GridLayout, { GridRow, GridColumn } from 'components/layout/GridLayout';
import RealtimeChart from '../metrics/RealtimeChart'; import RealtimeChart from '../metrics/RealtimeChart';
import RealtimeLog from '../metrics/RealtimeLog'; import RealtimeLog from '../metrics/RealtimeLog';
import styles from './RealtimeDashboard.module.css'; import styles from './RealtimeDashboard.module.css';
import RealtimeHeader from '../metrics/RealtimeHeader'; import RealtimeHeader from '../metrics/RealtimeHeader';
import useFetch from 'hooks/useFetch';
const REALTIME_RANGE = 30; const REALTIME_RANGE = 30;
const REALTIME_INTERVAL = 5000; const REALTIME_INTERVAL = 5000;
@ -36,10 +36,22 @@ export default function RealtimeDashboard() {
const realtimeData = useMemo(() => { const realtimeData = useMemo(() => {
if (websiteId) { if (websiteId) {
const { pageviews, sessions, events, ...props } = data; const { pageviews, sessions, events, ...props } = data;
const countries = sessions.reduce((obj, { country }) => {
if (country) {
if (!obj[country]) {
obj[country] = 1;
} else {
obj[country] += 1;
}
}
return obj;
}, {});
return { return {
pageviews: filterWebsite(pageviews, websiteId), pageviews: filterWebsite(pageviews, websiteId),
sessions: filterWebsite(sessions, websiteId), sessions: filterWebsite(sessions, websiteId),
events: filterWebsite(events, websiteId), events: filterWebsite(events, websiteId),
countries,
...props, ...props,
}; };
} }
@ -83,12 +95,24 @@ export default function RealtimeDashboard() {
records={REALTIME_RANGE} records={REALTIME_RANGE}
/> />
</div> </div>
<div className={classNames(styles.tables, 'row')}> <GridLayout>
<div className="col-12 col-lg-8"> <GridRow>
<RealtimeLog data={realtimeData} websites={websites} /> <GridColumn xs={12} lg={8}>
</div> <RealtimeLog data={realtimeData} websites={websites} />
<div className="col-12 col-lg-4">hi.</div> </GridColumn>
</div> <GridColumn xs={12} lg={4}>
x
</GridColumn>
</GridRow>
<GridRow>
<GridColumn xs={12} lg={4}>
x
</GridColumn>
<GridColumn xs={12} lg={8}>
x
</GridColumn>
</GridRow>
</GridLayout>
</Page> </Page>
); );
} }

View File

@ -4,6 +4,7 @@ import classNames from 'classnames';
import WebsiteChart from 'components/metrics/WebsiteChart'; import WebsiteChart from 'components/metrics/WebsiteChart';
import WorldMap from 'components/common/WorldMap'; import WorldMap from 'components/common/WorldMap';
import Page from 'components/layout/Page'; import Page from 'components/layout/Page';
import GridLayout, { GridRow, GridColumn } from 'components/layout/GridLayout';
import MenuLayout from 'components/layout/MenuLayout'; import MenuLayout from 'components/layout/MenuLayout';
import Link from 'components/common/Link'; import Link from 'components/common/Link';
import Loading from 'components/common/Loading'; import Loading from 'components/common/Loading';
@ -19,6 +20,7 @@ import EventsTable from '../metrics/EventsTable';
import EventsChart from '../metrics/EventsChart'; import EventsChart from '../metrics/EventsChart';
import useFetch from 'hooks/useFetch'; import useFetch from 'hooks/useFetch';
import usePageQuery from 'hooks/usePageQuery'; import usePageQuery from 'hooks/usePageQuery';
import { DEFAULT_ANIMATION_DURATION } from 'lib/constants';
const views = { const views = {
url: PagesTable, url: PagesTable,
@ -100,7 +102,7 @@ export default function WebsiteDetails({ websiteId, token }) {
function handleDataLoad() { function handleDataLoad() {
if (!chartLoaded) { if (!chartLoaded) {
setTimeout(() => setChartLoaded(true), 300); setTimeout(() => setChartLoaded(true), DEFAULT_ANIMATION_DURATION);
} }
} }
@ -124,45 +126,43 @@ export default function WebsiteDetails({ websiteId, token }) {
</div> </div>
{!chartLoaded && <Loading />} {!chartLoaded && <Loading />}
{chartLoaded && !view && ( {chartLoaded && !view && (
<> <GridLayout>
<div className={classNames(styles.row, 'row')}> <GridRow>
<div className="col-md-12 col-lg-6"> <GridColumn md={12} lg={6}>
<PagesTable {...tableProps} /> <PagesTable {...tableProps} />
</div> </GridColumn>
<div className="col-md-12 col-lg-6"> <GridColumn md={12} lg={6}>
<ReferrersTable {...tableProps} /> <ReferrersTable {...tableProps} />
</div> </GridColumn>
</div> </GridRow>
<div className={classNames(styles.row, 'row')}> <GridRow>
<div className="col-md-12 col-lg-4"> <GridColumn md={12} lg={4}>
<BrowsersTable {...tableProps} /> <BrowsersTable {...tableProps} />
</div> </GridColumn>
<div className="col-md-12 col-lg-4"> <GridColumn md={12} lg={4}>
<OSTable {...tableProps} /> <OSTable {...tableProps} />
</div> </GridColumn>
<div className="col-md-12 col-lg-4"> <GridColumn md={12} lg={4}>
<DevicesTable {...tableProps} /> <DevicesTable {...tableProps} />
</div> </GridColumn>
</div> </GridRow>
<div className={classNames(styles.row, 'row')}> <GridRow>
<div className="col-12 col-md-12 col-lg-8"> <GridColumn xs={12} md={12} lg={8}>
<WorldMap data={countryData} /> <WorldMap data={countryData} />
</div> </GridColumn>
<div className="col-12 col-md-12 col-lg-4"> <GridColumn xs={12} md={12} lg={4}>
<CountriesTable {...tableProps} onDataLoad={setCountryData} /> <CountriesTable {...tableProps} onDataLoad={setCountryData} />
</div> </GridColumn>
</div> </GridRow>
<div <GridRow className={classNames({ [styles.hidden]: !eventsData?.length > 0 })}>
className={classNames(styles.row, 'row', { [styles.hidden]: !eventsData?.length > 0 })} <GridColumn xs={12} md={12} lg={4}>
>
<div className="col-12 col-md-12 col-lg-4">
<EventsTable {...tableProps} onDataLoad={setEventsData} /> <EventsTable {...tableProps} onDataLoad={setEventsData} />
</div> </GridColumn>
<div className="col-12 col-md-12 col-lg-8 pt-5 pb-5"> <GridColumn xs={12} md={12} lg={8}>
<EventsChart websiteId={websiteId} token={token} /> <EventsChart className={styles.eventschart} websiteId={websiteId} token={token} />
</div> </GridColumn>
</div> </GridRow>
</> </GridLayout>
)} )}
{view && ( {view && (
<MenuLayout <MenuLayout

View File

@ -26,37 +26,10 @@
transform: rotate(180deg); transform: rotate(180deg);
} }
.row {
border-top: 1px solid var(--gray300);
min-height: 430px;
}
.row > [class*='col-'] {
border-left: 1px solid var(--gray300);
padding: 20px;
}
.row > [class*='col-']:first-child {
border-left: 0;
padding-left: 0;
}
.row > [class*='col-']:last-child {
padding-right: 0;
}
.hidden { .hidden {
display: none; display: none;
} }
@media only screen and (max-width: 992px) { .eventschart {
.row { padding: 30px 0;
border: 0;
}
.row > [class*='col-'] {
border-top: 1px solid var(--gray300);
border-left: 0;
padding: 0;
}
} }

View File

@ -37,6 +37,9 @@ h4,
h5, h5,
h6 { h6 {
font-weight: 400; font-weight: 400;
line-height: 30px;
padding: 0;
margin: 0;
} }
button, button,