Skip to content

Commit

Permalink
Merge pull request #1194 from dof-dss/D8NID-1661
Browse files Browse the repository at this point in the history
D8NID-1661 (hotfix)
  • Loading branch information
neilblair authored May 13, 2024
2 parents 24feeae + 6fc4332 commit 0fdcdd6
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 54 deletions.
108 changes: 58 additions & 50 deletions web/modules/custom/nidirect_webforms/js/prisonbooking.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,69 +49,76 @@
.prop('aria-pressed', true);
}

// Visit time slots preferences...

// Add aria-live region for announcing time slot preferences.
const $preferredStatus = $('<div role="region" class="visually-hidden" aria-live="polite" />');
$preferredStatus.append($('<h2 id="timeslots-announce-title" />'));
$preferredStatus.append($('<div id="timeslots-announce-description" />'));

$(once('pvPreferredStatus', '[data-webform-key="visit_preferred_day_and_time"]', context)).prepend($preferredStatus);

// Limit timeslots that can be selected and
// keep track of preferred time slots.
// Visit time slots ...
let $timeSlots = $('input[type="checkbox"]', $weekSlots);
$timeSlots.attr('aria-controls', 'timeslots-announce');

let preferredSlots = [];
// Array for tracking slot IDs as they are checked or unchecked.
let preferredSlotIds = [];

// Default visit type is 'F' for face to face.
// Get visit type from the booking reference and get
// the timeslot limit for that visit type from settings.
let pvTypeId = 'F';
// By default, user can choose 3 timeslots.
let pvTimeSlotLimit = 3;

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

