Skip to content

Commit

Permalink
match review feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
hoorayimhelping committed Feb 7, 2025
1 parent 500e3aa commit 7293a85
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 67 deletions.
21 changes: 14 additions & 7 deletions src/components/DateDetails/DateDetails.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import { Args } from "@storybook/react";
import { DateDetails } from "./DateDetails";

export default {
argTypes: {
locale: {
options: ["en-US", "en-GB", "fr-FR", "de-DE", "ru-RU"],
control: {
type: "select",
},
},
side: {
control: {
type: "select",
},
options: ["top", "right", "left", "bottom"],
},
date: {
control: "date",
},
systemTimeZone: {
options: [
"America/Denver",
Expand All @@ -39,9 +37,18 @@ export default {
export const Playground = {
args: {
date: new Date(),
locale: "en-US",
side: "top",
systemTimeZone: "America/Los_Angeles",
title: "DateDetails",
},
render: (args: Args) => {
const date = args.date ? new Date(args.date) : new Date();
return (
<DateDetails
date={date}
side={args.side}
systemTimeZone={args.systemTimeZone}
/>
);
},
};
40 changes: 30 additions & 10 deletions src/components/DateDetails/DateDetails.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,13 @@ describe("DateDetails", () => {
it("renders the DateDetails component with relevant timezone information", () => {
const baseDate = new Date("2024-12-24 11:45:00 AM");
const systemTimeZone = "America/Los_Angeles";
const locale = new Intl.Locale("en", { region: "US" });
vi.setSystemTime(baseDate);

const fiveMinutesAgo = new Date("2024-12-24 11:40:00 AM");

const { getByText } = renderCUI(
<DateDetails
date={fiveMinutesAgo}
locale={locale}
systemTimeZone={systemTimeZone}
/>
);
Expand All @@ -51,24 +49,46 @@ describe("DateDetails", () => {
return content.includes("PST");
})
).toBeInTheDocument();
expect(getByText("Dec 24, 2024, 4:40:00 PM")).toBeInTheDocument();
expect(getByText("Dec 24, 2024, 11:40:00 AM (EST)")).toBeInTheDocument();
expect(getByText("Dec 24, 2024, 8:40:00 AM (PST)")).toBeInTheDocument();
expect(getByText("Dec 24, 4:40 p.m.")).toBeInTheDocument();
expect(getByText("Dec 24, 11:40 a.m. (EST)")).toBeInTheDocument();
expect(getByText("Dec 24, 8:40 a.m. (PST)")).toBeInTheDocument();
expect(getByText(fiveMinutesAgo.getTime() / 1000)).toBeInTheDocument();
});

it("only shows the date if the previous date isn't in this year", () => {
const baseDate = new Date("2025-02-07 11:45:00 AM");
const systemTimeZone = "America/Los_Angeles";
vi.setSystemTime(baseDate);

const oneYearAgo = new Date("2024-02-07 11:45:00 AM");

const { getByText } = renderCUI(
<DateDetails
date={oneYearAgo}
systemTimeZone={systemTimeZone}
/>
);

const trigger = getByText("1 year ago");
expect(trigger).toBeInTheDocument();

fireEvent.click(trigger);
expect(getByText("Feb 7, 2024, 4:45 p.m.")).toBeInTheDocument();
expect(getByText("Feb 7, 2024, 11:45 a.m. (EST)")).toBeInTheDocument();
expect(getByText("Feb 7, 2024, 8:45 a.m. (PST)")).toBeInTheDocument();
expect(getByText(oneYearAgo.getTime() / 1000)).toBeInTheDocument();
});

it("handles Daylight Savings Time", () => {
const baseDate = new Date("2024-07-04 11:45:00 AM");
const systemTimeZone = "America/Los_Angeles";
const locale = new Intl.Locale("en", { region: "US" });
vi.setSystemTime(baseDate);

const fiveMinutesAgo = new Date("2024-07-04 11:40:00 AM");

const { getByText } = renderCUI(
<DateDetails
date={fiveMinutesAgo}
locale={locale}
systemTimeZone={systemTimeZone}
/>
);
Expand All @@ -87,9 +107,9 @@ describe("DateDetails", () => {
return content.includes("PDT");
})
).toBeInTheDocument();
expect(getByText("Jul 4, 2024, 3:40:00 PM")).toBeInTheDocument();
expect(getByText("Jul 4, 2024, 11:40:00 AM (EDT)")).toBeInTheDocument();
expect(getByText("Jul 4, 2024, 8:40:00 AM (PDT)")).toBeInTheDocument();
expect(getByText("Jul 4, 3:40 p.m.")).toBeInTheDocument();
expect(getByText("Jul 4, 11:40 a.m. (EDT)")).toBeInTheDocument();
expect(getByText("Jul 4, 8:40 a.m. (PDT)")).toBeInTheDocument();
expect(getByText(fiveMinutesAgo.getTime() / 1000)).toBeInTheDocument();
});
});
89 changes: 39 additions & 50 deletions src/components/DateDetails/DateDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import dayjs from "dayjs";
import dayjs, { Dayjs } from "dayjs";
import advancedFormat from "dayjs/plugin/advancedFormat";
import duration from "dayjs/plugin/duration";
import localizedFormat from "dayjs/plugin/localizedFormat";
Expand Down Expand Up @@ -62,66 +62,56 @@ const UnderlinedTrigger = styled(Popover.Trigger)<StyledLinkProps>`
${linkStyles}
`;

const dateStyle = "medium";
const timeStyle = "medium";
const formatDateDetails = (date: Dayjs, timezone?: string): string => {
const isCurrentYear = dayjs().year() === date.year();
const formatForCurrentYear = "MMM D, h:mm a";
const formatForPastYear = "MMM D, YYYY, h:mm a";

if (isCurrentYear) {
if (timezone) {
const dateWithTimezone = date.tz(timezone);
return dateWithTimezone
.format(formatForCurrentYear)
.replace("am", "a.m.")
.replace("pm", "p.m.");
}

const createBasicDateDetailsFormatter = () => {
return new Intl.DateTimeFormat(undefined, {
dateStyle,
timeStyle,
});
};
return date.format(formatForCurrentYear).replace("am", "a.m.").replace("pm", "p.m.");
}

const formatDateDetails = (date: Date, locale?: Intl.Locale, timeZone?: string) => {
let dateDetailsFormatter;
try {
dateDetailsFormatter = new Intl.DateTimeFormat(locale, {
dateStyle,
timeStyle,
timeZone,
});
} catch (error) {
if ((error as Error).message.includes("invalid time zone")) {
try {
dateDetailsFormatter = new Intl.DateTimeFormat(locale, {
dateStyle,
timeStyle,
});
} catch {
dateDetailsFormatter = createBasicDateDetailsFormatter();
}
} else if ((error as Error).message.includes("invalid language tag")) {
try {
dateDetailsFormatter = new Intl.DateTimeFormat(undefined, {
dateStyle,
timeStyle,
timeZone,
});
} catch {
dateDetailsFormatter = createBasicDateDetailsFormatter();
}
} else {
dateDetailsFormatter = createBasicDateDetailsFormatter();
}
if (timezone) {
const dateWithTimezone = date.tz(timezone);
return dateWithTimezone
.format(formatForPastYear)
.replace("am", "a.m.")
.replace("pm", "p.m.");
}
return date.format(formatForPastYear).replace("am", "a.m.").replace("pm", "p.m.");
};

return dateDetailsFormatter.format(date);
const formatTimezone = (date: Dayjs, timezone: string): string => {
return (
new Intl.DateTimeFormat("en-US", {
timeZone: timezone,
timeZoneName: "short",
})
.formatToParts(date.toDate())
.find(part => part.type === "timeZoneName")?.value ?? date.format("z")
);
};

export type ArrowPosition = "top" | "right" | "left" | "bottom";

export interface DateDetailsProps {
date: Date;
locale?: Intl.Locale;
side?: ArrowPosition;
systemTimeZone?: string;
}

export const DateDetails = ({
date,
locale,
side = "top",
systemTimeZone,
systemTimeZone = "America/New_York",
}: DateDetailsProps) => {
const dayjsDate = dayjs(date);

Expand Down Expand Up @@ -155,7 +145,8 @@ export const DateDetails = ({
<Text size="md">Local</Text>
<Container justifyContent="end">
<Text size="md">
{formatDateDetails(dayjsDate.toDate(), locale)} ({dayjsDate.format("z")})
{formatDateDetails(dayjsDate)} (
{formatTimezone(dayjsDate, dayjs.tz.guess())})
</Text>
</Container>

Expand All @@ -165,18 +156,16 @@ export const DateDetails = ({

<Container justifyContent="end">
<Text size="md">
{formatDateDetails(systemTime.toDate(), locale, systemTimeZone)} (
{systemTime.format("z")})
{formatDateDetails(systemTime, systemTimeZone)} (
{formatTimezone(systemTime, systemTimeZone)})
</Text>
</Container>
</>
)}

<Text size="md">UTC</Text>
<Container justifyContent="end">
<Text size="md">
{formatDateDetails(dayjsDate.utc().toDate(), locale, "UTC")}
</Text>
<Text size="md">{formatDateDetails(dayjsDate.utc(), "UTC")}</Text>
</Container>

<Text size="md">Unix</Text>
Expand Down

0 comments on commit 7293a85

Please sign in to comment.