first commit
This commit is contained in:
295
resources/js/views/apps/calendar/useCalendar.js
Normal file
295
resources/js/views/apps/calendar/useCalendar.js
Normal file
@@ -0,0 +1,295 @@
|
||||
import dayGridPlugin from '@fullcalendar/daygrid'
|
||||
import interactionPlugin from '@fullcalendar/interaction'
|
||||
import listPlugin from '@fullcalendar/list'
|
||||
import timeGridPlugin from '@fullcalendar/timegrid'
|
||||
import { useConfigStore } from '@core/stores/config'
|
||||
import { useCalendarStore } from '@/views/apps/calendar/useCalendarStore'
|
||||
|
||||
export const blankEvent = {
|
||||
title: '',
|
||||
start: '',
|
||||
end: '',
|
||||
allDay: false,
|
||||
url: '',
|
||||
extendedProps: {
|
||||
/*
|
||||
ℹ️ We have to use undefined here because if we have blank string as value then select placeholder will be active (moved to top).
|
||||
Hence, we need to set it to undefined or null
|
||||
*/
|
||||
calendar: undefined,
|
||||
guests: [],
|
||||
location: '',
|
||||
description: '',
|
||||
},
|
||||
}
|
||||
export const useCalendar = (event, isEventHandlerSidebarActive, isLeftSidebarOpen) => {
|
||||
const configStore = useConfigStore()
|
||||
|
||||
// 👉 Store
|
||||
const store = useCalendarStore()
|
||||
|
||||
// 👉 Calendar template ref
|
||||
const refCalendar = ref()
|
||||
|
||||
|
||||
// 👉 Calendar colors
|
||||
const calendarsColor = {
|
||||
Business: 'primary',
|
||||
Holiday: 'success',
|
||||
Personal: 'error',
|
||||
Family: 'warning',
|
||||
ETC: 'info',
|
||||
}
|
||||
|
||||
|
||||
// ℹ️ Extract event data from event API
|
||||
const extractEventDataFromEventApi = eventApi => {
|
||||
const { id, title, start, end, url, extendedProps: { calendar, guests, location, description }, allDay } = eventApi
|
||||
|
||||
return {
|
||||
id,
|
||||
title,
|
||||
start,
|
||||
end,
|
||||
url,
|
||||
extendedProps: {
|
||||
calendar,
|
||||
guests,
|
||||
location,
|
||||
description,
|
||||
},
|
||||
allDay,
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof process !== 'undefined' && process.server)
|
||||
store.fetchEvents()
|
||||
|
||||
|
||||
// 👉 Fetch events
|
||||
const fetchEvents = (info, successCallback) => {
|
||||
// If there's no info => Don't make useless API call
|
||||
if (!info)
|
||||
return
|
||||
store.fetchEvents()
|
||||
.then(r => {
|
||||
successCallback(r.map(e => ({
|
||||
...e,
|
||||
|
||||
// Convert string representation of date to Date object
|
||||
start: new Date(e.start),
|
||||
end: new Date(e.end),
|
||||
})))
|
||||
})
|
||||
.catch(e => {
|
||||
console.error('Error occurred while fetching calendar events', e)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 👉 Calendar API
|
||||
const calendarApi = ref(null)
|
||||
|
||||
|
||||
// 👉 Update event in calendar [UI]
|
||||
const updateEventInCalendar = (updatedEventData, propsToUpdate, extendedPropsToUpdate) => {
|
||||
const existingEvent = calendarApi.value?.getEventById(String(updatedEventData.id))
|
||||
if (!existingEvent) {
|
||||
console.warn('Can\'t found event in calendar to update')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ---Set event properties except date related
|
||||
// Docs: https://fullcalendar.io/docs/Event-setProp
|
||||
// dateRelatedProps => ['start', 'end', 'allDay']
|
||||
for (let index = 0; index < propsToUpdate.length; index++) {
|
||||
const 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
|
||||
for (let index = 0; index < extendedPropsToUpdate.length; index++) {
|
||||
const propName = extendedPropsToUpdate[index]
|
||||
|
||||
existingEvent.setExtendedProp(propName, updatedEventData.extendedProps[propName])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 👉 Remove event in calendar [UI]
|
||||
const removeEventInCalendar = eventId => {
|
||||
const _event = calendarApi.value?.getEventById(eventId)
|
||||
if (_event)
|
||||
_event.remove()
|
||||
}
|
||||
|
||||
|
||||
// 👉 refetch events
|
||||
const refetchEvents = () => {
|
||||
calendarApi.value?.refetchEvents()
|
||||
}
|
||||
|
||||
watch(() => store.selectedCalendars, refetchEvents)
|
||||
|
||||
|
||||
// 👉 Add event
|
||||
const addEvent = _event => {
|
||||
store.addEvent(_event)
|
||||
.then(() => {
|
||||
refetchEvents()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 👉 Update event
|
||||
const updateEvent = _event => {
|
||||
store.updateEvent(_event)
|
||||
.then(r => {
|
||||
const propsToUpdate = ['id', 'title', 'url']
|
||||
const extendedPropsToUpdate = ['calendar', 'guests', 'location', 'description']
|
||||
|
||||
updateEventInCalendar(r, propsToUpdate, extendedPropsToUpdate)
|
||||
})
|
||||
refetchEvents()
|
||||
}
|
||||
|
||||
|
||||
// 👉 Remove event
|
||||
const removeEvent = eventId => {
|
||||
store.removeEvent(eventId).then(() => {
|
||||
removeEventInCalendar(eventId)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 👉 Calendar options
|
||||
const calendarOptions = {
|
||||
plugins: [dayGridPlugin, interactionPlugin, timeGridPlugin, listPlugin],
|
||||
initialView: 'dayGridMonth',
|
||||
headerToolbar: {
|
||||
start: 'drawerToggler,prev,next title',
|
||||
end: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth',
|
||||
},
|
||||
events: fetchEvents,
|
||||
|
||||
// ❗ We need this to be true because when its false and event is allDay event and end date is same as start data then Full calendar will set end to null
|
||||
forceEventDuration: true,
|
||||
|
||||
/*
|
||||
Enable dragging and resizing event
|
||||
Docs: https://fullcalendar.io/docs/editable
|
||||
*/
|
||||
editable: true,
|
||||
|
||||
/*
|
||||
Enable resizing event from start
|
||||
Docs: https://fullcalendar.io/docs/eventResizableFromStart
|
||||
*/
|
||||
eventResizableFromStart: true,
|
||||
|
||||
/*
|
||||
Automatically scroll the scroll-containers during event drag-and-drop and date selecting
|
||||
Docs: https://fullcalendar.io/docs/dragScroll
|
||||
*/
|
||||
dragScroll: true,
|
||||
|
||||
/*
|
||||
Max number of events within a given day
|
||||
Docs: https://fullcalendar.io/docs/dayMaxEvents
|
||||
*/
|
||||
dayMaxEvents: 2,
|
||||
|
||||
/*
|
||||
Determines if day names and week names are clickable
|
||||
Docs: https://fullcalendar.io/docs/navLinks
|
||||
*/
|
||||
navLinks: true,
|
||||
eventClassNames({ event: calendarEvent }) {
|
||||
const colorName = calendarsColor[calendarEvent._def.extendedProps.calendar]
|
||||
|
||||
return [
|
||||
// Background Color
|
||||
`bg-light-${colorName} text-${colorName}`,
|
||||
]
|
||||
},
|
||||
eventClick({ event: clickedEvent, jsEvent }) {
|
||||
// Prevent the default action
|
||||
jsEvent.preventDefault()
|
||||
if (clickedEvent.url) {
|
||||
// Open the URL in a new tab
|
||||
window.open(clickedEvent.url, '_blank')
|
||||
}
|
||||
|
||||
// * Only grab required field otherwise it goes in infinity loop
|
||||
// ! Always grab all fields rendered by form (even if it get `undefined`) otherwise due to Vue3/Composition API you might get: "object is not extensible"
|
||||
event.value = extractEventDataFromEventApi(clickedEvent)
|
||||
isEventHandlerSidebarActive.value = true
|
||||
},
|
||||
|
||||
// customButtons
|
||||
dateClick(info) {
|
||||
event.value = { ...event.value, start: info.date }
|
||||
isEventHandlerSidebarActive.value = true
|
||||
},
|
||||
|
||||
/*
|
||||
Handle event drop (Also include dragged event)
|
||||
Docs: https://fullcalendar.io/docs/eventDrop
|
||||
We can use `eventDragStop` but it doesn't return updated event so we have to use `eventDrop` which returns updated event
|
||||
*/
|
||||
eventDrop({ event: droppedEvent }) {
|
||||
updateEvent(extractEventDataFromEventApi(droppedEvent))
|
||||
},
|
||||
|
||||
/*
|
||||
Handle event resize
|
||||
Docs: https://fullcalendar.io/docs/eventResize
|
||||
*/
|
||||
eventResize({ event: resizedEvent }) {
|
||||
if (resizedEvent.start && resizedEvent.end)
|
||||
updateEvent(extractEventDataFromEventApi(resizedEvent))
|
||||
},
|
||||
customButtons: {
|
||||
drawerToggler: {
|
||||
text: 'calendarDrawerToggler',
|
||||
click() {
|
||||
isLeftSidebarOpen.value = true
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
// 👉 onMounted
|
||||
onMounted(() => {
|
||||
calendarApi.value = refCalendar.value.getApi()
|
||||
})
|
||||
|
||||
|
||||
// 👉 Jump to date on sidebar(inline) calendar change
|
||||
const jumpToDate = currentDate => {
|
||||
calendarApi.value?.gotoDate(new Date(currentDate))
|
||||
}
|
||||
|
||||
watch(() => configStore.isAppRTL, val => {
|
||||
calendarApi.value?.setOption('direction', val ? 'rtl' : 'ltr')
|
||||
}, { immediate: true })
|
||||
|
||||
return {
|
||||
refCalendar,
|
||||
calendarOptions,
|
||||
refetchEvents,
|
||||
fetchEvents,
|
||||
addEvent,
|
||||
updateEvent,
|
||||
removeEvent,
|
||||
jumpToDate,
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user