if ($timeSlots.length) {

// Call function to disable checkboxes if time slot limit reached.
// Disable checkboxes if time slot limit reached.
disableCheckboxes($timeSlots, pvTimeSlotLimit);

// Prep timeslots to show preference rank.
$timeSlots.each(function() {
let $span = $('<span />');
$span.addClass('rank').attr('aria-hidden', 'true');
$(this).next('label').append($span);
});
// Add aria-live region for announcing slot preferences.
const $preferredStatus = $('<div role="region" class="visually-hidden" aria-live="polite" />');
$preferredStatus.append($('<h2 id="timeslots-announce-title" />'));
$preferredStatus.append($('<div id="timeslots-announce-description" />'));

$(once('pvPreferredStatus', '[data-webform-key="visit_preferred_day_and_time"]', context)).prepend($preferredStatus);

// Set aria-controls on timeslots to control the
// aria-live region.
$timeSlots.attr('aria-controls', 'timeslots-announce');

// Preferred time slots may already exist (stored in hidden inputs).
// Update ranks shown on time slot checkbox labels.
let hiddenTimeSlotSelectors = '';
hiddenTimeSlotSelectors += '[name="slot1_datetime"], ';
hiddenTimeSlotSelectors += '[name="slot2_datetime"], ';
hiddenTimeSlotSelectors += '[name="slot3_datetime"], ';
hiddenTimeSlotSelectors += '[name="slot4_datetime"], ';
hiddenTimeSlotSelectors += '[name="slot5_datetime"]';

$(hiddenTimeSlotSelectors).each(function(index) {
const $hiddenTimeSlots = $(hiddenTimeSlotSelectors);

// D8NID-1661.
if (settings.prisonVisitBooking.resetTimeslots === true) {
// Reset all timeslots user has selected.
$timeSlots.prop('checked', false);
$hiddenTimeSlots.val('').attr('value', '');
}

// Prep timeslots to show preference rank.
$timeSlots.each(function() {
let $span = $('<span />');
$span.addClass('rank').attr('aria-hidden', 'true');
$(this).next('label').append($span);
});

// Update preference rank shown on timeslots.
$hiddenTimeSlots.each(function(index) {
let value = $(this).val();
if (value.length) {
let $timeSlot = $('input[value="' + value + '"]');
let $timeSlot = $('input[value="' + value + '"]');
if (value.length && $timeSlot.length) {
$timeSlot.next('label').find('span.rank').text(index + 1);
preferredSlots.push($timeSlot.prop('id'));
preferredSlotIds.push($timeSlot.prop('id'));
}
});

// Trigger announcement of preferred timeslots.
updatePreferredStatus();

// When a timeslot is checked or unchecked, update preference
// ranks and hidden slot values.

$timeSlots.on('change', function(e) {

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

// By default a slot has no rank.
$slotRank.text('');
$(hiddenTimeSlotSelectors).eq(rank).val('').attr('value', '');
$hiddenTimeSlots.eq(rank).val('').attr('value', '');

if ($(this).is(':checked')) {
preferredSlots.push(slotId);
rank = preferredSlots.indexOf(slotId);
preferredSlotIds.push(slotId);
rank = preferredSlotIds.indexOf(slotId);
$slotRank.text(rank + 1);
$(hiddenTimeSlotSelectors).eq(rank).val(slotValue).attr('value', slotValue);
$hiddenTimeSlots.eq(rank).val(slotValue).attr('value', slotValue);
} else {
preferredSlots.splice(preferredSlots.indexOf(slotId), 1);
preferredSlotIds.splice(preferredSlotIds.indexOf(slotId), 1);

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

// Update hidden timeslots.
$(hiddenTimeSlotSelectors).each(function(index) {
const $slotVal = $('#' + preferredSlots[index]).val();
if (index in preferredSlots) {
$hiddenTimeSlots.each(function(index) {
const $slotVal = $('#' + preferredSlotIds[index]).val();
if (index in preferredSlotIds) {
$(this).val($slotVal).attr('value', $slotVal);
} else {
$(this).val('').attr('value', '');
Expand All @@ -169,25 +176,27 @@

function updatePreferredStatus() {

if (preferredSlots.length < pvTimeSlotLimit) {
$('#timeslots-announce-title').html('You have selected ' + preferredSlots.length + ' time slots');
if (preferredSlotIds.length < pvTimeSlotLimit) {
$('#timeslots-announce-title').html('You have selected ' + preferredSlotIds.length + ' time slots');
} else {
$('#timeslots-announce-title').html('You have selected a maximum of ' + preferredSlots.length + ' time slots');
$('#timeslots-announce-title').html('You have selected a maximum of ' + preferredSlotIds.length + ' time slots');
}

let items = '';
preferredSlots.forEach(function(value, index) {
preferredSlotIds.forEach(function(value, index) {
const options = {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
};
const date = new Date($('#' + value).val());
const prettyDate = date.toLocaleDateString('en-GB', options);
const prettyTime = date.toLocaleTimeString([], { hour12: true, hour: "numeric", minute: "2-digit" });
if (value.length) {
const date = new Date($('#' + value).val());
const prettyDate = date.toLocaleDateString('en-GB', options);
const prettyTime = date.toLocaleTimeString([], { hour12: true, hour: "numeric", minute: "2-digit" });

items += `<li>${prettyTime} on ${prettyDate}</li>`;
items += `<li>${prettyTime} on ${prettyDate}</li>`;
}
});

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

})(jQuery, Drupal, once);

Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,36 @@ public function alterForm(array &$form, FormStateInterface $form_state, WebformS
}
}

// Show available time slots in the form.
// Show available timeslots in the form.
if ($page === 'visit_preferred_day_and_time' && !empty($this->bookingReference)) {

// Reset timeslots when user changes visit_order_number.
// Some of the logic for setting timeslot preferences is handled
// via clientside JS. Flag to clientside when timeslots must be
// reset.
$form['#attached']['drupalSettings']['prisonVisitBooking']['resetTimeslots'] = FALSE;

// Check last_visitor_order_number. If different from the present
// visitor_order_number then timeslots need reset.
$last_visitor_order_number = $form_state->get('last_visitor_order_number');
if (!empty($last_visitor_order_number) && $last_visitor_order_number !== $form_state->getValue('visitor_order_number')) {
$form['#attached']['drupalSettings']['prisonVisitBooking']['resetTimeslots'] = TRUE;

$form_values = array_filter($form_state->getValues(), function ($key) {
return str_contains($key, '_week_');
}, ARRAY_FILTER_USE_KEY);

foreach ($form_values as $element_name => $element_value) {
$form_state->setValue($element_name, []);
$elements[$element_name]['#default_value'] = [];
$webform_submission->setElementData($element_name, []);
}
}

// Update last_visitor_order_number.
$form_state->set('last_visitor_order_number', $form_state->getValue('visitor_order_number'));

// Get available slots and show only those slots on the form.
$available_slots = $this->bookingReference['available_slots'];

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

// Alter form slots to correspond with available slots.
if (!empty($available_slots)) {
// Alter form slots to correspond with available slots.

for ($i = 4; $i >= 1; $i--) {

// Form slots for each week.
$form_slots_week = &$form['elements']['visit_preferred_day_and_time']['slots_week_' . $i];

$webform_submission_slots_week = $webform_submission->getWebform()->getElement('slots_week_' . $i, TRUE);

if ($form_slots_week['#access'] = FALSE) {
Expand Down Expand Up @@ -292,7 +321,10 @@ public function validateForm(array &$form, FormStateInterface $form_state, Webfo
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state, WebformSubmissionInterface $webform_submission) {
if ($form_state->isValidationComplete() && $form_state->get('current_page') === 'webform_preview') {

$page = $form_state->get('current_page');

if ($form_state->isValidationComplete() && $page === 'webform_preview') {

$temp_store = $this->tempStoreFactory->get('nidirect_webforms.prison_visit_booking');
$remember_visitors = $form_state->getValue('additional_visitors_remember') === 'yes' ?? FALSE;
Expand Down Expand Up @@ -640,6 +672,7 @@ private function validatePlainText(string $element_name, string $error_msg, arra
* Validate visitor one DOB.
*/
private function validateSlotPicked(array &$form, FormStateInterface $form_state) {

if ($form_state->get('current_page') !== 'visit_preferred_day_and_time') {
return;
}
Expand Down

0 comments on commit 0fdcdd6

Please sign in to comment.