improved date range selector with hotkeys
This commit is contained in:
65
apps/dashboard/src/modals/DateRangerPicker.tsx
Normal file
65
apps/dashboard/src/modals/DateRangerPicker.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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>}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user