improved date range selector with hotkeys

This commit is contained in:
Carl-Gerhard Lindesvärd
2024-04-27 09:52:24 +02:00
parent e2d56fb34f
commit 4059dad727
24 changed files with 520 additions and 319 deletions

View File

@@ -0,0 +1,65 @@
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Calendar } from '@/components/ui/calendar';
import { useBreakpoint } from '@/hooks/useBreakpoint';
import { subMonths } from 'date-fns';
import { popModal } from '.';
import { ModalContent, ModalHeader } from './Modal/Container';
type Props = {
onChange: (payload: { startDate: Date; endDate: Date }) => void;
startDate?: Date;
endDate?: Date;
};
export default function DateRangerPicker({
onChange,
startDate: initialStartDate,
endDate: initialEndDate,
}: Props) {
const { isBelowSm } = useBreakpoint('sm');
const [startDate, setStartDate] = useState(initialStartDate);
const [endDate, setEndDate] = useState(initialEndDate);
return (
<ModalContent className="max-w-[600px]">
<ModalHeader title="Pick a date range" className="mb-0" />
<Calendar
initialFocus
mode="range"
defaultMonth={subMonths(
startDate ? new Date(startDate) : new Date(),
isBelowSm ? 0 : 1
)}
selected={{
from: startDate,
to: endDate,
}}
toDate={new Date()}
onSelect={(range) => {
if (range?.from) {
setStartDate(range.from);
}
if (range?.to) {
setEndDate(range.to);
}
}}
numberOfMonths={isBelowSm ? 1 : 2}
className="min-h-[350px] [&_table]:mx-auto [&_table]:w-auto"
/>
<Button
className="mt-8"
onClick={() => {
popModal();
if (startDate && endDate) {
onChange({
startDate: startDate,
endDate: endDate,
});
}
}}
>
Select
</Button>
</ModalContent>
);
}

View File

@@ -2,6 +2,7 @@
import { Button } from '@/components/ui/button';
import { DialogContent } from '@/components/ui/dialog';
import { cn } from '@/utils/cn';
import type { DialogContentProps } from '@radix-ui/react-dialog';
import { X } from 'lucide-react';
@@ -19,11 +20,17 @@ interface ModalHeaderProps {
title: string | React.ReactNode;
text?: string | React.ReactNode;
onClose?: (() => void) | false;
className?: string;
}
export function ModalHeader({ title, text, onClose }: ModalHeaderProps) {
export function ModalHeader({
title,
text,
onClose,
className,
}: ModalHeaderProps) {
return (
<div className="mb-6 flex justify-between">
<div className={cn('mb-6 flex justify-between', className)}>
<div>
<div className="mt-0.5 font-medium">{title}</div>
{!!text && <div className="text-sm text-muted-foreground">{text}</div>}

View File

@@ -59,11 +59,19 @@ const modals = {
FunnelStepDetails: dynamic(() => import('./FunnelStepDetails'), {
loading: Loading,
}),
DateRangerPicker: dynamic(() => import('./DateRangerPicker'), {
loading: Loading,
}),
};
export const { pushModal, popModal, popAllModals, ModalProvider } =
createPushModal({
modals,
});
export const {
pushModal,
popModal,
popAllModals,
ModalProvider,
useOnPushModal,
} = createPushModal({
modals,
});
export const showConfirm = (props: ConfirmProps) => pushModal('Confirm', props);