|
49 | 49 | .prop('aria-pressed', true);
|
50 | 50 | }
|
51 | 51 |
|
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 ... |
63 | 53 | let $timeSlots = $('input[type="checkbox"]', $weekSlots);
|
64 |
| - $timeSlots.attr('aria-controls', 'timeslots-announce'); |
65 | 54 |
|
66 |
| - let preferredSlots = []; |
| 55 | + // Array for tracking slot IDs as they are checked or unchecked. |
| 56 | + let preferredSlotIds = []; |
67 | 57 |
|
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. |
69 | 60 | let pvTypeId = 'F';
|
70 |
| - // By default, user can choose 3 timeslots. |
71 | 61 | let pvTimeSlotLimit = 3;
|
72 | 62 |
|
73 |
| - // Get visit type from the booking reference and get |
74 |
| - // the timeslot limit for that visit type from settings. |
75 | 63 | if (settings.prisonVisitBooking['booking_ref'] !== null) {
|
76 | 64 | pvTypeId = settings.prisonVisitBooking.booking_ref.visit_type_id;
|
77 | 65 | pvTimeSlotLimit = settings.prisonVisitBooking.visit_type_time_slot_limit[pvTypeId];
|
78 | 66 | }
|
79 | 67 |
|
80 | 68 | if ($timeSlots.length) {
|
81 | 69 |
|
82 |
| - // Call function to disable checkboxes if time slot limit reached. |
| 70 | + // Disable checkboxes if time slot limit reached. |
83 | 71 | disableCheckboxes($timeSlots, pvTimeSlotLimit);
|
84 | 72 |
|
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'); |
91 | 83 |
|
92 |
| - // Preferred time slots may already exist (stored in hidden inputs). |
93 |
| - // Update ranks shown on time slot checkbox labels. |
94 | 84 | let hiddenTimeSlotSelectors = '';
|
95 | 85 | hiddenTimeSlotSelectors += '[name="slot1_datetime"], ';
|
96 | 86 | hiddenTimeSlotSelectors += '[name="slot2_datetime"], ';
|
97 | 87 | hiddenTimeSlotSelectors += '[name="slot3_datetime"], ';
|
98 | 88 | hiddenTimeSlotSelectors += '[name="slot4_datetime"], ';
|
99 | 89 | hiddenTimeSlotSelectors += '[name="slot5_datetime"]';
|
100 | 90 |
|
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) { |
102 | 109 | 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) { |
105 | 112 | $timeSlot.next('label').find('span.rank').text(index + 1);
|
106 |
| - preferredSlots.push($timeSlot.prop('id')); |
| 113 | + preferredSlotIds.push($timeSlot.prop('id')); |
107 | 114 | }
|
108 | 115 | });
|
109 | 116 |
|
| 117 | + // Trigger announcement of preferred timeslots. |
110 | 118 | updatePreferredStatus();
|
111 | 119 |
|
112 | 120 | // When a timeslot is checked or unchecked, update preference
|
113 | 121 | // ranks and hidden slot values.
|
114 |
| - |
115 | 122 | $timeSlots.on('change', function(e) {
|
116 | 123 |
|
117 | 124 | // Disable checkboxes if time slot limit reached.
|
|
121 | 128 | let slotId = $(this).prop('id');
|
122 | 129 | let slotValue = $(this).val();
|
123 | 130 | let $slotRank = $(this).next('label').find('span.rank');
|
124 |
| - let rank = preferredSlots.indexOf(slotId); |
| 131 | + let rank = preferredSlotIds.indexOf(slotId); |
125 | 132 |
|
126 | 133 | // By default a slot has no rank.
|
127 | 134 | $slotRank.text('');
|
128 |
| - $(hiddenTimeSlotSelectors).eq(rank).val('').attr('value', ''); |
| 135 | + $hiddenTimeSlots.eq(rank).val('').attr('value', ''); |
129 | 136 |
|
130 | 137 | if ($(this).is(':checked')) {
|
131 |
| - preferredSlots.push(slotId); |
132 |
| - rank = preferredSlots.indexOf(slotId); |
| 138 | + preferredSlotIds.push(slotId); |
| 139 | + rank = preferredSlotIds.indexOf(slotId); |
133 | 140 | $slotRank.text(rank + 1);
|
134 |
| - $(hiddenTimeSlotSelectors).eq(rank).val(slotValue).attr('value', slotValue); |
| 141 | + $hiddenTimeSlots.eq(rank).val(slotValue).attr('value', slotValue); |
135 | 142 | } else {
|
136 |
| - preferredSlots.splice(preferredSlots.indexOf(slotId), 1); |
| 143 | + preferredSlotIds.splice(preferredSlotIds.indexOf(slotId), 1); |
137 | 144 |
|
138 | 145 | // Update ranks shown on remaining preferred slots.
|
139 |
| - preferredSlots.forEach(function(value, index) { |
| 146 | + preferredSlotIds.forEach(function(value, index) { |
140 | 147 | let selector = '#' + value;
|
141 | 148 | $(selector).next('label').find('span.rank').text(index + 1);
|
142 | 149 | });
|
143 | 150 |
|
144 | 151 | // 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) { |
148 | 155 | $(this).val($slotVal).attr('value', $slotVal);
|
149 | 156 | } else {
|
150 | 157 | $(this).val('').attr('value', '');
|
|
169 | 176 |
|
170 | 177 | function updatePreferredStatus() {
|
171 | 178 |
|
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'); |
174 | 181 | } 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'); |
176 | 183 | }
|
177 | 184 |
|
178 | 185 | let items = '';
|
179 |
| - preferredSlots.forEach(function(value, index) { |
| 186 | + preferredSlotIds.forEach(function(value, index) { |
180 | 187 | const options = {
|
181 | 188 | weekday: "long",
|
182 | 189 | year: "numeric",
|
183 | 190 | month: "long",
|
184 | 191 | day: "numeric",
|
185 | 192 | };
|
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" }); |
189 | 197 |
|
190 |
| - items += `<li>${prettyTime} on ${prettyDate}</li>`; |
| 198 | + items += `<li>${prettyTime} on ${prettyDate}</li>`; |
| 199 | + } |
191 | 200 | });
|
192 | 201 |
|
193 | 202 | $('#timeslots-announce-description').html('<ol class="list--ordered-bullet">' + items + '</ol>');
|
|
197 | 206 | };
|
198 | 207 |
|
199 | 208 | })(jQuery, Drupal, once);
|
200 |
| - |
|
0 commit comments