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

fix(trip form): add callback for detecting when all submodes are disabled #28

Merged
merged 35 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
98ee788
feat(trip-form): create mode subsettings container and button
amy-corson-ibigroup Jun 4, 2024
f870be4
Clean up and rename components
amy-corson-ibigroup Jun 6, 2024
8c15d5f
clean up types, styling, and pass fillModeIcons
amy-corson-ibigroup Jun 6, 2024
b1d9825
update snapshots
daniel-heppner-ibigroup Jun 12, 2024
d99e2cd
Merge branch 'master' into wide-mode-buttons
daniel-heppner-ibigroup Jun 12, 2024
2c8e3ee
merge yarn
daniel-heppner-ibigroup Jun 12, 2024
8145226
deps: force animate height version
daniel-heppner-ibigroup Jun 15, 2024
1564638
fix(trip-form): clean up styling + pass props
amy-corson-ibigroup Jun 18, 2024
154a6bc
fix(trip-form): add cursor styling to mode button
amy-corson-ibigroup Jun 18, 2024
6954860
make accent color optional
amy-corson-ibigroup Jun 18, 2024
a2f34cc
fix(trip-form): remove max-width on wide mode buttons
amy-corson-ibigroup Jun 19, 2024
f97065e
clean up styling
amy-corson-ibigroup Jun 21, 2024
7c4e5dd
fix(trip-form): styling fixes
amy-corson-ibigroup Jun 21, 2024
3c4ff04
fix(trip-form): update input focus states
amy-corson-ibigroup Jul 2, 2024
bea6c49
fix(trip-form): add classNames to advanced mode buttons
amy-corson-ibigroup Jul 2, 2024
796bf0c
Merge branch 'master' into wide-mode-buttons
amy-corson-ibigroup Jul 16, 2024
7426879
Remove floating UI (#26)
josh-willis-arcadis Jul 17, 2024
b73aaba
feat(trip-form): add callback for disabling all submodes
daniel-heppner-ibigroup Sep 9, 2024
b800d70
fix(subsetting-pane): check if subsetting adds a transport mode
josh-willis-arcadis Sep 10, 2024
7f4c816
fix(subsettings-pane): handle change when all settings that add a tra…
josh-willis-arcadis Sep 10, 2024
a8d4ca8
Merge branch 'master' into wide-mode-buttons
amy-corson-ibigroup Sep 12, 2024
f520556
Merge branch 'wide-mode-buttons' into callback-disable-all-submodes
amy-corson-ibigroup Sep 12, 2024
6da3d7f
fix react version
amy-corson-ibigroup Sep 12, 2024
0834dd6
Merge branch 'wide-mode-buttons' into callback-disable-all-submodes
amy-corson-ibigroup Sep 12, 2024
acd40ec
fix(subsettings-pane): only reset submodes if onAllSubmodesDisabled p…
josh-willis-arcadis Sep 13, 2024
154589c
Merge branch 'callback-disable-all-submodes' of https://github.com/ib…
josh-willis-arcadis Sep 13, 2024
89e8c48
fix(i18n): remove unused string
josh-willis-arcadis Sep 13, 2024
10ac8a6
chore: update yarn.lock
josh-willis-arcadis Sep 13, 2024
e4dd828
chore(storybook): remove unneeded story file
josh-willis-arcadis Sep 16, 2024
1b1e94d
update snapshots
daniel-heppner-ibigroup Sep 16, 2024
46ee93f
fix(subsettings-pane): sort props
josh-willis-arcadis Sep 23, 2024
5ba1bb3
fix(subsettings-pane): move const outside of callback
josh-willis-arcadis Sep 24, 2024
d5680c6
fix(AMSB-story): add support for onAllSubmodesDisabled prop
josh-willis-arcadis Sep 24, 2024
f35cdb2
chore: rename mock mode button file and move to mocks folder
josh-willis-arcadis Sep 24, 2024
f147b68
use correct import
josh-willis-arcadis Sep 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
"workspaces": [
"packages/*"
],
"resolutions": {
"react": "18.2.0",
"react-animate-height": "3.0.4"
},
"devDependencies": {
"@babel/cli": "^7.10",
"@babel/core": "^7.10",
Expand Down
1 change: 1 addition & 0 deletions packages/trip-form/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

```
TBD

```
1 change: 0 additions & 1 deletion packages/trip-form/i18n/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ otpUi:
walkTolerance-labelHigh: More Walking
walkTolerance-labelLow: Less Walking
wheelchair-label: Accessible Routing
settingsLabel: "{mode} settings"
SettingsSelectorPanel:
bikeOnly: Bike Only
escooterOnly: E-scooter Only
Expand Down
1 change: 0 additions & 1 deletion packages/trip-form/i18n/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ otpUi:
walkTolerance-labelHigh: Plus de marche
walkTolerance-labelLow: Moins de marche
wheelchair-label: Accès avec mobilité réduite
settingsLabel: "Paramètres pour : {mode}"
SettingsSelectorPanel:
bikeOnly: Vélo uniquement
escooterOnly: Trottinette uniquement
Expand Down
2 changes: 2 additions & 0 deletions packages/trip-form/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
"private": false,
"dependencies": {
"@opentripplanner/core-utils": "^11.4.4",
"@opentripplanner/building-blocks": "^1.0.3",
"@floating-ui/react": "^0.19.2",
"@styled-icons/bootstrap": "^10.34.0",
"@styled-icons/boxicons-regular": "^10.38.0",
"@styled-icons/fa-regular": "^10.37.0",
"@styled-icons/fa-solid": "^10.37.0",
"date-fns": "^2.28.0",
"flat": "^5.0.2",
"react-animate-height": "^3.0.4",
"react-indiana-drag-scroll": "^2.0.1",
"react-inlinesvg": "^2.3.0"
},
Expand Down
josh-willis-arcadis marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React, { ReactElement, useState } from "react";
import { ModeButtonDefinition } from "@opentripplanner/types";
import * as Core from "..";
import { QueryParamChangeEvent } from "../types";
import {
addSettingsToButton,
extractModeSettingDefaultsToObject,
populateSettingWithValue,
setModeButtonEnabled
} from "./utils";
import {
defaultModeButtonDefinitions,
getIcon,
modeSettingDefinitionsWithDropdown
} from "./mockButtons";

const initialState = {
enabledModeButtons: ["transit"],
modeSettingValues: {}
};

function pipe<T>(...fns: Array<(arg: T) => T>) {
return (value: T) => fns.reduce((acc, fn) => fn(acc), value);
}

const MetroModeSubsettingsComponent = ({
fillModeIcons,
modeButtonDefinitions,
onSetModeSettingValue,
onToggleModeButton
}: {
fillModeIcons?: boolean;
modeButtonDefinitions: Array<ModeButtonDefinition>;
onSetModeSettingValue: (event: QueryParamChangeEvent) => void;
onToggleModeButton: (key: string, newState: boolean) => void;
}): ReactElement => {
const [modeSettingValues, setModeSettingValues] = useState({});
const modeSettingValuesWithDefaults = {
...extractModeSettingDefaultsToObject(modeSettingDefinitionsWithDropdown),
...initialState.modeSettingValues,
...modeSettingValues
};

const [activeModeButtonKeys, setModeButtonKeys] = useState(
initialState.enabledModeButtons
);

const addIconToModeSetting = msd => ({
...msd,
icon: getIcon(msd.iconName)
});

const processedModeSettings = modeSettingDefinitionsWithDropdown.map(
pipe(
addIconToModeSetting,
populateSettingWithValue(modeSettingValuesWithDefaults)
)
);

const processedModeButtons = modeButtonDefinitions.map(
pipe(
addSettingsToButton(processedModeSettings),
setModeButtonEnabled(activeModeButtonKeys)
)
);

const toggleModeButtonAction = (key: string, newState: boolean) => {
if (newState) {
setModeButtonKeys([...activeModeButtonKeys, key]);
} else {
setModeButtonKeys(activeModeButtonKeys.filter(button => button !== key));
}
// Storybook Action:
onToggleModeButton(key, newState);
};

const setModeSettingValueAction = (event: QueryParamChangeEvent) => {
setModeSettingValues({ ...modeSettingValues, ...event });
// Storybook Action:
onSetModeSettingValue(event);
};

return (
<div style={{ maxWidth: "500px" }}>
<Core.AdvancedModeSubsettingsContainer
fillModeIcons={fillModeIcons}
label="Select a transit mode"
modeButtons={processedModeButtons}
onSettingsUpdate={setModeSettingValueAction}
onToggleModeButton={toggleModeButtonAction}
/>
</div>
);
};

const Template = (args: {
fillModeIcons?: boolean;
onSetModeSettingValue: (event: QueryParamChangeEvent) => void;
onToggleModeButton: (key: string, newState: boolean) => void;
}): ReactElement => (
<MetroModeSubsettingsComponent
modeButtonDefinitions={defaultModeButtonDefinitions}
// eslint-disable-next-line react/jsx-props-no-spreading
{...args}
/>
);

export const AdvancedModeSettingsButtons = Template.bind({});

export default {
argTypes: {
fillModeIcons: { control: "boolean" },
onSetModeSettingValue: { action: "set mode setting value" },
onToggleModeButton: { action: "toggle button" }
},
component: MetroModeSubsettingsComponent,
title: "Trip Form Components/Advanced Mode Settings Buttons"
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import React from "react";
import AnimateHeight from "react-animate-height";
import styled from "styled-components";
import colors from "@opentripplanner/building-blocks";
import { Check2 } from "@styled-icons/bootstrap";
import { ModeButtonDefinition } from "@opentripplanner/types";
import { useIntl } from "react-intl";
import SubSettingsPane from "../SubSettingsPane";
import generateModeButtonLabel from "../i18n";
import { invisibleCss } from "..";
import { QueryParamChangeEvent } from "../../types";

const { blue, grey } = colors;

const SettingsContainer = styled.div`
width: 100%;
`;

const StyledModeSettingsButton = styled.div<{
accentColor: string;
fillModeIcons: boolean;
subsettings: boolean;
}>`
& > label {
align-items: center;
background-color: #fff;
border: 2px solid ${props => props.accentColor};
border-left-width: 2px;
border-right-width: 2px;
color: ${props => props.accentColor};
cursor: pointer;
display: grid;
font-size: 18px;
font-weight: 400;
gap: 20px;
grid-template-columns: 40px auto 40px;
height: 51px;
justify-items: center;
margin-bottom: 0;
margin-top: -2px;
padding: 0 10px;
}
& > input {
${invisibleCss}

&:checked + label {
background-color: ${props => props.accentColor};
color: #fff;
border-bottom-left-radius: ${props => props.subsettings && 0} !important;
border-bottom-right-radius: ${props => props.subsettings && 0} !important;
}

&:focus-visible + label,
&:focus + label {
outline: ${props => props.accentColor} 1px solid;
outline-offset: -4px;
}
}

& > input:checked {
&:focus-visible + label,
&:focus + label {
outline: white 1px solid;
}
}

span {
justify-self: flex-start;
}

svg {
height: 26px;
width: 26px;
fill: ${props =>
props.fillModeIcons === false ? "inherit" : "currentcolor"};
}

&:hover {
cursor: pointer;
}
`;

const StyledSettingsContainer = styled.div`
border: 1px solid ${grey[300]};
border-top: 0;
padding: 1em;
`;

interface Props {
accentColor?: string;
fillModeIcons: boolean;
id: string;
modeButton: ModeButtonDefinition;
onAllSubmodesDisabled?: (modeButton: ModeButtonDefinition) => void;
onSettingsUpdate: (event: QueryParamChangeEvent) => void;
onToggle: () => void;
}

const AdvancedModeSettingsButton = ({
accentColor = blue[700],
fillModeIcons,
id,
modeButton,
onSettingsUpdate,
onAllSubmodesDisabled,
onToggle
}: Props): JSX.Element => {
const intl = useIntl();
const label = generateModeButtonLabel(modeButton.key, intl, modeButton.label);
const checkboxId = `metro-submode-selector-mode-${id}`;
return (
<SettingsContainer className="advanced-submode-container">
<StyledModeSettingsButton
accentColor={accentColor}
className="advanced-submode-mode-button"
fillModeIcons={fillModeIcons}
id={modeButton.key}
subsettings={modeButton.modeSettings.length > 0}
>
<input
aria-label={label}
checked={modeButton.enabled ?? undefined}
id={checkboxId}
onChange={onToggle}
type="checkbox"
/>
<label htmlFor={checkboxId}>
<modeButton.Icon />
<span>{modeButton?.label}</span>
{modeButton.enabled && <Check2 />}
</label>
</StyledModeSettingsButton>
{modeButton.modeSettings.length > 0 && (
<AnimateHeight duration={300} height={modeButton.enabled ? "auto" : 0}>
<StyledSettingsContainer className="subsettings-container">
<SubSettingsPane
onSettingUpdate={onSettingsUpdate}
modeButton={modeButton}
onAllSubmodesDisabled={onAllSubmodesDisabled}
/>
</StyledSettingsContainer>
</AnimateHeight>
)}
</SettingsContainer>
);
};

export default AdvancedModeSettingsButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import styled from "styled-components";
import React, { useCallback } from "react";
import { ModeButtonDefinition } from "@opentripplanner/types";
import colors from "@opentripplanner/building-blocks";
import AdvancedModeSettingsButton from "./AdvancedModeSettingsButton";
import { invisibleCss } from ".";
import { QueryParamChangeEvent } from "../types";

const { grey } = colors;

const SubsettingsContainer = styled.fieldset`
border: none;
margin: 0;

legend {
${invisibleCss}
}

display: flex;
flex-direction: column;

div:first-of-type div label {
border-top-width: 2px;
border-radius: 8px 8px 0 0;
}

div:last-of-type div label {
border-bottom-width: 2px;
border-radius: 0 0 8px 8px;
}

div.advanced-submode-container:last-of-type div.subsettings-container {
border-radius: 0 0 8px 8px;
border-bottom: 1px solid ${grey[300]};
}
`;

interface Props {
accentColor?: string;
fillModeIcons: boolean | undefined;
label: string;
modeButtons: ModeButtonDefinition[];
onAllSubmodesDisabled?: (modeButton: ModeButtonDefinition) => void;
onSettingsUpdate: (event: QueryParamChangeEvent) => void;
onToggleModeButton: (key: string, newState: boolean) => void;
}

const AdvancedModeSubsettingsContainer = ({
accentColor,
fillModeIcons,
modeButtons,
label,
onAllSubmodesDisabled,
onSettingsUpdate,
onToggleModeButton
}: Props): JSX.Element => {
return (
<SubsettingsContainer>
<legend>{label}</legend>
{modeButtons.map(button => {
return (
<AdvancedModeSettingsButton
accentColor={accentColor}
fillModeIcons={fillModeIcons}
key={button.label}
modeButton={button}
onSettingsUpdate={onSettingsUpdate}
onAllSubmodesDisabled={onAllSubmodesDisabled}
onToggle={useCallback(() => {
onToggleModeButton(button.key, !button.enabled);
}, [button, onToggleModeButton])}
id={button.key}
/>
);
})}
</SubsettingsContainer>
);
};

export default AdvancedModeSubsettingsContainer;
Loading
Loading