Skip to content

Commit 79e2333

Browse files
committed
fix: date ranges, working stuff
1 parent 9fed8f7 commit 79e2333

File tree

10 files changed

+164
-319
lines changed

10 files changed

+164
-319
lines changed

apps/dashboard/app/(main)/websites/[id]/errors/_components/errors-page-content.tsx

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@
22

33
import type { DateRange, DynamicQueryFilter } from '@databuddy/shared';
44
import { ArrowClockwiseIcon, BugIcon } from '@phosphor-icons/react';
5+
import { useAtom } from 'jotai';
56
import { use, useCallback, useEffect, useMemo, useState } from 'react';
67
import { toast } from 'sonner';
78
import { AnimatedLoading } from '@/components/analytics/animated-loading';
89
import { Button } from '@/components/ui/button';
910
import { Card, CardContent } from '@/components/ui/card';
1011
import { useEnhancedErrorData } from '@/hooks/use-dynamic-query';
12+
import {
13+
formattedDateRangeAtom,
14+
isAnalyticsRefreshingAtom,
15+
timeGranularityAtom,
16+
} from '@/stores/jotai/filterAtoms';
1117
import { WebsitePageHeader } from '../../_components/website-page-header';
1218
import { ErrorDataTable } from './error-data-table';
1319
// Import our separated components
@@ -25,16 +31,19 @@ export const ErrorsPageContent = ({ params }: ErrorsPageContentProps) => {
2531
const resolvedParams = use(params);
2632
const websiteId = resolvedParams.id;
2733

28-
// Default to last 7 days
29-
const dateRange: DateRange = {
30-
start_date: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
31-
.toISOString()
32-
.split('T')[0],
33-
end_date: new Date().toISOString().split('T')[0],
34-
granularity: 'daily',
35-
};
36-
37-
const [isRefreshing, setIsRefreshing] = useState(false);
34+
// Use shared date range and refresh state
35+
const [formattedDateRangeState] = useAtom(formattedDateRangeAtom);
36+
const [currentGranularity] = useAtom(timeGranularityAtom);
37+
const [isRefreshing, setIsRefreshing] = useAtom(isAnalyticsRefreshingAtom);
38+
39+
const dateRange: DateRange = useMemo(
40+
() => ({
41+
start_date: formattedDateRangeState.startDate,
42+
end_date: formattedDateRangeState.endDate,
43+
granularity: currentGranularity,
44+
}),
45+
[formattedDateRangeState, currentGranularity]
46+
);
3847
const [loadingProgress, setLoadingProgress] = useState<number>(0);
3948

4049
// Filters state

apps/dashboard/app/(main)/websites/[id]/experiments/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22

33
import { FlaskIcon } from '@phosphor-icons/react';
4+
import { useAtom } from 'jotai';
45
import { useParams } from 'next/navigation';
56
import { Suspense, useCallback, useEffect, useRef, useState } from 'react';
67
import { Card, CardContent } from '@/components/ui/card';
@@ -10,6 +11,7 @@ import {
1011
useExperiments,
1112
} from '@/hooks/use-experiments';
1213
import { useWebsite } from '@/hooks/use-websites';
14+
import { isAnalyticsRefreshingAtom } from '@/stores/jotai/filterAtoms';
1315
import { WebsitePageHeader } from '../_components/website-page-header';
1416
import { DeleteExperimentDialog } from './_components/delete-experiment-dialog';
1517
import { ExperimentFormDialog } from './_components/experiment-form-dialog';
@@ -73,7 +75,7 @@ const ExperimentsListSkeleton = () => (
7375
export default function ExperimentsPage() {
7476
const { id } = useParams();
7577
const websiteId = id as string;
76-
const [isRefreshing, setIsRefreshing] = useState(false);
78+
const [isRefreshing, setIsRefreshing] = useAtom(isAnalyticsRefreshingAtom);
7779
const [isDialogOpen, setIsDialogOpen] = useState(false);
7880
const [editingExperiment, setEditingExperiment] = useState<Experiment | null>(
7981
null

apps/dashboard/app/(main)/websites/[id]/funnels/page.tsx

Lines changed: 3 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
'use client';
22

33
import { FunnelIcon, TrendDownIcon } from '@phosphor-icons/react';
4-
import dayjs from 'dayjs';
4+
55
import { useAtom } from 'jotai';
66
import { useParams } from 'next/navigation';
77
import { lazy, Suspense, useCallback, useMemo, useRef, useState } from 'react';
8-
import type { DateRange as DayPickerRange } from 'react-day-picker';
9-
import { DateRangePicker } from '@/components/date-range-picker';
10-
import { Button } from '@/components/ui/button';
118
import { Card, CardContent } from '@/components/ui/card';
129
import {
1310
type CreateFunnelData,
@@ -19,9 +16,8 @@ import {
1916
} from '@/hooks/use-funnels';
2017
import { useTrackingSetup } from '@/hooks/use-tracking-setup';
2118
import {
22-
dateRangeAtom,
2319
formattedDateRangeAtom,
24-
setDateRangeAndAdjustGranularityAtom,
20+
isAnalyticsRefreshingAtom,
2521
timeGranularityAtom,
2622
} from '@/stores/jotai/filterAtoms';
2723
import { WebsitePageHeader } from '../_components/website-page-header';
@@ -90,7 +86,7 @@ const FunnelsListSkeleton = () => (
9086
export default function FunnelsPage() {
9187
const { id } = useParams();
9288
const websiteId = id as string;
93-
const [isRefreshing, setIsRefreshing] = useState(false);
89+
const [isRefreshing, setIsRefreshing] = useAtom(isAnalyticsRefreshingAtom);
9490
const [expandedFunnelId, setExpandedFunnelId] = useState<string | null>(null);
9591
const [selectedReferrer, setSelectedReferrer] = useState('all');
9692
const [isDialogOpen, setIsDialogOpen] = useState(false);
@@ -101,46 +97,12 @@ export default function FunnelsPage() {
10197
const pageRef = useRef<HTMLDivElement>(null);
10298

10399
// Date range state
104-
const [currentDateRange] = useAtom(dateRangeAtom);
105100
const [currentGranularity] = useAtom(timeGranularityAtom);
106-
const [, setDateRangeAction] = useAtom(setDateRangeAndAdjustGranularityAtom);
107101
const [formattedDateRangeState] = useAtom(formattedDateRangeAtom);
108102

109103
const { isTrackingSetup, refetchTrackingSetup } = useTrackingSetup(websiteId);
110104

111-
// Date picker helpers
112-
const dayPickerSelectedRange: DayPickerRange | undefined = useMemo(
113-
() => ({
114-
from: currentDateRange.startDate,
115-
to: currentDateRange.endDate,
116-
}),
117-
[currentDateRange]
118-
);
119-
120-
const quickRanges = useMemo(
121-
() => [
122-
{ label: '24h', fullLabel: 'Last 24 hours', hours: 24 },
123-
{ label: '7d', fullLabel: 'Last 7 days', days: 7 },
124-
{ label: '30d', fullLabel: 'Last 30 days', days: 30 },
125-
{ label: '90d', fullLabel: 'Last 90 days', days: 90 },
126-
{ label: '180d', fullLabel: 'Last 180 days', days: 180 },
127-
{ label: '365d', fullLabel: 'Last 365 days', days: 365 },
128-
],
129-
[]
130-
);
131105

132-
const handleQuickRangeSelect = useCallback(
133-
(range: (typeof quickRanges)[0]) => {
134-
const now = new Date();
135-
const start = range.hours
136-
? dayjs(now).subtract(range.hours, 'hour').toDate()
137-
: dayjs(now)
138-
.subtract(range.days || 7, 'day')
139-
.toDate();
140-
setDateRangeAction({ startDate: start, endDate: now });
141-
},
142-
[setDateRangeAction]
143-
);
144106

145107
const memoizedDateRangeForTabs = useMemo(
146108
() => ({
@@ -325,60 +287,7 @@ export default function FunnelsPage() {
325287
websiteId={websiteId}
326288
/>
327289

328-
{/* Date Range Controls - Only show if tracking is set up */}
329-
{isTrackingSetup && (
330-
<div className="mt-3 flex flex-col gap-3 rounded-lg border bg-muted/30 p-2.5">
331-
<div className="flex items-center gap-2 overflow-x-auto rounded-md border bg-background p-1 shadow-sm">
332-
{quickRanges.map((range) => {
333-
const now = new Date();
334-
const start = range.hours
335-
? dayjs(now).subtract(range.hours, 'hour').toDate()
336-
: dayjs(now)
337-
.subtract(range.days || 7, 'day')
338-
.toDate();
339-
const dayPickerCurrentRange = dayPickerSelectedRange;
340-
const isActive =
341-
dayPickerCurrentRange?.from &&
342-
dayPickerCurrentRange?.to &&
343-
dayjs(dayPickerCurrentRange.from).format('YYYY-MM-DD') ===
344-
dayjs(start).format('YYYY-MM-DD') &&
345-
dayjs(dayPickerCurrentRange.to).format('YYYY-MM-DD') ===
346-
dayjs(now).format('YYYY-MM-DD');
347290

348-
return (
349-
<Button
350-
className={`h-6 cursor-pointer touch-manipulation whitespace-nowrap px-2 text-xs sm:px-2.5 ${isActive ? 'shadow-sm' : 'text-muted-foreground hover:text-foreground'}`}
351-
key={range.label}
352-
onClick={() => handleQuickRangeSelect(range)}
353-
size="sm"
354-
title={range.fullLabel}
355-
variant={isActive ? 'default' : 'ghost'}
356-
>
357-
<span className="sm:hidden">{range.label}</span>
358-
<span className="hidden sm:inline">{range.fullLabel}</span>
359-
</Button>
360-
);
361-
})}
362-
363-
<div className="ml-1 border-border/50 border-l pl-2 sm:pl-3">
364-
<DateRangePicker
365-
className="w-auto"
366-
maxDate={new Date()}
367-
minDate={new Date(2020, 0, 1)}
368-
onChange={(range) => {
369-
if (range?.from && range?.to) {
370-
setDateRangeAction({
371-
startDate: range.from,
372-
endDate: range.to,
373-
});
374-
}
375-
}}
376-
value={dayPickerSelectedRange}
377-
/>
378-
</div>
379-
</div>
380-
</div>
381-
)}
382291

383292
<Suspense fallback={<FunnelsListSkeleton />}>
384293
<FunnelsList

apps/dashboard/app/(main)/websites/[id]/goals/page.tsx

Lines changed: 2 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use client';
22

33
import { TargetIcon } from '@phosphor-icons/react';
4-
import dayjs from 'dayjs';
54
import { useAtom } from 'jotai';
65
import { useParams } from 'next/navigation';
76
import {
@@ -12,9 +11,6 @@ import {
1211
useRef,
1312
useState,
1413
} from 'react';
15-
import type { DateRange as DayPickerRange } from 'react-day-picker';
16-
import { DateRangePicker } from '@/components/date-range-picker';
17-
import { Button } from '@/components/ui/button';
1814
import { Card, CardContent } from '@/components/ui/card';
1915
import { useAutocompleteData } from '@/hooks/use-funnels';
2016
import {
@@ -26,9 +22,8 @@ import {
2622
import { useTrackingSetup } from '@/hooks/use-tracking-setup';
2723
import { useWebsite } from '@/hooks/use-websites';
2824
import {
29-
dateRangeAtom,
3025
formattedDateRangeAtom,
31-
setDateRangeAndAdjustGranularityAtom,
26+
isAnalyticsRefreshingAtom,
3227
timeGranularityAtom,
3328
} from '@/stores/jotai/filterAtoms';
3429
import { WebsitePageHeader } from '../_components/website-page-header';
@@ -74,7 +69,7 @@ const GoalsListSkeleton = () => (
7469
export default function GoalsPage() {
7570
const { id } = useParams();
7671
const websiteId = id as string;
77-
const [isRefreshing, setIsRefreshing] = useState(false);
72+
const [isRefreshing, setIsRefreshing] = useAtom(isAnalyticsRefreshingAtom);
7873
const [isDialogOpen, setIsDialogOpen] = useState(false);
7974
const [editingGoal, setEditingGoal] = useState<Goal | null>(null);
8075
const [deletingGoalId, setDeletingGoalId] = useState<string | null>(null);
@@ -100,46 +95,9 @@ export default function GoalsPage() {
10095
return () => observer.disconnect();
10196
}, []);
10297

103-
const [currentDateRange] = useAtom(dateRangeAtom);
10498
const [currentGranularity] = useAtom(timeGranularityAtom);
105-
const [, setDateRangeAction] = useAtom(setDateRangeAndAdjustGranularityAtom);
10699
const [formattedDateRangeState] = useAtom(formattedDateRangeAtom);
107100

108-
const { isTrackingSetup } = useTrackingSetup(websiteId);
109-
110-
const dayPickerSelectedRange: DayPickerRange | undefined = useMemo(
111-
() => ({
112-
from: currentDateRange.startDate,
113-
to: currentDateRange.endDate,
114-
}),
115-
[currentDateRange]
116-
);
117-
118-
const quickRanges = useMemo(
119-
() => [
120-
{ label: '24h', fullLabel: 'Last 24 hours', hours: 24 },
121-
{ label: '7d', fullLabel: 'Last 7 days', days: 7 },
122-
{ label: '30d', fullLabel: 'Last 30 days', days: 30 },
123-
{ label: '90d', fullLabel: 'Last 90 days', days: 90 },
124-
{ label: '180d', fullLabel: 'Last 180 days', days: 180 },
125-
{ label: '365d', fullLabel: 'Last 365 days', days: 365 },
126-
],
127-
[]
128-
);
129-
130-
const handleQuickRangeSelect = useCallback(
131-
(range: (typeof quickRanges)[0]) => {
132-
const now = new Date();
133-
const start = range.hours
134-
? dayjs(now).subtract(range.hours, 'hour').toDate()
135-
: dayjs(now)
136-
.subtract(range.days || 7, 'day')
137-
.toDate();
138-
setDateRangeAction({ startDate: start, endDate: now });
139-
},
140-
[setDateRangeAction]
141-
);
142-
143101
const memoizedDateRangeForTabs = useMemo(
144102
() => ({
145103
start_date: formattedDateRangeState.startDate,
@@ -284,59 +242,7 @@ export default function GoalsPage() {
284242
websiteName={websiteData?.name || undefined}
285243
/>
286244

287-
{isTrackingSetup && (
288-
<div className="mt-3 flex flex-col gap-3 rounded-lg border bg-muted/30 p-2.5">
289-
<div className="flex items-center gap-2 overflow-x-auto rounded-md border bg-background p-1 shadow-sm">
290-
{quickRanges.map((range) => {
291-
const now = new Date();
292-
const start = range.hours
293-
? dayjs(now).subtract(range.hours, 'hour').toDate()
294-
: dayjs(now)
295-
.subtract(range.days || 7, 'day')
296-
.toDate();
297-
const dayPickerCurrentRange = dayPickerSelectedRange;
298-
const isActive =
299-
dayPickerCurrentRange?.from &&
300-
dayPickerCurrentRange?.to &&
301-
dayjs(dayPickerCurrentRange.from).format('YYYY-MM-DD') ===
302-
dayjs(start).format('YYYY-MM-DD') &&
303-
dayjs(dayPickerCurrentRange.to).format('YYYY-MM-DD') ===
304-
dayjs(now).format('YYYY-MM-DD');
305-
306-
return (
307-
<Button
308-
className={`h-6 cursor-pointer touch-manipulation whitespace-nowrap px-2 text-xs sm:px-2.5 ${isActive ? 'shadow-sm' : 'text-muted-foreground hover:text-foreground'}`}
309-
key={range.label}
310-
onClick={() => handleQuickRangeSelect(range)}
311-
size="sm"
312-
title={range.fullLabel}
313-
variant={isActive ? 'default' : 'ghost'}
314-
>
315-
<span className="sm:hidden">{range.label}</span>
316-
<span className="hidden sm:inline">{range.fullLabel}</span>
317-
</Button>
318-
);
319-
})}
320245

321-
<div className="ml-1 border-border/50 border-l pl-2 sm:pl-3">
322-
<DateRangePicker
323-
className="w-auto"
324-
maxDate={new Date()}
325-
minDate={new Date(2020, 0, 1)}
326-
onChange={(range) => {
327-
if (range?.from && range?.to) {
328-
setDateRangeAction({
329-
startDate: range.from,
330-
endDate: range.to,
331-
});
332-
}
333-
}}
334-
value={dayPickerSelectedRange}
335-
/>
336-
</div>
337-
</div>
338-
</div>
339-
)}
340246

341247
{isVisible && (
342248
<Suspense fallback={<GoalsListSkeleton />}>

0 commit comments

Comments
 (0)