Files
helix-engage/src/components/application/date-picker/date-range-picker.tsx
saridsa2 6f40b82579 refactor: migrate all icons from Untitled UI to FontAwesome Pro Duotone
Replace all @untitledui/icons imports across 55 files with equivalent
@fortawesome/pro-duotone-svg-icons icons, using FontAwesomeIcon wrappers
(FC<{ className?: string }>) for prop-based usage and inline replacements
for direct JSX usage. Drops unsupported Untitled UI-specific props
(strokeWidth, numeric size). TypeScript compiles clean with no errors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 11:07:19 +05:30

166 lines
8.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { FC } from "react";
import { useMemo, useState } from "react";
import { endOfMonth, endOfWeek, getLocalTimeZone, startOfMonth, startOfWeek, today } from "@internationalized/date";
import { useControlledState } from "@react-stately/utils";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCalendar } from "@fortawesome/pro-duotone-svg-icons";
const CalendarIcon: FC<{ className?: string }> = ({ className }) => <FontAwesomeIcon icon={faCalendar} className={className} />;
import { useDateFormatter } from "react-aria";
import type { DateRangePickerProps as AriaDateRangePickerProps, DateValue } from "react-aria-components";
import { DateRangePicker as AriaDateRangePicker, Dialog as AriaDialog, Group as AriaGroup, Popover as AriaPopover, useLocale } from "react-aria-components";
import { Button } from "@/components/base/buttons/button";
import { cx } from "@/utils/cx";
import { DateInput } from "./date-input";
import { RangeCalendar } from "./range-calendar";
import { RangePresetButton } from "./range-preset";
const now = today(getLocalTimeZone());
const highlightedDates = [today(getLocalTimeZone())];
interface DateRangePickerProps extends AriaDateRangePickerProps<DateValue> {
/** The function to call when the apply button is clicked. */
onApply?: () => void;
/** The function to call when the cancel button is clicked. */
onCancel?: () => void;
}
export const DateRangePicker = ({ value: valueProp, defaultValue, onChange, onApply, onCancel, ...props }: DateRangePickerProps) => {
const { locale } = useLocale();
const formatter = useDateFormatter({
month: "short",
day: "numeric",
year: "numeric",
});
const [value, setValue] = useControlledState(valueProp, defaultValue || null, onChange);
const [focusedValue, setFocusedValue] = useState<DateValue | null>(null);
const formattedStartDate = value?.start ? formatter.format(value.start.toDate(getLocalTimeZone())) : "Select date";
const formattedEndDate = value?.end ? formatter.format(value.end.toDate(getLocalTimeZone())) : "Select date";
const presets = useMemo(
() => ({
today: { label: "Today", value: { start: now, end: now } },
yesterday: { label: "Yesterday", value: { start: now.subtract({ days: 1 }), end: now.subtract({ days: 1 }) } },
thisWeek: { label: "This week", value: { start: startOfWeek(now, locale), end: endOfWeek(now, locale) } },
lastWeek: {
label: "Last week",
value: {
start: startOfWeek(now, locale).subtract({ weeks: 1 }),
end: endOfWeek(now, locale).subtract({ weeks: 1 }),
},
},
thisMonth: { label: "This month", value: { start: startOfMonth(now), end: endOfMonth(now) } },
lastMonth: {
label: "Last month",
value: {
start: startOfMonth(now).subtract({ months: 1 }),
end: endOfMonth(now).subtract({ months: 1 }),
},
},
thisYear: { label: "This year", value: { start: startOfMonth(now.set({ month: 1 })), end: endOfMonth(now.set({ month: 12 })) } },
lastYear: {
label: "Last year",
value: {
start: startOfMonth(now.set({ month: 1 }).subtract({ years: 1 })),
end: endOfMonth(now.set({ month: 12 }).subtract({ years: 1 })),
},
},
allTime: {
label: "All time",
value: {
start: now.set({ year: 2000, month: 1, day: 1 }),
end: now,
},
},
}),
[locale],
);
return (
<AriaDateRangePicker aria-label="Date range picker" shouldCloseOnSelect={false} {...props} value={value} onChange={setValue}>
<AriaGroup>
<Button size="md" color="secondary" iconLeading={CalendarIcon}>
{!value ? <span className="text-placeholder">Select dates</span> : `${formattedStartDate} ${formattedEndDate}`}
</Button>
</AriaGroup>
<AriaPopover
placement="bottom right"
offset={8}
className={({ isEntering, isExiting }) =>
cx(
"origin-(--trigger-anchor-point) will-change-transform",
isEntering &&
"duration-150 ease-out animate-in fade-in placement-right:slide-in-from-left-0.5 placement-top:slide-in-from-bottom-0.5 placement-bottom:slide-in-from-top-0.5",
isExiting &&
"duration-100 ease-in animate-out fade-out placement-right:slide-out-to-left-0.5 placement-top:slide-out-to-bottom-0.5 placement-bottom:slide-out-to-top-0.5",
)
}
>
<AriaDialog className="flex rounded-2xl bg-primary shadow-xl ring ring-secondary_alt focus:outline-hidden">
{({ close }) => (
<>
<div className="hidden w-38 flex-col gap-0.5 border-r border-solid border-secondary p-3 lg:flex">
{Object.values(presets).map((preset) => (
<RangePresetButton
key={preset.label}
value={preset.value}
onClick={() => {
setValue(preset.value);
setFocusedValue(preset.value.start);
}}
>
{preset.label}
</RangePresetButton>
))}
</div>
<div className="flex flex-col">
<RangeCalendar
focusedValue={focusedValue}
onFocusChange={setFocusedValue}
highlightedDates={highlightedDates}
presets={{
lastWeek: presets.lastWeek,
lastMonth: presets.lastMonth,
lastYear: presets.lastYear,
}}
/>
<div className="flex justify-between gap-3 border-t border-secondary p-4">
<div className="hidden items-center gap-3 md:flex">
<DateInput slot="start" className="w-36" />
<div className="text-md text-quaternary"></div>
<DateInput slot="end" className="w-36" />
</div>
<div className="grid w-full grid-cols-2 gap-3 md:flex md:w-auto">
<Button
size="md"
color="secondary"
onClick={() => {
onCancel?.();
close();
}}
>
Cancel
</Button>
<Button
size="md"
color="primary"
onClick={() => {
onApply?.();
close();
}}
>
Apply
</Button>
</div>
</div>
</div>
</>
)}
</AriaDialog>
</AriaPopover>
</AriaDateRangePicker>
);
};