diff --git a/src/components/ui/Panel.jsx b/src/components/ui/Panel.jsx index 60e0cd6aa..ba1f8e958 100644 --- a/src/components/ui/Panel.jsx +++ b/src/components/ui/Panel.jsx @@ -51,6 +51,7 @@ class Panel extends React.Component { isMapBottomUIDisplayed: PropTypes.bool, floatingItems: PropTypes.arrayOf(PropTypes.object), onTransitionEnd: PropTypes.func, + onClose: PropTypes.func, }; static defaultProps = { diff --git a/src/panel/PanelManager.jsx b/src/panel/PanelManager.jsx index 3e0cbc665..7810a8136 100644 --- a/src/panel/PanelManager.jsx +++ b/src/panel/PanelManager.jsx @@ -9,7 +9,7 @@ import CategoryPanel from 'src/panel/category/CategoryPanel'; import DirectionPanel from 'src/panel/direction/DirectionPanel'; import Telemetry from 'src/libs/telemetry'; import CategoryService from 'src/adapters/category_service'; -import { parseQueryString, getCurrentUrl } from 'src/libs/url_utils'; +import { parseQueryString, getCurrentUrl, buildQueryString } from 'src/libs/url_utils'; import { fire, listen } from 'src/libs/customEvents'; import { isNullOrEmpty } from 'src/libs/object'; import { isMobileDevice } from 'src/libs/device'; @@ -77,18 +77,26 @@ export default class PanelManager extends React.Component { const { ActivePanel, options } = this.state; if (prevState.ActivePanel !== ActivePanel || prevState.options !== options) { - // poiFilters indicate we are in a "list of POI" context, where markers should be persistent + // Not in a "list of PoI" context (options.poiFilters is null) if (isNullOrEmpty(options?.poiFilters)) { + // Markers are not persistent fire('remove_category_markers'); } + // Handle search bar's style and text content this.updateSearchBarContent(options); + + // Handle top bar's return button + this.updateTopBarReturnButton(options); } } - updateSearchBarContent({ poiFilters = {}, query } = {}) { + updateSearchBarContent({ poiFilters = {}, poi = {}, query } = {}) { const topBarHandle = document.querySelector('.top_bar'); - if (poiFilters.category) { + if (poi.name) { + SearchInput.setInputValue(poi.name); + topBarHandle.classList.add('top_bar--search_filled'); + } else if (poiFilters.category) { const categoryLabel = CategoryService.getCategoryByName(poiFilters.category)?.getInputValue(); SearchInput.setInputValue(categoryLabel); topBarHandle.classList.add('top_bar--search_filled'); @@ -104,6 +112,61 @@ export default class PanelManager extends React.Component { } } + updateTopBarReturnButton({ poiFilters = {}, isFromFavorite, poi = {} } = {}) { + const topBarReturnButton = document.querySelector('.search_form__return-to-list'); + const backAction = + poiFilters.category || poiFilters.query + ? this.backToList + : isFromFavorite + ? this.backToFavorite + : () => {}; + topBarReturnButton.onclick = e => { + backAction(e, poiFilters); + }; + + const topBarHandle = document.querySelector('.top_bar'); + + // Show return arrow (on mobile) if user comes from PoI / favorites list + if (poi.name && (poiFilters.category || poiFilters.query || isFromFavorite)) { + topBarHandle.classList.add('top_bar--poi-from-list'); + } + // Hide return button when not on a POI anymore + else { + const topBarHandle = document.querySelector('.top_bar'); + topBarHandle.classList.remove('top_bar--poi-from-list'); + } + } + + backToList(e, poiFilters) { + e.stopPropagation(); + const queryObject = {}; + const mappingParams = { + query: 'q', + category: 'type', + }; + + for (const name in poiFilters) { + if (!poiFilters[name]) { + continue; + } + const key = mappingParams[name]; + queryObject[key || name] = poiFilters[name]; + } + + const params = buildQueryString(queryObject); + const uri = `/places/${params}`; + + Telemetry.add(Telemetry.POI_BACKTOLIST); + fire('restore_location'); + window.app.navigateTo(uri); + } + + backToFavorite(e) { + e.stopPropagation(); + Telemetry.add(Telemetry.POI_BACKTOFAVORITE); + window.app.navigateTo('/favs'); + } + initRouter() { const router = this.props.router; @@ -134,7 +197,12 @@ export default class PanelManager extends React.Component { const poiId = poiUrl.split('@')[0]; this.setState({ ActivePanel: PoiPanel, - options: { ...options, poiId }, + options: { + ...options, + poiId, + backToList: this.backToList, + backToFavorite: this.backToFavorite, + }, panelSize: 'default', }); }); diff --git a/src/panel/direction/RouteResult.jsx b/src/panel/direction/RouteResult.jsx index ce61b6893..36cb22d0a 100644 --- a/src/panel/direction/RouteResult.jsx +++ b/src/panel/direction/RouteResult.jsx @@ -3,7 +3,6 @@ import React, { useCallback, useEffect } from 'react'; import PropTypes from 'prop-types'; import { listen, unListen } from 'src/libs/customEvents'; import Telemetry from 'src/libs/telemetry'; - import RoutesList from './RoutesList'; import { SourceFooter } from 'src/components/ui'; diff --git a/src/panel/poi/PoiPanel.jsx b/src/panel/poi/PoiPanel.jsx index 533595a60..6b82e6101 100644 --- a/src/panel/poi/PoiPanel.jsx +++ b/src/panel/poi/PoiPanel.jsx @@ -9,7 +9,7 @@ import PoiBlockContainer from './PoiBlockContainer'; import OsmContribution from 'src/components/OsmContribution'; import CategoryList from 'src/components/CategoryList'; import { isFromPagesJaunes, isFromOSM } from 'src/libs/pois'; -import { buildQueryString, shouldShowBackToQwant } from 'src/libs/url_utils'; +import { shouldShowBackToQwant } from 'src/libs/url_utils'; import IdunnPoi from 'src/adapters/poi/idunn_poi'; import Poi from 'src/adapters/poi/poi.js'; import { fire, listen, unListen } from 'src/libs/customEvents'; @@ -17,7 +17,7 @@ import { addToFavorites, removeFromFavorites, isInFavorites } from 'src/adapters import PoiItem from 'src/components/PoiItem'; import { isNullOrEmpty } from 'src/libs/object'; import { DeviceContext } from 'src/libs/device'; -import { Flex, Panel, PanelNav, CloseButton, Divider, Button } from 'src/components/ui'; +import { Flex, Panel, PanelNav, Divider, Button } from 'src/components/ui'; import { BackToQwantButton } from 'src/components/BackToQwantButton'; const covid19Enabled = (nconf.get().covid19 || {}).enabled; @@ -28,6 +28,8 @@ export default class PoiPanel extends React.Component { poi: PropTypes.object, poiFilters: PropTypes.object, centerMap: PropTypes.bool, + backToList: PropTypes.func, + backToFavorite: PropTypes.func, }; static defaultProps = { @@ -130,12 +132,6 @@ export default class PoiPanel extends React.Component { }); } - backToFavorite = e => { - e.stopPropagation(); - Telemetry.add(Telemetry.POI_BACKTOFAVORITE); - window.app.navigateTo('/favs'); - }; - getBestPoi() { return this.state.fullPoi || this.props.poi; } @@ -156,31 +152,6 @@ export default class PoiPanel extends React.Component { window.app.navigateTo('/'); }; - backToList = e => { - e.stopPropagation(); - const { poiFilters } = this.props; - const queryObject = {}; - const mappingParams = { - query: 'q', - category: 'type', - }; - - for (const name in poiFilters) { - if (!poiFilters[name]) { - continue; - } - const key = mappingParams[name]; - queryObject[key || name] = poiFilters[name]; - } - - const params = buildQueryString(queryObject); - const uri = `/places/${params}`; - - Telemetry.add(Telemetry.POI_BACKTOLIST); - fire('restore_location'); - window.app.navigateTo(uri); - }; - onClickPhoneNumber = () => { const poi = this.getBestPoi(); const source = poi.meta && poi.meta.source; @@ -220,9 +191,9 @@ export default class PoiPanel extends React.Component { const backAction = poiFilters.category || poiFilters.query - ? this.backToList + ? this.props.backToList : isFromFavorite - ? this.backToFavorite + ? this.props.backToFavorite : this.closeAction; const NavHeader = ({ isMobile }) => { @@ -238,10 +209,17 @@ export default class PoiPanel extends React.Component { ); } + // If source is a PoI list: show a button to return to the list if (backAction !== this.closeAction) { return ( - @@ -276,10 +254,6 @@ export default class PoiPanel extends React.Component { withOpeningHours onClick={this.center} /> -
{ const LocalizedWarning = ({ countryCode }) => { const { frInformationUrl } = useConfig('covid19'); - return
-

{_('Please comply with government travel restrictions.', 'covid19')}

- {countryCode === 'FR' && ( -

- {_('More information at', 'covid19')}{' '} - - gouvernement.fr/info-coronavirus - -

- )} -
+ return ( +
+

{_('Please comply with government travel restrictions.', 'covid19')}

+ {countryCode === 'FR' && ( +

+ {_('More information at', 'covid19')}{' '} + + gouvernement.fr/info-coronavirus + +

+ )} +
+ ); }; const LegalWarning = ({ countryCode }) => ( diff --git a/src/scss/includes/search_form.scss b/src/scss/includes/search_form.scss index 8c12b7aee..819387f54 100644 --- a/src/scss/includes/search_form.scss +++ b/src/scss/includes/search_form.scss @@ -86,8 +86,9 @@ input[type="search"] { } } -// Return arrow -.search_form__return { +// Return arrows +.search_form__return, +.search_form__return-to-list { display: none; } @@ -191,7 +192,8 @@ input[type="search"] { font-size: 14px; } - .search_form__return { + .search_form__return, + .search_form__return-to-list { display: none; font-size: 20px; text-align: center; @@ -303,4 +305,25 @@ input[type="search"] { display: none; } } + + // When a PoI Panel is displayed + .top_bar--poi-from-list { + + // Show the return arrow + .search_form__return-to-list { + display: block; + } + + // If the search field is focused, hide it + &.top_bar--search_focus { + .search_form__return-to-list { + display: none; + } + } + + // Make room for it on the left of the field + .search_form__wrapper { + padding-left: $spacing-xxl-3; + } + } } diff --git a/tests/integration/tests/autocomplete.js b/tests/integration/tests/autocomplete.js index f859d5436..e9567ad8a 100644 --- a/tests/integration/tests/autocomplete.js +++ b/tests/integration/tests/autocomplete.js @@ -249,8 +249,8 @@ test('Search Query', async () => { await page.goto(`${APP_URL}/?q=${searchQuery}`); const searchValue = await getInputValue(page, '#search'); - // search input is filled with query - expect(searchValue).toEqual(searchQuery); + // search input is filled with PoI name (not the query) + expect(searchValue).toEqual('test result 1'); // app navigates to first result from autocomplete expect(page.url()).toEqual(`${APP_URL}/place/osm:node:4872758213@test_result_1`); diff --git a/tests/integration/tests/poi.desktop.js b/tests/integration/tests/poi.desktop.js index b16520c1e..daec025ea 100644 --- a/tests/integration/tests/poi.desktop.js +++ b/tests/integration/tests/poi.desktop.js @@ -84,7 +84,6 @@ test('add a poi as favorite and find it back in the favorite menu', async () => expect(await exists(page, '.poiTitle')).toBeTruthy(); expect(await exists(page, '.poi_panel')).toBeTruthy(); await page.click('.poi_panel__actions .poi_panel__action__favorite'); - await page.click('.poi_panel .closeButton'); // we check that the first favorite item is our poi await toggleFavoritePanel(page); let fav = await getFavorites(page); @@ -99,7 +98,6 @@ test('add a poi as favorite and find it back in the favorite menu', async () => expect(await exists(page, '.poi_panel')).toBeTruthy(); await page.click('.poi_panel__actions .poi_panel__action__favorite'); - await page.click('.poi_panel .closeButton'); // it should disappear from the favorites await toggleFavoritePanel(page); fav = await getFavorites(page); diff --git a/views/index.ejs b/views/index.ejs index 7b08b7eb9..6f1ce6176 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -49,6 +49,7 @@ >
+