diff --git a/app/assets/javascript/expandable-sections.js b/app/assets/javascript/expandable-sections.js index 9826e0bf..6d5883e1 100644 --- a/app/assets/javascript/expandable-sections.js +++ b/app/assets/javascript/expandable-sections.js @@ -1,10 +1,55 @@ // app/assets/javascript/expandable-sections.js +const BREAST_FEATURES_SECTION_ID = 'breast-features' +const REVIEW_AT_IMAGING_STATUS = 'Review at imaging' + // Handle expandable sections with completion tracking document.addEventListener('DOMContentLoaded', function () { // console.log('Expandable sections script loaded') // Debug log const sections = document.querySelectorAll('.js-expandable-section') const completedSections = new Set() + const reviewAfterImagingField = document.querySelector( + 'input[name="event[workflowStatus][review-breast-features-after-imaging]"]' + ) + + function setReviewAfterImagingFlag(statusValue) { + if (reviewAfterImagingField) { + reviewAfterImagingField.value = statusValue + } + } + + // Status implied by the review-at-imaging workflow flag, if any + function getReviewAfterImagingSectionStatus() { + const flagValue = reviewAfterImagingField + ? reviewAfterImagingField.value + : '' + + if (flagValue === 'yes') { + return REVIEW_AT_IMAGING_STATUS + } + if (flagValue === 'answered') { + return 'Reviewed' + } + return null + } + + function completeSectionAndContinue(section, index, forcedStatus) { + // Mark current section as completed + completedSections.add(index) + + const newStatus = + forcedStatus || getNextStatus(getCurrentSectionStatus(section)) + applySectionStatus(section, newStatus) + + // Close current section + section.removeAttribute('open') + + // Find and open the next incomplete section after this one + openNextIncompleteSection(index, sections, completedSections) + + // Update progress counter + updateProgress(sections, completedSections) + } sections.forEach(function (section, index) { const content = section.querySelector('.nhsuk-details__text') @@ -16,7 +61,18 @@ document.addEventListener('DOMContentLoaded', function () { // Create button container const buttonContainer = document.createElement('div') - buttonContainer.className = 'nhsuk-form-group' + buttonContainer.className = 'nhsuk-form-group nhsuk-button-group' + + const sectionId = section.getAttribute('id') + const isBreastFeaturesSection = sectionId === BREAST_FEATURES_SECTION_ID + + // Reflect any review-at-imaging decision in the section's status tag + if (isBreastFeaturesSection) { + const impliedStatus = getReviewAfterImagingSectionStatus() + if (impliedStatus) { + applySectionStatus(section, impliedStatus) + } + } // Create button const button = document.createElement('button') @@ -30,49 +86,36 @@ document.addEventListener('DOMContentLoaded', function () { buttonContainer.appendChild(button) + if (isBreastFeaturesSection) { + const reviewAfterImagingButton = document.createElement('button') + reviewAfterImagingButton.className = + 'nhsuk-button nhsuk-button--secondary nhsuk-u-margin-bottom-0 nhsuk-u-margin-top-3' + reviewAfterImagingButton.type = 'button' + reviewAfterImagingButton.textContent = 'Review at imaging' + + buttonContainer.appendChild(reviewAfterImagingButton) + + reviewAfterImagingButton.addEventListener('click', function () { + setReviewAfterImagingFlag('yes') + completeSectionAndContinue(section, index, REVIEW_AT_IMAGING_STATUS) + updateButtonText(section, button) + }) + } + // Append HR first, then button container content.appendChild(hr) content.appendChild(buttonContainer) // Add click handler button.addEventListener('click', function () { - // Mark current section as completed - completedSections.add(index) - - // Determine current status and set new status - const currentStatus = getCurrentSectionStatus(section) - let newStatus - - if (currentStatus === 'Incomplete') { - newStatus = 'Complete' - } else if (currentStatus === 'To review') { - newStatus = 'Reviewed' - } else if (currentStatus === 'Reviewed') { - newStatus = 'Reviewed' // Keep as reviewed - } else { - newStatus = 'Complete' // Default fallback + if (isBreastFeaturesSection) { + setReviewAfterImagingFlag('') } - // Update the status for this section - updateSectionStatus(section, newStatus) - - // Save status to sessionStorage - const sectionId = section.getAttribute('id') - if (sectionId && window.saveSectionStatus) { - window.saveSectionStatus(sectionId, newStatus) - } + completeSectionAndContinue(section, index) // Update button text based on new status updateButtonText(section, button) - - // Close current section - section.removeAttribute('open') - - // Find and open the next incomplete section after this one - openNextIncompleteSection(index, sections, completedSections) - - // Update progress counter - updateProgress(sections, completedSections) }) } }) @@ -88,32 +131,25 @@ document.addEventListener('DOMContentLoaded', function () { button.addEventListener('click', function (event) { // Mark all sections as completed sections.forEach(function (section, index) { + const sectionId = section.getAttribute('id') + const isBreastFeaturesSection = + sectionId === BREAST_FEATURES_SECTION_ID + // Add to completed set completedSections.add(index) - // Determine current status and set new status - const currentStatus = getCurrentSectionStatus(section) - let newStatus - - if (currentStatus === 'Incomplete') { - newStatus = 'Complete' - } else if (currentStatus === 'To review') { - newStatus = 'Reviewed' - } else if (currentStatus === 'Reviewed') { - newStatus = 'Reviewed' // Keep as reviewed - } else { - newStatus = 'Complete' // Default fallback + // The breast features section keeps any review-at-imaging status + // rather than being marked reviewed with the rest + let newStatus = null + if (isBreastFeaturesSection) { + newStatus = getReviewAfterImagingSectionStatus() } - - // Update the status for this section - updateSectionStatus(section, newStatus) - - // Save status to sessionStorage - const sectionId = section.getAttribute('id') - if (sectionId && window.saveSectionStatus) { - window.saveSectionStatus(sectionId, newStatus) + if (!newStatus) { + newStatus = getNextStatus(getCurrentSectionStatus(section)) } + applySectionStatus(section, newStatus) + // Close the section section.removeAttribute('open') }) @@ -190,11 +226,33 @@ function getCurrentSectionStatus(section) { return statusElement ? statusElement.textContent.trim() : 'Incomplete' } +// Work out the status a section moves to when marked as done +function getNextStatus(currentStatus) { + if (currentStatus === 'To review' || currentStatus === 'Reviewed') { + return 'Reviewed' + } + return 'Complete' +} + +// Update a section's status tag and persist it to sessionStorage +function applySectionStatus(section, statusText) { + updateSectionStatus(section, statusText) + + const sectionId = section.getAttribute('id') + if (sectionId && window.saveSectionStatus) { + window.saveSectionStatus(sectionId, statusText) + } +} + // Function to update button text based on section status function updateButtonText(section, button) { const currentStatus = getCurrentSectionStatus(section) - if (currentStatus === 'Reviewed' || currentStatus === 'Complete') { + if ( + currentStatus === 'Reviewed' || + currentStatus === 'Complete' || + currentStatus === REVIEW_AT_IMAGING_STATUS + ) { button.textContent = 'Next section' } else { button.textContent = 'Mark as reviewed' @@ -363,7 +421,11 @@ function updateSectionStatus(section, statusText) { 'nhsuk-tag--yellow' ) - if (statusText === 'Complete' || statusText === 'Reviewed') { + if ( + statusText === 'Complete' || + statusText === 'Reviewed' || + statusText === REVIEW_AT_IMAGING_STATUS + ) { statusElement.classList.add('nhsuk-tag--green') } else if (statusText === 'Incomplete') { statusElement.classList.add('nhsuk-tag--blue') diff --git a/app/assets/javascript/expanded-state-tracker.js b/app/assets/javascript/expanded-state-tracker.js index 5f6ac09d..6c676532 100644 --- a/app/assets/javascript/expanded-state-tracker.js +++ b/app/assets/javascript/expanded-state-tracker.js @@ -140,7 +140,11 @@ 'nhsuk-tag--yellow' ) - if (statusText === 'Complete' || statusText === 'Reviewed') { + if ( + statusText === 'Complete' || + statusText === 'Reviewed' || + statusText === 'Review at imaging' + ) { statusElement.classList.add('nhsuk-tag--green') } else if (statusText === 'Incomplete') { statusElement.classList.add('nhsuk-tag--blue') diff --git a/app/routes/events.js b/app/routes/events.js index c187fbf2..2e015fe5 100644 --- a/app/routes/events.js +++ b/app/routes/events.js @@ -1458,6 +1458,15 @@ module.exports = (router) => { } } + // Saving breast features resolves any 'review at imaging' reminder + if ( + data.event?.workflowStatus?.['review-breast-features-after-imaging'] === + 'yes' + ) { + data.event.workflowStatus['review-breast-features-after-imaging'] = + 'answered' + } + // Flash error message if needed if (errorCount > 0) { req.flash( diff --git a/app/views/events/check-information.html b/app/views/events/check-information.html index 0d7ab8ce..73f659a9 100644 --- a/app/views/events/check-information.html +++ b/app/views/events/check-information.html @@ -1,5 +1,7 @@ {% extends 'layout-appointment.html' %} +{% from '_components/notification-banner/macro.njk' import appNotificationBanner %} + {% set pageHeading = "Check information" %} {% set showNavigation = true %} @@ -19,6 +21,7 @@ #} {% set activeTab = 'review' %} +{% set showReviewAfterImagingReminder = data.event.workflowStatus['review-breast-features-after-imaging'] == 'yes' %} @@ -71,7 +74,10 @@ heading: "Medical information", headingLevel: "2", feature: true, - descriptionHtml: medicalInfoSummaryHtml + descriptionHtml: medicalInfoSummaryHtml, + attributes: { + id: "check-information-breast-features" + } }) }} {% endset %} @@ -132,7 +138,10 @@ heading: "Breast features", headingLevel: "2", feature: true, - descriptionHtml: breastFeaturesHtml + descriptionHtml: breastFeaturesHtml, + attributes: { + id: "check-information-breast-features" + } }) }} {# Other relevant information card #} @@ -155,6 +164,25 @@

