Files
cunningham/packages/react/src/components/Forms/DatePicker/utils.ts
jbpenrath b0b7061b7a ⬆️(deps) migrate to typescript-eslint 8
A major version of typescript-eslint has been released. This version contains
some breaking change and rules change so we have to tweak our eslint
configuration.

https://main--typescript-eslint.netlify.app/blog/announcing-typescript-eslint-v8
2024-08-20 13:51:29 +02:00

115 lines
3.9 KiB
TypeScript

import {
DateValue,
parseAbsoluteToLocal,
ZonedDateTime,
toZoned,
getLocalTimeZone,
parseAbsolute,
} from "@internationalized/date";
import { DateRange } from "react-aria";
import { DatePickerAuxSubProps } from ":/components/Forms/DatePicker/DatePickerAux";
/**
* Checks if a given time zone is valid and supported by the environment.
* @param timezone The time zone to validate.
* @returns true if the time zone is valid and supported, false otherwise.
*/
export const isValidTimeZone = (timezone: string) => {
try {
// Check if Intl is available and supports time zones
if (!Intl || !Intl.DateTimeFormat().resolvedOptions().timeZone) {
throw new Error("Time zones are not available in this environment");
}
// Test if the provided time zone is valid
Intl.DateTimeFormat(undefined, { timeZone: timezone });
return true;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (_error) {
// If an error occurs, it could be due to an invalid time zone or lack of Intl support
return false;
}
};
/**
* Parses an ISO 8601 date and time string with a UTC offset or in UTC.
* @param rawDate - The raw date string to parse.
* @param timezone - (Optional) The timezone to use for parsing. If not provided, the local timezone will be used.
* @returns The parsed ZonedDateTime object or undefined if the input date is undefined.
* @throws {Error} - If an invalid date or timezone format is encountered.
*/
export const parseDateValue = (
rawDate: string | undefined,
timezone?: string,
): undefined | ZonedDateTime => {
if (!rawDate) {
return undefined;
}
try {
if (timezone && !isValidTimeZone(timezone)) {
throw new Error("Invalid timezone provided.");
}
return timezone
? parseAbsolute(rawDate, timezone)
: parseAbsoluteToLocal(rawDate);
} catch (e) {
const errorMessage = e instanceof Error ? ": " + e.message : ".";
throw new Error("Failed to parse date value" + errorMessage);
}
};
/**
* Parses a range of ISO 8601 date and time string with a UTC offset or in UTC.
* @param rawRange - The range of raw date strings to parse.
* @param timezone - (Optional) The timezone to use for parsing. If not provided, the local timezone will be used.
* @returns The parsed DateRange object or undefined if the input date range is undefined or uncomplete.
*/
export const parseRangeDateValue = (
rawRange: [string, string] | undefined,
timezone?: string,
): DateRange | undefined => {
if (!rawRange || !rawRange[0] || !rawRange[1]) {
return undefined;
}
return {
start: parseDateValue(rawRange[0], timezone)!,
end: parseDateValue(rawRange[1], timezone)!,
};
};
/**
* Converts a DateValue object to an ISO 8601 formatted string in UTC.
* @param date - The DateValue object to convert.
* @param timezone - (Optional) The timezone to use for the conversion. If not provided, the local timezone will be used.
* @returns The string representation of the date or an empty string if the input date is null.
* @throws {Error} - If an invalid date or timezone format is encountered.
*/
export const convertDateValueToString = (
date: DateValue | null,
timezone?: string,
): string => {
try {
if (!date) {
return "";
}
const localTimezone = timezone || getLocalTimeZone();
if (!isValidTimeZone(localTimezone)) {
throw new Error("Invalid timezone provided.");
}
return toZoned(date, localTimezone).toAbsoluteString();
} catch (e) {
const errorMessage = e instanceof Error ? ": " + e.message : ".";
throw new Error("Failed to convert date value to string" + errorMessage);
}
};
export const getDefaultPickerOptions = (props: DatePickerAuxSubProps): any => ({
minValue: parseDateValue(props.minValue, props.timezone),
maxValue: parseDateValue(props.maxValue, props.timezone),
shouldCloseOnSelect: true,
granularity: "day",
isDisabled: props.disabled,
label: props.label,
});