Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 118 additions & 5 deletions src/css/frontend.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,82 @@
}
}

.wc-bookings-date-picker {
// Screen reader only text - visually hidden but accessible to screen readers
.screen-reader-text {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal !important;
}

fieldset.wc-bookings-date-picker {
fieldset {
position: relative;
}

&:not([data-selected-date-type="start"]) .ui-datepicker td.fully_booked_start_days:not(.selection-end-date),
&[data-selected-date-type="start"] .ui-datepicker td.fully_booked_end_days:not(.selection-start-date) {
opacity: 0.35;
opacity: 0.65;
}

.ui-datepicker {
td.fully_booked:not(.not_bookable_by_rules),
td.fully_booked {
opacity: 0.65;

span, a {
background-color: #000000 !important;
}
}
}

&:not([data-selected-date-type="start"]) .ui-datepicker td.fully_booked_start_days:not(.selection-end-date),
&[data-selected-date-type="start"] .ui-datepicker td.fully_booked_end_days:not(.selection-start-date),
.ui-datepicker td.fully_booked {
span, a {
background-color: #c0392b !important;
background-color: #000000 !important;
background-image: none !important;
border-color: rgba(0, 0, 0, 0.1) !important;
color: #fff !important;
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.1);
pointer-events: none;
position: relative;

// Add a cross/X indicator for fully unavailable dates
&::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 60%;
height: 2px;
background-color: rgba(255, 255, 255, 0.9);
transform: translate(-50%, -50%) rotate(45deg);
}

&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 60%;
height: 2px;
background-color: rgba(255, 255, 255, 0.9);
transform: translate(-50%, -50%) rotate(-45deg);
z-index: 1;
}
}
}

// Partially available dates - check-out only (start days are fully booked)
&:not([data-selected-date-type="start"]) .ui-datepicker td.fully_booked_start_days:not(.selection-end-date),
&[data-selected-date-type="start"] .ui-datepicker td.fully_booked_end_days:not(.selection-start-date) {
span, a {
background-color: #000000 !important;
background-image: none !important;
border-color: rgba(0, 0, 0, 0.1) !important;
color: #fff !important;
Expand All @@ -47,6 +108,58 @@
}
}

// Partially available - check-out only (available for leaving, not arriving)
.ui-datepicker td.fully_booked_start_days:not(.ui-datepicker-unselectable) {
span, a {
position: relative;

// Add a diagonal slash from top-left to bottom-right
&::after {
content: '';
position: absolute;
top: 10%;
left: 10%;
width: 80%;
height: 2px;
background-color: rgba(255, 255, 255, 0.9);
transform: rotate(45deg);
transform-origin: top left;
}
}
}

// Partially available - check-in only (available for arriving, not leaving)
.ui-datepicker td.fully_booked_end_days:not(.ui-datepicker-unselectable) {
span, a {
position: relative;

// Add a diagonal slash from top-right to bottom-left
&::after {
content: '';
position: absolute;
top: 10%;
right: 10%;
width: 80%;
height: 2px;
background-color: rgba(255, 255, 255, 0.9);
transform: rotate(-45deg);
transform-origin: top right;
}
}
}

// For fully booked dates (unavailable for both check-in and check-out).
// Increased specificity to override the styling from the WooCommerce Bookings plugin.
.wc-bookings-booking-form .wc-bookings-date-picker {
.ui-datepicker td.fully_booked:not(.not_bookable_by_rules) {
opacity: 0.65;
span,
a {
background-color: #000000 !important;
}
}
}

.ui-datepicker {
td.bookable-range.ui-state-disabled {
opacity: 1;
Expand Down
109 changes: 109 additions & 0 deletions src/js/booking-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,111 @@ import {
);
}

// Add data-day attribute for easier access to day value
attributes['data-day'] = day;

return attributes;
}
);