{{ pageHeading }}

+ {% if showReviewAfterImagingReminder %} + {% set breastFeaturesReminderHtml %} +

+ Are there any breast features to add for {{ participant | getFullName }}? +

+

+ This includes non-surgical scars, moles and other features that may appear on mammogram images +

+

+ Review breast features +

+ {% endset %} + + {{ appNotificationBanner({ + titleText: "Reminder to add breast features", + html: breastFeaturesReminderHtml + }) }} + {% endif %} +

To conclude this appointment, confirm this information is correct.

diff --git a/app/views/events/images-automatic.html b/app/views/events/images-automatic.html index e4f5b596..822ee615 100644 --- a/app/views/events/images-automatic.html +++ b/app/views/events/images-automatic.html @@ -50,6 +50,18 @@

{{ pageHeading }}

+
+
+

Observations during mammogram

+ {{ button({ + text: "Add breast features", + href: eventUrl + "/medical-information/record-breast-features" | urlWithReferrer(currentUrl), + variant: "secondary", + small: true + }) }} +
+
+ {% if data.event.workflowStatus["take-images"] == 'completed' %} diff --git a/app/views/events/images-before-mammography.html b/app/views/events/images-before-mammography.html index 83e0103c..0be536df 100644 --- a/app/views/events/images-before-mammography.html +++ b/app/views/events/images-before-mammography.html @@ -15,6 +15,18 @@

