declare var jQuery: any; declare var flatpickr: any; declare var acfw_edit_coupon: any; declare var vex: any; const $ = jQuery; let isValidating = false; /** * Edit link scheduler fields script. * * @since 2.0 * * @param object $ jQuery object. */ export default function edit_link_scheduler_fields() { // @ts-ignore const scheduler_tab = document.querySelector('#acfw_scheduler') as HTMLElement, schedule_start_field = scheduler_tab.querySelector('#_acfw_schedule_start') as HTMLInputElement, schedule_expire_field = scheduler_tab.querySelector('#_acfw_schedule_expire') as HTMLInputElement; $(scheduler_tab).on('change', '.date-field,.date-hour,.date-minute', toggle_fields_required_prop); $(scheduler_tab).on('click', '.clear-scheduler-fields', clear_scheduler_fields_values); $(schedule_start_field).trigger('change acfw_load'); $(schedule_expire_field).trigger('change acfw_load'); $(scheduler_tab).on('change acfw_load', '.acfw-section-toggle input', toggleSchedulerSection); $(scheduler_tab).find('.acfw-section-toggle input').trigger('acfw_load'); $('.wrap').on('submit', 'form#post', validateBeforeSaveCoupon); initDateFields(); } /** * Initialize date and time picker fields. * * @since 4.5 */ function initDateFields() { const scheduleStartField: any = document.querySelector('#_acfw_schedule_start'); const scheduleExpireField: any = document.querySelector('#_acfw_schedule_expire'); // create date objects for fields default min/max values. const startMaxDate = flatpickr.parseDate(scheduleExpireField.value, 'Y-m-d H:i:S') ?? null; const expireMinDate = flatpickr.parseDate(scheduleStartField.value, 'Y-m-d H:i:S') ?? null; // add/deduct 1 minute to the min/max values. if (startMaxDate) startMaxDate.setMinutes(startMaxDate.getMinutes() - 1); if (expireMinDate) expireMinDate.setMinutes(expireMinDate.getMinutes() + 1); $(scheduleStartField).flatpickr({ allowInput: true, enableTime: true, altInput: true, allowInvalidPreload: true, altFormat: 'Y-m-d h:i K', dateFormat: 'Y-m-d H:i:S', maxDate: startMaxDate, // change minimum datetime for expire field when start field value changes. onChange: function ([dateObject]: Date[], dateStr: string, instance: any) { if (dateObject) { dateObject.setMinutes(dateObject.getMinutes() + 1); scheduleExpireField._flatpickr.set('minDate', dateObject); validate_date_range_field_values(); } else { scheduleExpireField._flatpickr.set('minDate', null); } }, }); $(scheduleExpireField).flatpickr({ allowInput: true, enableTime: true, altInput: true, altFormat: 'Y-m-d h:i K', dateFormat: 'Y-m-d H:i:S', minDate: expireMinDate, // change maximum datetime for start field when expire field value changes. onChange: function ([dateObject]: Date[], dateStr: string, instance: any) { if (dateObject) { dateObject.setMinutes(dateObject.getMinutes() - 1); scheduleStartField._flatpickr.set('maxDate', dateObject); validate_date_range_field_values(); } else { scheduleStartField._flatpickr.set('maxDate', null); } }, }); } /** * Validate date range field values when the values are changed. * * @since 4.5 */ function validate_date_range_field_values() { const startDate = flatpickr.parseDate($('#_acfw_schedule_start').val(), 'Y-m-d H:i:S'); const expireDate = flatpickr.parseDate($('#_acfw_schedule_expire').val(), 'Y-m-d H:i:S'); if (startDate >= expireDate) { $('#_acfw_schedule_start').parent().addClass('error'); $('#_acfw_schedule_expire').parent().addClass('error'); } else { $('#_acfw_schedule_start').parent().removeClass('error'); $('#_acfw_schedule_expire').parent().removeClass('error'); } } /** * Prevent saving coupon when there is an error in the date fields. * * @param e Event object */ function validateBeforeSaveCoupon(e: any) { if ($('.acfw-date-range-schedules-section span.date-time-field').hasClass('error')) { e.preventDefault(); // display error message. vex.dialog.alert({ unsafeMessage: acfw_edit_coupon.invalid_scheduler_time, }); // re-enable publish button $('#publishing-action .spinner').removeClass('is-active'); $('#publishing-action #publish').removeClass('disabled'); } } /** * Toggle scheduler fields required prop. * Set to true when at least one of the date/time fields have value, false when all fields are blank. * * @since 2.1 */ function toggle_fields_required_prop() { // @ts-ignore const $parent = $(this).closest('.date-time-field'), $date = $parent.find('.date-field'); if ($date.val()) { $date.prop('required', true); } else { $date.prop('required', false); } } /** * Clear scheduler field values and set to not required. * * @since 2.1 */ function clear_scheduler_fields_values() { const scheduler_tab = document.querySelector('#acfw_scheduler') as HTMLElement, schedule_start_field = scheduler_tab.querySelector('#_acfw_schedule_start') as HTMLInputElement, schedule_expire_field = scheduler_tab.querySelector('#_acfw_schedule_expire') as HTMLInputElement; // @ts-ignore const $datefield = $(this).siblings('.date-time-field'); $datefield.find('input').prop('required', false).val(''); $datefield.find('input')[0]._flatpickr.clear(); $(schedule_start_field).trigger('change'); $(schedule_expire_field).trigger('change'); } /** * Toggle scheduler section fields when main section checkbox is checked/unchecked. * * @since 4.5 */ function toggleSchedulerSection() { // @ts-ignore const $input = $(this); const $section = $input.closest('.acfw-scheduler-section'); const $options = $section.find('.options_group'); if ($input.is(':checked')) { $options.removeClass('disabled'); $options.find('.date-field,.days-time-field label input,textarea').prop('disabled', false); $('#acfw_scheduler .options_group input').trigger('acfw_load'); } else { $options.addClass('disabled'); $options.find('.date-field,.days-time-field label input,textarea').prop('disabled', true); } // Only the date range schedules section replaces WooCommerce's own coupon expiry date field, // so only that section's toggle decides whether that field is shown. if ($section.hasClass('acfw-date-range-schedules-section')) { toggleDefaultExpiryField($input.is(':checked')); } $options.find('input').trigger('change'); } /** * Show or hide WooCommerce's own coupon expiry date field. * * The date range schedules replace that field, so it is hidden while they are in use and shown * again when they are not. Hiding sets the style inline to override the styling that shows the * field for BOGO coupons, and showing clears it again so that styling still applies. * * @since 4.8 * * @param {boolean} isSchedulerEnabled Whether the date range schedules are enabled. */ function toggleDefaultExpiryField(isSchedulerEnabled: boolean) { const wc_default_expiry_field = document.querySelector('#general_coupon_data p.expiry_date_field'); if (!wc_default_expiry_field) return; $(wc_default_expiry_field).css('display', isSchedulerEnabled ? 'none' : ''); }