Skip to content

Commit 0fdcdd6

Browse files
authored
Merge pull request #1194 from dof-dss/D8NID-1661
D8NID-1661 (hotfix)
2 parents 24feeae + 6fc4332 commit 0fdcdd6

File tree

2 files changed

+95
-54
lines changed

2 files changed

+95
-54
lines changed

Diff for: web/modules/custom/nidirect_webforms/js/prisonbooking.js

+58-50
Original file line numberDiff line numberDiff line change
@@ -49,69 +49,76 @@
4949
.prop('aria-pressed', true);
5050
}
5151

52-
// Visit time slots preferences...
53-
54-
// Add aria-live region for announcing time slot preferences.
55-
const $preferredStatus = $('<div role="region" class="visually-hidden" aria-live="polite" />');
56-
$preferredStatus.append($('<h2 id="timeslots-announce-title" />'));
57-
$preferredStatus.append($('<div id="timeslots-announce-description" />'));
58-
59-
$(once('pvPreferredStatus', '[data-webform-key="visit_preferred_day_and_time"]', context)).prepend($preferredStatus);
60-
61-
// Limit timeslots that can be selected and
62-
// keep track of preferred time slots.
52+
// Visit time slots ...
6353
let $timeSlots = $('input[type="checkbox"]', $weekSlots);
64-
$timeSlots.attr('aria-controls', 'timeslots-announce');
6554

66-
let preferredSlots = [];
55+
// Array for tracking slot IDs as they are checked or unchecked.
56+
let preferredSlotIds = [];
6757

68-
// Default visit type is 'F' for face to face.
58+
// Get visit type from the booking reference and get
59+
// the timeslot limit for that visit type from settings.
6960
let pvTypeId = 'F';
70-
// By default, user can choose 3 timeslots.
7161
let pvTimeSlotLimit = 3;
7262

73-
// Get visit type from the booking reference and get
74-
// the timeslot limit for that visit type from settings.
7563
if (settings.prisonVisitBooking['booking_ref'] !== null) {
7664
pvTypeId = settings.prisonVisitBooking.booking_ref.visit_type_id;
7765
pvTimeSlotLimit = settings.prisonVisitBooking.visit_type_time_slot_limit[pvTypeId];
7866
}
7967

