diff --git a/cypress/integration/smoke.cy.js b/cypress/integration/smoke.cy.js index be0d0f82d..d4de60548 100644 --- a/cypress/integration/smoke.cy.js +++ b/cypress/integration/smoke.cy.js @@ -8,7 +8,7 @@ context('Smoke Test', () => { cy.title().should('equal', 'Maps | DHIS2') }) - it('loads with map id', () => { + it('loads with map id using legacy query param format', () => { cy.intercept({ method: 'POST', url: /dataStatistics/ }).as( 'postDataStatistics' ) @@ -24,6 +24,15 @@ context('Smoke Test', () => { Layer.validateCardTitle('ANC 3 Coverage') }) + it('loads with map id using hash location', () => { + cy.visit('/#/zDP78aJU8nX', EXTENDED_TIMEOUT) //ANC: 1st visit coverage (%) by district last year + + cy.get('canvas', EXTENDED_TIMEOUT).should('be.visible') + + const Layer = new ThematicLayer() + Layer.validateCardTitle('ANC 1 Coverage') + }) + it('loads currentAnalyticalObject', () => { cy.intercept('**/userDataStore/analytics/settings', { fixture: 'analyticalObject.json', @@ -39,7 +48,7 @@ context('Smoke Test', () => { cy.get('canvas.maplibregl-canvas').should('be.visible') }) - it('loads with map id and interpretationid lowercase', () => { + it('loads with map id (legacy) and interpretationid lowercase', () => { cy.intercept({ method: 'POST', url: /dataStatistics/ }).as( 'postDataStatistics' ) @@ -60,7 +69,7 @@ context('Smoke Test', () => { .should('be.visible') }) - it('loads with map id and interpretationId uppercase', () => { + it('loads with map id (legacy) and interpretationId uppercase', () => { cy.intercept({ method: 'POST', url: /dataStatistics/ }).as( 'postDataStatistics' ) @@ -80,4 +89,47 @@ context('Smoke Test', () => { ) .should('be.visible') }) + + it('loads with map id (hash) and interpretationid lowercase', () => { + cy.intercept({ method: 'POST', url: /dataStatistics/ }).as( + 'postDataStatistics' + ) + + cy.visit( + '/#/ZBjCfSaLSqD&interpretationid=yKqhXZdeJ6a', + EXTENDED_TIMEOUT + ) //ANC: LLITN coverage district and facility + + cy.wait('@postDataStatistics') + .its('response.statusCode') + .should('eq', 201) + + cy.getByDataTest('interpretation-modal') + .find('h1') + .contains( + 'Viewing interpretation: ANC: LLITN coverage district and facility' + ) + .should('be.visible') + }) + + it('loads with map id (hash) and interpretationId uppercase', () => { + cy.intercept({ method: 'POST', url: /dataStatistics/ }).as( + 'postDataStatistics' + ) + cy.visit( + '/#/ZBjCfSaLSqD&interpretationId=yKqhXZdeJ6a', + EXTENDED_TIMEOUT + ) //ANC: LLITN coverage district and facility + + cy.wait('@postDataStatistics') + .its('response.statusCode') + .should('eq', 201) + + cy.getByDataTest('interpretation-modal') + .find('h1') + .contains( + 'Viewing interpretation: ANC: LLITN coverage district and facility' + ) + .should('be.visible') + }) }) diff --git a/package.json b/package.json index 124445fee..a67ee95e1 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "d3-time": "^3.1.0", "d3-time-format": "^4.1.0", "file-saver": "^2.0.5", + "history": "^5.3.0", "html-to-image": "^1.11.1", "lodash": "^4.17.21", "loglevel": "^1.8.1", diff --git a/src/components/app/App.js b/src/components/app/App.js index cb359998c..70df80728 100644 --- a/src/components/app/App.js +++ b/src/components/app/App.js @@ -8,11 +8,27 @@ import { tSetAnalyticalObject } from '../../actions/analyticalObject.js' import { setInterpretation } from '../../actions/interpretations.js' import { tOpenMap } from '../../actions/map.js' import { CURRENT_AO_KEY } from '../../util/analyticalObject.js' +import history from '../../util/history.js' import { getUrlParameter } from '../../util/requests.js' import AppLayout from './AppLayout.js' import './App.css' import './styles/App.module.css' +const parseLocation = (hashLocation) => { + const pathParts = hashLocation.pathname.slice(1).split('/') + return { id: pathParts[0] } +} + +const getMapId = (hashLocation) => { + const parsedHash = parseLocation(hashLocation) + if (parsedHash.id) { + return parsedHash.id + } + + // support /?id=ytkZY3ChM6J for backwards compatibility + return getUrlParameter('id') +} + const App = () => { const { systemSettings, basemaps } = useCachedDataQuery() const defaultBasemap = systemSettings.keyDefaultBaseMap @@ -22,7 +38,7 @@ const App = () => { useEffect(() => { async function fetchData() { - const mapId = getUrlParameter('id') + const mapId = getMapId(history.location) if (mapId) { await dispatch( tOpenMap({ @@ -36,7 +52,7 @@ const App = () => { await dispatch(tSetAnalyticalObject(currentAO)) } - // analytics interpretation component uses camelcase + // support both lower and camel case for backwards compatibility const interpretationId = getUrlParameter('interpretationid') || getUrlParameter('interpretationId') diff --git a/src/util/history.js b/src/util/history.js new file mode 100644 index 000000000..e192102b2 --- /dev/null +++ b/src/util/history.js @@ -0,0 +1,3 @@ +import { createHashHistory } from 'history' + +export default createHashHistory() diff --git a/yarn.lock b/yarn.lock index eb6b06666..dc7fab6b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1079,6 +1079,13 @@ dependencies: regenerator-runtime "^0.13.11" +"@babel/runtime@^7.7.6": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.10.tgz#ae3e9631fd947cb7e3610d3e9d8fef5f76696682" + integrity sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.3.3": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" @@ -8736,6 +8743,13 @@ highcharts@^10.3.3: resolved "https://registry.yarnpkg.com/highcharts/-/highcharts-10.3.3.tgz#b8acca24f2d4b1f2f726540734166e59e07b35c4" integrity sha512-r7wgUPQI9tr3jFDn3XT36qsNwEIZYcfgz4mkKEA6E4nn5p86y+u1EZjazIG4TRkl5/gmGRtkBUiZW81g029RIw== +history@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b" + integrity sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ== + dependencies: + "@babel/runtime" "^7.7.6" + hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -13404,6 +13418,11 @@ regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.9: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +regenerator-runtime@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" + integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== + regenerator-transform@^0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56"