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

Refacto directions (using a store, converting DirectionPanel to functional, etc.) #1227

Draft
wants to merge 19 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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: 2 additions & 2 deletions src/adapters/scene_direction.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,9 @@ export default class SceneDirection {
});
}

refreshDirection(type, lngLat) {
refreshDirection(which, lngLat) {
const newPoint = new LatLonPoi(lngLat);
fire('change_direction_point', type, '', newPoint);
fire('change_direction_point', which, newPoint);
}

reset() {
Expand Down
12 changes: 4 additions & 8 deletions src/panel/PanelManager.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import FavoritesPanel from './favorites/FavoritesPanel';
import PoiPanel from './poi/PoiPanel';
import ServicePanel from './service/ServicePanel';
import CategoryPanel from 'src/panel/category/CategoryPanel';
import DirectionPanel from 'src/panel/direction/DirectionPanel';
import Directions from 'src/panel/direction/Directions';
import Telemetry from 'src/libs/telemetry';
import { parseQueryString, buildQueryString } from 'src/libs/url_utils';
import { fire, listen, unListen } from 'src/libs/customEvents';
Expand Down Expand Up @@ -154,17 +154,13 @@ const PanelManager = ({ router }) => {
});

if (directionConf.enabled) {
const isPublicTransportActive =
(directionConf.publicTransport && directionConf.publicTransport.enabled) ||
parseQueryString(document.location.search)['pt'] === 'true';

router.addRoute('Routes', '/routes(?:/?)(.*)', (routeParams, options) => {
const params = parseQueryString(routeParams);
params.details = params.details === 'true';
params.activeDetails = params.details === 'true';
params.activeRouteId = Number(params.selected) || 0;
setPanelOptions({
ActivePanel: DirectionPanel,
options: { ...params, ...options, isPublicTransportActive },
ActivePanel: Directions,
options: { ...params, ...options },
panelSize: 'default',
});
});
Expand Down
35 changes: 35 additions & 0 deletions src/panel/direction/DesktopDirectionPanel.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { useContext } from 'react';
import { Panel, Divider, ShareMenu } from 'src/components/ui';
import { Button, IconShare } from '@qwant/qwant-ponents';
import { DirectionContext } from './directionStore';
import { useI18n } from 'src/hooks';

const DesktopDirectionPanel = ({ form, result, onClose, onShareClick }) => {
const { routes } = useContext(DirectionContext).state;
const { _ } = useI18n();

return (
<Panel className="direction-panel" onClose={onClose} renderHeader={form}>
<div className="direction-autocomplete_suggestions" />
{routes.length > 0 && (
<ShareMenu url={window.location.toString()}>
{openMenu => (
<Button
className="direction-panel-share-button u-ml-auto u-flex-shrink-0 u-mr-m"
variant="tertiary"
title={_('Share itinerary', 'direction')}
onClick={e => onShareClick(e, openMenu)}
>
<IconShare />
{_('Share itinerary', 'direction')}
</Button>
)}
</ShareMenu>
)}
<Divider paddingTop={8} paddingBottom={0} />
{result}
</Panel>
);
};

export default DesktopDirectionPanel;
78 changes: 53 additions & 25 deletions src/panel/direction/DirectionForm.jsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
import React, { useEffect, useRef } from 'react';
import React, { useEffect, useRef, useState, useContext, useCallback } from 'react';
import PropTypes from 'prop-types';
import DirectionInput from './DirectionInput';
import VehicleSelector from './VehicleSelector';
import { Divider } from 'src/components/ui';
import { IconArrowUpDown } from 'src/components/ui/icons';
import { Button } from '@qwant/qwant-ponents';
import * as address from 'src/libs/address';
import { getInputValue } from 'src/libs/suggest';
import { isNullOrEmpty } from 'src/libs/object';
import { useI18n, useDevice } from 'src/hooks';
import { DirectionContext } from './directionStore';

const DirectionForm = ({
isLoading,
origin,
destination,
onChangeDirectionPoint,
onReversePoints,
vehicles,
onSelectVehicle,
activeVehicle,
isInitializing,
originInputText,
destinationInputText,
}) => {
const DirectionForm = ({ onReversePoints, onSelectVehicle, isInitializing }) => {
const { _ } = useI18n();
const { isMobile } = useDevice();
const originRef = useRef(null);
const destinationRef = useRef(null);
const {
state: { origin, destination, vehicles, vehicle, isLoading },
setPoint,
} = useContext(DirectionContext);
const [originInputText, setOriginInputText] = useState('');
const [destinationInputText, setDestinationInputText] = useState('');

useEffect(() => {
if (isMobile || isInitializing) {
Expand All @@ -45,6 +43,44 @@ const DirectionForm = ({
}, 0);
};

const onChangePoint = which => (value, point) => {
if (which === 'origin') {
setOriginInputText(value);
} else {
setDestinationInputText(value);
}
if (point || value === '') {
setPoint(which, point);
}
};

const setText = useCallback((which, point) => {
const setter = which === 'origin' ? setOriginInputText : setDestinationInputText;

async function fetchAddress(poi) {
poi.address = await address.fetch(poi);
setter(getInputValue(poi));
}

if (point) {
if (point.type === 'geoloc') {
setter(point.name);
} else if (isNullOrEmpty(point.address)) {
fetchAddress(point);
} else {
setter(getInputValue(point));
}
}
}, []);

useEffect(() => {
setText('origin', origin);
}, [origin, setText]);

useEffect(() => {
setText('destination', destination);
}, [destination, setText]);

return (
<div className="direction-form">
<form className="direction-fields" noValidate>
Expand All @@ -55,7 +91,7 @@ const DirectionForm = ({
point={origin}
otherPoint={destination}
pointType="origin"
onChangePoint={(input, point) => onChangeDirectionPoint('origin', input, point)}
onChangePoint={onChangePoint('origin')}
ref={originRef}
withGeoloc={destination ? destination.type !== 'geoloc' : true}
/>
Expand All @@ -66,7 +102,7 @@ const DirectionForm = ({
point={destination}
otherPoint={origin}
pointType="destination"
onChangePoint={(input, point) => onChangeDirectionPoint('destination', input, point)}
onChangePoint={onChangePoint('destination')}
ref={destinationRef}
withGeoloc={origin ? origin.type !== 'geoloc' : true}
/>
Expand All @@ -85,25 +121,17 @@ const DirectionForm = ({
</form>
<VehicleSelector
vehicles={vehicles}
activeVehicle={activeVehicle}
activeVehicle={vehicle}
onSelectVehicle={onSelectVehicle}
/>
</div>
);
};

DirectionForm.propTypes = {
isLoading: PropTypes.bool,
origin: PropTypes.object,
destination: PropTypes.object,
onChangeDirectionPoint: PropTypes.func.isRequired,
onReversePoints: PropTypes.func.isRequired,
vehicles: PropTypes.array.isRequired,
onSelectVehicle: PropTypes.func.isRequired,
activeVehicle: PropTypes.string.isRequired,
isInitializing: PropTypes.bool,
originInputText: PropTypes.string,
destinationInputText: PropTypes.string,
};

export default DirectionForm;
65 changes: 65 additions & 0 deletions src/panel/direction/DirectionMap.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useContext, useEffect } from 'react';
import { fire, listen, unListen } from 'src/libs/customEvents';
import { DirectionContext } from './directionStore';

const DirectionMap = () => {
const { state, setPoint } = useContext(DirectionContext);
const { origin, destination, vehicle, routes, activeRouteId } = state;

useEffect(() => {
if (origin) {
window.execOnMapLoaded(() => {
fire('set_origin', origin);
if (!destination) {
fire('fit_map', origin);
}
});
}

if (destination) {
window.execOnMapLoaded(() => {
fire('set_destination', destination);
if (!origin) {
fire('fit_map', destination);
}
});
}
}, [origin, destination]);

useEffect(() => {
const dragPointHandler = listen('change_direction_point', setPoint);
const setPointHandler = listen('set_direction_point', point => {
if (origin && destination) {
return;
}
// if one point is already filled, fill the other
setPoint({ type: origin ? 'destination' : 'origin', data: point });
});

return () => {
unListen(dragPointHandler);
unListen(setPointHandler);
fire('clean_routes');
fire('update_map_paddings');
};
}, [origin, destination, setPoint]);

useEffect(() => {
window.execOnMapLoaded(() => {
fire('set_routes', {
routes,
vehicle,
activeRouteId,
});
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [routes /* Omit activeRouteId and vehicle to prevent costly redraws */]);

useEffect(() => {
fire('set_main_route', { routeId: activeRouteId, fitView: true });
}, [activeRouteId]);

return null;
};

export default DirectionMap;
Loading