من این سورس رو دارم

/**
 * App Calendar
 */

/**
 * ! If both start and end dates are same Full calendar will nullify the end date value.
 * ! Full calendar will end the event on a day before at 12:00:00AM thus, event won't extend to the end date.
 * ! We are getting events from a separate file named app-calendar-events.js. You can add or remove events from there.
 *
 **/

'use strict';

let direction = 'ltr';

if (isRtl) {
    direction = 'rtl';
}

document.addEventListener('DOMContentLoaded', function () {
    (function () {
        const calendarEl = document.getElementById('calendar'),
            appCalendarSidebar = document.querySelector('.app-calendar-sidebar'),
            addEventSidebar = document.getElementById('addEventSidebar'),
            appOverlay = document.querySelector('.app-overlay'),
            calendarsColor = {
                Business: 'primary',
                Holiday: 'success',
                Personal: 'danger',
                Family: 'warning',
                ETC: 'info'
            },
            offcanvasTitle = document.querySelector('.offcanvas-title'),
            btnToggleSidebar = document.querySelector('.btn-toggle-sidebar'),
            btnSubmit = document.querySelector('button[type="submit"]'),
            btnDeleteEvent = document.querySelector('.btn-delete-event'),
            btnCancel = document.querySelector('.btn-cancel'),
            eventTitle = document.querySelector('#eventTitle'),
            eventStartDate = document.querySelector('#eventStartDate'),
            eventEndDate = document.querySelector('#eventEndDate'),
            eventUrl = document.querySelector('#eventURL'),
            eventLabel = $('#eventLabel'), // ! Using jquery vars due to select2 jQuery dependency
            eventGuests = $('#eventGuests'), // ! Using jquery vars due to select2 jQuery dependency
            eventLocation = document.querySelector('#eventLocation'),
            eventDescription = document.querySelector('#eventDescription'),
            allDaySwitch = document.querySelector('.allDay-switch'),
            selectAll = document.querySelector('.select-all'),
            filterInput = [].slice.call(document.querySelectorAll('.input-filter')),
            inlineCalendar = document.querySelector('.inline-calendar');

        let eventToUpdate,
            currentEvents = events, // Assign app-calendar-events.js file events (assume events from API) to currentEvents (browser store/object) to manage and update calender events
            isFormValid = false,
            inlineCalInstance;

        // Init event Offcanvas
        const bsAddEventSidebar = new bootstrap.Offcanvas(addEventSidebar);

        //! TODO: Update Event label and guest code to JS once select removes jQuery dependency
        // Event Label (select2)
        if (eventLabel.length) {
            function renderBadges(option) {
                if (!option.id) {
                    return option.text;
                }
                var $badge =
                    "<span class='badge badge-dot bg-" + $(option.element).data('label') + " me-2'> " + '</span>' + option.text;

                return $badge;
            }

            eventLabel.wrap('<div class="position-relative"></div>').select2({
                placeholder: 'انتخاب کنید',
                dropdownParent: eventLabel.parent(),
                templateResult: renderBadges,
                templateSelection: renderBadges,
                minimumResultsForSearch: -1,
                escapeMarkup: function (es) {
                    return es;
                }
            });
        }

        // Event Guests (select2)
        if (eventGuests.length) {
            function renderGuestAvatar(option) {
                if (!option.id) {
                    return option.text;
                }
                var $avatar =
                    "<div class='d-flex flex-wrap align-items-center'>" +
                    "<div class='avatar avatar-xs me-2'>" +
                    "<img src='" +
                    assetsPath +
                    'img/avatars/' +
                    $(option.element).data('avatar') +
                    "' alt='avatar' class='rounded-circle' />" +
                    '</div>' +
                    option.text +
                    '</div>';

                return $avatar;
            }

            eventGuests.wrap('<div class="position-relative"></div>').select2({
                placeholder: 'انتخاب کنید',
                dropdownParent: eventGuests.parent(),
                closeOnSelect: false,
                templateResult: renderGuestAvatar,
                templateSelection: renderGuestAvatar,
                escapeMarkup: function (es) {
                    return es;
                }
            });
        }

        // Event start (flatpicker)
        if (eventStartDate) {
            var start = eventStartDate.flatpickr({
                disableMobile: "true",
                enableTime: true,
                altInput: true,
                locale: 'fa',
                altFormat: 'Y/m/d - H:i',
                onReady: function (selectedDates, dateStr, instance) {
                    if (instance.isMobile) {
                        instance.mobileInput.setAttribute('step', null);
                    }
                }
            });
        }

        // Event end (flatpicker)
        if (eventEndDate) {
            var end = eventEndDate.flatpickr({
                disableMobile: "true",
                enableTime: true,
                altInput: true,
                locale: 'fa',
                altFormat: 'Y/m/d - H:i',
                onReady: function (selectedDates, dateStr, instance) {
                    if (instance.isMobile) {
                        instance.mobileInput.setAttribute('step', null);
                    }
                }
            });
        }

        // Inline sidebar calendar (flatpicker)
        if (inlineCalendar) {
            inlineCalInstance = inlineCalendar.flatpickr({
                disableMobile: "true",
                monthSelectorType: 'static',
                locale: 'fa',
                inline: true,
            });
        }

        // Event click function
        function eventClick(info) {
            eventToUpdate = info.event;
            if (eventToUpdate.url) {
                info.jsEvent.preventDefault();
                window.open(eventToUpdate.url, '_blank');
            }
            bsAddEventSidebar.show();
            // For update event set offcanvas title text: Update Event
            if (offcanvasTitle) {
                offcanvasTitle.innerHTML = 'ویرایش رویداد';
            }
            btnSubmit.innerHTML = 'ویرایش';
            btnSubmit.classList.add('btn-update-event');
            btnSubmit.classList.remove('btn-add-event');
            btnDeleteEvent.classList.remove('d-none');

            eventTitle.value = eventToUpdate.title;
            start.setDate(eventToUpdate.start, true, 'Y-m-d');
            eventToUpdate.allDay === true ? (allDaySwitch.checked = true) : (allDaySwitch.checked = false);
            eventToUpdate.end !== null
                ? end.setDate(eventToUpdate.end, true, 'Y-m-d')
                : end.setDate(eventToUpdate.start, true, 'Y-m-d');
            eventLabel.val(eventToUpdate.extendedProps.calendar).trigger('change');
            eventToUpdate.extendedProps.location !== undefined
                ? (eventLocation.value = eventToUpdate.extendedProps.location)
                : null;
            eventToUpdate.extendedProps.guests !== undefined
                ? eventGuests.val(eventToUpdate.extendedProps.guests).trigger('change')
                : null;
            eventToUpdate.extendedProps.description !== undefined
                ? (eventDescription.value = eventToUpdate.extendedProps.description)
                : null;

            // // Call removeEvent function
            // btnDeleteEvent.addEventListener('click', e => {
            //   removeEvent(parseInt(eventToUpdate.id));
            //   // eventToUpdate.remove();
            //   bsAddEventSidebar.hide();
            // });
        }

        // Modify sidebar toggler
        function modifyToggler() {
            const fcSidebarToggleButton = document.querySelector('.fc-sidebarToggle-button');
            fcSidebarToggleButton.classList.remove('fc-button-primary');
            fcSidebarToggleButton.classList.add('d-lg-none', 'd-inline-block', 'ps-0');
            while (fcSidebarToggleButton.firstChild) {
                fcSidebarToggleButton.firstChild.remove();
            }
            fcSidebarToggleButton.setAttribute('data-bs-toggle', 'sidebar');
            fcSidebarToggleButton.setAttribute('data-overlay', '');
            fcSidebarToggleButton.setAttribute('data-target', '#app-calendar-sidebar');
            fcSidebarToggleButton.insertAdjacentHTML('beforeend', '<i class="ti ti-menu-2 ti-sm text-heading"></i>');
        }

        // Filter events by calender
        function selectedCalendars() {
            let selected = [],
                filterInputChecked = [].slice.call(document.querySelectorAll('.input-filter:checked'));

            filterInputChecked.forEach(item => {
                selected.push(item.getAttribute('data-value'));
            });

            return selected;
        }

        // --------------------------------------------------------------------------------------------------
        // AXIOS: fetchEvents
        // * This will be called by fullCalendar to fetch events. Also this can be used to refetch events.
        // --------------------------------------------------------------------------------------------------
        function fetchEvents(info, successCallback) {
            // Fetch Events from API endpoint reference
            /* $.ajax(
              {
                url: '../../app-assets/data/app-calendar-events.js',
                type: 'GET',
                success: function (result) {
                  // Get requested calendars as Array
                  var calendars = selectedCalendars();

                  return [result.events.filter(event => calendars.includes(event.extendedProps.calendar))];
                },
                error: function (error) {
                  console.log(error);
                }
              }
            ); */

            let calendars = selectedCalendars();
            // We are reading event object from app-calendar-events.js file directly by including that file above app-calendar file.
            // You should make an API call, look into above commented API call for reference
            let selectedEvents = currentEvents.filter(function (event) {
                // console.log(event.extendedProps.calendar.toLowerCase());
                return calendars.includes(event.extendedProps.calendar.toLowerCase());
            });
            // if (selectedEvents.length > 0) {
            successCallback(selectedEvents);
            // }
        }

        // Init FullCalendar
        // ------------------------------------------------

        let calendar = new Calendar(calendarEl, {
            initialView: 'dayGridMonth',
            events: fetchEvents,
            plugins: [dayGridPlugin, interactionPlugin, listPlugin, timegridPlugin],
            editable: true,
            dragScroll: true,
            dayMaxEvents: 2,
            eventResizableFromStart: true,
            customButtons: {
                sidebarToggle: {
                    text: 'Sidebar'
                }
            },
            headerToolbar: {
                start: 'sidebarToggle, prev,next, title',
                end: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
            },
            direction: direction,
            initialDate: new Date(),
            navLinks: true, // can click day/week names to navigate views
            eventClassNames: function ({event: calendarEvent}) {
                const colorName = calendarsColor[calendarEvent._def.extendedProps.calendar];
                // Background Color
                return ['fc-event-' + colorName];
            },
            dateClick: function (info) {
                let date = moment(info.date).format('YYYY-MM-DD');
                resetValues();
                bsAddEventSidebar.show();

                // For new event set offcanvas title text: Add Event
                if (offcanvasTitle) {
                    offcanvasTitle.innerHTML = 'افزودن رویداد';
                }
                btnSubmit.innerHTML = 'افزودن';
                btnSubmit.classList.remove('btn-update-event');
                btnSubmit.classList.add('btn-add-event');
                btnDeleteEvent.classList.add('d-none');
                eventStartDate.value = date;
                eventEndDate.value = date;
            },
            eventClick: function (info) {
                eventClick(info);
            },
            datesSet: function () {
                modifyToggler();
            },
            viewDidMount: function () {
                modifyToggler();
            },
            locale: 'fa',
            firstDay: 6,
            buttonText: {
                today: 'امروز',
                month: 'ماه',
                week: 'هفته',
                day: 'روز',
                list: 'لیست'
            },
            weekText: 'هفته',
            allDayText: 'کل روز',
            moreLinkText: function (n) {
                return '+' + n + ' آیتم دیگر';
            },
            noEventsText: 'رویدادی برای نمایش وجود ندارد'
        });

        // Render calendar
        calendar.render();
        // Modify sidebar toggler
        modifyToggler();

        const eventForm = document.getElementById('eventForm');
        const fv = FormValidation.formValidation(eventForm, {
            fields: {
                eventTitle: {
                    validators: {
                        notEmpty: {
                            message: 'لطفا عنوان را وارد کنید '
                        }
                    }
                },
                eventStartDate: {
                    validators: {
                        notEmpty: {
                            message: 'لطفا تاریخ شروع را وارد کنید '
                        }
                    }
                },
                eventEndDate: {
                    validators: {
                        notEmpty: {
                            message: 'لطفا تاریخ اتمام را وارد کنید'
                        }
                    }
                }
            },
            plugins: {
                trigger: new FormValidation.plugins.Trigger(),
                bootstrap5: new FormValidation.plugins.Bootstrap5({
                    // Use this for enabling/changing valid/invalid class
                    eleValidClass: '',
                    rowSelector: function (field, ele) {
                        // field is the field name & ele is the field element
                        return '.mb-3';
                    }
                }),
                submitButton: new FormValidation.plugins.SubmitButton(),
                // Submit the form when all fields are valid
                // defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
                autoFocus: new FormValidation.plugins.AutoFocus()
            }
        })
            .on('core.form.valid', function () {
                // Jump to the next step when all fields in the current step are valid
                isFormValid = true;
            })
            .on('core.form.invalid', function () {
                // if fields are invalid
                isFormValid = false;
            });

        // Sidebar Toggle Btn
        if (btnToggleSidebar) {
            btnToggleSidebar.addEventListener('click', e => {
                btnCancel.classList.remove('d-none');
            });
        }

        // Add Event
        // ------------------------------------------------
        function addEvent(eventData) {
            // ? Add new event data to current events object and refetch it to display on calender
            // ? You can write below code to AJAX call success response

            currentEvents.push(eventData);
            calendar.refetchEvents();

            // ? To add event directly to calender (won't update currentEvents object)
            // calendar.addEvent(eventData);
        }

        // Update Event
        // ------------------------------------------------
        function updateEvent(eventData) {
            // ? Update existing event data to current events object and refetch it to display on calender
            // ? You can write below code to AJAX call success response
            eventData.id = parseInt(eventData.id);
            currentEvents[currentEvents.findIndex(el => el.id === eventData.id)] = eventData; // Update event by id
            calendar.refetchEvents();

            // ? To update event directly to calender (won't update currentEvents object)
            // let propsToUpdate = ['id', 'title', 'url'];
            // let extendedPropsToUpdate = ['calendar', 'guests', 'location', 'description'];

            // updateEventInCalendar(eventData, propsToUpdate, extendedPropsToUpdate);
        }

        // Remove Event
        // ------------------------------------------------

        function removeEvent(eventId) {
            // ? Delete existing event data to current events object and refetch it to display on calender
            // ? You can write below code to AJAX call success response
            currentEvents = currentEvents.filter(function (event) {
                return event.id != eventId;
            });
            calendar.refetchEvents();

            // ? To delete event directly to calender (won't update currentEvents object)
            // removeEventInCalendar(eventId);
        }

        // (Update Event In Calendar (UI Only)
        // ------------------------------------------------
        const updateEventInCalendar = (updatedEventData, propsToUpdate, extendedPropsToUpdate) => {
            const existingEvent = calendar.getEventById(updatedEventData.id);

            // --- Set event properties except date related ----- //
            // ? Docs: https://fullcalendar.io/docs/Event-setProp
            // dateRelatedProps => ['start', 'end', 'allDay']
            // eslint-disable-next-line no-plusplus
            for (var index = 0; index < propsToUpdate.length; index++) {
                var propName = propsToUpdate[index];
                existingEvent.setProp(propName, updatedEventData[propName]);
            }

            // --- Set date related props ----- //
            // ? Docs: https://fullcalendar.io/docs/Event-setDates
            existingEvent.setDates(updatedEventData.start, updatedEventData.end, {
                allDay: updatedEventData.allDay
            });

            // --- Set event's extendedProps ----- //
            // ? Docs: https://fullcalendar.io/docs/Event-setExtendedProp
            // eslint-disable-next-line no-plusplus
            for (var index = 0; index < extendedPropsToUpdate.length; index++) {
                var propName = extendedPropsToUpdate[index];
                existingEvent.setExtendedProp(propName, updatedEventData.extendedProps[propName]);
            }
        };

        // Remove Event In Calendar (UI Only)
        // ------------------------------------------------
        function removeEventInCalendar(eventId) {
            calendar.getEventById(eventId).remove();
        }

        // Add new event
        // ------------------------------------------------
        btnSubmit.addEventListener('click', e => {
            if (btnSubmit.classList.contains('btn-add-event')) {
                if (isFormValid) {
                    let newEvent = {
                        id: calendar.getEvents().length + 1,
                        title: eventTitle.value,
                        start: eventStartDate.value,
                        end: eventEndDate.value,
                        startStr: eventStartDate.value,
                        endStr: eventEndDate.value,
                        display: 'block',
                        extendedProps: {
                            location: eventLocation.value,
                            guests: eventGuests.val(),
                            calendar: eventLabel.val(),
                            description: eventDescription.value
                        }
                    };
                    if (eventUrl.value) {
                        newEvent.url = eventUrl.value;
                    }
                    if (allDaySwitch.checked) {
                        newEvent.allDay = true;
                    }
                    addEvent(newEvent);
                    bsAddEventSidebar.hide();
                }
            } else {
                // Update event
                // ------------------------------------------------
                if (isFormValid) {
                    let eventData = {
                        id: eventToUpdate.id,
                        title: eventTitle.value,
                        start: eventStartDate.value,
                        end: eventEndDate.value,
                        url: eventUrl.value,
                        extendedProps: {
                            location: eventLocation.value,
                            guests: eventGuests.val(),
                            calendar: eventLabel.val(),
                            description: eventDescription.value
                        },
                        display: 'block',
                        allDay: allDaySwitch.checked ? true : false
                    };

                    updateEvent(eventData);
                    bsAddEventSidebar.hide();
                }
            }
        });

        // Call removeEvent function
        btnDeleteEvent.addEventListener('click', e => {
            removeEvent(parseInt(eventToUpdate.id));
            // eventToUpdate.remove();
            bsAddEventSidebar.hide();
        });

        // Reset event form inputs values
        // ------------------------------------------------
        function resetValues() {
            eventEndDate.value = '';
            eventUrl.value = '';
            eventStartDate.value = '';
            eventTitle.value = '';
            eventLocation.value = '';
            allDaySwitch.checked = false;
            eventGuests.val('').trigger('change');
            eventDescription.value = '';
        }

        // When modal hides reset input values
        addEventSidebar.addEventListener('hidden.bs.offcanvas', function () {
            resetValues();
        });

        // Hide left sidebar if the right sidebar is open
        btnToggleSidebar.addEventListener('click', e => {
            if (offcanvasTitle) {
                offcanvasTitle.innerHTML = 'افزودن رویداد';
            }
            btnSubmit.innerHTML = 'افزودن';
            btnSubmit.classList.remove('btn-update-event');
            btnSubmit.classList.add('btn-add-event');
            btnDeleteEvent.classList.add('d-none');
            appCalendarSidebar.classList.remove('show');
            appOverlay.classList.remove('show');
        });

        // Calender filter functionality
        // ------------------------------------------------
        if (selectAll) {
            selectAll.addEventListener('click', e => {
                if (e.currentTarget.checked) {
                    document.querySelectorAll('.input-filter').forEach(c => (c.checked = 1));
                } else {
                    document.querySelectorAll('.input-filter').forEach(c => (c.checked = 0));
                }
                calendar.refetchEvents();
            });
        }

        if (filterInput) {
            filterInput.forEach(item => {
                item.addEventListener('click', () => {
                    document.querySelectorAll('.input-filter:checked').length < document.querySelectorAll('.input-filter').length
                        ? (selectAll.checked = false)
                        : (selectAll.checked = true);
                    calendar.refetchEvents();
                });
            });
        }

        // Jump to date on sidebar(inline) calendar change
        inlineCalInstance.config.onChange.push(function (date) {
            calendar.changeView(calendar.view.type, moment(date[0]).format('YYYY-MM-DD'));
            modifyToggler();
            appCalendarSidebar.classList.remove('show');
            appOverlay.classList.remove('show');
        });
    })();
});