Fixed date range calculations.

This commit is contained in:
Mike Cao 2020-07-30 22:40:16 -07:00
parent 9f112c8cc9
commit 38abd673f3
8 changed files with 55 additions and 21 deletions

View File

@ -7,6 +7,9 @@ const filterOptions = [
{ label: 'Last 7 days', value: '7day' }, { label: 'Last 7 days', value: '7day' },
{ label: 'Last 30 days', value: '30day' }, { label: 'Last 30 days', value: '30day' },
{ label: 'Last 90 days', value: '90day' }, { label: 'Last 90 days', value: '90day' },
{ label: 'Today', value: '1day' },
{ label: 'This week', value: '1week' },
{ label: 'This month', value: '1month' },
]; ];
export default function DateFilter({ value, onChange }) { export default function DateFilter({ value, onChange }) {

View File

@ -9,13 +9,15 @@ export default function DropDown({ value, options = [], onChange }) {
setShowMenu(state => !state); setShowMenu(state => !state);
} }
function handleSelect(value) { function handleSelect(value, e) {
e.stopPropagation();
setShowMenu(false);
onChange(value); onChange(value);
} }
useEffect(() => { useEffect(() => {
function hideMenu(e) { function hideMenu(e) {
if (ref.current && !ref.current.contains(e.target)) { if (!ref.current.contains(e.target)) {
setShowMenu(false); setShowMenu(false);
} }
} }

View File

@ -18,13 +18,13 @@
margin-top: 4px; margin-top: 4px;
border: 1px solid #b3b3b3; border: 1px solid #b3b3b3;
border-radius: 4px; border-radius: 4px;
overflow: hidden;
z-index: 1; z-index: 1;
} }
.option { .option {
background: #fff; background: #fff;
padding: 4px 8px; padding: 4px 8px;
border-radius: 4px;
cursor: pointer; cursor: pointer;
} }

View File

@ -14,7 +14,7 @@ export default function PageviewsChart({ data, unit, children }) {
const n = data.pageviews.length; const n = data.pageviews.length;
switch (unit) { switch (unit) {
case 'day': case 'day':
if (n > 7) { if (n >= 15) {
return index % ~~(n / 15) === 0 ? format(d, 'MMM d') : ''; return index % ~~(n / 15) === 0 ? format(d, 'MMM d') : '';
} }
return format(d, 'EEE M/d'); return format(d, 'EEE M/d');

View File

@ -10,7 +10,7 @@ import DateFilter from './DateFilter';
export default function WebsiteChart({ title, websiteId }) { export default function WebsiteChart({ title, websiteId }) {
const [data, setData] = useState(); const [data, setData] = useState();
const [dateRange, setDateRange] = useState(getDateRange('7day')); const [dateRange, setDateRange] = useState(getDateRange('7day'));
const { startDate, endDate, unit } = dateRange; const { startDate, endDate, unit, value } = dateRange;
const [pageviews, uniques] = useMemo(() => { const [pageviews, uniques] = useMemo(() => {
if (data) { if (data) {
@ -46,10 +46,10 @@ export default function WebsiteChart({ title, websiteId }) {
<div className={styles.title}>{title}</div> <div className={styles.title}>{title}</div>
<div className={styles.header}> <div className={styles.header}>
<MetricsBar websiteId={websiteId} startDate={startDate} endDate={endDate} /> <MetricsBar websiteId={websiteId} startDate={startDate} endDate={endDate} />
<DateFilter value={dateRange.value} onChange={handleDateChange} /> <DateFilter value={value} onChange={handleDateChange} />
</div> </div>
<PageviewsChart data={{ pageviews, uniques }} unit={unit}> <PageviewsChart data={{ pageviews, uniques }} unit={unit}>
<QuickButtons value={dateRange.value} onChange={handleDateChange} /> <QuickButtons value={value} onChange={handleDateChange} />
</PageviewsChart> </PageviewsChart>
</div> </div>
); );

View File

@ -1,7 +1,6 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { get } from 'lib/web'; import { get } from 'lib/web';
import WebsiteChart from './WebsiteChart'; import WebsiteChart from './WebsiteChart';
import DateFilter from './DateFilter';
import styles from './WebsiteList.module.css'; import styles from './WebsiteList.module.css';
export default function WebsiteList() { export default function WebsiteList() {

View File

@ -7,10 +7,14 @@ import {
subDays, subDays,
startOfHour, startOfHour,
startOfDay, startOfDay,
startOfWeek,
startOfMonth,
endOfHour, endOfHour,
endOfDay, endOfDay,
endOfWeek,
endOfMonth,
differenceInHours, differenceInHours,
differenceInDays, differenceInCalendarDays,
} from 'date-fns'; } from 'date-fns';
export function getTimezone() { export function getTimezone() {
@ -23,23 +27,47 @@ export function getLocalTime(t) {
export function getDateRange(value) { export function getDateRange(value) {
const now = new Date(); const now = new Date();
const hour = endOfHour(now);
const day = endOfDay(now);
const { num, unit } = value.match(/^(?<num>[0-9]+)(?<unit>hour|day)$/).groups; const { num, unit } = value.match(/^(?<num>[0-9]+)(?<unit>hour|day|week|month)$/).groups;
if (+num === 1) {
switch (unit) {
case 'day':
return {
startDate: startOfDay(now),
endDate: endOfDay(now),
unit: 'hour',
value,
};
case 'week':
return {
startDate: startOfWeek(now),
endDate: endOfWeek(now),
unit: 'day',
value,
};
case 'month':
return {
startDate: startOfMonth(now),
endDate: endOfMonth(now),
unit: 'day',
value,
};
}
}
switch (unit) { switch (unit) {
case 'day': case 'day':
return { return {
startDate: subDays(day, num), startDate: subDays(startOfDay(now), num - 1),
endDate: day, endDate: endOfDay(now),
unit, unit,
value, value,
}; };
case 'hour': case 'hour':
return { return {
startDate: subHours(hour, num), startDate: subHours(startOfHour(now), num - 1),
endDate: hour, endDate: endOfHour(now),
unit, unit,
value, value,
}; };
@ -48,20 +76,22 @@ export function getDateRange(value) {
const dateFuncs = { const dateFuncs = {
hour: [differenceInHours, addHours, startOfHour], hour: [differenceInHours, addHours, startOfHour],
day: [differenceInDays, addDays, startOfDay], day: [differenceInCalendarDays, addDays, startOfDay],
}; };
export function getDateArray(data, startDate, endDate, unit) { export function getDateArray(data, startDate, endDate, unit) {
const arr = []; const arr = [];
const [diff, add, normalize] = dateFuncs[unit]; const [diff, add, normalize] = dateFuncs[unit];
const n = diff(endDate, startDate); const n = diff(endDate, startDate) + 1;
function findData(t) { function findData(t) {
return data.find(e => getLocalTime(e.t).getTime() === normalize(t).getTime())?.y || 0; const x = data.find(e => new Date(e.t).getTime() === normalize(new Date(t)).getTime());
return x?.y || 0;
} }
for (let i = 0; i < n; i++) { for (let i = 0; i < n; i++) {
const t = add(startDate, i + 1); const t = add(startDate, i);
const y = findData(t); const y = findData(t);
arr.push({ t, y }); arr.push({ t, y });

View File

@ -165,7 +165,7 @@ export async function getPageviewData(
return runQuery( return runQuery(
prisma.queryRaw( prisma.queryRaw(
` `
select date_trunc('${unit}', created_at at time zone '${timezone}') t, select date_trunc('${unit}', created_at at time zone '${timezone}') at time zone '${timezone}' t,
count(${count}) y count(${count}) y
from pageview from pageview
where website_id=$1 where website_id=$1