8068
if ($timeSlots.length) {
8169

82-
// Call function to disable checkboxes if time slot limit reached.
70+
// Disable checkboxes if time slot limit reached.
8371
disableCheckboxes($timeSlots, pvTimeSlotLimit);
8472

85-
// Prep timeslots to show preference rank.
86-
$timeSlots.each(function() {
87-
let $span = $('<span />');
88-
$span.addClass('rank').attr('aria-hidden', 'true');
89-
$(this).next('label').append($span);
90-
});
73+
// Add aria-live region for announcing slot preferences.
74+
const $preferredStatus = $('<div role="region" class="visually-hidden" aria-live="polite" />');
75+
$preferredStatus.append($('<h2 id="timeslots-announce-title" />'));
76+
$preferredStatus.append($('<div id="timeslots-announce-description" />'));
77+
78+
$(once('pvPreferredStatus', '[data-webform-key="visit_preferred_day_and_time"]', context)).prepend($preferredStatus);
79+
80+
// Set aria-controls on timeslots to control the
81+
// aria-live region.
82+
$timeSlots.attr('aria-controls', 'timeslots-announce');
9183

92-
// Preferred time slots may already exist (stored in hidden inputs).
93-
// Update ranks shown on time slot checkbox labels.
9484
let hiddenTimeSlotSelectors = '';
9585
hiddenTimeSlotSelectors += '[name="slot1_datetime"], ';
9686
hiddenTimeSlotSelectors += '[name="slot2_datetime"], ';
9787
hiddenTimeSlotSelectors += '[name="slot3_datetime"], ';
9888
hiddenTimeSlotSelectors += '[name="slot4_datetime"], ';
9989
hiddenTimeSlotSelectors += '[name="slot5_datetime"]';
10090

101-
$(hiddenTimeSlotSelectors).each(function(index) {
91+
const $hiddenTimeSlots = $(hiddenTimeSlotSelectors);
92+
93+
// D8NID-1661.
94+
if (settings.prisonVisitBooking.resetTimeslots === true) {
95+
// Reset all timeslots user has selected.
96+
$timeSlots.prop('checked', false);
97+
$hiddenTimeSlots.val('').attr('value', '');
98+
}
99+
100+
// Prep timeslots to show preference rank.
101+
$timeSlots.each(function() {
102+
let $span = $('<span />');
103+
$span.addClass('rank').attr('aria-hidden', 'true');
104+
$(this).next('label').append($span);
105+
});
106+
107+
// Update preference rank shown on timeslots.
108+
$hiddenTimeSlots.each(function(index) {
102109
let value = $(this).val();
103-
if (value.length) {
104-
let $timeSlot = $('input[value="' + value + '"]');
110+
let $timeSlot = $('input[value="' + value + '"]');
111+
if (value.length && $timeSlot.length) {
105112
$timeSlot.next('label').find('span.rank').text(index + 1);
106-
preferredSlots.push($timeSlot.prop('id'));
113+
preferredSlotIds.push($timeSlot.prop('id'));
107114
}
108115
});
109116

117+
// Trigger announcement of preferred timeslots.
110118
updatePreferredStatus();
111119

112120
// When a timeslot is checked or unchecked, update preference
113121
// ranks and hidden slot values.
114-
115122
$timeSlots.on('change', function(e) {
116123

117124
// Disable checkboxes if time slot limit reached.
@@ -121,30 +128,30 @@
121128
let slotId = $(this).prop('id');
122129
let slotValue = $(this).val();
123130
let $slotRank = $(this).next('label').find('span.rank');
124-
let rank = preferredSlots.indexOf(slotId);
131+
let rank = preferredSlotIds.indexOf(slotId);
125132

126133
// By default a slot has no rank.
127134
$slotRank.text('');
128-
$(hiddenTimeSlotSelectors).eq(rank).val('').attr('value', '');
135+
$hiddenTimeSlots.eq(rank).val('').attr('value', '');
129136

130137
if ($(this).is(':checked')) {
131-
preferredSlots.push(slotId);
132-
rank = preferredSlots.indexOf(slotId);
138+
preferredSlotIds.push(slotId);
139+
rank = preferredSlotIds.indexOf(slotId);
133140
$slotRank.text(rank + 1);
134-
$(hiddenTimeSlotSelectors).eq(rank).val(slotValue).attr('value', slotValue);
141+
$hiddenTimeSlots.eq(rank).val(slotValue).attr('value', slotValue);
135142
} else {
136-
preferredSlots.splice(preferredSlots.indexOf(slotId), 1);
143+
preferredSlotIds.splice(preferredSlotIds.indexOf(slotId), 1);
137144

138145
// Update ranks shown on remaining preferred slots.
139-
preferredSlots.forEach(function(value, index) {
146+
preferredSlotIds.forEach(function(value, index) {
140147
let selector = '#' + value;
141148
$(selector).next('label').find('span.rank').text(index + 1);
142149
});
143150

144151
// Update hidden timeslots.
145-
$(hiddenTimeSlotSelectors).each(function(index) {
146-
const $slotVal = $('#' + preferredSlots[index]).val();
147-
if (index in preferredSlots) {
152+
$hiddenTimeSlots.each(function(index) {
153+
const $slotVal = $('#' + preferredSlotIds[index]).val();
154+
if (index in preferredSlotIds) {
148155
$(this).val($slotVal).attr('value', $slotVal);
149156
} else {
150157
$(this).val('').attr('value', '');
@@ -169,25 +176,27 @@
169176

170177
function updatePreferredStatus() {
171178

172-
if (preferredSlots.length < pvTimeSlotLimit) {
173-
$('#timeslots-announce-title').html('You have selected ' + preferredSlots.length + ' time slots');
179+
if (preferredSlotIds.length < pvTimeSlotLimit) {
180+
$('#timeslots-announce-title').html('You have selected ' + preferredSlotIds.length + ' time slots');
174181
} else {
175-
$('#timeslots-announce-title').html('You have selected a maximum of ' + preferredSlots.length + ' time slots');
182+
$('#timeslots-announce-title').html('You have selected a maximum of ' + preferredSlotIds.length + ' time slots');
176183
}
177184

178185
let items = '';
179-
preferredSlots.forEach(function(value, index) {
186+
preferredSlotIds.forEach(function(value, index) {
180187
const options = {
181188
weekday: "long",
182189
year: "numeric",
183190
month: "long",
184191
day: "numeric",
185192
};
186-
const date = new Date($('#' + value).val());
187-
const prettyDate = date.toLocaleDateString('en-GB', options);
188-
const prettyTime = date.toLocaleTimeString([], { hour12: true, hour: "numeric", minute: "2-digit" });
193+
if (value.length) {
194+
const date = new Date($('#' + value).val());
195+
const prettyDate = date.toLocaleDateString('en-GB', options);
196+
const prettyTime = date.toLocaleTimeString([], { hour12: true, hour: "numeric", minute: "2-digit" });
189197

190-
items += `<li>${prettyTime} on ${prettyDate}</li>`;
198+
items += `<li>${prettyTime} on ${prettyDate}</li>`;
199+
}
191200
});
192201

193202
$('#timeslots-announce-description').html('<ol class="list--ordered-bullet">' + items + '</ol>');
@@ -197,4 +206,3 @@
197206
};
198207

199208
})(jQuery, Drupal, once);
200-

Diff for: web/modules/custom/nidirect_webforms/src/Plugin/WebformHandler/PrisonVisitBookingHandler.php

+37-4
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,36 @@ public function alterForm(array &$form, FormStateInterface $form_state, WebformS
133133
}
134134
}
135135

136-
// Show available time slots in the form.
136+
// Show available timeslots in the form.
137137
if ($page === 'visit_preferred_day_and_time' && !empty($this->bookingReference)) {
138+
139+
// Reset timeslots when user changes visit_order_number.
140+
// Some of the logic for setting timeslot preferences is handled
141+
// via clientside JS. Flag to clientside when timeslots must be
142+
// reset.
143+
$form['#attached']['drupalSettings']['prisonVisitBooking']['resetTimeslots'] = FALSE;
144+
145+
// Check last_visitor_order_number. If different from the present
146+
// visitor_order_number then timeslots need reset.
147+
$last_visitor_order_number = $form_state->get('last_visitor_order_number');
148+
if (!empty($last_visitor_order_number) && $last_visitor_order_number !== $form_state->getValue('visitor_order_number')) {
149+
$form['#attached']['drupalSettings']['prisonVisitBooking']['resetTimeslots'] = TRUE;
150+
151+
$form_values = array_filter($form_state->getValues(), function ($key) {
152+
return str_contains($key, '_week_');
153+
}, ARRAY_FILTER_USE_KEY);
154+
155+
foreach ($form_values as $element_name => $element_value) {
156+
$form_state->setValue($element_name, []);
157+
$elements[$element_name]['#default_value'] = [];
158+
$webform_submission->setElementData($element_name, []);
159+
}
160+
}
161+
162+
// Update last_visitor_order_number.
163+
$form_state->set('last_visitor_order_number', $form_state->getValue('visitor_order_number'));
164+
165+
// Get available slots and show only those slots on the form.
138166
$available_slots = $this->bookingReference['available_slots'];
139167

140168
// Determine dates.
@@ -145,12 +173,13 @@ public function alterForm(array &$form, FormStateInterface $form_state, WebformS
145173
$visit_booking_ref_valid_from = clone $visit_booking_week_start;
146174
}
147175

176+
// Alter form slots to correspond with available slots.
148177
if (!empty($available_slots)) {
149-
// Alter form slots to correspond with available slots.
178+
150179
for ($i = 4; $i >= 1; $i--) {
180+
151181
// Form slots for each week.
152182
$form_slots_week = &$form['elements']['visit_preferred_day_and_time']['slots_week_' . $i];
153-
154183
$webform_submission_slots_week = $webform_submission->getWebform()->getElement('slots_week_' . $i, TRUE);
155184

156185
if ($form_slots_week['#access'] = FALSE) {
@@ -292,7 +321,10 @@ public function validateForm(array &$form, FormStateInterface $form_state, Webfo
292321
* {@inheritdoc}
293322
*/
294323
public function submitForm(array &$form, FormStateInterface $form_state, WebformSubmissionInterface $webform_submission) {
295-
if ($form_state->isValidationComplete() && $form_state->get('current_page') === 'webform_preview') {
324+
325+
$page = $form_state->get('current_page');
326+
327+
if ($form_state->isValidationComplete() && $page === 'webform_preview') {
296328

297329
$temp_store = $this->tempStoreFactory->get('nidirect_webforms.prison_visit_booking');
298330
$remember_visitors = $form_state->getValue('additional_visitors_remember') === 'yes' ?? FALSE;
@@ -640,6 +672,7 @@ private function validatePlainText(string $element_name, string $error_msg, arra
640672
* Validate visitor one DOB.
641673
*/
642674
private function validateSlotPicked(array &$form, FormStateInterface $form_state) {
675+
643676
if ($form_state->get('current_page') !== 'visit_preferred_day_and_time') {
644677
return;
645678
}

0 commit comments

Comments
 (0)