From 00f147a7a687d5772bcc538bc606cfff972178cd Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Thu, 12 Oct 2023 17:24:13 +0200 Subject: feat(components): add a Time component Instead of using helpers functions to format the date each time we need to use a time element, it makes more sense to create a new component dedicated to this task. --- src/components/atoms/layout/time/time.tsx | 136 ++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/components/atoms/layout/time/time.tsx (limited to 'src/components/atoms/layout/time/time.tsx') diff --git a/src/components/atoms/layout/time/time.tsx b/src/components/atoms/layout/time/time.tsx new file mode 100644 index 0000000..02b4763 --- /dev/null +++ b/src/components/atoms/layout/time/time.tsx @@ -0,0 +1,136 @@ +import { + type ForwardRefRenderFunction, + type TimeHTMLAttributes, + forwardRef, +} from 'react'; +import { useIntl } from 'react-intl'; +import { settings } from '../../../../utils/config'; + +type GetDateOptionsConfig = { + hasDay: boolean; + hasMonth: boolean; + hasWeekDay: boolean; + hasYear: boolean; +}; + +const getDateOptions = ({ + hasDay, + hasMonth, + hasWeekDay, + hasYear, +}: GetDateOptionsConfig): Intl.DateTimeFormatOptions => { + const day: Intl.DateTimeFormatOptions['day'] = 'numeric'; + const month: Intl.DateTimeFormatOptions['month'] = 'long'; + const weekDay: Intl.DateTimeFormatOptions['weekday'] = 'long'; + const year: Intl.DateTimeFormatOptions['year'] = 'numeric'; + const options: [ + keyof Intl.DateTimeFormatOptions, + Intl.DateTimeFormatOptions[keyof Intl.DateTimeFormatOptions], + ][] = []; + + if (hasDay) options.push(['day', day]); + if (hasMonth) options.push(['month', month]); + if (hasWeekDay) options.push(['weekday', weekDay]); + if (hasYear) options.push(['year', year]); + + return Object.fromEntries(options); +}; + +export type TimeProps = Omit< + TimeHTMLAttributes, + 'children' | 'dateTime' +> & { + /** + * A valid date string. + */ + date: string; + /** + * Should we hide the day number? + * + * @default false + */ + hideDay?: boolean; + /** + * Should we hide the month? + * + * @default false + */ + hideMonth?: boolean; + /** + * Should we hide the year? + * + * @default false + */ + hideYear?: boolean; + /** + * The current locale. + * + * @default settings.locales.defaultLocale + */ + locale?: string; + /** + * Should we display the time in addition to the date? + * + * @default false + */ + showTime?: boolean; + /** + * Should we display the week day? + * + * @default false + */ + showWeekDay?: boolean; +}; + +const TimeWithRef: ForwardRefRenderFunction = ( + { + date, + hideDay = false, + hideMonth = false, + hideYear = false, + locale = settings.locales.defaultLocale, + showTime = false, + showWeekDay = false, + ...props + }, + ref +) => { + const intl = useIntl(); + const dateOptions = getDateOptions({ + hasDay: !hideDay, + hasMonth: !hideMonth, + hasWeekDay: showWeekDay, + hasYear: !hideYear, + }); + const fullDate = new Date(date); + const dateTime = fullDate.toISOString(); + const readableDate = fullDate.toLocaleDateString(locale, dateOptions); + const formattedTime = fullDate.toLocaleTimeString(locale, { + hour: 'numeric', + minute: 'numeric', + }); + const readableTime = + locale === 'fr' ? formattedTime.replace(':', 'h') : formattedTime; + + return ( + + ); +}; + +/** + * Time component. + * + * Render a date with an optional time in a `