diff --git a/app/routes.js b/app/routes.js index fb6a4e7..6e79bbf 100644 --- a/app/routes.js +++ b/app/routes.js @@ -3,6 +3,8 @@ const express = require('express') const router = express.Router() +const isWholeNumber = str => /^\d+$/.test(str) + 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) || [] @@ -31,6 +33,64 @@ router.get('/september-iteration-2/clickthru/04a-example-search-result', functio }) }) +router.post('/sessions/02-organise-slots', function (req, res) { + const session = (req.body && req.body.newSession) || {} + const startTime = session.startTime || {} + const endTime = session.endTime || {} + + const startHourStr = (startTime.hour || '').trim() + const startMinuteStr = (startTime.minute || '').trim() + const endHourStr = (endTime.hour || '').trim() + const endMinuteStr = (endTime.minute || '').trim() + const durationStr = (session.duration || '').trim() + + const startHour = parseInt(startHourStr, 10) + const startMinute = parseInt(startMinuteStr, 10) + const endHour = parseInt(endHourStr, 10) + const endMinute = parseInt(endMinuteStr, 10) + const duration = parseInt(durationStr, 10) + + const validStartHour = isWholeNumber(startHourStr) && startHour >= 0 && startHour <= 23 + const validStartMinute = isWholeNumber(startMinuteStr) && startMinute >= 0 && startMinute <= 59 + const validEndHour = isWholeNumber(endHourStr) && endHour >= 0 && endHour <= 23 + const validEndMinute = isWholeNumber(endMinuteStr) && endMinute >= 0 && endMinute <= 59 + + const errors = {} + + if (!validStartHour || !validStartMinute) { + errors.startTime = 'Start time must be entered, in 24 hour format' + } + + if (!validEndHour || !validEndMinute) { + errors.endTime = 'End time must be entered, in 24 hour format' + } + + const validDuration = isWholeNumber(durationStr) && duration > 0 + if (!validDuration) { + errors.duration = 'Slot length must be entered, in minutes, as a whole number' + } + + if (!errors.startTime && !errors.endTime) { + const startTotalMinutes = startHour * 60 + startMinute + const endTotalMinutes = endHour * 60 + endMinute + if (endTotalMinutes <= startTotalMinutes) { + errors.startTime = 'Start time must be earlier than end time' + errors.endTime = 'End time must be later than start time' + } else if (!errors.duration && duration > endTotalMinutes - startTotalMinutes) { + errors.duration = 'Slot length must be shorter than the total session duration' + } + } + + req.session.data.newSession = session + + if (Object.keys(errors).length > 0) { + return res.render('sessions/01-set-timings', { + errors + }) + } + res.redirect('/sessions/02-organise-slots') +}) + 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) diff --git a/app/views/index.html b/app/views/index.html index 2777a90..77ea7fb 100755 --- a/app/views/index.html +++ b/app/views/index.html @@ -39,6 +39,14 @@


+

July 2026

+

Sessions: first run

+
    +
  1. + Set up session +
  2. +
+

May–June 2026

Clinics: first run

    diff --git a/app/views/sessions/01-set-timings.html b/app/views/sessions/01-set-timings.html new file mode 100644 index 0000000..04324e9 --- /dev/null +++ b/app/views/sessions/01-set-timings.html @@ -0,0 +1,260 @@ +{% extends 'layout.html' %} + +{% set errorState = "true" if errors else "false" %} + +{% set pageName = "Create session: set timings" %} + +{% from "_includes/primary-navigation.html" import primaryNavigation %} +{% block header %} + {{ primaryNavigation("Clinics", serviceName) }} +{% endblock %} + +{% block beforeContent %}{% endblock %} + +{% block content %} + +{% set tickSvg %} + +{% endset %} + +
    +
    + +
    + +
    + +
    +
    +
    + + {% if errorState === "true" %} + {% set errorList = [] %} + {% if errors.startTime %} + {% set errorList = errorList.concat([{ text: errors.startTime, href: "#start-time-hour" }]) %} + {% endif %} + {% if errors.endTime %} + {% set errorList = errorList.concat([{ text: errors.endTime, href: "#end-time-hour" }]) %} + {% endif %} + {% if errors.duration %} + {% set errorList = errorList.concat([{ text: errors.duration, href: "#duration" }]) %} + {% endif %} + {{ errorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + +

    Set timings

    + +
    + +
    +
    + + Session start time + +
    + Use 24 hour format, for example, 10:00 +
    + {% if errors and errors.startTime %} + + Error: {{ errors.startTime }} + + {% endif %} + +
    +
    +
    + + +
    +
    + +
    +
    + + +
    +
    +
    +
    +
    + +
    +
    + + Session end time + +
    + Use 24 hour format, for example, 17:00 +
    + {% if errors and errors.endTime %} + + Error: {{ errors.endTime }} + + {% endif %} + +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
    + + {% if errors and errors.duration %} + + Error: {{ errors.duration }} + + {% endif %} +
    + + +
    +
    + +
    + Information: +

    Capacity calculator

    +

    X total slots in the + session

    + +
    + + + +
    +
    +
    +
    + +{% endblock %} + +{% block pageScripts %} + +{% endblock %} \ No newline at end of file diff --git a/app/views/sessions/02-organise-slots.html b/app/views/sessions/02-organise-slots.html new file mode 100644 index 0000000..11893fc --- /dev/null +++ b/app/views/sessions/02-organise-slots.html @@ -0,0 +1,574 @@ +{% extends 'layout.html' %} + +{% set pageName = "Create session: organise slots" %} + +{% from "_includes/primary-navigation.html" import primaryNavigation %} +{% block header %} + {{ primaryNavigation("Clinics", serviceName) }} +{% endblock %} + +{% block beforeContent %}{% endblock %} + +{% block content %} + + + +{% set tickSvg %} + +{% endset %} + +
    +
    + +
    + +
    + +
    +
    + +
    +

    Organise slots

    +

    + Session time + {{ data.newSession.startTime.hour | zeroPad }}:{{ data.newSession.startTime.minute | zeroPad }} to {{ data.newSession.endTime.hour | zeroPad }}:{{ data.newSession.endTime.minute | zeroPad }} +

    +
    + +
    + + + + + +

    + Click to select a slot. Press shift and click to select a range. +

    + +
    +
    +
    +
    +
    +
    +

    With selected:

    + +
    + +
    +
    +

    + {{ data.newSession.totalSlots }} slots available +

    +

    + +

    +
    +
    + +
    +
    +
    + +{% endblock %} + +{% block pageScripts %} + +{% endblock %} \ No newline at end of file