Files
stats/apps/start/src/components/time-window-picker.tsx
Carl-Gerhard Lindesvärd 81a7e5d62e feat: dashboard v2, esm, upgrades (#211)
* esm

* wip

* wip

* wip

* wip

* wip

* wip

* subscription notice

* wip

* wip

* wip

* fix envs

* fix: update docker build

* fix

* esm/types

* delete dashboard :D

* add patches to dockerfiles

* update packages + catalogs + ts

* wip

* remove native libs

* ts

* improvements

* fix redirects and fetching session

* try fix favicon

* fixes

* fix

* order and resize reportds within a dashboard

* improvements

* wip

* added userjot to dashboard

* fix

* add op

* wip

* different cache key

* improve date picker

* fix table

* event details loading

* redo onboarding completely

* fix login

* fix

* fix

* extend session, billing and improve bars

* fix

* reduce price on 10M
2025-10-16 12:27:44 +02:00

206 lines
6.6 KiB
TypeScript

import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { pushModal, useOnPushModal } from '@/modals';
import { cn } from '@/utils/cn';
import { bind } from 'bind-event-listener';
import { CalendarIcon } from 'lucide-react';
import { useCallback, useEffect, useRef } from 'react';
import { shouldIgnoreKeypress } from '@/utils/should-ignore-keypress';
import { timeWindows } from '@openpanel/constants';
import type { IChartRange } from '@openpanel/validation';
import { endOfDay, format, startOfDay } from 'date-fns';
type Props = {
value: IChartRange;
onChange: (value: IChartRange) => void;
onStartDateChange: (date: string) => void;
onEndDateChange: (date: string) => void;
endDate: string | null;
startDate: string | null;
className?: string;
};
export function TimeWindowPicker({
value,
onChange,
startDate,
onStartDateChange,
endDate,
onEndDateChange,
className,
}: Props) {
const isDateRangerPickerOpen = useRef(false);
useOnPushModal('DateRangerPicker', (open) => {
isDateRangerPickerOpen.current = open;
});
const timeWindow = timeWindows[value ?? '30d'];
const handleCustom = useCallback(() => {
pushModal('DateRangerPicker', {
onChange: ({ startDate, endDate }) => {
onStartDateChange(format(startOfDay(startDate), 'yyyy-MM-dd HH:mm:ss'));
onEndDateChange(format(endOfDay(endDate), 'yyyy-MM-dd HH:mm:ss'));
onChange('custom');
},
startDate: startDate ? new Date(startDate) : undefined,
endDate: endDate ? new Date(endDate) : undefined,
});
}, [startDate, endDate]);
useEffect(() => {
return bind(document, {
type: 'keydown',
listener(event) {
if (shouldIgnoreKeypress(event)) {
return;
}
if (isDateRangerPickerOpen.current) {
return;
}
const match = Object.values(timeWindows).find(
(tw) => event.key === tw.shortcut.toLowerCase(),
);
if (match?.key === 'custom') {
handleCustom();
} else if (match) {
onChange(match.key);
}
},
});
}, [handleCustom]);
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
icon={CalendarIcon}
className={cn('justify-start', className)}
>
{timeWindow?.label}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56">
<DropdownMenuLabel>Time window</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem onClick={() => onChange(timeWindows['30min'].key)}>
{timeWindows['30min'].label}
<DropdownMenuShortcut>
{timeWindows['30min'].shortcut}
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onChange(timeWindows.lastHour.key)}>
{timeWindows.lastHour.label}
<DropdownMenuShortcut>
{timeWindows.lastHour.shortcut}
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onChange(timeWindows.today.key)}>
{timeWindows.today.label}
<DropdownMenuShortcut>
{timeWindows.today.shortcut}
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onChange(timeWindows.yesterday.key)}>
{timeWindows.yesterday.label}
<DropdownMenuShortcut>
{timeWindows.yesterday.shortcut}
</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem onClick={() => onChange(timeWindows['7d'].key)}>
{timeWindows['7d'].label}
<DropdownMenuShortcut>
{timeWindows['7d'].shortcut}
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onChange(timeWindows['30d'].key)}>
{timeWindows['30d'].label}
<DropdownMenuShortcut>
{timeWindows['30d'].shortcut}
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onChange(timeWindows['6m'].key)}>
{timeWindows['6m'].label}
<DropdownMenuShortcut>
{timeWindows['6m'].shortcut}
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onChange(timeWindows['12m'].key)}>
{timeWindows['12m'].label}
<DropdownMenuShortcut>
{timeWindows['12m'].shortcut}
</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem
onClick={() => onChange(timeWindows.monthToDate.key)}
>
{timeWindows.monthToDate.label}
<DropdownMenuShortcut>
{timeWindows.monthToDate.shortcut}
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onChange(timeWindows.lastMonth.key)}>
{timeWindows.lastMonth.label}
<DropdownMenuShortcut>
{timeWindows.lastMonth.shortcut}
</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem
onClick={() => onChange(timeWindows.yearToDate.key)}
>
{timeWindows.yearToDate.label}
<DropdownMenuShortcut>
{timeWindows.yearToDate.shortcut}
</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onChange(timeWindows.lastYear.key)}>
{timeWindows.lastYear.label}
<DropdownMenuShortcut>
{timeWindows.lastYear.shortcut}
</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem onClick={() => handleCustom()}>
{timeWindows.custom.label}
<DropdownMenuShortcut>
{timeWindows.custom.shortcut}
</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
);
}