From 2223da99b99698e367425fa2f433e5f19e46e078 Mon Sep 17 00:00:00 2001 From: Katherina Marcenko Date: Thu, 14 Nov 2019 09:47:58 +0100 Subject: [PATCH 1/4] feat(url): sync selected layers state to url --- package-lock.json | 34 ++--- src/scripts/actions/set-selected-layer-ids.ts | 18 --- src/scripts/components/app/app.tsx | 5 +- .../data-set-info/data-set-info.tsx | 10 +- src/scripts/components/globe/globe.tsx | 6 +- src/scripts/components/globes/globes.tsx | 25 +++- .../components/info-button/info-button.tsx | 3 +- .../components/layer-list/layer-list.tsx | 120 +++++++++++------- .../components/layer-loader/layer-loader.tsx | 16 +-- .../layer-selector/layer-selector.tsx | 20 +-- .../remove-compare/remove-compare.tsx | 21 ++- .../components/time-slider/time-slider.tsx | 13 +- src/scripts/reducers/layers/index.ts | 4 +- src/scripts/reducers/layers/selected-ids.ts | 31 ----- src/scripts/selectors/layers/active.ts | 14 +- src/scripts/selectors/layers/selected-ids.ts | 6 - src/scripts/selectors/layers/selected.ts | 33 +++-- 17 files changed, 179 insertions(+), 200 deletions(-) delete mode 100644 src/scripts/actions/set-selected-layer-ids.ts delete mode 100644 src/scripts/reducers/layers/selected-ids.ts delete mode 100644 src/scripts/selectors/layers/selected-ids.ts diff --git a/package-lock.json b/package-lock.json index c7ca50d19..c80a2fd66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7389,6 +7389,24 @@ "prepend-http": "^1.0.0", "query-string": "^4.1.0", "sort-keys": "^1.0.0" + }, + "dependencies": { + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + } } }, "npm-run-path": { @@ -9146,16 +9164,6 @@ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", "dev": true }, - "query-string": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", - "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", - "dev": true, - "requires": { - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -10781,12 +10789,6 @@ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", "dev": true }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "dev": true - }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", diff --git a/src/scripts/actions/set-selected-layer-ids.ts b/src/scripts/actions/set-selected-layer-ids.ts deleted file mode 100644 index fd3223019..000000000 --- a/src/scripts/actions/set-selected-layer-ids.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const SET_SELECTED_LAYER_IDS = 'SET_SELECTED_LAYER_IDS'; - -export interface SetSelectedLayerIdsAction { - type: typeof SET_SELECTED_LAYER_IDS; - layerIds: string | null; - isPrimary: boolean; -} - -const setSelectedLayerIdsAction = ( - layerIds: string | null, - isPrimary: boolean -): SetSelectedLayerIdsAction => ({ - type: SET_SELECTED_LAYER_IDS, - layerIds, - isPrimary -}); - -export default setSelectedLayerIdsAction; diff --git a/src/scripts/components/app/app.tsx b/src/scripts/components/app/app.tsx index 7b2181a9a..14ff4c428 100644 --- a/src/scripts/components/app/app.tsx +++ b/src/scripts/components/app/app.tsx @@ -45,7 +45,7 @@ const TranslatedApp: FunctionComponent = () => {
- +
@@ -54,6 +54,7 @@ const TranslatedApp: FunctionComponent = () => {
+
@@ -74,6 +75,7 @@ const TranslatedApp: FunctionComponent = () => { render={props => ( )}> +
@@ -87,7 +89,6 @@ const TranslatedApp: FunctionComponent = () => { - ); diff --git a/src/scripts/components/data-set-info/data-set-info.tsx b/src/scripts/components/data-set-info/data-set-info.tsx index dd2075e47..15d028faa 100644 --- a/src/scripts/components/data-set-info/data-set-info.tsx +++ b/src/scripts/components/data-set-info/data-set-info.tsx @@ -1,20 +1,16 @@ import React, {FunctionComponent} from 'react'; -import {useSelector} from 'react-redux'; - -import {selectedLayersSelector} from '../../selectors/layers/selected'; import RemoveCompare from '../remove-compare/remove-compare'; import InfoButton from '../info-button/info-button'; import styles from './data-set-info.styl'; +import {LayerListItem} from '../../types/layer-list'; interface Props { isMain?: boolean; + layer: LayerListItem | null; } -const DataSetInfo: FunctionComponent = ({isMain}) => { - const {main, compare} = useSelector(selectedLayersSelector); - const layer = isMain ? main : compare; - +const DataSetInfo: FunctionComponent = ({layer, isMain}) => { return (

{layer && layer.name}

diff --git a/src/scripts/components/globe/globe.tsx b/src/scripts/components/globe/globe.tsx index c33914ff2..be3df56eb 100644 --- a/src/scripts/components/globe/globe.tsx +++ b/src/scripts/components/globe/globe.tsx @@ -14,6 +14,8 @@ import {GlobeProjection} from '../../types/globe-projection'; import 'cesium/Source/Widgets/widgets.css'; import 'cesium/Build/Cesium/Cesium'; +import {LayerListItem} from '../../types/layer-list'; + import styles from './globe.styl'; const Cesium = window.Cesium; @@ -44,6 +46,7 @@ const cesiumOptions = { interface Props { active: boolean; + layer: LayerListItem | null; isMain?: boolean; view: GlobeView; projection: GlobeProjection; @@ -59,6 +62,7 @@ const Globe: FunctionComponent = ({ projection, imageUrl, active, + layer, isMain, flyTo, onMouseEnter, @@ -177,7 +181,7 @@ const Globe: FunctionComponent = ({ return (
onMouseEnter()} ref={ref}> - +
); }; diff --git a/src/scripts/components/globes/globes.tsx b/src/scripts/components/globes/globes.tsx index 7dd13df09..3bf57b853 100644 --- a/src/scripts/components/globes/globes.tsx +++ b/src/scripts/components/globes/globes.tsx @@ -5,8 +5,8 @@ import React, { useCallback } from 'react'; import {useSelector, useDispatch} from 'react-redux'; +import {matchPath, useLocation} from 'react-router'; -import {selectedLayerIdsSelector} from '../../selectors/layers/selected-ids'; import {activeLayersSelector} from '../../selectors/layers/active'; import {globeViewSelector} from '../../selectors/globe/view'; import {timeSelector} from '../../selectors/globe/time'; @@ -15,20 +15,31 @@ import setGlobeViewAction from '../../actions/set-globe-view'; import Globe from '../globe/globe'; import {getLayerTileUrl} from '../../libs/get-layer-tile-url'; import {flyToSelector} from '../../selectors/fly-to'; +import {State} from '../../reducers'; import {GlobeView} from '../../types/globe-view'; import styles from './globes.styl'; +import {selectedLayersSelector} from '../../selectors/layers/selected'; const Globes: FunctionComponent = () => { + const location = useLocation(); + const match = matchPath(location.pathname, { + path: '(/|/layers)/:mainLayerId?/:compareLayerId?', + exact: true + }); const dispatch = useDispatch(); const projection = useSelector(projectionSelector); const globalGlobeView = useSelector(globeViewSelector); - const activeLayers = useSelector(activeLayersSelector); + const {mainLayerDetails, compareLayerDetails} = useSelector((state: State) => + activeLayersSelector(state, match && match.params) + ); + const {main, compare} = useSelector((state: State) => + selectedLayersSelector(state, match && match.params) + ); const time = useSelector(timeSelector); const [currentView, setCurrentView] = useState(globalGlobeView); const [isMainActive, setIsMainActive] = useState(true); - const selectedLayerIds = useSelector(selectedLayerIdsSelector); const flyTo = useSelector(flyToSelector); const onChangeHandler = useCallback( (view: GlobeView) => setCurrentView(view), @@ -39,8 +50,8 @@ const Globes: FunctionComponent = () => { [dispatch] ); - const mainImageUrl = getLayerTileUrl(activeLayers.main, time); - const compareImageUrl = getLayerTileUrl(activeLayers.compare, time); + const mainImageUrl = getLayerTileUrl(mainLayerDetails, time); + const compareImageUrl = getLayerTileUrl(compareLayerDetails, time); // apply changes in the app state view to our local view copy // we don't use the app state view all the time to keep store updates low @@ -51,6 +62,7 @@ const Globes: FunctionComponent = () => { return (
{ onMoveEnd={onMoveEndHandler} /> - {selectedLayerIds.compare && ( + {compare && ( void; + isMain: boolean; } -const LayerList: FunctionComponent = ({layers, selected, onSelect}) => ( -
    - {layers.map(layer => { - const layerClickHandler = () => { +const LayerList: FunctionComponent = ({layers, isMain}) => { + const history = useHistory(); + const {mainLayerId = '', compareLayerId = ''} = useParams(); + const selectedLayerId = isMain ? mainLayerId : compareLayerId; + + const layerClickHandler = (event: MouseEvent, id: string) => { + event.stopPropagation(); + + if (id === selectedLayerId) { + if (!isMain || !compareLayerId) { + const newPath = isMain ? '/' : `/layers/${mainLayerId}`; + history.push(newPath); + } + return; + } + + const newPath = isMain + ? `/layers/${id}/${compareLayerId}` + : `/layers/${mainLayerId}/${id}`; + + history.push(newPath); + }; + + return ( +
      + {layers.map(layer => { + const isSelected = selectedLayerId === layer.id; + const layerItemClasses = cx( + styles.layerItem, + isSelected && styles.layerItemSelected + ); + if (layer.subLayers.length === 0) { - onSelect(layer.id); + return ( +
    • layerClickHandler(event, layer.id)}> + {layer.name} +
    • + ); } - }; - const isSelected = selected === layer.id; - const layerItemClasses = cx( - styles.layerItem, - isSelected && styles.layerItemSelected - ); - return ( -
    • layerClickHandler()}> - {layer.name} + return ( +
    • + {layer.name} - {layer.subLayers && ( -
        - {layer.subLayers.map(subLayer => { - const subLayerClickHandler = (event: MouseEvent) => { - event.stopPropagation(); - onSelect(subLayer.id); - }; - const isSubSelected = selected === subLayer.id; - const subLayerItemClasses = cx( - styles.subLayerItem, - isSubSelected && styles.subLayerItemSelected - ); + {layer.subLayers && ( +
          + {layer.subLayers.map(subLayer => { + const isSubSelected = selectedLayerId === subLayer.id; + const subLayerItemClasses = cx( + styles.subLayerItem, + isSubSelected && styles.subLayerItemSelected + ); - return ( -
        • subLayerClickHandler(event)}> - {subLayer.name} -
        • - ); - })} -
        - )} - - ); - })} -
      -); + return ( +
    • layerClickHandler(event, subLayer.id)} + key={subLayer.id}> + {subLayer.name} +
    • + ); + })} +
    + )} + + ); + })} +
+ ); +}; export default LayerList; diff --git a/src/scripts/components/layer-loader/layer-loader.tsx b/src/scripts/components/layer-loader/layer-loader.tsx index 17f5c70d4..c861b915c 100644 --- a/src/scripts/components/layer-loader/layer-loader.tsx +++ b/src/scripts/components/layer-loader/layer-loader.tsx @@ -1,9 +1,9 @@ import {FunctionComponent, useEffect} from 'react'; import {useSelector, useDispatch} from 'react-redux'; +import {useParams} from 'react-router'; import fetchLayers from '../../actions/fetch-layers'; import fetchLayerAction from '../../actions/fetch-layer'; -import {selectedLayerIdsSelector} from '../../selectors/layers/selected-ids'; import {detailedLayersSelector} from '../../selectors/layers/details'; /** @@ -11,7 +11,7 @@ import {detailedLayersSelector} from '../../selectors/layers/details'; */ const LayerLoader: FunctionComponent = () => { const dispatch = useDispatch(); - const selectedLayerIds = useSelector(selectedLayerIdsSelector); + const {mainLayerId, compareLayerId} = useParams(); const detailedLayers = useSelector(detailedLayersSelector); // load layer list on mount @@ -21,16 +21,14 @@ const LayerLoader: FunctionComponent = () => { // fetch layer if it is selected and not already downloaded useEffect(() => { - const {main, compare} = selectedLayerIds; - - if (main && !detailedLayers[main]) { - dispatch(fetchLayerAction(main)); + if (mainLayerId && !detailedLayers[mainLayerId]) { + dispatch(fetchLayerAction(mainLayerId)); } - if (compare && !detailedLayers[compare]) { - dispatch(fetchLayerAction(compare)); + if (compareLayerId && !detailedLayers[compareLayerId]) { + dispatch(fetchLayerAction(compareLayerId)); } - }, [dispatch, selectedLayerIds, detailedLayers]); + }, [dispatch, detailedLayers, mainLayerId, compareLayerId]); return null; }; diff --git a/src/scripts/components/layer-selector/layer-selector.tsx b/src/scripts/components/layer-selector/layer-selector.tsx index 04e122a86..25b83759a 100644 --- a/src/scripts/components/layer-selector/layer-selector.tsx +++ b/src/scripts/components/layer-selector/layer-selector.tsx @@ -1,12 +1,10 @@ import React, {FunctionComponent, useState} from 'react'; -import {useSelector, useDispatch} from 'react-redux'; +import {useSelector} from 'react-redux'; import {useIntl} from 'react-intl'; import {layersSelector} from '../../selectors/layers/list'; -import {selectedLayerIdsSelector} from '../../selectors/layers/selected-ids'; import {LayersIcon} from '../icons/layers-icon'; import {CompareIcon} from '../icons/compare-icon'; -import setSelectedLayerIdAction from '../../actions/set-selected-layer-ids'; import LayerList from '../layer-list/layer-list'; import Tabs from '../tabs/tabs'; @@ -17,8 +15,6 @@ import styles from './layer-selector.styl'; const LayerSelector: FunctionComponent = () => { const intl = useIntl(); const layers = useSelector(layersSelector); - const layerIds = useSelector(selectedLayerIdsSelector); - const dispatch = useDispatch(); const tabs: Tab[] = [ { id: 'main', @@ -35,7 +31,6 @@ const LayerSelector: FunctionComponent = () => { const [activeTabId, setActiveTabId] = useState(tabs[0].id); const [isOpen, setIsOpen] = useState(false); const isMainTabSelected = activeTabId === tabs[0].id; - const selectedLayer = isMainTabSelected ? layerIds.main : layerIds.compare; const onTabClick = (id: string) => { setActiveTabId(id); @@ -50,11 +45,6 @@ const LayerSelector: FunctionComponent = () => { } }; - const onLayerClick = (id: string) => { - const newId = selectedLayer === id ? null : id; - dispatch(setSelectedLayerIdAction(newId, isMainTabSelected)); - }; - return (
{ activeTabId={activeTabId} onTabChanged={id => onTabClick(id)} /> - {isOpen && ( - onLayerClick(id)} - /> - )} + {isOpen && }
); }; diff --git a/src/scripts/components/remove-compare/remove-compare.tsx b/src/scripts/components/remove-compare/remove-compare.tsx index fbe432428..153826f83 100644 --- a/src/scripts/components/remove-compare/remove-compare.tsx +++ b/src/scripts/components/remove-compare/remove-compare.tsx @@ -1,28 +1,23 @@ import React, {FunctionComponent} from 'react'; -import {useDispatch} from 'react-redux'; import {useIntl} from 'react-intl'; +import {Link} from 'react-router-dom'; -import setSelectedLayerIdsAction from '../../actions/set-selected-layer-ids'; import {RemoveIcon} from '../icons/remove-icon'; import styles from './remove-compare.styl'; const RemoveCompare: FunctionComponent = () => { const intl = useIntl(); - const dispatch = useDispatch(); - - const onButtonClick = () => { - dispatch(setSelectedLayerIdsAction(null, false)); - }; return (
- + + +
); }; diff --git a/src/scripts/components/time-slider/time-slider.tsx b/src/scripts/components/time-slider/time-slider.tsx index 82b0d1af6..1b71c420f 100644 --- a/src/scripts/components/time-slider/time-slider.tsx +++ b/src/scripts/components/time-slider/time-slider.tsx @@ -6,12 +6,14 @@ import React, { useCallback } from 'react'; import {useSelector, useDispatch} from 'react-redux'; +import {useParams} from 'react-router'; import debounce from 'lodash.debounce'; import {languageSelector} from '../../selectors/language'; import {activeLayersSelector} from '../../selectors/layers/active'; import setGlobeTime from '../../actions/set-globe-time'; import {getTimeRanges} from '../../libs/get-time-ranges'; +import {State} from '../../reducers'; import styles from './time-slider.styl'; @@ -19,14 +21,17 @@ import styles from './time-slider.styl'; const DELAY = 200; const TimeSlider: FunctionComponent = () => { + const params = useParams(); const dispatch = useDispatch(); const [time, setTime] = useState(0); const stepSize = 1000 * 60 * 60 * 24; // one day const language = useSelector(languageSelector); - const activeLayers = useSelector(activeLayersSelector); + const {mainLayerDetails, compareLayerDetails} = useSelector((state: State) => + activeLayersSelector(state, params) + ); // date format - const mainDateFormat = activeLayers.main && activeLayers.main.timeFormat; + const mainDateFormat = mainLayerDetails && mainLayerDetails.timeFormat; const {format} = useMemo( () => new Intl.DateTimeFormat(language, mainDateFormat || {}), [language, mainDateFormat] @@ -34,8 +39,8 @@ const TimeSlider: FunctionComponent = () => { // ranges const {main, compare, combined} = useMemo( - () => getTimeRanges(activeLayers.main, activeLayers.compare), - [activeLayers.main, activeLayers.compare] + () => getTimeRanges(mainLayerDetails, compareLayerDetails), + [mainLayerDetails, compareLayerDetails] ); const timestampsAvailable = combined.timestamps.length > 0; const totalRange = combined.max - combined.min; diff --git a/src/scripts/reducers/layers/index.ts b/src/scripts/reducers/layers/index.ts index aa71e39a4..5550a59ef 100644 --- a/src/scripts/reducers/layers/index.ts +++ b/src/scripts/reducers/layers/index.ts @@ -2,12 +2,10 @@ import {combineReducers} from 'redux'; import listReducer from './list'; import detailsReducer from './details'; -import selectedIdsReducer from './selected-ids'; const layersReducer = combineReducers({ list: listReducer, - details: detailsReducer, - selectedIds: selectedIdsReducer + details: detailsReducer }); export default layersReducer; diff --git a/src/scripts/reducers/layers/selected-ids.ts b/src/scripts/reducers/layers/selected-ids.ts deleted file mode 100644 index 573bb2de7..000000000 --- a/src/scripts/reducers/layers/selected-ids.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { - SET_SELECTED_LAYER_IDS, - SetSelectedLayerIdsAction -} from '../../actions/set-selected-layer-ids'; - -export interface SelectedLayerIdsState { - main: string | null; - compare: string | null; -} - -const initialState = { - main: null, - compare: null -}; - -function selectedLayerIdsReducer( - state: SelectedLayerIdsState = initialState, - action: SetSelectedLayerIdsAction -): SelectedLayerIdsState { - switch (action.type) { - case SET_SELECTED_LAYER_IDS: - const newState = {...state}; - const key = action.isPrimary ? 'main' : 'compare'; - newState[key] = action.layerIds; - return newState; - default: - return state; - } -} - -export default selectedLayerIdsReducer; diff --git a/src/scripts/selectors/layers/active.ts b/src/scripts/selectors/layers/active.ts index 470ba925d..19bf61046 100644 --- a/src/scripts/selectors/layers/active.ts +++ b/src/scripts/selectors/layers/active.ts @@ -1,11 +1,15 @@ import {State} from '../../reducers/index'; -import {selectedLayerIdsSelector} from './selected-ids'; -export function activeLayersSelector(state: State) { - const {main: mainId, compare: compareId} = selectedLayerIdsSelector(state); +export function activeLayersSelector( + state: State, + props: {[key: string]: string} | null +) { + const {mainLayerId, compareLayerId} = props || {}; return { - main: (mainId && state.layers.details[mainId]) || null, - compare: (compareId && state.layers.details[compareId]) || null + mainLayerDetails: + (mainLayerId && state.layers.details[mainLayerId]) || null, + compareLayerDetails: + (compareLayerId && state.layers.details[compareLayerId]) || null }; } diff --git a/src/scripts/selectors/layers/selected-ids.ts b/src/scripts/selectors/layers/selected-ids.ts deleted file mode 100644 index ba4467eba..000000000 --- a/src/scripts/selectors/layers/selected-ids.ts +++ /dev/null @@ -1,6 +0,0 @@ -import {SelectedLayerIdsState} from '../../reducers/layers/selected-ids'; -import {State} from '../../reducers/index'; - -export function selectedLayerIdsSelector(state: State): SelectedLayerIdsState { - return state.layers.selectedIds; -} diff --git a/src/scripts/selectors/layers/selected.ts b/src/scripts/selectors/layers/selected.ts index dafaccea3..9ca51b81e 100644 --- a/src/scripts/selectors/layers/selected.ts +++ b/src/scripts/selectors/layers/selected.ts @@ -1,6 +1,4 @@ -import {SelectedLayerIdsState} from '../../reducers/layers/selected-ids'; import {layersSelector} from '../../selectors/layers/list'; -import {selectedLayerIdsSelector} from '../../selectors/layers/selected-ids'; import {State} from '../../reducers/index'; import {LayerList, LayerListItem} from '../../types/layer-list'; @@ -10,21 +8,28 @@ interface SelectedLayerItems { compare: LayerListItem | null; } +interface SelectedLayerIds { + mainLayerId: string | undefined; + compareLayerId: string | undefined; +} + const getSelectedLayers = ( layers: LayerList, - selectedLayerIds: SelectedLayerIdsState -): SelectedLayerItems => - layers.reduce( + selectedLayerIds: SelectedLayerIds +): SelectedLayerItems => { + const {mainLayerId, compareLayerId} = selectedLayerIds; + + return layers.reduce( ( selectedLayers: SelectedLayerItems, layer: LayerListItem ): SelectedLayerItems => { if (layer.subLayers.length) { const mainLayer = layer.subLayers.find( - subLayer => subLayer.id === selectedLayerIds.main + subLayer => subLayer.id === mainLayerId ); const compareLayer = layer.subLayers.find( - subLayer => subLayer.id === selectedLayerIds.compare + subLayer => subLayer.id === compareLayerId ); return { @@ -33,8 +38,8 @@ const getSelectedLayers = ( }; } - const isMainLayer = layer.id === selectedLayerIds.main; - const isCompareLayer = layer.id === selectedLayerIds.compare; + const isMainLayer = layer.id === mainLayerId; + const isCompareLayer = layer.id === compareLayerId; return { main: isMainLayer ? layer : selectedLayers.main, @@ -43,9 +48,13 @@ const getSelectedLayers = ( }, {main: null, compare: null} ); +}; -export function selectedLayersSelector(state: State): SelectedLayerItems { +export function selectedLayersSelector( + state: State, + props: {[key: string]: string} | null +): SelectedLayerItems { const layers = layersSelector(state); - const selectedLayerIds = selectedLayerIdsSelector(state); - return getSelectedLayers(layers, selectedLayerIds); + const {mainLayerId, compareLayerId} = props || {}; + return getSelectedLayers(layers, {mainLayerId, compareLayerId}); } From d57a511d82ba61d4eecb70cbcf1690010fa910b2 Mon Sep 17 00:00:00 2001 From: Katherina Marcenko Date: Thu, 14 Nov 2019 09:47:58 +0100 Subject: [PATCH 2/4] feat(url): sync selected layers state to url --- package-lock.json | 34 ++--- src/scripts/actions/set-selected-layer-ids.ts | 18 --- src/scripts/components/app/app.tsx | 9 +- .../data-set-info/data-set-info.tsx | 28 ++-- src/scripts/components/globe/globe.tsx | 6 +- src/scripts/components/globes/globes.tsx | 25 +++- .../components/info-button/info-button.tsx | 3 +- .../components/layer-list/layer-list.tsx | 120 +++++++++++------- .../components/layer-loader/layer-loader.tsx | 16 +-- .../layer-selector/layer-selector.tsx | 20 +-- .../remove-compare/remove-compare.tsx | 21 ++- .../components/time-slider/time-slider.tsx | 13 +- src/scripts/reducers/layers/index.ts | 4 +- src/scripts/reducers/layers/selected-ids.ts | 31 ----- src/scripts/selectors/layers/active.ts | 14 +- src/scripts/selectors/layers/selected-ids.ts | 6 - src/scripts/selectors/layers/selected.ts | 33 +++-- 17 files changed, 188 insertions(+), 213 deletions(-) delete mode 100644 src/scripts/actions/set-selected-layer-ids.ts delete mode 100644 src/scripts/reducers/layers/selected-ids.ts delete mode 100644 src/scripts/selectors/layers/selected-ids.ts diff --git a/package-lock.json b/package-lock.json index c7ca50d19..c80a2fd66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7389,6 +7389,24 @@ "prepend-http": "^1.0.0", "query-string": "^4.1.0", "sort-keys": "^1.0.0" + }, + "dependencies": { + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + } } }, "npm-run-path": { @@ -9146,16 +9164,6 @@ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", "dev": true }, - "query-string": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", - "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", - "dev": true, - "requires": { - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -10781,12 +10789,6 @@ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", "dev": true }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "dev": true - }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", diff --git a/src/scripts/actions/set-selected-layer-ids.ts b/src/scripts/actions/set-selected-layer-ids.ts deleted file mode 100644 index fd3223019..000000000 --- a/src/scripts/actions/set-selected-layer-ids.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const SET_SELECTED_LAYER_IDS = 'SET_SELECTED_LAYER_IDS'; - -export interface SetSelectedLayerIdsAction { - type: typeof SET_SELECTED_LAYER_IDS; - layerIds: string | null; - isPrimary: boolean; -} - -const setSelectedLayerIdsAction = ( - layerIds: string | null, - isPrimary: boolean -): SetSelectedLayerIdsAction => ({ - type: SET_SELECTED_LAYER_IDS, - layerIds, - isPrimary -}); - -export default setSelectedLayerIdsAction; diff --git a/src/scripts/components/app/app.tsx b/src/scripts/components/app/app.tsx index 7b2181a9a..be1ac1b76 100644 --- a/src/scripts/components/app/app.tsx +++ b/src/scripts/components/app/app.tsx @@ -45,7 +45,7 @@ const TranslatedApp: FunctionComponent = () => {
- +
@@ -54,6 +54,7 @@ const TranslatedApp: FunctionComponent = () => {
+
@@ -70,13 +71,13 @@ const TranslatedApp: FunctionComponent = () => { ( )}> + +
-
@@ -85,9 +86,7 @@ const TranslatedApp: FunctionComponent = () => {
- - ); diff --git a/src/scripts/components/data-set-info/data-set-info.tsx b/src/scripts/components/data-set-info/data-set-info.tsx index dd2075e47..dcdcfc065 100644 --- a/src/scripts/components/data-set-info/data-set-info.tsx +++ b/src/scripts/components/data-set-info/data-set-info.tsx @@ -1,30 +1,24 @@ import React, {FunctionComponent} from 'react'; -import {useSelector} from 'react-redux'; - -import {selectedLayersSelector} from '../../selectors/layers/selected'; import RemoveCompare from '../remove-compare/remove-compare'; import InfoButton from '../info-button/info-button'; import styles from './data-set-info.styl'; +import {LayerListItem} from '../../types/layer-list'; interface Props { isMain?: boolean; + layer: LayerListItem | null; } -const DataSetInfo: FunctionComponent = ({isMain}) => { - const {main, compare} = useSelector(selectedLayersSelector); - const layer = isMain ? main : compare; - - return ( -
-

{layer && layer.name}

-

{layer && layer.description}

-
- - {!isMain && } -
+const DataSetInfo: FunctionComponent = ({layer, isMain}) => ( +
+

{layer && layer.name}

+

{layer && layer.description}

+
+ + {!isMain && }
- ); -}; +
+); export default DataSetInfo; diff --git a/src/scripts/components/globe/globe.tsx b/src/scripts/components/globe/globe.tsx index c33914ff2..be3df56eb 100644 --- a/src/scripts/components/globe/globe.tsx +++ b/src/scripts/components/globe/globe.tsx @@ -14,6 +14,8 @@ import {GlobeProjection} from '../../types/globe-projection'; import 'cesium/Source/Widgets/widgets.css'; import 'cesium/Build/Cesium/Cesium'; +import {LayerListItem} from '../../types/layer-list'; + import styles from './globe.styl'; const Cesium = window.Cesium; @@ -44,6 +46,7 @@ const cesiumOptions = { interface Props { active: boolean; + layer: LayerListItem | null; isMain?: boolean; view: GlobeView; projection: GlobeProjection; @@ -59,6 +62,7 @@ const Globe: FunctionComponent = ({ projection, imageUrl, active, + layer, isMain, flyTo, onMouseEnter, @@ -177,7 +181,7 @@ const Globe: FunctionComponent = ({ return (
onMouseEnter()} ref={ref}> - +
); }; diff --git a/src/scripts/components/globes/globes.tsx b/src/scripts/components/globes/globes.tsx index 7dd13df09..3bf57b853 100644 --- a/src/scripts/components/globes/globes.tsx +++ b/src/scripts/components/globes/globes.tsx @@ -5,8 +5,8 @@ import React, { useCallback } from 'react'; import {useSelector, useDispatch} from 'react-redux'; +import {matchPath, useLocation} from 'react-router'; -import {selectedLayerIdsSelector} from '../../selectors/layers/selected-ids'; import {activeLayersSelector} from '../../selectors/layers/active'; import {globeViewSelector} from '../../selectors/globe/view'; import {timeSelector} from '../../selectors/globe/time'; @@ -15,20 +15,31 @@ import setGlobeViewAction from '../../actions/set-globe-view'; import Globe from '../globe/globe'; import {getLayerTileUrl} from '../../libs/get-layer-tile-url'; import {flyToSelector} from '../../selectors/fly-to'; +import {State} from '../../reducers'; import {GlobeView} from '../../types/globe-view'; import styles from './globes.styl'; +import {selectedLayersSelector} from '../../selectors/layers/selected'; const Globes: FunctionComponent = () => { + const location = useLocation(); + const match = matchPath(location.pathname, { + path: '(/|/layers)/:mainLayerId?/:compareLayerId?', + exact: true + }); const dispatch = useDispatch(); const projection = useSelector(projectionSelector); const globalGlobeView = useSelector(globeViewSelector); - const activeLayers = useSelector(activeLayersSelector); + const {mainLayerDetails, compareLayerDetails} = useSelector((state: State) => + activeLayersSelector(state, match && match.params) + ); + const {main, compare} = useSelector((state: State) => + selectedLayersSelector(state, match && match.params) + ); const time = useSelector(timeSelector); const [currentView, setCurrentView] = useState(globalGlobeView); const [isMainActive, setIsMainActive] = useState(true); - const selectedLayerIds = useSelector(selectedLayerIdsSelector); const flyTo = useSelector(flyToSelector); const onChangeHandler = useCallback( (view: GlobeView) => setCurrentView(view), @@ -39,8 +50,8 @@ const Globes: FunctionComponent = () => { [dispatch] ); - const mainImageUrl = getLayerTileUrl(activeLayers.main, time); - const compareImageUrl = getLayerTileUrl(activeLayers.compare, time); + const mainImageUrl = getLayerTileUrl(mainLayerDetails, time); + const compareImageUrl = getLayerTileUrl(compareLayerDetails, time); // apply changes in the app state view to our local view copy // we don't use the app state view all the time to keep store updates low @@ -51,6 +62,7 @@ const Globes: FunctionComponent = () => { return (
{ onMoveEnd={onMoveEndHandler} /> - {selectedLayerIds.compare && ( + {compare && ( void; + isMain: boolean; } -const LayerList: FunctionComponent = ({layers, selected, onSelect}) => ( -
    - {layers.map(layer => { - const layerClickHandler = () => { +const LayerList: FunctionComponent = ({layers, isMain}) => { + const history = useHistory(); + const {mainLayerId = '', compareLayerId = ''} = useParams(); + const selectedLayerId = isMain ? mainLayerId : compareLayerId; + + const layerClickHandler = (event: MouseEvent, id: string) => { + event.stopPropagation(); + + if (id === selectedLayerId) { + if (!isMain || !compareLayerId) { + const newPath = isMain ? '/' : `/layers/${mainLayerId}`; + history.push(newPath); + } + return; + } + + const newPath = isMain + ? `/layers/${id}/${compareLayerId}` + : `/layers/${mainLayerId}/${id}`; + + history.push(newPath); + }; + + return ( +
      + {layers.map(layer => { + const isSelected = selectedLayerId === layer.id; + const layerItemClasses = cx( + styles.layerItem, + isSelected && styles.layerItemSelected + ); + if (layer.subLayers.length === 0) { - onSelect(layer.id); + return ( +
    • layerClickHandler(event, layer.id)}> + {layer.name} +
    • + ); } - }; - const isSelected = selected === layer.id; - const layerItemClasses = cx( - styles.layerItem, - isSelected && styles.layerItemSelected - ); - return ( -
    • layerClickHandler()}> - {layer.name} + return ( +
    • + {layer.name} - {layer.subLayers && ( -
        - {layer.subLayers.map(subLayer => { - const subLayerClickHandler = (event: MouseEvent) => { - event.stopPropagation(); - onSelect(subLayer.id); - }; - const isSubSelected = selected === subLayer.id; - const subLayerItemClasses = cx( - styles.subLayerItem, - isSubSelected && styles.subLayerItemSelected - ); + {layer.subLayers && ( +
          + {layer.subLayers.map(subLayer => { + const isSubSelected = selectedLayerId === subLayer.id; + const subLayerItemClasses = cx( + styles.subLayerItem, + isSubSelected && styles.subLayerItemSelected + ); - return ( -
        • subLayerClickHandler(event)}> - {subLayer.name} -
        • - ); - })} -
        - )} - - ); - })} -
      -); + return ( +
    • layerClickHandler(event, subLayer.id)} + key={subLayer.id}> + {subLayer.name} +
    • + ); + })} +
    + )} + + ); + })} +
+ ); +}; export default LayerList; diff --git a/src/scripts/components/layer-loader/layer-loader.tsx b/src/scripts/components/layer-loader/layer-loader.tsx index 17f5c70d4..c861b915c 100644 --- a/src/scripts/components/layer-loader/layer-loader.tsx +++ b/src/scripts/components/layer-loader/layer-loader.tsx @@ -1,9 +1,9 @@ import {FunctionComponent, useEffect} from 'react'; import {useSelector, useDispatch} from 'react-redux'; +import {useParams} from 'react-router'; import fetchLayers from '../../actions/fetch-layers'; import fetchLayerAction from '../../actions/fetch-layer'; -import {selectedLayerIdsSelector} from '../../selectors/layers/selected-ids'; import {detailedLayersSelector} from '../../selectors/layers/details'; /** @@ -11,7 +11,7 @@ import {detailedLayersSelector} from '../../selectors/layers/details'; */ const LayerLoader: FunctionComponent = () => { const dispatch = useDispatch(); - const selectedLayerIds = useSelector(selectedLayerIdsSelector); + const {mainLayerId, compareLayerId} = useParams(); const detailedLayers = useSelector(detailedLayersSelector); // load layer list on mount @@ -21,16 +21,14 @@ const LayerLoader: FunctionComponent = () => { // fetch layer if it is selected and not already downloaded useEffect(() => { - const {main, compare} = selectedLayerIds; - - if (main && !detailedLayers[main]) { - dispatch(fetchLayerAction(main)); + if (mainLayerId && !detailedLayers[mainLayerId]) { + dispatch(fetchLayerAction(mainLayerId)); } - if (compare && !detailedLayers[compare]) { - dispatch(fetchLayerAction(compare)); + if (compareLayerId && !detailedLayers[compareLayerId]) { + dispatch(fetchLayerAction(compareLayerId)); } - }, [dispatch, selectedLayerIds, detailedLayers]); + }, [dispatch, detailedLayers, mainLayerId, compareLayerId]); return null; }; diff --git a/src/scripts/components/layer-selector/layer-selector.tsx b/src/scripts/components/layer-selector/layer-selector.tsx index 04e122a86..25b83759a 100644 --- a/src/scripts/components/layer-selector/layer-selector.tsx +++ b/src/scripts/components/layer-selector/layer-selector.tsx @@ -1,12 +1,10 @@ import React, {FunctionComponent, useState} from 'react'; -import {useSelector, useDispatch} from 'react-redux'; +import {useSelector} from 'react-redux'; import {useIntl} from 'react-intl'; import {layersSelector} from '../../selectors/layers/list'; -import {selectedLayerIdsSelector} from '../../selectors/layers/selected-ids'; import {LayersIcon} from '../icons/layers-icon'; import {CompareIcon} from '../icons/compare-icon'; -import setSelectedLayerIdAction from '../../actions/set-selected-layer-ids'; import LayerList from '../layer-list/layer-list'; import Tabs from '../tabs/tabs'; @@ -17,8 +15,6 @@ import styles from './layer-selector.styl'; const LayerSelector: FunctionComponent = () => { const intl = useIntl(); const layers = useSelector(layersSelector); - const layerIds = useSelector(selectedLayerIdsSelector); - const dispatch = useDispatch(); const tabs: Tab[] = [ { id: 'main', @@ -35,7 +31,6 @@ const LayerSelector: FunctionComponent = () => { const [activeTabId, setActiveTabId] = useState(tabs[0].id); const [isOpen, setIsOpen] = useState(false); const isMainTabSelected = activeTabId === tabs[0].id; - const selectedLayer = isMainTabSelected ? layerIds.main : layerIds.compare; const onTabClick = (id: string) => { setActiveTabId(id); @@ -50,11 +45,6 @@ const LayerSelector: FunctionComponent = () => { } }; - const onLayerClick = (id: string) => { - const newId = selectedLayer === id ? null : id; - dispatch(setSelectedLayerIdAction(newId, isMainTabSelected)); - }; - return (
{ activeTabId={activeTabId} onTabChanged={id => onTabClick(id)} /> - {isOpen && ( - onLayerClick(id)} - /> - )} + {isOpen && }
); }; diff --git a/src/scripts/components/remove-compare/remove-compare.tsx b/src/scripts/components/remove-compare/remove-compare.tsx index fbe432428..153826f83 100644 --- a/src/scripts/components/remove-compare/remove-compare.tsx +++ b/src/scripts/components/remove-compare/remove-compare.tsx @@ -1,28 +1,23 @@ import React, {FunctionComponent} from 'react'; -import {useDispatch} from 'react-redux'; import {useIntl} from 'react-intl'; +import {Link} from 'react-router-dom'; -import setSelectedLayerIdsAction from '../../actions/set-selected-layer-ids'; import {RemoveIcon} from '../icons/remove-icon'; import styles from './remove-compare.styl'; const RemoveCompare: FunctionComponent = () => { const intl = useIntl(); - const dispatch = useDispatch(); - - const onButtonClick = () => { - dispatch(setSelectedLayerIdsAction(null, false)); - }; return (
- + + +
); }; diff --git a/src/scripts/components/time-slider/time-slider.tsx b/src/scripts/components/time-slider/time-slider.tsx index 82b0d1af6..1b71c420f 100644 --- a/src/scripts/components/time-slider/time-slider.tsx +++ b/src/scripts/components/time-slider/time-slider.tsx @@ -6,12 +6,14 @@ import React, { useCallback } from 'react'; import {useSelector, useDispatch} from 'react-redux'; +import {useParams} from 'react-router'; import debounce from 'lodash.debounce'; import {languageSelector} from '../../selectors/language'; import {activeLayersSelector} from '../../selectors/layers/active'; import setGlobeTime from '../../actions/set-globe-time'; import {getTimeRanges} from '../../libs/get-time-ranges'; +import {State} from '../../reducers'; import styles from './time-slider.styl'; @@ -19,14 +21,17 @@ import styles from './time-slider.styl'; const DELAY = 200; const TimeSlider: FunctionComponent = () => { + const params = useParams(); const dispatch = useDispatch(); const [time, setTime] = useState(0); const stepSize = 1000 * 60 * 60 * 24; // one day const language = useSelector(languageSelector); - const activeLayers = useSelector(activeLayersSelector); + const {mainLayerDetails, compareLayerDetails} = useSelector((state: State) => + activeLayersSelector(state, params) + ); // date format - const mainDateFormat = activeLayers.main && activeLayers.main.timeFormat; + const mainDateFormat = mainLayerDetails && mainLayerDetails.timeFormat; const {format} = useMemo( () => new Intl.DateTimeFormat(language, mainDateFormat || {}), [language, mainDateFormat] @@ -34,8 +39,8 @@ const TimeSlider: FunctionComponent = () => { // ranges const {main, compare, combined} = useMemo( - () => getTimeRanges(activeLayers.main, activeLayers.compare), - [activeLayers.main, activeLayers.compare] + () => getTimeRanges(mainLayerDetails, compareLayerDetails), + [mainLayerDetails, compareLayerDetails] ); const timestampsAvailable = combined.timestamps.length > 0; const totalRange = combined.max - combined.min; diff --git a/src/scripts/reducers/layers/index.ts b/src/scripts/reducers/layers/index.ts index aa71e39a4..5550a59ef 100644 --- a/src/scripts/reducers/layers/index.ts +++ b/src/scripts/reducers/layers/index.ts @@ -2,12 +2,10 @@ import {combineReducers} from 'redux'; import listReducer from './list'; import detailsReducer from './details'; -import selectedIdsReducer from './selected-ids'; const layersReducer = combineReducers({ list: listReducer, - details: detailsReducer, - selectedIds: selectedIdsReducer + details: detailsReducer }); export default layersReducer; diff --git a/src/scripts/reducers/layers/selected-ids.ts b/src/scripts/reducers/layers/selected-ids.ts deleted file mode 100644 index 573bb2de7..000000000 --- a/src/scripts/reducers/layers/selected-ids.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { - SET_SELECTED_LAYER_IDS, - SetSelectedLayerIdsAction -} from '../../actions/set-selected-layer-ids'; - -export interface SelectedLayerIdsState { - main: string | null; - compare: string | null; -} - -const initialState = { - main: null, - compare: null -}; - -function selectedLayerIdsReducer( - state: SelectedLayerIdsState = initialState, - action: SetSelectedLayerIdsAction -): SelectedLayerIdsState { - switch (action.type) { - case SET_SELECTED_LAYER_IDS: - const newState = {...state}; - const key = action.isPrimary ? 'main' : 'compare'; - newState[key] = action.layerIds; - return newState; - default: - return state; - } -} - -export default selectedLayerIdsReducer; diff --git a/src/scripts/selectors/layers/active.ts b/src/scripts/selectors/layers/active.ts index 470ba925d..19bf61046 100644 --- a/src/scripts/selectors/layers/active.ts +++ b/src/scripts/selectors/layers/active.ts @@ -1,11 +1,15 @@ import {State} from '../../reducers/index'; -import {selectedLayerIdsSelector} from './selected-ids'; -export function activeLayersSelector(state: State) { - const {main: mainId, compare: compareId} = selectedLayerIdsSelector(state); +export function activeLayersSelector( + state: State, + props: {[key: string]: string} | null +) { + const {mainLayerId, compareLayerId} = props || {}; return { - main: (mainId && state.layers.details[mainId]) || null, - compare: (compareId && state.layers.details[compareId]) || null + mainLayerDetails: + (mainLayerId && state.layers.details[mainLayerId]) || null, + compareLayerDetails: + (compareLayerId && state.layers.details[compareLayerId]) || null }; } diff --git a/src/scripts/selectors/layers/selected-ids.ts b/src/scripts/selectors/layers/selected-ids.ts deleted file mode 100644 index ba4467eba..000000000 --- a/src/scripts/selectors/layers/selected-ids.ts +++ /dev/null @@ -1,6 +0,0 @@ -import {SelectedLayerIdsState} from '../../reducers/layers/selected-ids'; -import {State} from '../../reducers/index'; - -export function selectedLayerIdsSelector(state: State): SelectedLayerIdsState { - return state.layers.selectedIds; -} diff --git a/src/scripts/selectors/layers/selected.ts b/src/scripts/selectors/layers/selected.ts index dafaccea3..9ca51b81e 100644 --- a/src/scripts/selectors/layers/selected.ts +++ b/src/scripts/selectors/layers/selected.ts @@ -1,6 +1,4 @@ -import {SelectedLayerIdsState} from '../../reducers/layers/selected-ids'; import {layersSelector} from '../../selectors/layers/list'; -import {selectedLayerIdsSelector} from '../../selectors/layers/selected-ids'; import {State} from '../../reducers/index'; import {LayerList, LayerListItem} from '../../types/layer-list'; @@ -10,21 +8,28 @@ interface SelectedLayerItems { compare: LayerListItem | null; } +interface SelectedLayerIds { + mainLayerId: string | undefined; + compareLayerId: string | undefined; +} + const getSelectedLayers = ( layers: LayerList, - selectedLayerIds: SelectedLayerIdsState -): SelectedLayerItems => - layers.reduce( + selectedLayerIds: SelectedLayerIds +): SelectedLayerItems => { + const {mainLayerId, compareLayerId} = selectedLayerIds; + + return layers.reduce( ( selectedLayers: SelectedLayerItems, layer: LayerListItem ): SelectedLayerItems => { if (layer.subLayers.length) { const mainLayer = layer.subLayers.find( - subLayer => subLayer.id === selectedLayerIds.main + subLayer => subLayer.id === mainLayerId ); const compareLayer = layer.subLayers.find( - subLayer => subLayer.id === selectedLayerIds.compare + subLayer => subLayer.id === compareLayerId ); return { @@ -33,8 +38,8 @@ const getSelectedLayers = ( }; } - const isMainLayer = layer.id === selectedLayerIds.main; - const isCompareLayer = layer.id === selectedLayerIds.compare; + const isMainLayer = layer.id === mainLayerId; + const isCompareLayer = layer.id === compareLayerId; return { main: isMainLayer ? layer : selectedLayers.main, @@ -43,9 +48,13 @@ const getSelectedLayers = ( }, {main: null, compare: null} ); +}; -export function selectedLayersSelector(state: State): SelectedLayerItems { +export function selectedLayersSelector( + state: State, + props: {[key: string]: string} | null +): SelectedLayerItems { const layers = layersSelector(state); - const selectedLayerIds = selectedLayerIdsSelector(state); - return getSelectedLayers(layers, selectedLayerIds); + const {mainLayerId, compareLayerId} = props || {}; + return getSelectedLayers(layers, {mainLayerId, compareLayerId}); } From f3d43463b8bb868073dc29ec7fb019b56c7ef39f Mon Sep 17 00:00:00 2001 From: Katherina Marcenko Date: Thu, 14 Nov 2019 14:50:09 +0100 Subject: [PATCH 3/4] feat(story): set default view for globe --- src/scripts/components/story/story.tsx | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/scripts/components/story/story.tsx b/src/scripts/components/story/story.tsx index c1c428992..27d63187b 100644 --- a/src/scripts/components/story/story.tsx +++ b/src/scripts/components/story/story.tsx @@ -23,18 +23,33 @@ const Story: FunctionComponent = () => { const pageNumber = parseInt(page || '0', 10); const slide = story && story.slides[pageNumber]; const storyListItem = stories.find(storyItem => storyItem.id === storyId); + const defaultView = { + position: { + height: 14484862, + latitude: 40.659017, + longitude: 0.002816 + }, + orientation: { + heading: 0, + pitch: -90, + roll: 0 + } + }; // fetch story of active storyId useEffect(() => { storyId && dispatch(fetchStory(storyId)); }, [dispatch, storyId]); - // fly to position given in a slide + // fly to position given in a slide, if none given set to default useEffect(() => { if (slide && slide.flyTo) { dispatch(setFlyToAction(slide.flyTo)); } - }, [dispatch, slide]); + if (slide && !slide.flyTo) { + dispatch(setFlyToAction(defaultView)); + } + }, [dispatch, slide, defaultView]); // redirect to first slide when current slide does not exist if (story && !slide) { From ebfc850cd78a57fbeea0330a0bb6bd9dbffd208e Mon Sep 17 00:00:00 2001 From: Katherina Marcenko Date: Fri, 15 Nov 2019 11:00:06 +0100 Subject: [PATCH 4/4] refactor(story): remove if condition --- src/scripts/components/story/story.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/scripts/components/story/story.tsx b/src/scripts/components/story/story.tsx index 27d63187b..b8b737c32 100644 --- a/src/scripts/components/story/story.tsx +++ b/src/scripts/components/story/story.tsx @@ -43,13 +43,11 @@ const Story: FunctionComponent = () => { // fly to position given in a slide, if none given set to default useEffect(() => { - if (slide && slide.flyTo) { - dispatch(setFlyToAction(slide.flyTo)); + if (slide) { + dispatch(setFlyToAction(slide.flyTo || defaultView)); } - if (slide && !slide.flyTo) { - dispatch(setFlyToAction(defaultView)); - } - }, [dispatch, slide, defaultView]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [dispatch, slide]); // redirect to first slide when current slide does not exist if (story && !slide) {