Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions app/data/participants.js

Large diffs are not rendered by default.

19 changes: 17 additions & 2 deletions app/data/session-data-defaults.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
// Use this file to set any default data
const participants = require('./participants')

module.exports = {}
// currently just for the September Test "clickthru"
module.exports = {
participants,
stagedCount: 0,
clinicName: 'Worthing - test day September 2026',
clinicId: 'HWO-NNN-standard-20260501',
unitName: 'West Sussex Breast Screening Centre',
unitId: 'HWO-static-1',
locationName: 'Worthing',
locationAddressLine1: "Worthing Hospital",
clinicTimespan: "1 September 2026",
clinicLength: "1 day",
clinicCapacityPercentBooked: "0",
clinicCapacityAvailable: "48",
clinicCapacityTotal: "48"
}
52 changes: 51 additions & 1 deletion app/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,56 @@ const express = require('express')

const router = express.Router()

// Add your routes here - above the module.exports line
router.get('/september-iteration-2/clickthru/04a-example-search-result', function (req, res) {
const query = (req.query['search-params'] || '').trim()
const allParticipants = (req.session.data.participants && req.session.data.participants.default) || []
const normalizedQuery = query.toLowerCase().replace(/\s+/g, ' ')
const nhsQuery = normalizedQuery.replace(/\s+/g, '')

const searchResults = (normalizedQuery ? allParticipants.map((participant, index) => {
const nhs = participant.nhs_number.toLowerCase().replace(/\s+/g, '')
const name = participant.full_name.toLowerCase()
const dob = participant.date_of_birth.toLowerCase()

if (
nhs.includes(nhsQuery) ||
name.includes(normalizedQuery) ||
dob.includes(normalizedQuery)
) {
return Object.assign({}, participant, { participantIndex: index })
}

return null
}).filter(Boolean) : allParticipants.map((participant, index) => Object.assign({}, participant, { participantIndex: index })))

res.render('september-iteration-2/clickthru/04a-example-search-result', {
participants: searchResults,
searchQuery: query
})
})

router.get('/action/stage/:participantId', function (req, res) {
const participants = (req.session.data.participants && req.session.data.participants.default) || []
const participantIndex = participants.findIndex((participant) => participant.participantId === req.params.participantId)

if (participantIndex !== -1) {
participants[participantIndex].status = 'staged'
req.session.data.stagedCount++
}

res.redirect(req.get('referer') || '/september-iteration-2/clickthru/04-choose-participants')
});

router.get('/action/unstage/:participantId', function (req, res) {
const participants = (req.session.data.participants && req.session.data.participants.default) || []
const participantIndex = participants.findIndex((participant) => participant.participantId === req.params.participantId)

if (participantIndex !== -1) {
participants[participantIndex].status = 'unstaged'
req.session.data.stagedCount--
}

res.redirect(req.get('referer') || '/september-iteration-2/clickthru/04-choose-participants')
});

module.exports = router
3 changes: 3 additions & 0 deletions app/views/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ <h2 class="nhsuk-heading-m">March 2026</h2>

<h3 class="nhsuk-heading-m">Work for September Test</h3>
<h4 class="nhsuk-heading-s">Iteration 2</h4>
<p>
<a href="/september-iteration-2/clickthru/01-upload">Click-thru journey (all hard coded as an example)</a>
</p>
<ol>
<li>
<a href="/september-iteration-2/upload-a-batch">Upload a batch</a>
Expand Down
21 changes: 21 additions & 0 deletions app/views/september-iteration-2/clickthru/01-upload.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{% extends 'layout.html' %}

{% set pageName = "" %}

{% from "z-september-transactional-journey/_includes/min-primary-navigation.html" import primaryNavigation %}
{% block header %}
{{ primaryNavigation() }}
{% endblock %}

{% block beforeContent %}{% endblock %}

{% block content %}
{% from "september-iteration-2/macros/batch-upload.html" import upload %}
{{ upload({
button_url:"02-batch-detail"
}) }}
{% endblock %}

