import { _x } from '@wordpress/i18n';
import { WcDatepicker } from 'wc-datepicker/dist/components/wc-datepicker';
import 'wc-datepicker/dist/themes/light.css';
customElements.define( 'wc-datepicker', WcDatepicker );
const findstr = window.findstr || {};
const moment = window.moment || {};
const labels = {
clearButton: _x( 'Clear value', 'datepicker labels', 'findstr' ),
monthSelect: _x( 'Select month', 'datepicker labels', 'findstr' ),
nextMonthButton: _x( 'Next month', 'datepicker labels', 'findstr' ),
nextYearButton: _x( 'Next year', 'datepicker labels', 'findstr' ),
picker: _x( 'Choose date', 'datepicker labels', 'findstr' ),
previousMonthButton: _x( 'Previous month', 'datepicker labels', 'findstr' ),
previousYearButton: _x( 'Previous year', 'datepicker labels', 'findstr' ),
todayButton: _x( 'Show today', 'datepicker labels', 'findstr' ),
yearSelect: _x( 'Select year', 'datepicker labels', 'findstr' ),
};
const DEFAULT_DATE_FORMAT = _x(
'YYYY-MM-DD',
'datepicker input date format',
'findstr'
);
document.addEventListener( 'findstrLoaded', async function ( e ) {
/**
* On load
*/
const datePickers = document.querySelectorAll(
'[id^="findstr-datepicker-"]'
);
if ( datePickers.length > 0 ) {
datePickers.forEach( ( datepicker ) => {
datepicker.labels = labels;
} );
}
findstr.hooks.addAction( 'findstrInit', 'datepicker', async function () {
const datePickerFields = document.querySelectorAll(
'.findstr-field.findstr-field-datepicker'
);
for ( const fieldItem of datePickerFields ) {
const field = JSON.parse( fieldItem.dataset.field );
const group = fieldItem.dataset.group;
field.source_name = field.source_name + '_timestamp';
let facetDates = [];
if ( field.options.showEvents ) {
//get group default query
const defaultQuery = findstr.groups[ group ].defaultQuery;
defaultQuery.facets = [ field.source_name ];
//do search to get facet dates
facetDates = await findstr
.search( '', defaultQuery )
.then( ( response ) => {
const datesTimestamp =
response?.facetDistribution?.[
field.source_name
] || {};
return Object.keys( datesTimestamp ).map(
( timestamp ) => {
return new Date(
timestamp * 1000
).toISOString().split( 'T' )[ 0 ];
}
);
} );
}
const input = fieldItem.querySelector( 'input' );
//set selected dates
const selectedDatesTimeStamp =
JSON.parse( input.dataset.findstrSelectedDates ) || [];
const selectedDates = selectedDatesTimeStamp.map( ( timestamp ) => {
const offset = new Date().getTimezoneOffset() * 60;
return new Date( ( parseInt( timestamp ) + offset ) * 1000 );
} );
const currentDatepicker = document.getElementById(
'findstr-datepicker-' +
fieldItem.dataset.id +
'-' +
fieldItem.dataset.group
);
if ( selectedDates.length > 0 ) {
currentDatepicker.value =
field.options.dateType === 'single'
? new Date( selectedDates[ 0 ] )
: [
new Date( selectedDates[ 0 ] ),
new Date( selectedDates[ 1 ] ),
];
}
updateCalendarOccurrences( currentDatepicker, facetDates );
const datepickerWrapper = document.querySelector(
`.findstr-field-datepicker[data-id="${ fieldItem.dataset.id }"][data-group="${ fieldItem.dataset.group }"]`
);
const datepickerInput = datepickerWrapper.querySelector(
'input[data-field-type="datepicker"]'
);
const statusElement = document.getElementById(
'findstr-datepicker-status-' +
fieldItem.dataset.id +
'-' +
fieldItem.dataset.group
);
const openDatepicker = () => {
if ( field.options?.inline !== true ) {
const datepicker = document.getElementById(
'findstr-datepicker-' +
fieldItem.dataset.id +
'-' +
fieldItem.dataset.group
);
if ( datepicker ) {
datepicker.style.position = 'absolute';
datepicker.style.display = 'block';
datepickerInput.setAttribute( 'aria-expanded', 'true' );
const today = datepickerWrapper.querySelector(
'.wc-datepicker__date--today'
);
statusElement.textContent = '';
if ( today ) {
today.focus();
}
}
}
};
const closeDatepicker = () => {
const datepicker = document.getElementById(
'findstr-datepicker-' +
fieldItem.dataset.id +
'-' +
fieldItem.dataset.group
);
if ( datepicker ) {
datepickerInput.setAttribute( 'aria-expanded', 'false' );
datepicker.style.display = 'none';
datepicker.style.position = 'relative';
if ( datepickerInput.value ) {
statusElement.textContent =
_x(
'Selected dates:',
'datepicker aria live',
'findstr'
) +
' ' +
datepickerInput.value;
}
}
};
datepickerInput.addEventListener( 'click', ( event ) => {
openDatepicker();
} );
datepickerInput.addEventListener( 'keyup', ( event ) => {
if ( event.key === 'Enter' ) {
openDatepicker();
}
} );
datepickerWrapper.addEventListener( 'focusout', () => {
setTimeout( () => {
if (
field.options?.inline !== true &&
! datepickerWrapper.contains( document.activeElement )
) {
closeDatepicker();
}
}, 0 );
} );
document.addEventListener( 'keyup', ( event ) => {
if ( event.key === 'Escape' ) {
closeDatepicker();
}
} );
currentDatepicker.addEventListener( 'selectDate', ( event ) => {
if ( ! event.detail ) {
input.dataset.findstrSelectedDates = '';
input.value = '';
input.dispatchEvent( new Event( 'input' ) );
return;
}
/**
* Filter the input field date format for the datepicker (single or range).
*
* @hook findstrDatePickerInputFormat
*
* @param {string} format - The default date format (e.g., 'YYYY-MM-DD')
* @param {Object} field - The datepicker field object
*
* @return {string} The date format to use for the input display
*/
const inputFormat = findstr.hooks.applyFilters(
'findstrDatePickerInputFormat',
DEFAULT_DATE_FORMAT,
field
);
if ( Array.isArray( event.detail ) ) {
const [ startDate, endDate ] = event.detail;
const startTimestamp = moment( startDate )
.utcOffset( 0, true )
.unix();
const endTimestamp = moment( endDate )
.utcOffset( 0, true )
.unix();
input.dataset.findstrSelectedDates = JSON.stringify( [
startTimestamp,
endTimestamp,
] );
/**
* Filter the separator string used between start and end dates in the input field.
*
* @hook findstrDatePickerRangeSeparator
*
* @param {string} separator - The default separator string (e.g., 'to')
*
* @return {string} The separator string to use between dates
*/
input.value = `${ moment( startDate ).format(
inputFormat
) } ${ findstr.hooks.applyFilters(
'findstrDatePickerRangeSeparator',
_x( 'to', 'date range separator', 'findstr' )
) } ${ moment( endDate ).format( inputFormat ) }`;
} else {
const selectedDate = event.detail;
const timestamp = moment( selectedDate )
.utcOffset( 0, true )
.unix();
input.dataset.findstrSelectedDates = JSON.stringify( [
timestamp,
] );
input.value = moment( selectedDate ).format( inputFormat );
}
input.dispatchEvent( new Event( 'input' ) );
} );
currentDatepicker.addEventListener( 'changeMonth', ( event ) => {
setTimeout( () => {
updateCalendarOccurrences( currentDatepicker, facetDates );
} );
} );
}
} );
/**
* Build search query based on select value
*/
findstr.hooks.addFilter(
'findstrBuildSearchQuery',
'findstr-search',
( query, items, group ) => {
for ( const [ filter_name, inputs ] of Object.entries( items ) ) {
inputs.forEach( ( input ) => {
if (
input.dataset.fieldType === 'datepicker' &&
input.value
) {
const field = findstr.getField(
input.dataset.findstrId,
group
);
if ( ! input.dataset.findstrSelectedDates ) {
return;
}
const date = input.dataset.findstrSelectedDates
? JSON.parse( input.dataset.findstrSelectedDates )
: [];
const isSingleDate =
field.options.dateType === 'single';
const behavior = field.options.singleDateBehavior;
if ( ! date[ 1 ] ) {
date[ 1 ] = moment( date[ 0 ] * 1000 )
.utc()
.endOf( 'day' )
.unix();
} else {
date[ 1 ] = moment( date[ 1 ] * 1000 )
.utc()
.endOf( 'day' )
.unix();
}
switch ( behavior ) {
case 'after':
query.filter.clauses[ filter_name ] = {
value: date[ 0 ],
compare: '>=',
};
break;
case 'before':
query.filter.clauses[ filter_name ] = {
value: moment( date[ 0 ] * 1000 )
.utc()
.endOf( 'day' )
.unix(),
compare: '<=',
};
break;
default:
query.filter.clauses[ filter_name ] = {
value: date,
compare: 'BETWEEN',
};
break;
}
}
} );
}
return query;
}
);
findstr.hooks.addAction(
'resetFilters',
'findstr-search',
( group, query ) => {
findstr.groups[ group ].items.forEach( ( item ) => {
if ( item.dataset.fieldType === 'datepicker' ) {
const datepicker = document.getElementById(
'findstr-datepicker-' + item.dataset.findstrId + '-' + item.dataset.findstrGroup
);
datepicker.startDate = new Date();
datepicker.value = undefined;
item.dataset.findstrSelectedDates = '';
item.value = '';
}
} );
}
);
} );
function updateCalendarOccurrences( currentDatepicker, facetDates ) {
const calendar = currentDatepicker.querySelectorAll(
'.wc-datepicker__calendar td'
);
calendar.forEach( ( td ) => {
const date = td.dataset.date;
if ( facetDates.includes( date ) ) {
td.classList.add( 'has-occurrence' );
const eventsSpan = document.createElement( 'span' );
eventsSpan.classList.add(
'occurrence-dot',
'visually-hidden',
'sc-wc-datepicker'
);
/**
* Filter the aria-label for the occurrence dot in the datepicker.
*
* @hook findstrDatePickerOccurrenceLabel
*
* @param {string} label - The default aria-label for the occurrence dot
*
* @return {string} The aria-label to use for the occurrence dot
*/
eventsSpan.setAttribute(
'aria-label',
findstr.hooks.applyFilters(
'findstrDatePickerOccurrenceLabel',
_x(
'Occurrences available on this date',
'datepicker aria label',
'findstr'
)
)
);
td.appendChild( eventsSpan );
} else {
td.classList.remove( 'has-occurrence' );
const existingSpan = td.querySelector( '.occurrence-dot' );
if ( existingSpan ) {
td.removeChild( existingSpan );
}
}
} );
}