Skip to content
This repository has been archived by the owner on Jul 2, 2024. It is now read-only.

Commit

Permalink
DEVPROD-838: Add user time format preference (#2280)
Browse files Browse the repository at this point in the history
  • Loading branch information
sophstad authored Feb 29, 2024
1 parent aca2e80 commit d5c6303
Show file tree
Hide file tree
Showing 12 changed files with 103 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/components/Header/UserDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const UserDropdown = () => {
},
];
if (permissions?.canEditAdminSettings) {
menuItems.splice(1, 0, {
menuItems.splice(2, 0, {
"data-cy": "admin-link",
text: "Admin",
href: adminSettingsURL,
Expand Down
17 changes: 12 additions & 5 deletions src/components/SpruceForm/Widgets/LeafyGreenWidgets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ export const LeafyGreenSelect: React.FC<

export const LeafyGreenRadio: React.FC<EnumSpruceWidgetProps> = ({
disabled,
id,
label,
onChange,
options,
Expand All @@ -224,11 +225,17 @@ export const LeafyGreenRadio: React.FC<EnumSpruceWidgetProps> = ({
} = options;
return (
<ElementWrapper css={elementWrapperCSS}>
{label && (
<LabelContainer>
<Label htmlFor={id}>{label}</Label>
</LabelContainer>
)}
<RadioGroup
data-cy={dataCy}
id={id}
name={label}
value={value}
onChange={(e) => onChange(e.target.value)}
data-cy={dataCy}
value={value}
>
{enumOptions.map((o) => {
const optionDisabled = enumDisabled?.includes(o.value) ?? false;
Expand Down Expand Up @@ -275,12 +282,12 @@ export const LeafyGreenRadioBox: React.FC<
return (
<ElementWrapper css={elementWrapperCSS}>
{showLabel !== false && (
<RadioBoxLabelContainer>
<LabelContainer>
<Label htmlFor={id} disabled={disabled}>
{label}
</Label>
{description && <Description>{description}</Description>}
</RadioBoxLabelContainer>
</LabelContainer>
)}
{!!errors && (
<StyledBanner variant="danger" data-cy="error-banner">
Expand Down Expand Up @@ -320,7 +327,7 @@ const StyledBanner = styled(Banner)`
margin-bottom: ${size.s};
`;

const RadioBoxLabelContainer = styled.div`
const LabelContainer = styled.div`
margin-bottom: ${size.xs};
`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ exports[`Snapshot Tests SpruceForm.stories Example2 1`] = `
<div
aria-label="radio-group-"
class="leafygreen-ui-14o8ny9"
id="root_reprovisionMethod"
role="group"
>
<div
Expand Down
15 changes: 5 additions & 10 deletions src/constants/fieldMaps.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { getDateCopy } from "utils/string";

export const timeZones = [
{
str: "Coordinated Universal Time",
Expand Down Expand Up @@ -167,7 +165,7 @@ export const timeZones = [
},
];

const listOfDateFormatStrings = [
export const listOfDateFormatStrings = [
"MM-dd-yyyy",
"dd-MM-yyyy",
"yyyy-MM-dd",
Expand All @@ -177,13 +175,10 @@ const listOfDateFormatStrings = [
"MMM d, yyyy",
];

export const dateFormats = listOfDateFormatStrings.map((format) => ({
value: format,
str: `${format} - ${getDateCopy("08/31/2022", {
dateFormat: format,
dateOnly: true,
})}`,
}));
export enum TimeFormat {
TwelveHour = "h:mm:ss aa",
TwentyFourHour = "H:mm:ss",
}

export const notificationFields = {
patchFinish: "Patch finish",
Expand Down
1 change: 1 addition & 0 deletions src/gql/generated/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8724,6 +8724,7 @@ export type UserSettingsQuery = {
region?: string | null;
slackMemberId?: string | null;
slackUsername?: string | null;
timeFormat?: string | null;
timezone?: string | null;
githubUser?: {
__typename?: "GithubUser";
Expand Down
1 change: 1 addition & 0 deletions src/gql/queries/user-settings.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ query UserSettings {
region
slackMemberId
slackUsername
timeFormat
timezone
useSpruceOptions {
hasUsedMainlineCommitsBefore
Expand Down
3 changes: 2 additions & 1 deletion src/hooks/useDateFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import { useUserTimeZone } from "./useUserTimeZone";
export const useDateFormat = () => {
const timezone = useUserTimeZone();
const { userSettings } = useUserSettings();
const { dateFormat } = userSettings || {};
const { dateFormat, timeFormat } = userSettings || {};

return (date: string | number | Date, options: DateCopyOptions = {}) =>
getDateCopy(date, {
tz: timezone,
dateFormat,
timeFormat,
...options,
});
};
52 changes: 48 additions & 4 deletions src/pages/preferences/preferencesTabs/ProfileTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import { Skeleton } from "antd";
import { usePreferencesAnalytics } from "analytics";
import { SettingsCard } from "components/SettingsCard";
import { SpruceForm } from "components/SpruceForm";
import { timeZones, dateFormats } from "constants/fieldMaps";
import {
listOfDateFormatStrings,
timeZones,
TimeFormat,
} from "constants/fieldMaps";
import { useToastContext } from "context/toast";
import {
UpdateUserSettingsMutation,
Expand All @@ -16,15 +20,30 @@ import {
import { UPDATE_USER_SETTINGS } from "gql/mutations";
import { AWS_REGIONS } from "gql/queries";
import { useUserSettings } from "hooks";
import { omitTypename } from "utils/string";
import { getDateCopy, omitTypename } from "utils/string";

const dateFormats = listOfDateFormatStrings.map((format) => ({
value: format,
str: `${format} - ${getDateCopy("08/31/2022", {
dateFormat: format,
dateOnly: true,
})}`,
}));

export const ProfileTab: React.FC = () => {
const { sendEvent } = usePreferencesAnalytics();
const dispatchToast = useToastContext();

const { loading, userSettings } = useUserSettings();
const { dateFormat, githubUser, region, timezone } = userSettings ?? {};
const {
dateFormat,
githubUser,
region,
timeFormat: dbTimeFormat,
timezone,
} = userSettings ?? {};
const lastKnownAs = githubUser?.lastKnownAs || "";
const timeFormat = dbTimeFormat || TimeFormat.TwelveHour;

const { data: awsRegionData, loading: awsRegionLoading } =
useQuery<AwsRegionsQuery>(AWS_REGIONS);
Expand All @@ -49,11 +68,13 @@ export const ProfileTab: React.FC = () => {
region: string;
githubUser: { lastKnownAs?: string };
dateFormat: string;
timeFormat: string;
}>({
timezone,
region,
githubUser: { lastKnownAs },
dateFormat,
timeFormat,
});

useEffect(() => {
Expand All @@ -62,8 +83,9 @@ export const ProfileTab: React.FC = () => {
timezone,
region,
dateFormat,
timeFormat,
});
}, [dateFormat, githubUser, region, timezone]);
}, [dateFormat, githubUser, region, timeFormat, timezone]);

const handleSubmit = () => {
updateUserSettings({
Expand Down Expand Up @@ -111,6 +133,9 @@ export const ProfileTab: React.FC = () => {
dateFormat: {
"ui:placeholder": "Select a date format",
},
timeFormat: {
"ui:widget": "radio",
},
}}
schema={{
properties: {
Expand Down Expand Up @@ -150,6 +175,25 @@ export const ProfileTab: React.FC = () => {
})),
],
},
timeFormat: {
type: "string",
title: "Time Format",
oneOf: [
{
type: "string" as "string",
title: "12-hour clock",
description: "Display time with AM/PM, e.g. 12:34 PM",
enum: [TimeFormat.TwelveHour],
},

{
type: "string" as "string",
title: "24-hour clock",
description: "Use 24-hour notation, e.g. 13:34",
enum: [TimeFormat.TwentyFourHour],
},
],
},
},
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ export const getFormSchema = (
properties: {
mergeQueue: {
type: "string" as "string",
title: "",
oneOf: [
{
type: "string" as "string",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export const getFormSchema = (
properties: {
projectHealthView: {
type: "string" as "string",
title: "",
oneOf: [
{
type: "string" as "string",
Expand Down
16 changes: 11 additions & 5 deletions src/utils/string/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { format, utcToZonedTime } from "date-fns-tz";
import get from "lodash/get";
import { TimeFormat } from "constants/fieldMaps";

export { githubPRLinkify } from "./githubPRLinkify";

Expand Down Expand Up @@ -100,6 +101,7 @@ export type DateCopyOptions = {
omitSeconds?: boolean;
omitTimezone?: boolean;
dateFormat?: string;
timeFormat?: string;
};

/**
Expand All @@ -111,7 +113,7 @@ export type DateCopyOptions = {
* @param options.omitSeconds - if true, will not return the seconds
* @param options.omitTimezone - if true, will not return the timezone
* @param options.dateFormat - a date format string, such as "MMM d, yyyy"
* @returns - a string representing the date in the format of "MMM d, yyyy h:mm:ss a z"
* @returns - a string representing the date in either the user's specified format or the default, "MMM d, yyyy h:mm:ss aa z"
*/
export const getDateCopy = (
time: string | number | Date,
Expand All @@ -121,15 +123,19 @@ export const getDateCopy = (
return "";
}
const { dateOnly, omitSeconds, omitTimezone, tz } = options || {};
let { dateFormat } = options || {};
let { dateFormat, timeFormat } = options || {};
if (!dateFormat) {
dateFormat = "MMM d, yyyy";
}
if (!timeFormat) {
timeFormat = TimeFormat.TwelveHour;
}
if (omitSeconds) {
timeFormat = timeFormat.replace(":ss", "");
}
const finalDateFormat = dateOnly
? dateFormat
: `${dateFormat}, h:mm${omitSeconds ? "" : ":ss"} aa${
omitTimezone ? "" : " z"
}`;
: `${dateFormat}, ${timeFormat}${omitTimezone ? "" : " z"}`;
if (tz) {
return format(utcToZonedTime(time, tz), finalDateFormat, {
timeZone: tz,
Expand Down
19 changes: 19 additions & 0 deletions src/utils/string/string.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TimeFormat } from "constants/fieldMaps";
import {
msToDuration,
sortFunctionDate,
Expand Down Expand Up @@ -292,7 +293,25 @@ describe("getDateCopy", () => {
getDateCopy("08/31/1996", { dateFormat: "MM/dd/yyyy", dateOnly: true }),
).toBe("08/31/1996");
});

it("returns dates with a custom time format when supplied with the option", () => {
expect(
getDateCopy(new Date("2020-11-16T22:17:29z"), {
omitTimezone: true,
timeFormat: TimeFormat.TwentyFourHour,
}),
).toBe("Nov 16, 2020, 22:17:29");

expect(
getDateCopy(new Date("2020-11-16T22:17:29z"), {
omitSeconds: true,
omitTimezone: true,
timeFormat: TimeFormat.TwelveHour,
}),
).toBe("Nov 16, 2020, 10:17 PM");
});
});

describe("applyStrictRegex", () => {
it("converts string to strict regex", () => {
expect(applyStrictRegex("dog")).toBe("^dog$");
Expand Down

0 comments on commit d5c6303

Please sign in to comment.