{% block footer %}
{{ footer() }}
{% endblock %}
36 changes: 36 additions & 0 deletions app/views/september-iteration-2/clickthru/02-batch-detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{% extends 'layout.html' %}

{% set pageName = "" %}

{% from "z-september-transactional-journey/_includes/min-primary-navigation.html" import primaryNavigation %}
{% block header %}
{{ primaryNavigation() }}
{% endblock %}

{% block beforeContent %}{% endblock %}

{% block content %}

<div class="nhsuk-grid-row">
<div class="nhsuk-grid-column-full">
{% set html %}
<p class="nhsuk-notification-banner__heading">Batch uploaded</p>
{% endset %}
{{ notificationBanner({
html: html,
type: "success"
}) }}
</div>
</div>

{% from "september-iteration-2/macros/batch-detail.html" import batch_detail %}
{{ batch_detail({
participant_count: data.participants.default.length,
button_url:"03-select-clinic"
}) }}

{% endblock %}

{% block footer %}
{{ footer() }}
{% endblock %}
50 changes: 50 additions & 0 deletions app/views/september-iteration-2/clickthru/03-select-clinic.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{% extends 'layout.html' %}

{% set pageName = "" %}

{% from "z-september-transactional-journey/_includes/min-primary-navigation.html" import primaryNavigation %}
{% block header %}
{{ primaryNavigation() }}
{% endblock %}

{% block beforeContent %}{% endblock %}

{% block content %}

<div class="nhsuk-u-reading-width">
<h1 class="nhsuk-heading-l">
Select clinic
</h1>
</div>
<div class="nhsuk-grid-row">
<div class="nhsuk-grid-column-full">

{% from "september-iteration-2/macros/clinic-listing.html" import clinic_listing %}
{{ clinic_listing({
controls: true,
clinics: [
{
clinic_name: data.clinicName,
clinic_id: data.clinicId,
clinic_location_name: data.locationName,
clinic_location_address_line_1: data.locationAddressLine1,
clinic_unit_name: data.unitName,
clinic_unit_id: data.unitId,
clinic_timespan: data.clinicTimespan,
clinic_length: data.clinicLength,
clinic_capacity_percent_booked: data.clinicCapacityPercentBooked,
clinic_capacity_available: data.clinicCapacityAvailable,
clinic_capacity_total: data.clinicCapacityTotal,
button_url: "04-choose-participants"
}
]
}) }}

</div>
</div>

{% endblock %}

{% block footer %}
{{ footer() }}
{% endblock %}
153 changes: 153 additions & 0 deletions app/views/september-iteration-2/clickthru/04-choose-participants.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
{% extends 'layout.html' %}

{% set pageName = "" %}

{% from "z-september-transactional-journey/_includes/min-primary-navigation.html" import primaryNavigation %}
{% block header %}
{{ primaryNavigation() }}
{% endblock %}

{% block beforeContent %}{% endblock %}

{% block content %}

<div class="nhsuk-u-reading-width">
<h1 class="nhsuk-heading-l">
Choose participants to book
</h1>
</div>

{% from "september-iteration-2/macros/search-component.html" import participant_search %}
{{ participant_search({
form_action: "04a-example-search-result",
search_query: searchQuery
}) }}

<div class="nhsuk-grid-row">
<div class="nhsuk-grid-column-full">
{% from "september-iteration-2/macros/participant-listing.html" import participant_listing %}
{{ participant_listing({
mode: "browse",
participants: data.participants.default
}) }}
</div>
</div>