{{ pageHeading }}

+
+
+

Observations during mammogram

+ {{ button({ + text: "Add breast features", + href: eventUrl + "/medical-information/record-breast-features" | urlWithReferrer(currentUrl), + variant: "secondary", + small: true + }) }} +
+
+ {% set insetHtml %}

Mammography images will appear below once they have been received @@ -25,7 +37,6 @@

{{ pageHeading }}

html: insetHtml }) }} - {{ appHiddenInput({ name: "event[workflowStatus][awaiting-images]", value: "completed" @@ -42,7 +53,6 @@

{{ pageHeading }}

{% include "_includes/images/image-troubleshooting.njk" %} - {% endblock %} diff --git a/app/views/events/images-manual.html b/app/views/events/images-manual.html index a027441d..97369e88 100644 --- a/app/views/events/images-manual.html +++ b/app/views/events/images-manual.html @@ -52,6 +52,14 @@

{{ pageHeading }}

{% endif %} +

Observations during mammogram

+ {{ button({ + text: "Add breast features", + href: eventUrl + "/medical-information/record-breast-features" | urlWithReferrer(currentUrl), + variant: "secondary", + small: true + }) }} + {# {{ radios({ name: "event[mammogramDataTemp][machineRoom]", value: mammogramSource.machineRoom, @@ -87,9 +95,9 @@

{{ pageHeading }}

{% set troubleshootingIssue = event.mammogramDataTemp.troubleshootingIssue %} {% set hasTroubleshootingIssue = troubleshootingIssue in ['worklist-participant', 'wrong-image-count', 'incorrect-image-labels'] %} {% set showWorklistMatchingContent = troubleshootingIssue == 'worklist-participant' %} - {% set showDefaultManualContent = data.settings.screening.manualImageCollection == 'true' or data.event.isManualImageCollection or isManualFailover %} + {% set showManualParticipantDetails = showWorklistMatchingContent or isManualFailover %} - {% if (hasTroubleshootingIssue and showWorklistMatchingContent) or (not hasTroubleshootingIssue and showDefaultManualContent) %} + {% if showManualParticipantDetails %}

Manually add participant details

Set up an unscheduled appointment using the following information so mammograms can be assigned correctly:

{{ summaryList({ diff --git a/app/views/events/review-medical-information.html b/app/views/events/review-medical-information.html index 0972de72..112643a5 100644 --- a/app/views/events/review-medical-information.html +++ b/app/views/events/review-medical-information.html @@ -27,6 +27,11 @@

value: "completed" }) }} + {{ appHiddenInput({ + name: "event[workflowStatus][review-breast-features-after-imaging]", + value: data.event.workflowStatus['review-breast-features-after-imaging'] + }) }} +
{{ button({