umami/src/components/input/DateFilter.tsx

179 lines
4.2 KiB
TypeScript
Raw Normal View History

import { useState } from 'react';
import { Icon, Modal, Dropdown, Item, Text, Flexbox } from 'react-basics';
import { endOfYear, isSameDay } from 'date-fns';
import DatePickerForm from 'components/metrics/DatePickerForm';
2024-02-03 07:35:46 +01:00
import { useLocale, useMessages } from 'components/hooks';
2023-12-03 12:07:03 +01:00
import Icons from 'components/icons';
2024-01-30 22:46:16 +01:00
import { formatDate, parseDateValue } from 'lib/date';
2023-12-03 12:07:03 +01:00
export interface DateFilterProps {
value: string;
startDate: Date;
endDate: Date;
2024-02-01 07:08:48 +01:00
offset?: number;
2023-12-03 12:07:03 +01:00
className?: string;
onChange?: (value: string) => void;
showAllTime?: boolean;
alignment?: 'start' | 'center' | 'end';
}
2023-05-18 08:20:06 +02:00
export function DateFilter({
startDate,
endDate,
2024-01-30 22:46:16 +01:00
value,
2024-02-01 07:08:48 +01:00
offset = 0,
2023-05-18 08:20:06 +02:00
className,
onChange,
showAllTime = false,
alignment = 'end',
2023-12-03 12:07:03 +01:00
}: DateFilterProps) {
2023-03-22 22:05:55 +01:00
const { formatMessage, labels } = useMessages();
2020-09-13 10:26:54 +02:00
const [showPicker, setShowPicker] = useState(false);
2024-01-30 22:46:16 +01:00
const { locale } = useLocale();
const options = [
2024-03-20 23:29:59 +01:00
{ label: formatMessage(labels.today), value: '0day' },
{
label: formatMessage(labels.lastHours, { x: 24 }),
value: '24hour',
},
{
label: formatMessage(labels.thisWeek),
2024-03-20 23:29:59 +01:00
value: '0week',
divider: true,
},
{
label: formatMessage(labels.lastDays, { x: 7 }),
value: '7day',
},
{
label: formatMessage(labels.thisMonth),
2024-03-20 23:29:59 +01:00
value: '0month',
divider: true,
},
{
label: formatMessage(labels.lastDays, { x: 30 }),
value: '30day',
},
{
label: formatMessage(labels.lastDays, { x: 90 }),
value: '90day',
},
2024-03-20 23:29:59 +01:00
{ label: formatMessage(labels.thisYear), value: '0year' },
2023-05-18 08:20:06 +02:00
showAllTime && {
label: formatMessage(labels.allTime),
value: 'all',
divider: true,
},
{
label: formatMessage(labels.customRange),
value: 'custom',
divider: true,
},
2023-04-25 23:41:54 +02:00
].filter(n => n);
2023-12-03 12:07:03 +01:00
const handleChange = (value: string) => {
2020-09-13 10:26:54 +02:00
if (value === 'custom') {
setShowPicker(true);
return;
}
2023-05-18 08:20:06 +02:00
onChange(value);
};
2023-12-03 12:07:03 +01:00
const handlePickerChange = (value: string) => {
2020-09-13 10:26:54 +02:00
setShowPicker(false);
2023-05-18 08:20:06 +02:00
onChange(value);
};
const handleClose = () => setShowPicker(false);
2020-09-13 10:26:54 +02:00
2024-01-30 22:46:16 +01:00
const renderValue = (value: string) => {
const { unit } = parseDateValue(value) || {};
2024-01-30 22:46:16 +01:00
if (offset && unit === 'year') {
return formatDate(startDate, 'yyyy', locale);
}
if (offset && unit === 'month') {
return formatDate(startDate, 'MMMM yyyy', locale);
}
if (value.startsWith('range') || offset) {
return (
<CustomRange
startDate={startDate}
endDate={endDate}
unit={unit}
onClick={() => handleChange('custom')}
/>
);
}
2024-03-27 10:06:16 +01:00
return options.find(e => e.value === value)?.label;
2024-01-30 22:46:16 +01:00
};
2020-08-02 06:20:52 +02:00
return (
2020-09-13 10:26:54 +02:00
<>
<Dropdown
2020-09-13 10:26:54 +02:00
className={className}
items={options}
renderValue={renderValue}
value={value}
2023-05-18 08:20:06 +02:00
alignment={alignment}
placeholder={formatMessage(labels.selectDate)}
2024-01-19 01:46:40 +01:00
onChange={key => handleChange(key as any)}
>
{({ label, value, divider }) => (
<Item key={value} divider={divider}>
{label}
</Item>
)}
</Dropdown>
2020-09-13 10:26:54 +02:00
{showPicker && (
<Modal onClose={handleClose}>
2020-09-13 10:26:54 +02:00
<DatePickerForm
startDate={startDate}
endDate={endDate}
minDate={new Date(2000, 0, 1)}
maxDate={endOfYear(new Date())}
onChange={handlePickerChange}
onClose={() => setShowPicker(false)}
/>
</Modal>
)}
</>
2020-08-02 06:20:52 +02:00
);
}
2024-01-30 22:46:16 +01:00
const CustomRange = ({ startDate, endDate, unit, onClick }) => {
const { locale } = useLocale();
2024-01-30 22:46:16 +01:00
const monthFormat = unit === 'month';
2023-08-22 00:53:19 +02:00
function handleClick(e) {
e.stopPropagation();
onClick();
}
return (
<Flexbox gap={10} alignItems="center" wrap="nowrap">
<Icon className="mr-2" onClick={handleClick}>
<Icons.Calendar />
</Icon>
<Text>
2023-08-22 00:53:19 +02:00
{monthFormat ? (
<>{formatDate(startDate, 'MMMM yyyy', locale)}</>
) : (
<>
{formatDate(startDate, 'd LLL y', locale)}
{!isSameDay(startDate, endDate) && `${formatDate(endDate, 'd LLL y', locale)}`}
</>
)}
</Text>
</Flexbox>
);
};
export default DateFilter;