diff --git a/package-lock.json b/package-lock.json index 670f5e1b..3f39e868 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "client", - "version": "2.3.3", + "version": "2.6.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "client", - "version": "2.3.3", + "version": "2.6.6", "dependencies": { "@emotion/cache": "^11.5.0", "@emotion/react": "^11.5.0", diff --git a/src/components/Home.js b/src/components/Home.js index 37179a94..ee8ba7ed 100644 --- a/src/components/Home.js +++ b/src/components/Home.js @@ -4,10 +4,10 @@ import Typography from '@mui/material/Typography'; import log from 'loglevel'; import { useRouter } from 'next/router'; import React from 'react'; +import { useMapContext } from 'mapContext'; import { makeStyles } from 'models/makeStyles'; -import * as pathResolver from 'models/pathResolver'; +import { moveMapByUrl } from 'models/utils'; import Link from './Link'; -import { useMapContext } from '../mapContext'; const backgroundImage = `${process.env.NEXT_PUBLIC_BASE}/images/bg.webp`; const useStyles = makeStyles()((theme) => ({ @@ -66,14 +66,7 @@ export default function Home(props) { await map.setFilters({}); log.warn('location:', window.location); log.warn('router:', router); - const bounds = pathResolver.getBounds(router); - if (bounds) { - log.warn('goto bounds found in url'); - await map.gotoBounds(bounds); - } else { - log.warn('goto global view'); - await map.gotoView(0, 0, 2); - } + moveMapByUrl({ map, router }); } } reload(); diff --git a/src/models/pathResolver.js b/src/models/pathResolver.js index edf557a5..4d303caf 100644 --- a/src/models/pathResolver.js +++ b/src/models/pathResolver.js @@ -79,8 +79,13 @@ function getPathWhenClickTree(tree, location, router, map, options = {}) { query: optionalParams, }; } - -function updatePathWhenMapMoveEnd(location, map, router) { +/** + * if {isView} is true,view's is used (lat,long,zoomLevel z) + * + * else bounds is used (southWestLng, southWestLat, northEastLng, northEastLat) + * @returns string url + */ +function updatePathWhenMapMoveEnd(location, map, router, isView = true) { log.warn( 'updatePathWhenMapMoveEnd: location:', location, @@ -89,7 +94,17 @@ function updatePathWhenMapMoveEnd(location, map, router) { ' router:', router, ); - let result = `${location.pathname}?bounds=${map.getCurrentBounds()}${ + + // determine to use which format to use for coordinate + let coordinate = ''; + if (!isView) { + coordinate = `bounds=${map.getCurrentBounds()}`; + } else { + const { center, zoomLevel } = map.getCurrentView(); + coordinate = `view=${center.lat},${center.lng},${zoomLevel}z`; + } + + let result = `${location.pathname}?${coordinate}${ router.query.timeline ? `&timeline=${router.query.timeline}` : '' }${router.query.embed ? `&embed=true` : ''}`; if (router.query.tree_id) { @@ -133,9 +148,28 @@ function getContext(router, options = {}) { function getBounds(router) { return router.query.bounds; } + +function getView(router) { + const { view } = router.query; + try { + if (view) { + const [lat, lon, zoomLevel] = view.split(','); + return { + lat: parseFloat(lat), + lon: parseFloat(lon), + zoomLevel: parseFloat(zoomLevel.substring(0, zoomLevel.length - 1)), + }; + } + } catch (e) { + console.warn("view's format is not correct"); + } + return null; +} + export { getPathWhenClickTree, updatePathWhenMapMoveEnd, getContext, getBounds, + getView, }; diff --git a/src/models/pathResolver.test.js b/src/models/pathResolver.test.js index af6a21fb..3a2e6174 100644 --- a/src/models/pathResolver.test.js +++ b/src/models/pathResolver.test.js @@ -141,7 +141,7 @@ describe('Test pathResolver', () => { }); }); - describe('updatePathWhenMapMoveEnd', () => { + describe('updatePathWhenMapMoveEnd bounds coordinate ', () => { it('update path when ', () => { const result = pathResolver.updatePathWhenMapMoveEnd( { @@ -154,6 +154,7 @@ describe('Test pathResolver', () => { { query: {}, }, + false, ); expect(result).toBe( '/wallets/0cdf4219-869a-41ce-953a-a8421d8353f7?bounds=37.44990348815919,-3.315482794386477,37.46535301208497,-3.307471024919109', @@ -174,6 +175,7 @@ describe('Test pathResolver', () => { tree_id: '14615', }, }, + false, ); expect(result).toBe( '/wallets/0cdf4219-869a-41ce-953a-a8421d8353f7?bounds=37.44990348815919,-3.315482794386477,37.46535301208497,-3.307471024919109&tree_id=14615', @@ -194,6 +196,7 @@ describe('Test pathResolver', () => { tree_id: '5413738', }, }, + false, ); expect(result).toBe( '/wallets/5f5939ae-91ce-49cd-81ba-7fdba81e250a/tokens?bounds=46.38155221939087,-15.762146918354096,46.3908863067627,-15.74444839985392&tree_id=5413738', @@ -201,6 +204,84 @@ describe('Test pathResolver', () => { }); }); + describe('updatePathWhenMapMoveEnd view coordinate ', () => { + it('update path when ', () => { + const result = pathResolver.updatePathWhenMapMoveEnd( + { + pathname: '/wallets/0cdf4219-869a-41ce-953a-a8421d8353f7', + }, + { + getCurrentView: () => ({ + center: { + lat: 2.4601811810210052, + lng: 32.16796875000001, + }, + zoomLevel: 2, + }), + }, + { + query: {}, + }, + true, + ); + expect(result).toBe( + '/wallets/0cdf4219-869a-41ce-953a-a8421d8353f7?view=2.4601811810210052,32.16796875000001,2z', + ); + }); + + it('update path when /wallets/1f2a0862-66d1-4b42-8216-5a5cb9c6eca5/tokens?tree_id=14615', () => { + const result = pathResolver.updatePathWhenMapMoveEnd( + { + pathname: '/wallets/0cdf4219-869a-41ce-953a-a8421d8353f7', + }, + { + getCurrentView: () => ({ + center: { + lat: 2.4601811810210052, + lng: 32.16796875000001, + }, + zoomLevel: 2, + }), + }, + { + query: { + tree_id: '14615', + }, + }, + true, + ); + expect(result).toBe( + '/wallets/0cdf4219-869a-41ce-953a-a8421d8353f7?view=2.4601811810210052,32.16796875000001,2z&tree_id=14615', + ); + }); + + it('update path when /wallets/5f5939ae-91ce-49cd-81ba-7fdba81e250a/tokens?tree_id=5413738', () => { + const result = pathResolver.updatePathWhenMapMoveEnd( + { + pathname: '/wallets/5f5939ae-91ce-49cd-81ba-7fdba81e250a/tokens', + }, + { + getCurrentView: () => ({ + center: { + lat: 2.4601811810210052, + lng: 32.16796875000001, + }, + zoomLevel: 2, + }), + }, + { + query: { + tree_id: '5413738', + }, + }, + true, + ); + expect(result).toBe( + '/wallets/5f5939ae-91ce-49cd-81ba-7fdba81e250a/tokens?view=2.4601811810210052,32.16796875000001,2z&tree_id=5413738', + ); + }); + }); + describe('getContext', () => { it('org context', () => { const result = pathResolver.getContext({ @@ -259,4 +340,19 @@ describe('Test pathResolver', () => { ); }); }); + + describe('getView', () => { + it('?view=2.4601811810210052,32.16796875000001,2z', () => { + const bounds = pathResolver.getView({ + query: { + view: '2.4601811810210052,32.16796875000001,2z', + }, + }); + expect(bounds).toMatchObject({ + lat: 2.4601811810210052, + lon: 32.16796875000001, + zoomLevel: 2, + }); + }); + }); }); diff --git a/src/models/utils.js b/src/models/utils.js index 3e2652c0..734a99cb 100644 --- a/src/models/utils.js +++ b/src/models/utils.js @@ -304,6 +304,37 @@ const abbreviateNumber = (number) => notation: 'compact', }).format(number); +/** + * @description move the position view of the map base on the url. + * If not found, move to the global view + */ +const moveMapByUrl = async ({ map, router, getInitial = false }) => { + const { bounds, view } = router.query; + + if (bounds) { + log.warn('goto bounds found in url'); + await map.gotoBounds(bounds); + } else if (view) { + log.warn('goto view found in url'); + const [lat, lon, zoomLevel] = view.split(','); + await map.gotoView( + parseFloat(lat), + parseFloat(lon), + parseFloat(zoomLevel.substring(0, zoomLevel.length - 1)), + ); + } else if (getInitial) { + const initView = await map.getInitialView(); + await map.gotoView( + initView.center.lat, + initView.center.lon, + initView.zoomLevel, + ); + } else { + console.warn('Goto global view'); + await map.gotoView(0, 0, 2); + } +}; + export { hideLastName, parseDomain, @@ -326,4 +357,5 @@ export { setPropByPath, getPropByPath, abbreviateNumber, + moveMapByUrl, }; diff --git a/src/pages/organizations/[organizationid].js b/src/pages/organizations/[organizationid].js index 84cca865..5549d07f 100644 --- a/src/pages/organizations/[organizationid].js +++ b/src/pages/organizations/[organizationid].js @@ -28,8 +28,12 @@ import imagePlaceholder from 'images/image-placeholder.png'; import SearchIcon from 'images/search.svg'; import { useMapContext } from 'mapContext'; import { getOrganizationById, getOrgLinks } from 'models/api'; -import * as pathResolver from 'models/pathResolver'; -import { getLocationString, getContinent, wrapper } from 'models/utils'; +import { + getLocationString, + getContinent, + wrapper, + moveMapByUrl, +} from 'models/utils'; export default function Organization(props) { log.warn('props for org page:', props); @@ -69,14 +73,7 @@ export default function Organization(props) { await map.setFilters({ map_name: organization.map_name, }); - const bounds = pathResolver.getBounds(router); - if (bounds) { - log.warn('goto bounds found in url'); - await map.gotoBounds(bounds); - } else { - const view = await map.getInitialView(); - await map.gotoView(view.center.lat, view.center.lon, view.zoomLevel); - } + await moveMapByUrl({ map, router, getInitial: true }); } else { log.warn('no data:', map, organization); } diff --git a/src/pages/planters/[planterid].js b/src/pages/planters/[planterid].js index 0106d52d..e69a8bca 100644 --- a/src/pages/planters/[planterid].js +++ b/src/pages/planters/[planterid].js @@ -35,7 +35,12 @@ import { useMapContext } from 'mapContext'; import { getPlanterById, getOrgLinks } from 'models/api'; import { makeStyles } from 'models/makeStyles'; import * as pathResolver from 'models/pathResolver'; -import { getLocationString, getPlanterName, wrapper } from 'models/utils'; +import { + getLocationString, + getPlanterName, + moveMapByUrl, + wrapper, +} from 'models/utils'; // make styles for component with material-ui const useStyles = makeStyles()((theme) => ({ @@ -118,14 +123,7 @@ export default function Planter(props) { await map.setFilters({ userid: planter.id, }); - const bounds = pathResolver.getBounds(router); - if (bounds) { - log.warn('goto bounds found in url'); - await map.gotoBounds(bounds); - } else { - const view = await map.getInitialView(); - map.gotoView(view.center.lat, view.center.lon, view.zoomLevel); - } + moveMapByUrl({ map, router, getInitial: true }); } } reload(); diff --git a/src/pages/wallets/[walletid].js b/src/pages/wallets/[walletid].js index f06bfe6d..2bdffbbe 100644 --- a/src/pages/wallets/[walletid].js +++ b/src/pages/wallets/[walletid].js @@ -31,7 +31,7 @@ import SearchIcon from 'images/search.svg'; import { useMapContext } from 'mapContext'; import { getWalletById, getSpeciesByWalletId } from 'models/api'; import * as pathResolver from 'models/pathResolver'; -import { requestAPI, wrapper } from 'models/utils'; +import { requestAPI, wrapper, moveMapByUrl } from 'models/utils'; const placeholderText = `Lorem ipsum dolor sit amet consectetur adipisicing elit. Culpa iusto nesciunt quasi praesentium non cupiditate ratione nihil. Perferendis, @@ -80,18 +80,7 @@ export default function Wallet(props) { await map.setFilters({ wallet: wallet.name, }); - const bounds = pathResolver.getBounds(router); - if (bounds) { - log.warn('goto bounds found in url'); - await map.gotoBounds(bounds); - } else { - const view = await map.getInitialView(); - - if (view.zoomLevel < 2) { - view.zoomLevel = 2; - } - await map.gotoView(view.center.lat, view.center.lon, view.zoomLevel); - } + await moveMapByUrl({ map, router, getInitial: true }); } } reload();