diff --git a/packages/frontend/src/components/shared/DatePicker/DatePicker.theme.ts b/packages/frontend/src/components/shared/DatePicker/DatePicker.theme.ts new file mode 100644 index 00000000..522bd348 --- /dev/null +++ b/packages/frontend/src/components/shared/DatePicker/DatePicker.theme.ts @@ -0,0 +1,9 @@ +import { VariantProps, tv } from 'tailwind-variants'; + +export const datePickerTheme = tv({ + slots: { + input: [], + }, +}); + +export type DatePickerTheme = VariantProps; diff --git a/packages/frontend/src/components/shared/DatePicker/DatePicker.tsx b/packages/frontend/src/components/shared/DatePicker/DatePicker.tsx new file mode 100644 index 00000000..69b44e84 --- /dev/null +++ b/packages/frontend/src/components/shared/DatePicker/DatePicker.tsx @@ -0,0 +1,100 @@ +import React, { useCallback, useState } from 'react'; +import { Input, InputProps } from 'components/shared/Input'; +import * as Popover from '@radix-ui/react-popover'; +import { datePickerTheme } from './DatePicker.theme'; +import { Calendar, CalendarProps } from 'components/shared/Calendar'; +import { CalendarIcon } from 'components/shared/CustomIcon'; +import { Value } from 'react-calendar/dist/cjs/shared/types'; +import { format } from 'date-fns'; + +export interface DatePickerProps + extends Omit { + /** + * The props for the calendar component. + */ + calendarProps?: CalendarProps; + /** + * Optional callback function that is called when the value of the input changes. + * @param {string} value - The new value of the input. + * @returns None + */ + onChange?: (value: Value) => void; + /** + * The value of the input. + */ + value?: Value; + /** + * Whether to allow the selection of a date range. + */ + selectRange?: boolean; +} + +/** + * A date picker component that allows users to select a date from a calendar. + * @param {DatePickerProps} props - The props for the date picker component. + * @returns The rendered date picker component. + */ +export const DatePicker = ({ + className, + calendarProps, + value, + onChange, + selectRange = false, + ...props +}: DatePickerProps) => { + const { input } = datePickerTheme(); + + const [open, setOpen] = useState(false); + + /** + * Renders the value of the date based on the current state of `props.value`. + * @returns {string | undefined} - The formatted date value or `undefined` if `props.value` is falsy. + */ + const renderValue = useCallback(() => { + if (!value) return undefined; + if (Array.isArray(value)) { + return value + .map((date) => format(date as Date, 'dd/MM/yyyy')) + .join(' - '); + } + return format(value, 'dd/MM/yyyy'); + }, [value]); + + /** + * Handles the selection of a date from the calendar. + */ + const handleSelect = useCallback( + (date: Value) => { + setOpen(false); + onChange?.(date); + }, + [setOpen, onChange], + ); + + return ( + + + setOpen(true)} />} + readOnly + placeholder="Select a date..." + value={renderValue()} + className={input({ className })} + onClick={() => setOpen(true)} + /> + + + setOpen(false)}> + setOpen(false)} + onSelect={handleSelect} + /> + + + + ); +}; diff --git a/packages/frontend/src/components/shared/DatePicker/index.ts b/packages/frontend/src/components/shared/DatePicker/index.ts new file mode 100644 index 00000000..a48b62e4 --- /dev/null +++ b/packages/frontend/src/components/shared/DatePicker/index.ts @@ -0,0 +1 @@ +export * from './DatePicker';