Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Date/Time Selector #793

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
103 changes: 40 additions & 63 deletions packages/trip-form/src/DateTimeSelector/index.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
import CSS from "csstype";
import { format, parse } from "date-fns";
import flatten from "flat";
import coreUtils from "@opentripplanner/core-utils";
import React, { ChangeEvent, ReactElement, ReactNode, useCallback } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import React, { ChangeEvent, ReactElement, useCallback } from "react";
import { useIntl } from "react-intl";

import ModeButton from "../ModeButton";
import colors, { Dropdown } from "@opentripplanner/building-blocks";
import * as S from "../styled";

// eslint-disable-next-line prettier/prettier
import type { QueryParamChangeEvent } from "../types";

// Load the default messages.
import defaultEnglishMessages from "../../i18n/en-US.yml";

// HACK: We should flatten the messages loaded above because
// the YAML loaders behave differently between webpack and our version of jest:
// - the yaml loader for webpack returns a nested object,
// - the yaml loader for jest returns messages with flattened ids.
const defaultMessages: Record<string, string> = flatten(defaultEnglishMessages);

const {
getCurrentDate,
Expand All @@ -28,6 +19,8 @@ const {
OTP_API_TIME_FORMAT
} = coreUtils.time;

const { grey } = colors;

type DepartArriveValue = "NOW" | "DEPART" | "ARRIVE";

interface DateTimeSelectorProps {
Expand Down Expand Up @@ -77,8 +70,7 @@ interface DateTimeSelectorProps {
}

interface DepartArriveOption {
isSelected?: boolean;
text: ReactNode;
text: string;
type: DepartArriveValue;
}

Expand All @@ -99,6 +91,8 @@ function isInputTypeSupported(type: string): boolean {

const supportsDateTimeInputs = isInputTypeSupported("date") && isInputTypeSupported("time");

const buttonStyle = { backgroundColor: S.baseColor() || grey[700], border: "0px", borderRadius: "3px 0px 0px 3px", color: "white", height: "45px" }

/**
* Reference date for parsing.
*/
Expand Down Expand Up @@ -137,6 +131,23 @@ export default function DateTimeSelector({
timeZone = getUserTimezone()
}: DateTimeSelectorProps): ReactElement {
const intl = useIntl()
const baseColor = S.baseColor()

const departureOptions: DepartArriveOption[] = [
{
// Default option.
type: "NOW",
text: intl.formatMessage({ id: "otpUi.DateTimeSelector.now" })
},
{
type: "DEPART",
text: intl.formatMessage({ id: "otpUi.DateTimeSelector.depart" })
},
{
type: "ARRIVE",
text: intl.formatMessage({ id: "otpUi.DateTimeSelector.arrive" })
}
];

const handleQueryParamChange = useCallback(
(queryParam: QueryParamChangeEvent): void => {
Expand All @@ -150,8 +161,12 @@ export default function DateTimeSelector({
const handleInputChange = (key: string) => useCallback(
(evt: ChangeEvent<HTMLInputElement>): void => {
handleQueryParamChange({ [key]: evt.target.value });
// If the user changes the time, it doesn't make sense for them to be departing now.
if (departArrive === "NOW") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: if departureOptions were an enum then we could reuse that instead of using a magic string

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you change departureOptions to

departureOptions = {
now: "NOW"
etc

And then render the text strings dynamically?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes! but it's such a nitpick

handleQueryParamChange({ departArrive: "DEPART" });
}
},
[onQueryParamChange, key]
[onQueryParamChange, key, departArrive]
);

const handleDateChange = handleInputChange("date");
Expand Down Expand Up @@ -182,51 +197,16 @@ export default function DateTimeSelector({
departArrive: "NOW",
time: getCurrentTime(timeZone)
});
} else if (!option.isSelected) {
} else if (!(option.type === departArrive)) {
handleQueryParamChange({
departArrive: option.type
});
}
},
[onQueryParamChange, option.type, option.isSelected, timeZone]
[onQueryParamChange, option.type, timeZone]
);

const departureOptions: DepartArriveOption[] = [
{
// Default option.
type: "NOW",
text: (
<FormattedMessage
defaultMessage={defaultMessages["otpUi.DateTimeSelector.now"]}
description="Text indicating that the traveler wants to depart as soon as possible (i.e. 'now')"
id="otpUi.DateTimeSelector.now"
/>
)
},
{
type: "DEPART",
text: (
<FormattedMessage
defaultMessage={defaultMessages["otpUi.DateTimeSelector.depart"]}
description="Text indicating that the traveler wants to depart at a given date/time"
id="otpUi.DateTimeSelector.depart"
/>
)
},
{
type: "ARRIVE",
text: (
<FormattedMessage
defaultMessage={defaultMessages["otpUi.DateTimeSelector.arrive"]}
description="Text indicating that the traveler wants to arrive by a certain date/time"
id="otpUi.DateTimeSelector.arrive"
/>
)
}
];
departureOptions.forEach(opt => {
opt.isSelected = departArrive === opt.type;
});


const isLegacy = forceLegacy || !supportsDateTimeInputs;

Expand All @@ -236,21 +216,19 @@ export default function DateTimeSelector({
className={className}
role="group"
style={style}
baseColor={baseColor}
>
<S.DateTimeSelector.DepartureRow>
<Dropdown alignMenuLeft id="date-time-depart-arrive" text={departureOptions.find(opt => opt.type === departArrive).text} buttonStyle={buttonStyle}>
{departureOptions.map(opt => (
<ModeButton
aria-pressed={opt.isSelected}
<button
aria-pressed={opt.type === departArrive}
key={opt.type}
onClick={setDepartArrive(opt)}
selected={opt.isSelected}
type="button"
>
{opt.text}
</ModeButton>
))}
</S.DateTimeSelector.DepartureRow>

{departArrive !== "NOW" && !isLegacy && (
</button>))}
</Dropdown>
<S.DateTimeSelector.DateTimeRow>
{/* The <div> elements below are used for layout, see S.DateTimeSelector. */}
<div>
Expand All @@ -272,7 +250,6 @@ export default function DateTimeSelector({
/>
</div>
</S.DateTimeSelector.DateTimeRow>
)}

{/* Backup controls (for older browsers) */}
{departArrive !== "NOW" && isLegacy && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ exports[`Trip Form Components/Advanced Mode Settings Buttons AdvancedModeSetting
</label>
</div>
</div>
<div class="styled__DropdownSelector-sc-122ziys-17 kiQdDP">
<div class="styled__DropdownSelector-sc-122ziys-16 jBvmxW">
<div>
<label for="id-query-param-busColor"
class="styled__SettingLabel-sc-122ziys-2 hlSjLd"
Expand Down
5 changes: 3 additions & 2 deletions packages/trip-form/src/__mocks__/trimet-styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ const TriMetStyled = styled.div`
text-decoration: underline;
}
}
${TripFormClasses.DateTimeSelector} {
max-width: 550px;
}
${TripFormClasses.DateTimeSelector.DateTimeRow} {
margin: 15px 0px;
input {
padding: 6px 12px;
text-align: center;
font-size: inherit;
font-family: inherit;
Expand Down
Loading