Skip to content

Commit

Permalink
Merge pull request #584 from digital-land/rosado/557-check-back-button
Browse files Browse the repository at this point in the history
Sets the "back" link on page user arrives at via a deep link to the linked from page (using the referer header when available).
  • Loading branch information
rosado authored Oct 24, 2024
2 parents b10507d + cd70737 commit 1148958
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 9 deletions.
27 changes: 25 additions & 2 deletions src/controllers/deepLinkController.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,28 @@ const QueryParams = v.object({
orgName: NonEmptyString
})

/**
* Potentially updates sessionData with 'referrer'
*
* @param req
* @param sessionData
*/
function maybeSetReferrer (req, sessionData) {
if (req.headers.referer) {
try {
/* eslint-disable-next-line no-new */
new URL(req.headers.referer)
sessionData.referrer = req.headers.referer
} catch (err) {
logger.info('DeepLinkController.get(): invalid referrer URL, skipping', {
type: types.App,
referrer: req.headers.referer,
errorMessage: err.message
})
}
}
}

/**
* Handles deep links in the Check Tool.
*
Expand All @@ -33,8 +55,9 @@ class DeepLinkController extends PageController {
req.sessionModel.set('dataset', dataset)
const datasetInfo = datasets.get(dataset) ?? { dataSubject: '', requiresGeometryTypeSelection: false }
req.sessionModel.set('data-subject', datasetInfo.dataSubject)
req.sessionModel.set(this.checkToolDeepLinkSessionKey,
{ 'data-subject': datasetInfo.dataSubject, orgName, dataset, datasetName: datasetInfo.text })
const sessionData = { 'data-subject': datasetInfo.dataSubject, orgName, dataset, datasetName: datasetInfo.text }
maybeSetReferrer(req, sessionData)
req.sessionModel.set(this.checkToolDeepLinkSessionKey, sessionData)

this.#addHistoryStep(req, '/check/dataset')

Expand Down
47 changes: 41 additions & 6 deletions src/controllers/pageController.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
import hmpoFormWizard from 'hmpo-form-wizard'
import { logPageView } from '../utils/logging.js'
import { logPageView, types } from '../utils/logging.js'
import logger from '../utils/logger.js'
const { Controller } = hmpoFormWizard

/**
* If we arrived at the page via deep from another page, we'll use that page as the back link.
*
* @param {string} url current page URL
* @param {{ referrer?: string, dataset: string }} deepLinkInfo deep link info from the session
* @returns {string|undefined} back link URL
*/
function wizardBackLink (currentUrl, deepLinkInfo) {
if (deepLinkInfo && 'referrer' in deepLinkInfo) {
const { referrer, dataset } = deepLinkInfo
if (dataset === 'tree' && currentUrl === '/check/geometry-type') {
return referrer
}
if (dataset !== 'tree' && currentUrl === '/check/upload-method') {
return referrer
}
}

return undefined
}

class PageController extends Controller {
checkToolDeepLinkSessionKey = 'check-tool-deep-link'

Expand All @@ -11,12 +33,25 @@ class PageController extends Controller {
}

locals (req, res, next) {
if (this.options.backLink) {
req.form.options.lastPage = this.options.backLink
}
if (req.sessionModel) {
req.form.options.deepLink = req.sessionModel.get(this.checkToolDeepLinkSessionKey)
try {
let backLink
const deepLinkInfo = req?.sessionModel?.get(this.checkToolDeepLinkSessionKey)
if (deepLinkInfo) {
req.form.options.deepLink = deepLinkInfo
backLink = wizardBackLink(req.originalUrl, deepLinkInfo)
}

backLink = backLink ?? this.options.backLink
if (backLink) {
req.form.options.lastPage = backLink
}
} catch (e) {
logger.warn('PageController.locals(): error setting back link', {
type: types.App,
errorMessage: e.message
})
}

super.locals(req, res, next)
}
}
Expand Down
45 changes: 45 additions & 0 deletions test/unit/PageController.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,48 @@ describe('PageController', () => {
expect(callArgs.service).toEqual('lpa-data-validation-frontend')
})
})

describe('Correctly detects the wizard back link', () => {
const referrer = 'https://example.com/this-is-where-we-came-from'
const makeReq = () => {
return ({
originalUrl: '/check/upload-method',
sessionID: '123',
sessionModel: {
get: vi.fn().mockReturnValue({ referrer })
},
form: {
options: {}
}
})
}

it('arriving at the deep link entry point', () => {
const pageController = new PageController({ route: '/upload-method' })
const req = makeReq()
pageController.locals(req, {}, vi.fn())
expect(req.form.options.lastPage).toEqual(referrer)
})

it('arriving at some other step', () => {
const pageController = new PageController({ route: '/upload-method' })
const req = { ...makeReq(), originalUrl: '/check/another-step' }
pageController.locals(req, {}, vi.fn())
expect(req.form.options.lastPage).toBe(undefined)
})

it('don\'t touch the back link if there\'s no deep link session info (lastPage not set)', () => {
const pageController = new PageController({ route: '/upload-method' })
const req = { ...makeReq(), sessionModel: new Map() }
pageController.locals(req, {}, vi.fn())
expect(req.form.options.lastPage).toEqual(undefined)
})

it('don\'t touch the back link if there\'s no deep link session info (lastPage set)', () => {
const pageController = new PageController({ route: '/upload-method' })
pageController.options.backLink = '/go-back'
const req = { ...makeReq(), sessionModel: new Map() }
pageController.locals(req, {}, vi.fn())
expect(req.form.options.lastPage).toEqual('/go-back')
})
})
2 changes: 1 addition & 1 deletion test/unit/deepLinkController.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import DeepLinkController from '../../src/controllers/deepLinkController.js'
function mockRequestObject () {
const sessionModel = new Map()
const journeyModel = new Map()
return { sessionModel, journeyModel, query: {} }
return { sessionModel, journeyModel, query: {}, headers: {} }
}

function mockMiddlewareArgs (reqOpts) {
Expand Down

0 comments on commit 1148958

Please sign in to comment.