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 https://github.com/vector-im/element-web/issues/20800pull/28217/head
parent
3eb6a55b93
commit
ed88e0cdce
|
@ -102,6 +102,21 @@ export function formatFullDate(date: Date, showTwelveHour = false, showSeconds =
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats dates to be compatible with attributes of a `<input type="date">`. Dates
|
||||
* should be formatted like "2020-06-23" (formatted according to ISO8601)
|
||||
*
|
||||
* @param date The date to format.
|
||||
* @returns The date string in ISO8601 format ready to be used with an `<input>`
|
||||
*/
|
||||
export function formatDateForInput(date: Date): string {
|
||||
const year = `${date.getFullYear()}`.padStart(4, "0");
|
||||
const month = `${date.getMonth() + 1}`.padStart(2, "0");
|
||||
const day = `${date.getDate()}`.padStart(2, "0");
|
||||
const dateInputValue = `${year}-${month}-${day}`;
|
||||
return dateInputValue;
|
||||
}
|
||||
|
||||
export function formatFullTime(date: Date, showTwelveHour = false): string {
|
||||
if (showTwelveHour) {
|
||||
return twelveHourTime(date, true);
|
||||
|
|
|
@ -19,6 +19,7 @@ import React, { useState, FormEvent } from "react";
|
|||
import { _t } from "../../../languageHandler";
|
||||
import Field from "../elements/Field";
|
||||
import { RovingAccessibleButton, useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
|
||||
import { formatDateForInput } from "../../../DateUtils";
|
||||
|
||||
interface IProps {
|
||||
ts: number;
|
||||
|
@ -27,12 +28,9 @@ interface IProps {
|
|||
|
||||
const JumpToDatePicker: React.FC<IProps> = ({ ts, onDatePicked }: IProps) => {
|
||||
const date = new Date(ts);
|
||||
const year = date.getFullYear();
|
||||
const month = `${date.getMonth() + 1}`.padStart(2, "0");
|
||||
const day = `${date.getDate()}`.padStart(2, "0");
|
||||
const dateDefaultValue = `${year}-${month}-${day}`;
|
||||
const dateInputDefaultValue = formatDateForInput(date);
|
||||
|
||||
const [dateValue, setDateValue] = useState(dateDefaultValue);
|
||||
const [dateValue, setDateValue] = useState(dateInputDefaultValue);
|
||||
const [onFocus, isActive, ref] = useRovingTabIndex<HTMLInputElement>();
|
||||
|
||||
const onDateValueInput = (ev: React.ChangeEvent<HTMLInputElement>): void => setDateValue(ev.target.value);
|
||||
|
@ -49,6 +47,9 @@ const JumpToDatePicker: React.FC<IProps> = ({ ts, onDatePicked }: IProps) => {
|
|||
type="date"
|
||||
onInput={onDateValueInput}
|
||||
value={dateValue}
|
||||
// Prevent people from selecting a day in the future (there won't be any
|
||||
// events there anyway).
|
||||
max={formatDateForInput(new Date())}
|
||||
className="mx_JumpToDatePicker_datePicker"
|
||||
label={_t("Pick a date to jump to")}
|
||||
onFocus={onFocus}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
|
||||
import JumpToDatePicker from "../../../../src/components/views/messages/JumpToDatePicker";
|
||||
|
||||
describe("JumpToDatePicker", () => {
|
||||
const nowDate = new Date("2021-12-17T08:09:00.000Z");
|
||||
beforeEach(() => {
|
||||
// Set a stable fake time here so the test is always consistent
|
||||
jest.useFakeTimers();
|
||||
jest.setSystemTime(nowDate.getTime());
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it("renders the date picker correctly", () => {
|
||||
const { asFragment } = render(
|
||||
<JumpToDatePicker ts={new Date("2020-07-04T05:55:00.000Z").getTime()} onDatePicked={() => {}} />,
|
||||
);
|
||||
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,41 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`JumpToDatePicker renders the date picker correctly 1`] = `
|
||||
<DocumentFragment>
|
||||
<form
|
||||
class="mx_JumpToDatePicker_form"
|
||||
>
|
||||
<span
|
||||
class="mx_JumpToDatePicker_label"
|
||||
>
|
||||
Jump to date
|
||||
</span>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_JumpToDatePicker_datePicker"
|
||||
>
|
||||
<input
|
||||
id="mx_Field_1"
|
||||
label="Pick a date to jump to"
|
||||
max="2021-12-17"
|
||||
placeholder="Pick a date to jump to"
|
||||
tabindex="-1"
|
||||
type="date"
|
||||
value="2020-07-04"
|
||||
/>
|
||||
<label
|
||||
for="mx_Field_1"
|
||||
>
|
||||
Pick a date to jump to
|
||||
</label>
|
||||
</div>
|
||||
<button
|
||||
class="mx_AccessibleButton mx_JumpToDatePicker_submitButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
type="submit"
|
||||
>
|
||||
Go
|
||||
</button>
|
||||
</form>
|
||||
</DocumentFragment>
|
||||
`;
|
|
@ -19,6 +19,7 @@ import {
|
|||
formatRelativeTime,
|
||||
formatDuration,
|
||||
formatFullDateNoDayISO,
|
||||
formatDateForInput,
|
||||
formatTimeLeft,
|
||||
formatPreciseDuration,
|
||||
formatLocalDateShort,
|
||||
|
@ -126,6 +127,15 @@ describe("formatFullDateNoDayISO", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("formatDateForInput", () => {
|
||||
it.each([["1993-11-01"], ["1066-10-14"], ["0571-04-22"], ["0062-02-05"]])(
|
||||
"should format %s",
|
||||
(dateString: string) => {
|
||||
expect(formatDateForInput(new Date(dateString))).toBe(dateString);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("formatTimeLeft", () => {
|
||||
it.each([
|
||||
[0, "0s left"],
|
||||
|
|
Loading…
Reference in New Issue