Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit ed88e0c

Browse files
Prevent future date selection in jump to date (#10419)
You can still type in whatever date you want (native date input behavior) but the UI picker has future dates disabled. Fix element-hq/element-web#20800
1 parent 3eb6a55 commit ed88e0c

File tree

5 files changed

+113
-5
lines changed

5 files changed

+113
-5
lines changed

Diff for: src/DateUtils.ts

+15
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,21 @@ export function formatFullDate(date: Date, showTwelveHour = false, showSeconds =
102102
});
103103
}
104104

105+
/**
106+
* Formats dates to be compatible with attributes of a `<input type="date">`. Dates
107+
* should be formatted like "2020-06-23" (formatted according to ISO8601)
108+
*
109+
* @param date The date to format.
110+
* @returns The date string in ISO8601 format ready to be used with an `<input>`
111+
*/
112+
export function formatDateForInput(date: Date): string {
113+
const year = `${date.getFullYear()}`.padStart(4, "0");
114+
const month = `${date.getMonth() + 1}`.padStart(2, "0");
115+
const day = `${date.getDate()}`.padStart(2, "0");
116+
const dateInputValue = `${year}-${month}-${day}`;
117+
return dateInputValue;
118+
}
119+
105120
export function formatFullTime(date: Date, showTwelveHour = false): string {
106121
if (showTwelveHour) {
107122
return twelveHourTime(date, true);

Diff for: src/components/views/messages/JumpToDatePicker.tsx

+6-5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import React, { useState, FormEvent } from "react";
1919
import { _t } from "../../../languageHandler";
2020
import Field from "../elements/Field";
2121
import { RovingAccessibleButton, useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
22+
import { formatDateForInput } from "../../../DateUtils";
2223

2324
interface IProps {
2425
ts: number;
@@ -27,12 +28,9 @@ interface IProps {
2728

2829
const JumpToDatePicker: React.FC<IProps> = ({ ts, onDatePicked }: IProps) => {
2930
const date = new Date(ts);
30-
const year = date.getFullYear();
31-
const month = `${date.getMonth() + 1}`.padStart(2, "0");
32-
const day = `${date.getDate()}`.padStart(2, "0");
33-
const dateDefaultValue = `${year}-${month}-${day}`;
31+
const dateInputDefaultValue = formatDateForInput(date);
3432

35-
const [dateValue, setDateValue] = useState(dateDefaultValue);
33+
const [dateValue, setDateValue] = useState(dateInputDefaultValue);
3634
const [onFocus, isActive, ref] = useRovingTabIndex<HTMLInputElement>();
3735

3836
const onDateValueInput = (ev: React.ChangeEvent<HTMLInputElement>): void => setDateValue(ev.target.value);
@@ -49,6 +47,9 @@ const JumpToDatePicker: React.FC<IProps> = ({ ts, onDatePicked }: IProps) => {
4947
type="date"
5048
onInput={onDateValueInput}
5149
value={dateValue}
50+
// Prevent people from selecting a day in the future (there won't be any
51+
// events there anyway).
52+
max={formatDateForInput(new Date())}
5253
className="mx_JumpToDatePicker_datePicker"
5354
label={_t("Pick a date to jump to")}
5455
onFocus={onFocus}
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
Copyright 2021 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import React from "react";
18+
import { render } from "@testing-library/react";
19+
20+
import JumpToDatePicker from "../../../../src/components/views/messages/JumpToDatePicker";
21+
22+
describe("JumpToDatePicker", () => {
23+
const nowDate = new Date("2021-12-17T08:09:00.000Z");
24+
beforeEach(() => {
25+
// Set a stable fake time here so the test is always consistent
26+
jest.useFakeTimers();
27+
jest.setSystemTime(nowDate.getTime());
28+
});
29+
30+
afterAll(() => {
31+
jest.useRealTimers();
32+
});
33+
34+
it("renders the date picker correctly", () => {
35+
const { asFragment } = render(
36+
<JumpToDatePicker ts={new Date("2020-07-04T05:55:00.000Z").getTime()} onDatePicked={() => {}} />,
37+
);
38+
39+
expect(asFragment()).toMatchSnapshot();
40+
});
41+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`JumpToDatePicker renders the date picker correctly 1`] = `
4+
<DocumentFragment>
5+
<form
6+
class="mx_JumpToDatePicker_form"
7+
>
8+
<span
9+
class="mx_JumpToDatePicker_label"
10+
>
11+
Jump to date
12+
</span>
13+
<div
14+
class="mx_Field mx_Field_input mx_JumpToDatePicker_datePicker"
15+
>
16+
<input
17+
id="mx_Field_1"
18+
label="Pick a date to jump to"
19+
max="2021-12-17"
20+
placeholder="Pick a date to jump to"
21+
tabindex="-1"
22+
type="date"
23+
value="2020-07-04"
24+
/>
25+
<label
26+
for="mx_Field_1"
27+
>
28+
Pick a date to jump to
29+
</label>
30+
</div>
31+
<button
32+
class="mx_AccessibleButton mx_JumpToDatePicker_submitButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
33+
role="button"
34+
tabindex="-1"
35+
type="submit"
36+
>
37+
Go
38+
</button>
39+
</form>
40+
</DocumentFragment>
41+
`;

Diff for: test/utils/DateUtils-test.ts

+10
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
formatRelativeTime,
2020
formatDuration,
2121
formatFullDateNoDayISO,
22+
formatDateForInput,
2223
formatTimeLeft,
2324
formatPreciseDuration,
2425
formatLocalDateShort,
@@ -126,6 +127,15 @@ describe("formatFullDateNoDayISO", () => {
126127
});
127128
});
128129

130+
describe("formatDateForInput", () => {
131+
it.each([["1993-11-01"], ["1066-10-14"], ["0571-04-22"], ["0062-02-05"]])(
132+
"should format %s",
133+
(dateString: string) => {
134+
expect(formatDateForInput(new Date(dateString))).toBe(dateString);
135+
},
136+
);
137+
});
138+
129139
describe("formatTimeLeft", () => {
130140
it.each([
131141
[0, "0s left"],

0 commit comments

Comments
 (0)