/**
* Add accessible text to datepicker cells.
*
* @param {jQuery} $cell - The datepicker cell element.
* @param {string} accessibleText - The text to announce to screen readers.
*/
const addAccessibleText = ($cell, accessibleText) => {
const $dayElement = $cell.find('span, a').first();

// Remove any existing screen reader text to avoid duplication
$dayElement.find('.screen-reader-text').remove();

// Add screen reader text
$dayElement.append(
`<span class="screen-reader-text"> ${accessibleText}</span>`
);
};

/**
* Format date for screen reader announcement.
*
* @param {jQuery} $cell - The datepicker cell element.
* @return {string} Formatted date string.
*/
const formatDateForScreenReader = ($cell) => {
const day = $cell.attr('data-day');
const dataMonth = $cell.attr('data-month');
const dataYear = $cell.attr('data-year');

if (!day || !dataMonth || !dataYear) {
return '';
}

const date = new Date(
parseInt(dataYear, 10),
parseInt(dataMonth, 10),
parseInt(day, 10)
);

const monthNames = [
__('January', 'woocommerce-accommodation-bookings'),
__('February', 'woocommerce-accommodation-bookings'),
__('March', 'woocommerce-accommodation-bookings'),
__('April', 'woocommerce-accommodation-bookings'),
__('May', 'woocommerce-accommodation-bookings'),
__('June', 'woocommerce-accommodation-bookings'),
__('July', 'woocommerce-accommodation-bookings'),
__('August', 'woocommerce-accommodation-bookings'),
__('September', 'woocommerce-accommodation-bookings'),
__('October', 'woocommerce-accommodation-bookings'),
__('November', 'woocommerce-accommodation-bookings'),
__('December', 'woocommerce-accommodation-bookings'),
];

const dayNames = [
__('Sunday', 'woocommerce-accommodation-bookings'),
__('Monday', 'woocommerce-accommodation-bookings'),
__('Tuesday', 'woocommerce-accommodation-bookings'),
__('Wednesday', 'woocommerce-accommodation-bookings'),
__('Thursday', 'woocommerce-accommodation-bookings'),
__('Friday', 'woocommerce-accommodation-bookings'),
__('Saturday', 'woocommerce-accommodation-bookings'),
];

return `${monthNames[date.getMonth()]} ${day}, ${dataYear}, ${dayNames[date.getDay()]},`;
};

/**
* Add accessible text to all booking date types in the form.
*
* @param {jQuery} $form - The booking form element.
*/
const addAccessibleTextToBookingDates = ($form) => {
// Add screen reader text for partially available dates (check-out only)
$form.find('.fully_booked_start_days').each(function() {
const $cell = $(this);
const formattedDate = formatDateForScreenReader($cell);
const accessibleText = `${formattedDate} ${__('Available for check-out only.', 'woocommerce-accommodation-bookings')}`;
addAccessibleText($cell, accessibleText);
});

// Add screen reader text for partially available dates (check-in only)
$form.find('.fully_booked_end_days').each(function() {
const $cell = $(this);
const formattedDate = formatDateForScreenReader($cell);
const accessibleText = `${formattedDate} ${__('Available for check-in only.', 'woocommerce-accommodation-bookings')}`;
addAccessibleText($cell, accessibleText);
});

// Add screen reader text for fully booked dates (both start and end unavailable)
$form.find('.fully_booked').each(function() {
const $cell = $(this);
const formattedDate = formatDateForScreenReader($cell);
const accessibleText = `${formattedDate} ${__('Fully booked and unavailable.', 'woocommerce-accommodation-bookings')}`;
addAccessibleText($cell, accessibleText);
});
};

// Make the days disable and unselectable according to the selection.
HookApi.addAction(
'wc_bookings_date_picker_refreshed',
Expand All @@ -93,6 +194,9 @@ import {
$form
.find('.fully_booked_end_days')
.removeClass('ui-datepicker-unselectable ui-state-disabled');

// Add screen reader text for all booking date types
addAccessibleTextToBookingDates($form);
}
);

Expand Down Expand Up @@ -131,6 +235,11 @@ import {
}

$fieldset.attr('data-content', data_content);

// Re-add screen reader text after date selection triggers refresh
setTimeout(() => {
addAccessibleTextToBookingDates($form);
}, 100);
}
);

Expand Down
Loading