<nav id="participant-pagination" class="nhsuk-pagination nhsuk-pagination--numbered nhsuk-u-margin-top-0" role="navigation" aria-label="Pagination" aria-live="polite">
<a href="#" class="nhsuk-pagination__previous" rel="prev">
<svg class="nhsuk-icon nhsuk-icon--arrow-left" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" focusable="false" aria-hidden="true">
<path d="M10.7 6.3c.4.4.4 1 0 1.4L7.4 11H19a1 1 0 0 1 0 2H7.4l3.3 3.3c.4.4.4 1 0 1.4a1 1 0 0 1-1.4 0l-5-5A1 1 0 0 1 4 12c0-.3.1-.5.3-.7l5-5a1 1 0 0 1 1.4 0Z" />
</svg>
<span class="nhsuk-pagination__title">
Previous<span class="nhsuk-u-visually-hidden"> page</span>
</span>
</a>
<ul class="nhsuk-pagination__list"></ul>
<a href="#" class="nhsuk-pagination__next" rel="next" aria-label="Next page">
<span class="nhsuk-pagination__title">
Next<span class="nhsuk-u-visually-hidden"> page</span>
</span>
<svg class="nhsuk-icon nhsuk-icon--arrow-right" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" focusable="false" aria-hidden="true">
<path d="m14.7 6.3 5 5c.2.2.3.4.3.7 0 .3-.1.5-.3.7l-5 5a1 1 0 0 1-1.4-1.4l3.3-3.3H5a1 1 0 0 1 0-2h11.6l-3.3-3.3a1 1 0 1 1 1.4-1.4Z" />
</svg>
</a>
</nav>

{% include "september-iteration-2/includes/participant-staging-control.html" %}
{% endblock %}

{% block pageScripts %}
<script>
document.addEventListener('DOMContentLoaded', function () {
var table = document.getElementById('search-results');
var nav = document.getElementById('participant-pagination');
if (!table || !nav) return;

var rows = Array.prototype.slice.call(table.querySelectorAll('tbody tr'));
var pageSize = 16;
var totalPages = Math.max(1, Math.ceil(rows.length / pageSize));
var currentPage = 1;
var list = nav.querySelector('.nhsuk-pagination__list');
var prevLink = nav.querySelector('.nhsuk-pagination__previous');
var nextLink = nav.querySelector('.nhsuk-pagination__next');

function updateRows(page) {
var start = (page - 1) * pageSize;
var end = page * pageSize;
rows.forEach(function (row, index) {
row.hidden = index < start || index >= end;
});
}

function renderPagination(page) {
currentPage = page;
list.innerHTML = '';

for (var pageIndex = 1; pageIndex <= totalPages; pageIndex += 1) {
var item = document.createElement('li');
item.className = 'nhsuk-pagination__item' + (pageIndex === currentPage ? ' nhsuk-pagination__item--current' : '');

var link = document.createElement('a');
link.className = 'nhsuk-pagination__link';
link.href = '#';
link.textContent = pageIndex;
link.setAttribute('aria-label', 'Page ' + pageIndex);
if (pageIndex === currentPage) {
link.setAttribute('aria-current', 'page');
} else {
link.addEventListener('click', function (event) {
event.preventDefault();
var pageNumber = parseInt(this.textContent, 10);
showPage(pageNumber);
});
}

item.appendChild(link);
list.appendChild(item);
}

if (prevLink) {
var prevDisabled = currentPage <= 1;
prevLink.classList.toggle('nhsuk-u-visually-hidden', prevDisabled);
prevLink.setAttribute('aria-disabled', prevDisabled ? 'true' : 'false');
}
if (nextLink) {
var nextDisabled = currentPage >= totalPages;
nextLink.classList.toggle('nhsuk-u-visually-hidden', nextDisabled);
nextLink.setAttribute('aria-disabled', nextDisabled ? 'true' : 'false');
}
}

function showPage(page) {
if (page < 1) page = 1;
if (page > totalPages) page = totalPages;
updateRows(page);
renderPagination(page);
}

if (prevLink) {
prevLink.addEventListener('click', function (event) {
event.preventDefault();
if (currentPage > 1) {
showPage(currentPage - 1);
}
});
}

if (nextLink) {
nextLink.addEventListener('click', function (event) {
event.preventDefault();
if (currentPage < totalPages) {
showPage(currentPage + 1);
}
});
}

showPage(1);
});
</script>
{% endblock %}

{% block footer %}
{{ footer() }}
{% endblock %}
Loading