diff --git a/app/routes/meetings.js b/app/routes/meetings.js index 5add084d..9a2b134e 100644 --- a/app/routes/meetings.js +++ b/app/routes/meetings.js @@ -743,9 +743,12 @@ module.exports = router => { var selected = [].concat(data[selectedKey] || []).filter(function(p){ return p && p !== '_unchecked' }) persons.forEach(function(p){ if (!p) return - var name = (p.first_name || '').trim() - var role = (p.last_name || '').trim() - if (!name && !role) return + var first = (p.first_name || '').trim() + var last = (p.last_name || '').trim() + var role = (p.role || '').trim() + if (!first && !last && !role) return + // Display as "LASTNAME, Firstname" to match the predefined options. + var name = last ? (last.toUpperCase() + (first ? ', ' + first : '')) : first var label = role ? (name + ' (' + role + ')') : name if (pool.indexOf(label) === -1) pool.push(label) if (selected.indexOf(label) === -1) selected.push(label) @@ -756,19 +759,90 @@ module.exports = router => { // --- Confirm meeting arrangements flow (shared: bfs, v50, v51) --- + // The reschedule flow reuses the confirm-arrangements edit pages. When the + // user is rescheduling, changeMode edits must return to the reschedule + // check-answers page (not confirm-arrangements) and mark that a change was made. + var rescheduleCheckAnswers = '/bfs/meetings-2/rescheduled/check-answers' + + // Arriving on the reschedule check-answers page. ?start=true means a fresh + // entry from the arranged/rescheduled state, so reset the "changed" flag and + // snapshot the current arrangement into previous_* keys so the rescheduled + // view can show what was previously arranged. + var rescheduleSnapshotKeys = ['meetingDate','meetingHour','meetingMinutes','meetingRequestedBy','meetingFormat','meetingLocationType','cpsLocation','magistratesLocation','crownLocation','policeStationLocation','otherLocation','attendees','meetingLead','interpreterNeeded','interpreterDetails','supportPersonNeeded','supportPersonDetails','otherSupportNeeds'] + router.get(rescheduleCheckAnswers, function(request, response, next) { + var data = request.session.data + if (request.query.start === 'true') { + data['rescheduleChanged'] = '' + rescheduleSnapshotKeys.forEach(function(key){ + data['previous_' + key] = data[key] + }) + } + data['rescheduleMode'] = 'true' + next() + }) + + // Confirm the (possibly unchanged) reschedule details. Only when a change + // was made do we ask for a reason before returning to the Meetings sub-tab. + router.post('/bfs/meetings-2/rescheduled/check-answers-answer', function(request, response) { + var data = request.session.data + var changed = data['rescheduleChanged'] === 'true' + data['rescheduleMode'] = '' + if (changed) { + return response.redirect('/bfs/meetings-2/rescheduled/reason-why') + } + data['rescheduleChanged'] = '' + response.redirect('/bfs/victim/index?secondaryNav=ptm&meetingState=arranged#communications') + }) + + // After capturing the reason for change, return to the Meetings sub-tab in + // the rescheduled state. + router.post('/bfs/meetings-2/rescheduled/reason-why-answer', function(request, response) { + request.session.data['rescheduleChanged'] = '' + request.session.data['meetingRescheduled'] = 'true' + response.redirect('/bfs/victim/index?secondaryNav=ptm&meetingState=rescheduled&meetingSuccess=yes#communications') + }) + + // Cancel flow: capture when the meeting was cancelled, then ask for a reason. + router.post('/bfs/meetings-2/cancelled/meeting-date-answer', function(request, response) { + response.redirect('/bfs/meetings-2/cancelled/reason-why') + }) + + // Cancel flow: after capturing the reason, return to the Meetings sub-tab in + // the cancelled state. + router.post('/bfs/meetings-2/cancelled/reason-why-answer', function(request, response) { + response.redirect('/bfs/victim/index?secondaryNav=ptm&meetingState=cancelled&meetingSuccess=yes#communications') + }) + + // Where a confirm-arrangements answer route should return after a Change. + // In reschedule mode it returns to the reschedule check-answers and records + // that a change was made. + function caCheckAnswersTarget(request, caBase) { + if (request.session.data['rescheduleMode'] === 'true') { + request.session.data['rescheduleChanged'] = 'true' + return rescheduleCheckAnswers + } + return caBase + 'check-answers' + } + // When a "Change" link on check-answers is used, ?changeMode=true is stored // in the session; each answer route returns to check-answers instead of // advancing the flow. function caChangeReturn(request, response, caBase, nextUrl) { if (request.session.data['changeMode'] === 'true') { request.session.data['changeMode'] = '' - return response.redirect(caBase + 'check-answers') + return response.redirect(caCheckAnswersTarget(request, caBase)) } response.redirect(nextUrl) } function registerConfirmArrangements(caBase) { + // Loading the normal arrange check-answers means we are not rescheduling. + router.get(caBase + 'check-answers', function(request, response, next) { + request.session.data['rescheduleMode'] = '' + next() + }) + router.post(caBase + 'who-requested-meeting-answer', function(request, response) { var data = request.session.data if (!data['meetingRequestedBy']){ @@ -804,7 +878,7 @@ module.exports = router => { return response.redirect(caBase + 'meeting-location?changeMode=true') } data['changeMode'] = '' - return response.redirect(caBase + 'check-answers') + return response.redirect(caCheckAnswersTarget(request, caBase)) } if (needsLocation){ response.redirect(caBase + 'meeting-location') @@ -848,6 +922,18 @@ module.exports = router => { caChangeReturn(request, response, caBase, caBase + 'support-needs') }) + // "Add another person" submits the attendees form so the current checkbox + // selections are saved to the session before navigating to the add page. + router.post(caBase + 'attendees-add-another', function(request, response) { + response.redirect(caBase + 'add-attendee') + }) + + // "Add another person" submits the meeting-lead form so the current lead + // selection is saved to the session before navigating to the add page. + router.post(caBase + 'meeting-lead-add-another', function(request, response) { + response.redirect(caBase + 'add-meeting-lead') + }) + // Custom attendee added on the attendees page -> becomes a selected attendee router.post(caBase + 'add-attendee-answer', function(request, response) { appendAddedPeople(request, 'addedAttendees', 'attendees') @@ -871,10 +957,12 @@ module.exports = router => { data['interpreterNeededError'] = '' data['supportPersonNeededError'] = '' data['changeMode'] = '' - response.redirect(caBase + 'check-answers') + response.redirect(caCheckAnswersTarget(request, caBase)) }) router.post(caBase + 'check-answers-answer', function(request, response) { + // A freshly arranged meeting has no prior arrangement to show as previous. + request.session.data['meetingRescheduled'] = '' if (caBase.indexOf('/bfs') === 0) { response.redirect('/bfs/victim/index?secondaryNav=ptm&meetingState=arranged&meetingSuccess=yes#communications') } else { diff --git a/app/views/bfs/meetings-2/cancelled/meeting-date.html b/app/views/bfs/meetings-2/cancelled/meeting-date.html index a94121f0..dd742bd3 100644 --- a/app/views/bfs/meetings-2/cancelled/meeting-date.html +++ b/app/views/bfs/meetings-2/cancelled/meeting-date.html @@ -16,20 +16,20 @@

When was the meeting cancelled?

-
+
-
+ {% endif %}
diff --git a/app/views/bfs/victim/pre-trial/states/offered-multi.html b/app/views/bfs/victim/pre-trial/states/offered-multi.html index 8d70406b..b299b167 100644 --- a/app/views/bfs/victim/pre-trial/states/offered-multi.html +++ b/app/views/bfs/victim/pre-trial/states/offered-multi.html @@ -86,8 +86,8 @@


diff --git a/app/views/bfs/victim/pre-trial/states/offered.html b/app/views/bfs/victim/pre-trial/states/offered.html index 3ca083c9..64da3198 100644 --- a/app/views/bfs/victim/pre-trial/states/offered.html +++ b/app/views/bfs/victim/pre-trial/states/offered.html @@ -15,8 +15,8 @@

diff --git a/app/views/bfs/victim/pre-trial/states/rescheduled.html b/app/views/bfs/victim/pre-trial/states/rescheduled.html index 3261184c..cd3bdeb6 100644 --- a/app/views/bfs/victim/pre-trial/states/rescheduled.html +++ b/app/views/bfs/victim/pre-trial/states/rescheduled.html @@ -1,3 +1,31 @@ +{% set victimName = data['victimForename'] + " " + data['victimSurname'] %} + +{% macro arrangedTextFor(requestedBy, name) %}{% if requestedBy == "family" %}{{ name }}'s bereaved family requested it{% elif requestedBy == "cps" %}CPS offered and {{ name }}'s bereaved family accepted{% elif requestedBy == "third-party" %}Requested by a third party{% endif %}{% endmacro %} +{% macro formatTextFor(format) %}{% if format == "in-person" %}In person{% elif format == "virtual" %}Virtual call{% elif format == "hybrid" %}Hybrid{% endif %}{% endmacro %} + +{% set arrangedText = arrangedTextFor(data['meetingRequestedBy'], victimName) | trim %} +{% set formatText = formatTextFor(data['meetingFormat']) | trim %} +{% if data['meetingLocationType'] == "cps" %}{% set locationText = data['cpsLocation'] %} +{% elif data['meetingLocationType'] == "magistrates" %}{% set locationText = data['magistratesLocation'] %} +{% elif data['meetingLocationType'] == "crown" %}{% set locationText = data['crownLocation'] %} +{% elif data['meetingLocationType'] == "police" %}{% set locationText = data['policeStationLocation'] %} +{% elif data['meetingLocationType'] == "other" %}{% set locationText = data['otherLocation'] %} +{% else %}{% set locationText = "" %}{% endif %} +{% set attendeesList = data['attendees'] %} +{% if attendeesList is string %}{% set attendeesList = [attendeesList] %}{% endif %} +{% if data['rescheduleReason'] == "Other" %}{% set reasonText = data['rescheduleReasonOther'] %}{% else %}{% set reasonText = data['rescheduleReason'] %}{% endif %} + +{% set prevArrangedText = arrangedTextFor(data['previous_meetingRequestedBy'], victimName) | trim %} +{% set prevFormatText = formatTextFor(data['previous_meetingFormat']) | trim %} +{% if data['previous_meetingLocationType'] == "cps" %}{% set prevLocationText = data['previous_cpsLocation'] %} +{% elif data['previous_meetingLocationType'] == "magistrates" %}{% set prevLocationText = data['previous_magistratesLocation'] %} +{% elif data['previous_meetingLocationType'] == "crown" %}{% set prevLocationText = data['previous_crownLocation'] %} +{% elif data['previous_meetingLocationType'] == "police" %}{% set prevLocationText = data['previous_policeStationLocation'] %} +{% elif data['previous_meetingLocationType'] == "other" %}{% set prevLocationText = data['previous_otherLocation'] %} +{% else %}{% set prevLocationText = "" %}{% endif %} +{% set prevAttendeesList = data['previous_attendees'] %} +{% if prevAttendeesList is string %}{% set prevAttendeesList = [prevAttendeesList] %}{% endif %} + Log new meeting details @@ -8,8 +36,16 @@

- {{ meetingPurpose or "CPS pre-trial meeting" }} + {{ data['meetingPurpose'] | meetingPurposeLabel(data['meetingPurposeDetails']) }}

+
@@ -20,143 +56,201 @@

Date and time
- 15 April 2025 at 14:00pm + {{ data['meetingDate'] | formatDate }}{% if data['meetingHour'] %} at {{ data['meetingHour'] }}:{{ data['meetingMinutes'] }}{% endif %}

- Reason for change + How meeting was arranged
- Sarah Phillips's bereaved family not available + {{ arrangedText }}
- How meeting was arranged + How meeting will take place
- CPS offered and Sarah Phillips's bereaved family accepted + {{ formatText }}
+ {% if locationText %}
- How meeting will take place + Location
- In person + {{ locationText }}
+ {% endif %}
- Location + Attendees
- Birmingham Magistrates’ Court +

{{ victimName }}'s bereaved family

+ {% for attendee in attendeesList %}{% if attendee != "_unchecked" %}

{{ attendee }}

{% endif %}{% endfor %}
- Attendees + Meeting lead +
+
+ {{ data['meetingLead'] }} +
+
+ +
+
+ Interpreter needed +
+
+ {{ "Yes" if data['interpreterNeeded'] == "yes" else "No" }} +
+
+ +
+
+ Person for support
- (Meeting lead) PC FISHER, Jane (Police officer in charge), Sarah Phillips's bereaved family, SHEAF, Jessica (High court advocate), BIDWELL, Jane (Family liaison officer), SAKAMOTO, Hadji (Independent domestic violence adviser (IDVA)) + {{ "Yes" if data['supportPersonNeeded'] == "yes" else "No" }}
- Support needs + Other support
- Interpreter needed: No, Person for support: Yes -
- Other support: Victim's family will need a room with step free access + {{ data['otherSupportNeeds'] if data['otherSupportNeeds'] else "None" }}
+ {% if reasonText %} +
+
+ Reason for change +
+
+ {{ reasonText }} +
+
+ {% endif %} +
- -
- Arranged meetings + Previously arranged meetings
+
+ +
+
+ Date and time +
+
+ {{ data['previous_meetingDate'] | formatDate }}{% if data['previous_meetingHour'] %} at {{ data['previous_meetingHour'] }}:{{ data['previous_meetingMinutes'] }}{% endif %} +
+
+ +
+
+ How meeting will take place +
+
+ {{ prevFormatText }} +
+
+ + {% if prevLocationText %} +
+
+ Location +
+
+ {{ prevLocationText }} +
+
+ {% endif %} + +
+
+ Attendees +
+
+

{{ victimName }}'s bereaved family

+ {% for attendee in prevAttendeesList %}{% if attendee != "_unchecked" %}

{{ attendee }}

{% endif %}{% endfor %} +
+
+ +
+
+ Meeting lead +
+
+ {{ data['previous_meetingLead'] }} +
+
+ +
+
+ Interpreter needed +
+
+ {{ "Yes" if data['previous_interpreterNeeded'] == "yes" else "No" }} +
+
+ +
+
+ Person for support +
+
+ {{ "Yes" if data['previous_supportPersonNeeded'] == "yes" else "No" }} +
+
+ +
+
+ Other support +
+
+ {{ data['previous_otherSupportNeeds'] if data['previous_otherSupportNeeds'] else "None" }} +
+
+ +
+
+
- -
- -
-
- Date and time -
-
- 11 April 2025 at 11:45am -
-
- -
-
- How meeting will take place -
-
- In person -
-
- -
-
- Location -
-
- Birmingham Magistrates’ Court -
-
- -
-
- Attendees -
-
- (Meeting lead) PC FISHER, Jane (Police officer in charge), Sarah Phillips's bereaved family, SHEAF, Jessica (High court advocate), BIDWELL, Jane (Family liaison officer), SAKAMOTO, Hadji (Independent domestic violence adviser (IDVA)) -
-
- -
-
- Support needs -
-
- Interpreter needed: No, Person for support: Yes -
- Other support: Victim's family will need a room with step free access -
-
- -
+
+ + + Offer reponses + + +
+ {% set hideResponseActions = true %} + {% include "/bfs/meetings-2/cps-offer/partials/logged-responses.html" %} + {% set hideResponseActions = false %} +
@@ -166,54 +260,16 @@

-

{{ meetingPurpose or "CPS pre-trial meeting" }} offer accepted

-
-
-
- How meeting offer was accepted -
-
- Letter by post -
- -
-
-
- Date accepted -
-
- 11 April 2025 -
- -
- -
- -
- -

{{ meetingPurpose or "CPS pre-trial meeting" }} offered

-
-
-
- How offered -
-
- Letter by post -
- -
-
-
- Date offered -
-
- 11 April 2025 -
- -
- -
+ {% set hideNoResponseOffers = true %} + {% include "/bfs/meetings-2/cps-offer/partials/logged-offers.html" %} + {% set hideNoResponseOffers = false %} +
- - +
+ + + Log meeting outcome + + + \ No newline at end of file