ability to use custom dates everywhere
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { StickyBelowHeader } from '@/app/(app)/[organizationId]/[projectId]/layout-sticky-below-header';
|
||||
import { useOverviewOptions } from '@/components/overview/useOverviewOptions';
|
||||
import { LazyChart } from '@/components/report/chart/LazyChart';
|
||||
import { ReportRange } from '@/components/report/ReportRange';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -18,9 +17,13 @@ import { ChevronRight, MoreHorizontal, PlusIcon, Trash } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { getDefaultIntervalByRange } from '@mixan/constants';
|
||||
import {
|
||||
getDefaultIntervalByDates,
|
||||
getDefaultIntervalByRange,
|
||||
} from '@mixan/constants';
|
||||
import type { getReportsByDashboardId } from '@mixan/db';
|
||||
import type { IChartRange } from '@mixan/validation';
|
||||
|
||||
import { OverviewReportRange } from '../../overview-sticky-header';
|
||||
|
||||
interface ListReportsProps {
|
||||
reports: Awaited<ReturnType<typeof getReportsByDashboardId>>;
|
||||
@@ -29,16 +32,12 @@ interface ListReportsProps {
|
||||
export function ListReports({ reports }: ListReportsProps) {
|
||||
const router = useRouter();
|
||||
const params = useAppParams<{ dashboardId: string }>();
|
||||
const [range, setRange] = useState<null | IChartRange>(null);
|
||||
const { range, startDate, endDate } = useOverviewOptions();
|
||||
|
||||
return (
|
||||
<>
|
||||
<StickyBelowHeader className="p-4 items-center justify-between flex">
|
||||
<ReportRange
|
||||
placeholder="Override range"
|
||||
value={range}
|
||||
onChange={(value) => setRange((p) => (p === value ? null : value))}
|
||||
/>
|
||||
<OverviewReportRange />
|
||||
<Button
|
||||
icon={PlusIcon}
|
||||
onClick={() => {
|
||||
@@ -72,10 +71,20 @@ export function ListReports({ reports }: ListReportsProps) {
|
||||
<div className="font-medium">{report.name}</div>
|
||||
{chartRange !== null && (
|
||||
<div className="mt-2 text-sm flex gap-2">
|
||||
<span className={range !== null ? 'line-through' : ''}>
|
||||
<span
|
||||
className={
|
||||
range !== null || (startDate && endDate)
|
||||
? 'line-through'
|
||||
: ''
|
||||
}
|
||||
>
|
||||
{chartRange}
|
||||
</span>
|
||||
{range !== null && <span>{range}</span>}
|
||||
{startDate && endDate ? (
|
||||
<span>Custom dates</span>
|
||||
) : (
|
||||
range !== null && <span>{range}</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -116,8 +125,11 @@ export function ListReports({ reports }: ListReportsProps) {
|
||||
<LazyChart
|
||||
{...report}
|
||||
range={range ?? report.range}
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
interval={
|
||||
range ? getDefaultIntervalByRange(range) : report.interval
|
||||
getDefaultIntervalByDates(startDate, endDate) ||
|
||||
(range ? getDefaultIntervalByRange(range) : report.interval)
|
||||
}
|
||||
editMode={false}
|
||||
/>
|
||||
|
||||
@@ -14,13 +14,16 @@ interface OverviewMetricsProps {
|
||||
}
|
||||
|
||||
export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
||||
const { previous, range, interval, metric, setMetric } = useOverviewOptions();
|
||||
const { previous, range, interval, metric, setMetric, startDate, endDate } =
|
||||
useOverviewOptions();
|
||||
const [filters] = useEventQueryFilters();
|
||||
|
||||
const reports = [
|
||||
{
|
||||
id: 'Visitors',
|
||||
projectId,
|
||||
startDate,
|
||||
endDate,
|
||||
events: [
|
||||
{
|
||||
segment: 'user',
|
||||
@@ -42,6 +45,8 @@ export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
||||
{
|
||||
id: 'Sessions',
|
||||
projectId,
|
||||
startDate,
|
||||
endDate,
|
||||
events: [
|
||||
{
|
||||
segment: 'event',
|
||||
@@ -63,6 +68,8 @@ export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
||||
{
|
||||
id: 'Pageviews',
|
||||
projectId,
|
||||
startDate,
|
||||
endDate,
|
||||
events: [
|
||||
{
|
||||
segment: 'event',
|
||||
@@ -84,6 +91,8 @@ export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
||||
{
|
||||
id: 'Views per session',
|
||||
projectId,
|
||||
startDate,
|
||||
endDate,
|
||||
events: [
|
||||
{
|
||||
segment: 'user_average',
|
||||
@@ -105,6 +114,8 @@ export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
||||
{
|
||||
id: 'Bounce rate',
|
||||
projectId,
|
||||
startDate,
|
||||
endDate,
|
||||
events: [
|
||||
{
|
||||
segment: 'event',
|
||||
@@ -143,6 +154,8 @@ export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
||||
{
|
||||
id: 'Visit duration',
|
||||
projectId,
|
||||
startDate,
|
||||
endDate,
|
||||
events: [
|
||||
{
|
||||
segment: 'property_average',
|
||||
|
||||
@@ -2,8 +2,36 @@
|
||||
|
||||
import { useOverviewOptions } from '@/components/overview/useOverviewOptions';
|
||||
import { ReportRange } from '@/components/report/ReportRange';
|
||||
import { endOfDay, startOfDay } from 'date-fns';
|
||||
|
||||
export function OverviewReportRange() {
|
||||
const { range, setRange } = useOverviewOptions();
|
||||
return <ReportRange value={range} onChange={(value) => setRange(value)} />;
|
||||
const { range, setRange, setEndDate, setStartDate, startDate, endDate } =
|
||||
useOverviewOptions();
|
||||
return (
|
||||
<ReportRange
|
||||
range={range}
|
||||
onRangeChange={(value) => {
|
||||
setRange(value);
|
||||
setStartDate(null);
|
||||
setEndDate(null);
|
||||
}}
|
||||
dates={{
|
||||
startDate,
|
||||
endDate,
|
||||
}}
|
||||
onDatesChange={(val) => {
|
||||
if (!val) return;
|
||||
|
||||
if (val.from && val.to) {
|
||||
setRange(null);
|
||||
setStartDate(startOfDay(val.from).toISOString());
|
||||
setEndDate(endOfDay(val.to).toISOString());
|
||||
} else if (val.from) {
|
||||
setStartDate(startOfDay(val.from).toISOString());
|
||||
} else if (val.to) {
|
||||
setEndDate(endOfDay(val.to).toISOString());
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import OverviewTopEvents from '@/components/overview/overview-top-events';
|
||||
import OverviewTopGeo from '@/components/overview/overview-top-geo';
|
||||
import OverviewTopPages from '@/components/overview/overview-top-pages';
|
||||
import OverviewTopSources from '@/components/overview/overview-top-sources';
|
||||
import { Dialog } from '@/components/ui/dialog';
|
||||
import { getExists } from '@/server/pageExists';
|
||||
|
||||
import { db } from '@mixan/db';
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import PageLayout from '@/app/(app)/[organizationId]/[projectId]/page-layout';
|
||||
import { ListProperties } from '@/components/events/ListProperties';
|
||||
import { OverviewFiltersButtons } from '@/components/overview/filters/overview-filters-buttons';
|
||||
import { OverviewFiltersDrawer } from '@/components/overview/filters/overview-filters-drawer';
|
||||
import { ProfileAvatar } from '@/components/profiles/ProfileAvatar';
|
||||
import { ChartSwitch } from '@/components/report/chart';
|
||||
import { GradientBackground } from '@/components/ui/gradient-background';
|
||||
import { KeyValue } from '@/components/ui/key-value';
|
||||
import { Widget, WidgetBody, WidgetHead } from '@/components/Widget';
|
||||
import {
|
||||
@@ -12,25 +10,21 @@ import {
|
||||
eventQueryNamesFilter,
|
||||
} from '@/hooks/useEventQueryFilters';
|
||||
import { getExists } from '@/server/pageExists';
|
||||
import { formatDateTime } from '@/utils/date';
|
||||
import { getProfileName } from '@/utils/getters';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { parseAsInteger } from 'nuqs';
|
||||
import { parseAsInteger, parseAsString } from 'nuqs';
|
||||
|
||||
import type { GetEventListOptions } from '@mixan/db';
|
||||
import {
|
||||
getConversionEventNames,
|
||||
getEventList,
|
||||
getEventMeta,
|
||||
getEventsCount,
|
||||
getProfileById,
|
||||
getProfilesByExternalId,
|
||||
} from '@mixan/db';
|
||||
import type { IChartInput } from '@mixan/validation';
|
||||
import type { IChartEvent, IChartInput } from '@mixan/validation';
|
||||
|
||||
import { EventList } from '../../events/event-list';
|
||||
import { StickyBelowHeader } from '../../layout-sticky-below-header';
|
||||
import ListProfileEvents from './list-profile-events';
|
||||
|
||||
interface PageProps {
|
||||
params: {
|
||||
@@ -42,6 +36,8 @@ interface PageProps {
|
||||
events?: string;
|
||||
cursor?: string;
|
||||
f?: string;
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -57,6 +53,8 @@ export default async function Page({
|
||||
events: eventQueryNamesFilter.parse(searchParams.events ?? ''),
|
||||
filters: eventQueryFiltersParser.parse(searchParams.f ?? '') ?? undefined,
|
||||
};
|
||||
const startDate = parseAsString.parse(searchParams.startDate);
|
||||
const endDate = parseAsString.parse(searchParams.endDate);
|
||||
const [profile, events, count, conversions] = await Promise.all([
|
||||
getProfileById(profileId),
|
||||
getEventList(eventListOptions),
|
||||
@@ -65,7 +63,7 @@ export default async function Page({
|
||||
getExists(organizationId, projectId),
|
||||
]);
|
||||
|
||||
const chartSelectedEvents = [
|
||||
const chartSelectedEvents: IChartEvent[] = [
|
||||
{
|
||||
segment: 'event',
|
||||
filters: [
|
||||
@@ -107,6 +105,8 @@ export default async function Page({
|
||||
|
||||
const profileChart: IChartInput = {
|
||||
projectId,
|
||||
startDate,
|
||||
endDate,
|
||||
chartType: 'histogram',
|
||||
events: chartSelectedEvents,
|
||||
breakdowns: [],
|
||||
|
||||
@@ -10,6 +10,9 @@ import { ReportRange } from '@/components/report/ReportRange';
|
||||
import { ReportSaveButton } from '@/components/report/ReportSaveButton';
|
||||
import {
|
||||
changeDateRanges,
|
||||
changeDates,
|
||||
changeEndDate,
|
||||
changeStartDate,
|
||||
ready,
|
||||
reset,
|
||||
setReport,
|
||||
@@ -19,6 +22,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { useDispatch, useSelector } from '@/redux';
|
||||
import { endOfDay, startOfDay } from 'date-fns';
|
||||
import { GanttChartSquareIcon } from 'lucide-react';
|
||||
|
||||
import type { IServiceReport } from '@mixan/db';
|
||||
@@ -61,10 +65,30 @@ export default function ReportEditor({
|
||||
<ReportChartType className="min-w-0 flex-1" />
|
||||
<ReportRange
|
||||
className="min-w-0 flex-1"
|
||||
value={report.range}
|
||||
onChange={(value) => {
|
||||
range={report.range}
|
||||
onRangeChange={(value) => {
|
||||
dispatch(changeDateRanges(value));
|
||||
}}
|
||||
dates={{
|
||||
startDate: report.startDate,
|
||||
endDate: report.endDate,
|
||||
}}
|
||||
onDatesChange={(val) => {
|
||||
if (!val) return;
|
||||
|
||||
if (val.from && val.to) {
|
||||
dispatch(
|
||||
changeDates({
|
||||
startDate: startOfDay(val.from).toISOString(),
|
||||
endDate: endOfDay(val.to).toISOString(),
|
||||
})
|
||||
);
|
||||
} else if (val.from) {
|
||||
dispatch(changeStartDate(startOfDay(val.from).toISOString()));
|
||||
} else if (val.to) {
|
||||
dispatch(changeEndDate(endOfDay(val.to).toISOString()));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<ReportInterval className="min-w-0 flex-1" />
|
||||
<ReportLineType className="min-w-0 flex-1" />
|
||||
|
||||
Reference in New Issue
Block a user