Skip to content

Commit

Permalink
Add direct mode and transit mode selects
Browse files Browse the repository at this point in the history
  • Loading branch information
testower committed Oct 30, 2023
1 parent d4d2a03 commit f1189d2
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 0 deletions.
1 change: 1 addition & 0 deletions client-next/src/components/SearchBar/AccessSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function AccessSelect({
Access
</Form.Label>
<Form.Select
id="accessSelect"
size="sm"
onChange={(e) => {
if (e.target.value !== 'not_selected') {
Expand Down
54 changes: 54 additions & 0 deletions client-next/src/components/SearchBar/DirectModeSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Form } from 'react-bootstrap';
import { StreetMode, TripQueryVariables } from '../../gql/graphql.ts';

export function DirectModeSelect({
tripQueryVariables,
setTripQueryVariables,
}: {
tripQueryVariables: TripQueryVariables;
setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void;
}) {
return (
<Form.Group>
<Form.Label column="sm" htmlFor="directModeSelect">
Direct mode
</Form.Label>
<Form.Select
id="directModeSelect"
size="sm"
onChange={(e) => {
if (e.target.value !== 'not_selected') {
setTripQueryVariables({
...tripQueryVariables,
modes: {
...tripQueryVariables.modes,
directMode: e.target.value as StreetMode,
},
});
} else {
setTripQueryVariables({
...tripQueryVariables,
modes:
tripQueryVariables.modes?.accessMode ||
tripQueryVariables.modes?.egressMode ||
tripQueryVariables.modes?.transportModes
? {
...tripQueryVariables.modes,
directMode: undefined,
}
: undefined,
});
}
}}
value={tripQueryVariables.modes?.directMode || 'not_selected'}
>
<option value="not_selected">Not selected</option>
{Object.values(StreetMode).map((mode) => (
<option key={mode} value={mode}>
{mode}
</option>
))}
</Form.Select>
</Form.Group>
);
}
1 change: 1 addition & 0 deletions client-next/src/components/SearchBar/EgressSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function EgressSelect({
Egress
</Form.Label>
<Form.Select
id="egressSelect"
size="sm"
onChange={(e) => {
if (e.target.value !== 'not_selected') {
Expand Down
65 changes: 65 additions & 0 deletions client-next/src/components/SearchBar/MultiSelectDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { ChangeEvent, useState } from 'react';
import { Form } from 'react-bootstrap';

type MultiSelectDropdownOption<T> = {
id: T;
label: string;
};

type MultiSelectDropdownProps<T> = {
label: string;
options: MultiSelectDropdownOption<T>[];
values: T[];
onChange: (value: T[]) => void;
};

const MultiSelectDropdown = <T extends unknown>({ label, options, values, onChange }: MultiSelectDropdownProps<T>) => {

Check failure on line 16 in client-next/src/components/SearchBar/MultiSelectDropdown.tsx

View workflow job for this annotation

GitHub Actions / build-linux

Constraining the generic type `T` to `unknown` does nothing and is unnecessary
const [isOpen, setIsOpen] = useState(false);

const toggleDropdown = () => {
setIsOpen(!isOpen);
};

const handleOptionChange = (event: ChangeEvent<HTMLInputElement>) => {
const optionId = event.target.value as T;
const isChecked = event.target.checked;

if (isChecked) {
onChange([...values, optionId]);
} else {
onChange(values.filter((id) => id !== optionId));
}
};

return (
<div className={`dropdown ${isOpen ? 'show' : ''}`}>
<Form.Label column="sm" htmlFor="multiSelectDropdown">
{label}
</Form.Label>
<Form.Control
type="text"
id="multiSelectDropdown"
size="sm"
value={values.join(', ')}
onClick={toggleDropdown}
onChange={() => {}}
/>
<div style={{ width: '20%' }} className={`dropdown-menu ${isOpen ? 'show' : ''}`}>
{options.map((option) => (
<Form.Check
style={{ marginLeft: '10%' }}
key={`${option.id}`}
type="checkbox"
id={`option_${option.id}`}
label={option.label}
checked={values.includes(option.id)}
onChange={handleOptionChange}
value={`${option.id}`}
/>
))}
</div>
</div>
);
};

export default MultiSelectDropdown;
4 changes: 4 additions & 0 deletions client-next/src/components/SearchBar/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { DateInputField } from './DateInputField.tsx';
import { SearchWindowInput } from './SearchWindowInput.tsx';
import { AccessSelect } from './AccessSelect.tsx';
import { EgressSelect } from './EgressSelect.tsx';
import { DirectModeSelect } from './DirectModeSelect.tsx';
import { TransitModeSelect } from './TransitModeSelect.tsx';

export function SearchBar({
onRoute,
Expand All @@ -27,7 +29,9 @@ export function SearchBar({
<DateInputField tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<SearchWindowInput tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<AccessSelect tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<TransitModeSelect tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<EgressSelect tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<DirectModeSelect tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<div className="search-bar-route-button-wrapper">
<Button variant="primary" onClick={onRoute}>
Route
Expand Down
60 changes: 60 additions & 0 deletions client-next/src/components/SearchBar/TransitModeSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { TransportMode, TripQueryVariables } from '../../gql/graphql.ts';
import MultiSelectDropdown from './MultiSelectDropdown.tsx';
import { useCallback, useMemo } from 'react';

export function TransitModeSelect({
tripQueryVariables,
setTripQueryVariables,
}: {
tripQueryVariables: TripQueryVariables;
setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void;
}) {
const values = useMemo(() => {
return (
tripQueryVariables?.modes?.transportModes
?.map((transportMode) => transportMode?.transportMode)
.filter((v) => !!v) || []
);
}, [tripQueryVariables.modes?.transportModes]);

const onChange = useCallback(
(values: (TransportMode | null | undefined)[]) => {
const newTransportModes = values.map((v) => ({
transportMode: v,
}));

if (newTransportModes.length === 0) {
setTripQueryVariables({
...tripQueryVariables,
modes:
tripQueryVariables.modes?.directMode ||
tripQueryVariables.modes?.accessMode ||
tripQueryVariables.modes?.egressMode
? { ...tripQueryVariables.modes }
: undefined,
});
} else {
setTripQueryVariables({
...tripQueryVariables,
modes: {
...tripQueryVariables.modes,
transportModes: newTransportModes.length > 0 ? newTransportModes : undefined,
},
});
}
},
[tripQueryVariables.modes, setTripQueryVariables],

Check warning on line 46 in client-next/src/components/SearchBar/TransitModeSelect.tsx

View workflow job for this annotation

GitHub Actions / build-linux

React Hook useCallback has a missing dependency: 'tripQueryVariables'. Either include it or remove the dependency array
);

return (
<MultiSelectDropdown
label="Transit mode"
options={Object.values(TransportMode).map((mode) => ({
id: mode,
label: mode.toString(),
}))}
values={values}
onChange={onChange}
/>
);
}

0 comments on commit f1189d2

Please sign in to comment.