I’ve tried to read everywhere and asked chatgpt but i cant find a solution.
i created this plugin here and its working fine via the following page
https://nourhammoury.com/make-an-appointment
However, on the home page if you scroll down, am getting moment.tz is not defined
below is the code am using. I hope i can find a solution
<?php
// Enqueue scripts and styles for the client-side
function nh_appointments_enqueue_client_scripts() {
// Enqueue Stripe.js
wp_enqueue_script('stripe', 'https://js.stripe.com/v3/');
// Enqueue FullCalendar CSS and JS
wp_enqueue_style('fullcalendar-style', 'https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.2/fullcalendar.min.css');
// Check if moment.js is already loaded to avoid conflicts
if (!wp_script_is('moment', 'enqueued')) {
wp_enqueue_script('moment', 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js', array('jquery'), '2.29.1', true);
}
// Check if moment-timezone is already loaded to avoid conflicts
if (!wp_script_is('moment-timezone', 'enqueued')) {
wp_enqueue_script('moment-timezone', 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js', array('moment'), '0.5.34', true);
}
wp_enqueue_script('fullcalendar', 'https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.2/fullcalendar.min.js', array('jquery', 'moment', 'moment-timezone'), '3.10.2', true);
// Enqueue custom CSS
wp_enqueue_style('nh-appointments-style', plugin_dir_url(__FILE__) . '../css/style.css');
// Check if the site is being viewed in Arabic and enqueue the Arabic CSS file
if (defined('ICL_LANGUAGE_CODE') && ICL_LANGUAGE_CODE == 'ar') {
wp_enqueue_style('nh-arabic-style', plugin_dir_url(__FILE__) . '../css/style-ar.css');
}
// Localize and enqueue custom JS
wp_enqueue_script('nh-appointments-script', plugin_dir_url(__FILE__) . '../js/script.js', array('jquery', 'fullcalendar', 'moment-timezone'), null, true);
wp_localize_script('nh-appointments-script', 'nhAppointments', array(
'ajax_url' => admin_url('admin-ajax.php'),
'slotAlreadyBooked' => __('This slot is already booked. Please choose another time.', 'nh-appointments'),
'slotAvailable' => __('Available', 'nh-appointments'),
'slotBooked' => __('Booked', 'nh-appointments'),
'slotNotAvailable' => __('This slot is not available. Please choose another time.', 'nh-appointments'),
'bookingSuccessful' => __('Booking Successful!', 'nh-appointments'),
'appointmentConfirmed' => __('Your appointment is confirmed.', 'nh-appointments'),
'nameLabel' => __('Name:', 'nh-appointments'),
'phoneLabel' => __('Phone:', 'nh-appointments'),
'dateLabel' => __('Date:', 'nh-appointments'),
'timeLabel' => __('Time:', 'nh-appointments'),
'timezoneLabel' => __('Timezone:', 'nh-appointments')
));
}
add_action('wp_enqueue_scripts', 'nh_appointments_enqueue_client_scripts');
// Enqueue scripts and styles for the admin-side
function nh_appointments_enqueue_admin_scripts($hook) {
if ($hook != 'toplevel_page_nh_appointments') {
return;
}
// Enqueue FullCalendar CSS and JS
wp_enqueue_style('fullcalendar-style', 'https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.2/fullcalendar.min.css');
// Check if moment.js is already loaded to avoid conflicts
if (!wp_script_is('moment', 'enqueued')) {
wp_enqueue_script('moment', 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js', array('jquery'), '2.29.1', true);
}
// Check if moment-timezone is already loaded to avoid conflicts
if (!wp_script_is('moment-timezone', 'enqueued')) {
wp_enqueue_script('moment-timezone', 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js', array('moment'), '0.5.34', true);
}
wp_enqueue_script('fullcalendar', 'https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.2/fullcalendar.min.js', array('jquery', 'moment', 'moment-timezone'), '3.10.2', true);
// Enqueue custom admin CSS and JS
wp_enqueue_style('nh-appointments-admin-style', plugin_dir_url(__FILE__) . '../css/style.css');
wp_enqueue_script('nh-admin-calendar', plugin_dir_url(__FILE__) . '../js/admin-calendar.js', array('jquery', 'fullcalendar', 'moment-timezone'), null, true);
// Localize the script with new data
wp_localize_script('nh-admin-calendar', 'nh_appointments_ajax', array(
'ajax_url' => admin_url('admin-ajax.php')
));
// Enqueue slot management script
wp_enqueue_script('nh-slots-script', plugin_dir_url(__FILE__) . '../js/slots.js', array('jquery'), null, true);
wp_localize_script('nh-slots-script', 'nh_appointments_slots_ajax', array(
'ajax_url' => admin_url('admin-ajax.php')
));
}
add_action('admin_enqueue_scripts', 'nh_appointments_enqueue_admin_scripts');
?>
and this is my script.js
jQuery(document).ready(function($) {
// Ensure nhAppointments and moment.tz are defined before using them
if (typeof nhAppointments === 'undefined') {
console.error('nhAppointments is not defined');
return;
}
if (typeof moment.tz === 'undefined') {
console.error('moment.tz is not defined');
return;
}
var stripe = Stripe('*****');
var elements = stripe.elements();
var style = {
base: {
color: '#32325d',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
};
var card = elements.create('card', { style: style });
card.mount('#card-element');
var availableDates = {};
var bookedSlots = {};
// Initialize FullCalendar
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
defaultView: 'month',
events: function(start, end, timezone, callback) {
$.ajax({
url: nhAppointments.ajax_url,
dataType: 'json',
method: 'POST',
data: {
action: 'nh_get_client_slots',
start_date: start.format('YYYY-MM-DD'),
end_date: end.format('YYYY-MM-DD')
},
success: function(response) {
var events = [];
availableDates = {}; // Clear previous data
bookedSlots = {}; // Clear previous data
if (response.success) {
// Process booked slots
$.each(response.data.booked_slots, function(index, slot) {
var originalDateTime = slot.date + ' ' + slot.time + ' ' + slot.timezone;
var selectedTimezone = moment.tz.guess();
var convertedDateTime = moment.utc(slot.date + 'T' + slot.time).tz(selectedTimezone).format();
bookedSlots[convertedDateTime] = true;
events.push({
title: nhAppointments.slotBooked,
start: convertedDateTime,
allDay: false,
color: 'red', // Custom color for booked slots
editable: false
});
});
// Process available slots
$.each(response.data.available_slots, function(index, slot) {
var originalDateTime = slot.date + ' ' + slot.time + ' ' + slot.timezone;
var convertedDateTime = moment.utc(slot.date + 'T' + slot.time).tz(moment.tz.guess()).format();
availableDates[convertedDateTime] = true;
if (!bookedSlots[convertedDateTime]) {
events.push({
title: nhAppointments.slotAvailable,
start: convertedDateTime,
allDay: false,
color: 'blue' // Custom color for available slots
});
}
});
}
callback(events);
},
error: function(xhr, status, error) {
console.error('Error fetching slots:', error); // You may want to keep this for catching AJAX errors
}
});
},
selectable: true,
selectHelper: true,
select: function(start, end) {
var selectedDate = start.format('YYYY-MM-DD');
var selectedTime = start.format('HH:mm');
var selectedTimezone = moment.tz.guess();
var dateTime = selectedDate + 'T' + selectedTime + ':00';
if (!bookedSlots[dateTime] && availableDates[dateTime]) {
$('#appointment-date').val(selectedDate);
$('#appointment-time').val(selectedTime);
$('#appointment-timezone').val(selectedTimezone);
$('#nh-booking-form').show();
$('#calendar').hide();
} else {
alert(nhAppointments.slotNotAvailable);
}
},
dayRender: function(date, cell) {
var dateStr = date.format('YYYY-MM-DD');
if (!availableDates[dateStr]) {
cell.addClass('fc-disabled');
cell.css('background-color', '#f4f4f4');
cell.css('cursor', 'default');
}
},
eventClick: function(event) {
var selectedDate = event.start.format('YYYY-MM-DD');
var selectedTime = event.start.format('HH:mm');
var selectedTimezone = moment.tz.guess();
var dateTime = selectedDate + 'T' + selectedTime + ':00';
if (event.title === nhAppointments.slotAvailable) {
$('#appointment-date').val(selectedDate);
$('#appointment-time').val(selectedTime);
$('#appointment-timezone').val(selectedTimezone);
$('#nh-booking-form').show();
$('#calendar').hide();
} else {
alert(nhAppointments.slotAlreadyBooked);
}
},
eventRender: function(event, element) {
if (event.color) {
element.css('background-color', event.color);
element.css('border-color', event.color);
}
}
});
$('#nh-booking-form').on('submit', function(e) {
e.preventDefault();
stripe.createPaymentMethod('card', card).then(function(result) {
if (result.error) {
alert(result.error.message);
} else {
var formData = $('#nh-booking-form').serialize();
formData += '&payment_method_id=' + result.paymentMethod.id;
$.ajax({
type: 'POST',
url: nhAppointments.ajax_url,
data: {
action: 'nh_handle_booking',
data: formData
},
success: function(response) {
if (response.success) {
// Convert the UTC time to the user's local time
var utcDateTime = moment.utc(response.data.date + 'T' + response.data.time);
var localDateTime = utcDateTime.local();
var localDate = localDateTime.format('YYYY-MM-DD');
var localTime = localDateTime.format('HH:mm');
var localTimezone = moment.tz.guess(); // Get the user's local timezone
$('#nh-booking-form').hide();
$('#confirmation-message').html('<h2>' + nhAppointments.bookingSuccessful + '</h2>' +
'<p>' + nhAppointments.appointmentConfirmed + '</p>' +
'<p><strong>' + nhAppointments.nameLabel + '</strong> ' + response.data.name + '</p>' +
'<p><strong>' + nhAppointments.phoneLabel + '</strong> ' + response.data.phone + '</p>' +
'<p><strong>' + nhAppointments.dateLabel + '</strong> ' + localDate + '</p>' +
'<p><strong>' + nhAppointments.timeLabel + '</strong> ' + localTime + ' (' + localTimezone + ')</p>');
// Refetch events to update the calendar
$('#calendar').fullCalendar('refetchEvents');
} else {
alert('Error: ' + response.data.message);
}
},
error: function(xhr, status, error) {
alert('AJAX error: ' + error);
}
});
}
});
});
});
i tried everything i can including ChatGPT and Gemini AI