Added sample behaviour for category modal
This commit is contained in:
@@ -22,7 +22,7 @@
|
||||
--primary: 245 58% 51%;
|
||||
--primary-foreground: 0 0% 100%;
|
||||
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary: 210 50% 95%;
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--accent: 210 40% 96.1%;
|
||||
|
||||
@@ -52,6 +52,7 @@ onMounted(() => {
|
||||
<component :is="currentViewComponent" />
|
||||
|
||||
<LazyCalendarSearch />
|
||||
<LazyCalendarDialogCategories v-if="!isReadOnly" />
|
||||
<LazyCalendarDialogUpdateEvent v-if="!isReadOnly" />
|
||||
<LazyCalendarDialogDeleteEvent v-if="!isReadOnly" />
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { useCalendar } from "@/stores/CalendarStore"
|
||||
|
||||
import { PhMagnifyingGlass } from "@phosphor-icons/vue"
|
||||
import CalendarOptions from "./CalendarOptions.vue"
|
||||
|
||||
const { revealAdvancedSearch } = useCalendar()
|
||||
const { isReadOnly } = storeToRefs(useCalendar())
|
||||
@@ -13,7 +12,7 @@ const { isReadOnly } = storeToRefs(useCalendar())
|
||||
<div class="px-8 flex items-center justify-between gap-2">
|
||||
<menu class="flex items-center gap-2">
|
||||
<li v-if="!isReadOnly">
|
||||
<CalendarDialogQuickCreateEvent />
|
||||
<LazyCalendarDialogQuickCreateEvent />
|
||||
</li>
|
||||
<li>
|
||||
<CalendarMenuToday />
|
||||
@@ -33,7 +32,10 @@ const { isReadOnly } = storeToRefs(useCalendar())
|
||||
</UiButton>
|
||||
</li>
|
||||
<li>
|
||||
<CalendarOptions />
|
||||
<CalendarCategoriesCTA />
|
||||
</li>
|
||||
<li>
|
||||
<CalendarOptionsCTA />
|
||||
</li>
|
||||
</menu>
|
||||
</div>
|
||||
|
||||
23
components/calendar/CategoriesCTA.vue
Normal file
23
components/calendar/CategoriesCTA.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<script lang="ts" setup>
|
||||
import { PhTag } from "@phosphor-icons/vue"
|
||||
|
||||
const { toggleCategoriesModal } = useCalendar()
|
||||
const { isReadOnly } = storeToRefs(useCalendar())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UiTooltipProvider :delay-duration="250">
|
||||
<UiTooltip>
|
||||
<UiTooltipTrigger as-child>
|
||||
<UiButton v-if="!isReadOnly" variant="secondary" size="icon" @click="toggleCategoriesModal(true)">
|
||||
<PhTag size="20" weight="light" />
|
||||
</UiButton>
|
||||
</UiTooltipTrigger>
|
||||
<UiTooltipContent>
|
||||
<p>
|
||||
{{ $t('entity.calendar.seeCategories') }}
|
||||
</p>
|
||||
</UiTooltipContent>
|
||||
</UiTooltip>
|
||||
</UiTooltipProvider>
|
||||
</template>
|
||||
@@ -1,32 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from "@/lib/utils"
|
||||
import { useCalendar } from "@/stores/CalendarStore"
|
||||
import { PhCalendarBlank, PhCheckCircle, PhGear, PhTag } from "@phosphor-icons/vue"
|
||||
import { PhCalendarBlank, PhCheckCircle, PhGear } from "@phosphor-icons/vue"
|
||||
import { computed } from "vue"
|
||||
|
||||
const optionsOpened = ref<boolean>(false)
|
||||
|
||||
const user = useSupabaseUser()
|
||||
|
||||
function closeMenu() {
|
||||
optionsOpened.value = false
|
||||
}
|
||||
watch(user, closeMenu)
|
||||
|
||||
const { currentConfig, viewTypeOptions, getViewTypeTitle, setViewType } = useCalendar()
|
||||
const { isReadOnly } = storeToRefs(useCalendar())
|
||||
|
||||
const viewTypeTitle = computed(() => getViewTypeTitle(currentConfig.viewType))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UiDropdownMenu v-model:open="optionsOpened">
|
||||
<UiDropdownMenu>
|
||||
<UiDropdownMenuTrigger as-child>
|
||||
<UiButton variant="secondary" size="icon">
|
||||
<PhGear size="20" weight="fill" />
|
||||
</UiButton>
|
||||
</UiDropdownMenuTrigger>
|
||||
|
||||
<UiDropdownMenuContent :side="'bottom'" :align="'start'" :side-offset="10" :align-offset="25" :collision-padding="40" class="text-right">
|
||||
<UiDropdownMenuArrow />
|
||||
<UiDropdownMenuLabel>
|
||||
{{ $t('entity.calendar.seeOptions') }}
|
||||
</UiDropdownMenuLabel>
|
||||
@@ -54,16 +45,6 @@ const viewTypeTitle = computed(() => getViewTypeTitle(currentConfig.viewType))
|
||||
</UiDropdownMenuSubContent>
|
||||
</UiDropdownMenuPortal>
|
||||
</UiDropdownMenuSub>
|
||||
|
||||
<template v-if="!isReadOnly">
|
||||
<UiDropdownMenuSeparator />
|
||||
|
||||
<UiDropdownMenuItem class="flex gap-[1ch] justify-end items-center">
|
||||
{{ $t('entity.category.namePlural') }}
|
||||
|
||||
<PhTag size="18" weight="fill" />
|
||||
</UiDropdownMenuItem>
|
||||
</template>
|
||||
</UiDropdownMenuContent>
|
||||
</UiDropdownMenu>
|
||||
</template>
|
||||
36
components/calendar/dialog/Categories.vue
Normal file
36
components/calendar/dialog/Categories.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<script lang="ts" setup>
|
||||
import { PhX } from "@phosphor-icons/vue";
|
||||
|
||||
const { toggleCategoriesModal } = useCalendar()
|
||||
const { isCategoriesModalOpen } = storeToRefs(useCalendar())
|
||||
|
||||
function handleClosing() {
|
||||
toggleCategoriesModal(false)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UiAlertDialog :open="isCategoriesModalOpen">
|
||||
<UiAlertDialogContent
|
||||
class="grid grid-rows-[auto_1fr_auto] items-start min-h-[66vh] max-w-4xl gap-6"
|
||||
:disable-outside-pointer-events="true"
|
||||
:trap-focus="true"
|
||||
@escape-key-down="handleClosing"
|
||||
@focus-outside="handleClosing"
|
||||
@interact-outside="handleClosing"
|
||||
@close-auto-focus="(e) => e.preventDefault()"
|
||||
>
|
||||
<UiAlertDialogTitle>
|
||||
<span class="text-2xl">
|
||||
<strong class="font-bold">Gestion des catégories</strong>
|
||||
</span>
|
||||
</UiAlertDialogTitle>
|
||||
|
||||
<UiButton size="icon" variant="ghost" class="absolute top-4 right-4" title="Fermer la fenêtre" @click="handleClosing">
|
||||
<PhX size="20" />
|
||||
</UiButton>
|
||||
|
||||
catégories là
|
||||
</UiAlertDialogContent>
|
||||
</UiAlertDialog>
|
||||
</template>
|
||||
@@ -25,7 +25,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
<template>
|
||||
<AlertDialogPortal>
|
||||
<AlertDialogOverlay
|
||||
class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
||||
class="fixed inset-0 z-50 bg-black/60 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
||||
/>
|
||||
<AlertDialogContent
|
||||
v-bind="forwarded"
|
||||
|
||||
@@ -10,7 +10,7 @@ export const buttonVariants = cva(
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
outline: "border border-input hover:bg-accent hover:text-accent-foreground",
|
||||
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
secondary: "bg-secondary text-secondary-foreground hover:bg-primary/20",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline"
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
<template>
|
||||
<DialogPortal>
|
||||
<DialogOverlay
|
||||
class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
||||
class="fixed inset-0 z-50 bg-black/60 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
||||
/>
|
||||
<DialogContent
|
||||
v-bind="forwarded"
|
||||
|
||||
@@ -27,7 +27,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
<template>
|
||||
<DialogPortal>
|
||||
<DialogOverlay
|
||||
class="fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
||||
class="fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-black/60 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
||||
>
|
||||
<DialogContent
|
||||
:class="
|
||||
|
||||
13
components/ui/dropdown-menu/DropdownMenuArrow.vue
Normal file
13
components/ui/dropdown-menu/DropdownMenuArrow.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { DropdownMenuArrow, type DropdownMenuArrowProps, useForwardProps } from "radix-vue"
|
||||
|
||||
const props = defineProps<DropdownMenuArrowProps>()
|
||||
|
||||
const forwardedProps = useForwardProps(props)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenuArrow class="fill-border" v-bind="forwardedProps">
|
||||
<slot />
|
||||
</DropdownMenuArrow>
|
||||
</template>
|
||||
@@ -1,6 +1,7 @@
|
||||
export { DropdownMenuPortal } from "radix-vue"
|
||||
|
||||
export { default as DropdownMenu } from "./DropdownMenu.vue"
|
||||
export { default as DropdownMenuArrow } from "./DropdownMenuArrow.vue"
|
||||
export { default as DropdownMenuTrigger } from "./DropdownMenuTrigger.vue"
|
||||
export { default as DropdownMenuContent } from "./DropdownMenuContent.vue"
|
||||
export { default as DropdownMenuGroup } from "./DropdownMenuGroup.vue"
|
||||
|
||||
@@ -148,6 +148,7 @@ export default defineI18nConfig(() => ({
|
||||
backToList: "Go back to calendars",
|
||||
isLoading: "Calendar is loading…",
|
||||
hasXEvents: "{count} available events",
|
||||
seeCategories: "Modify categories",
|
||||
seeOptions: "Calendar options",
|
||||
date: {
|
||||
start: "Start date",
|
||||
@@ -395,7 +396,7 @@ export default defineI18nConfig(() => ({
|
||||
search: "Rechercher les catégories",
|
||||
notFoundAny: "Aucune catégorie trouvée.",
|
||||
addPrimary: "Ajouter une catégorie principale",
|
||||
addSecondaries: "Ajouter des catégories secondaires"
|
||||
addSecondaries: "Ajouter des catégories secondaires",
|
||||
},
|
||||
isLoading: "Chargement en cours…",
|
||||
addDescription: "Ajouter une description",
|
||||
@@ -450,6 +451,7 @@ export default defineI18nConfig(() => ({
|
||||
backToList: "Retourner aux calendriers",
|
||||
isLoading: "Chargement du calendrier…",
|
||||
hasXEvents: "{count} évènements disponibles",
|
||||
seeCategories: "Gestion des catégories",
|
||||
seeOptions: "Options du calendrier",
|
||||
date: {
|
||||
start: "Date de début",
|
||||
|
||||
@@ -819,7 +819,7 @@ export const useCalendar = defineStore("calendar", () => {
|
||||
}
|
||||
|
||||
/**
|
||||
* State for event modal edition
|
||||
* State for event modal deletion
|
||||
*/
|
||||
const isDeleteEventModalOpen = ref<boolean>(false)
|
||||
|
||||
@@ -910,6 +910,15 @@ export const useCalendar = defineStore("calendar", () => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* State for categories modal
|
||||
*/
|
||||
const isCategoriesModalOpen = ref<boolean>(false)
|
||||
|
||||
function toggleCategoriesModal(state: boolean) {
|
||||
isCategoriesModalOpen.value = state
|
||||
}
|
||||
|
||||
return {
|
||||
isReadOnly,
|
||||
setReadStatus,
|
||||
@@ -969,6 +978,8 @@ export const useCalendar = defineStore("calendar", () => {
|
||||
isEditEventModalOpen,
|
||||
revealEditEventModal,
|
||||
isDeleteEventModalOpen,
|
||||
revealDeleteEventModal
|
||||
revealDeleteEventModal,
|
||||
isCategoriesModalOpen,
|
||||
toggleCategoriesModal
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,306 +0,0 @@
|
||||
import type { CalendarEvent } from "@/models/CalendarEvent"
|
||||
import type { RPGDate } from "@/models/Date"
|
||||
import { defineStore } from "pinia"
|
||||
import { ref, watch, type Ref } from "vue"
|
||||
import type { Category } from "~/models/Category"
|
||||
import { useCalendar } from "./CalendarStore"
|
||||
|
||||
export const useCalendarEvents = defineStore("calendar-events", () => {
|
||||
const { activeCalendar, defaultDate, currentConfig, convertDateToDays, compareDates } = useCalendar()
|
||||
const { currentRPGDate } = storeToRefs(useCalendar())
|
||||
|
||||
const baseEvents = ref<CalendarEvent[]>([])
|
||||
|
||||
async function fetchCalendarEvents(calendarId: number) {
|
||||
try {
|
||||
const res = await $fetch("/api/calendars/events/query", { query: { calendarId } })
|
||||
|
||||
const eventData = res.data as CalendarEvent[]
|
||||
|
||||
if (!eventData.length) return
|
||||
|
||||
baseEvents.value = eventData
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
const categories = ref<Category[]>([])
|
||||
|
||||
function setCategories(data: Category[]) {
|
||||
categories.value = data
|
||||
}
|
||||
|
||||
// Order base events by dates
|
||||
const allEvents = computed(() => baseEvents.value.sort((a, b) => {
|
||||
return compareDates(a.startDate, b.startDate, "desc")
|
||||
}))
|
||||
|
||||
// Gets all current event in its default state
|
||||
const currentEvents: Ref<CalendarEvent[]> = ref([])
|
||||
|
||||
// Watch for currentDate or events' list changes
|
||||
// This is deep because we're watching an array, and changes need to trigger and mutations like .push and .splice
|
||||
watch([currentRPGDate, allEvents], () => {
|
||||
currentEvents.value = computeCurrentEvents()
|
||||
}, { deep: true, immediate: true })
|
||||
|
||||
/**
|
||||
* Determines if the event can appear in the front end
|
||||
*
|
||||
* This function takes into consideration the viewType of the calendar config
|
||||
*
|
||||
* @param event The event to analyze
|
||||
* @returns Whether the event should appear in the current view
|
||||
*/
|
||||
function shouldEventBeDisplayed(event: CalendarEvent): boolean {
|
||||
const isEventOnCurrentScreen =
|
||||
(event.startDate.year === currentRPGDate.value.day &&
|
||||
event.startDate.month === currentRPGDate.value.month) ||
|
||||
(event.endDate &&
|
||||
event.endDate.year === currentRPGDate.value.year &&
|
||||
event.endDate.month === currentRPGDate.value.month)
|
||||
|
||||
switch (currentConfig.viewType) {
|
||||
case "month":
|
||||
return isEventOnCurrentScreen!
|
||||
|
||||
case "year":
|
||||
return event.startDate.year === currentRPGDate.value.year
|
||||
|
||||
case "decade":
|
||||
return (
|
||||
event.startDate.year >= currentRPGDate.value.year &&
|
||||
event.startDate.year <= currentRPGDate.value.year + 10
|
||||
)
|
||||
|
||||
case "century":
|
||||
return (
|
||||
event.startDate.year >= currentRPGDate.value.year &&
|
||||
event.startDate.year <= currentRPGDate.value.year + 100
|
||||
)
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all the current events for the current view
|
||||
*
|
||||
* @returns A list of events that can appear in the current view
|
||||
*/
|
||||
function computeCurrentEvents(): CalendarEvent[] {
|
||||
return allEvents.value.filter((event) => shouldEventBeDisplayed(event))
|
||||
}
|
||||
|
||||
/**
|
||||
* From a base event, gets the next or previous one in the timeline
|
||||
*
|
||||
* @param event The event at a given position in the data
|
||||
* @param position Whether we should get the next or previous event
|
||||
* @returns The next event in chronological order
|
||||
*/
|
||||
function getRelativeEventFromEvent(
|
||||
event: CalendarEvent,
|
||||
position: "next" | "prev" = "next",
|
||||
initialIsEnd: boolean = false
|
||||
): { event: CalendarEvent; targetDate: RPGDate } {
|
||||
let dateToParse: RPGDate // Day value of the date that the user interacted with
|
||||
|
||||
if (initialIsEnd && event.endDate) {
|
||||
dateToParse = event.endDate
|
||||
} else {
|
||||
dateToParse = event.startDate
|
||||
}
|
||||
|
||||
return getRelativeEventFromDate(dateToParse, position)
|
||||
}
|
||||
|
||||
/**
|
||||
* From a date, gets the next or previous event in the timeline
|
||||
*
|
||||
* @param date The starting date from which to get the next event
|
||||
* @param position Whether we should get the next or previous event
|
||||
* @returns The next event in chronological order
|
||||
*/
|
||||
function getRelativeEventFromDate(
|
||||
date: RPGDate,
|
||||
position: "next" | "prev" = "next"
|
||||
): { event: CalendarEvent; targetDate: RPGDate } {
|
||||
const pivotValue = convertDateToDays(date)
|
||||
let t: { eventData: CalendarEvent; distance: number; targetKey: "startDate" | "endDate" }[] = []
|
||||
|
||||
// Loop over all event once to convert the structure to a usable one
|
||||
for (let i = 0; i < allEvents.value.length; i++) {
|
||||
const e: CalendarEvent = allEvents.value[i]
|
||||
|
||||
// Estimate distance from pivot
|
||||
const startDateDays: number = convertDateToDays(e.startDate)
|
||||
const startDistance: number = startDateDays - pivotValue
|
||||
|
||||
// Push startDate to comparator array
|
||||
t.push({
|
||||
eventData: e,
|
||||
distance: startDistance,
|
||||
targetKey: "startDate"
|
||||
})
|
||||
|
||||
// Check the same things for endDate
|
||||
if (e.endDate) {
|
||||
const endDateDays: number = convertDateToDays(e.endDate)
|
||||
const endDistance: number = endDateDays - pivotValue
|
||||
|
||||
// Push optional endDate to comparator array
|
||||
t.push({
|
||||
eventData: e,
|
||||
distance: endDistance,
|
||||
targetKey: "endDate"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Based on the direction, either ignore negative distance (past) or positive distance (future)
|
||||
t = t.filter((i) => {
|
||||
return position === "next" ? i.distance > 0 : i.distance < 0
|
||||
})
|
||||
|
||||
if (!t.length) {
|
||||
throw new Error(
|
||||
"Aucun évènement suivant ou précédent trouvé ; Peut-être l'évènement se situe au début ou à la fin du calendrier ?"
|
||||
)
|
||||
}
|
||||
|
||||
// Get event with remaining minimum distance
|
||||
const closestEvent = t.reduce((a, b) => {
|
||||
return Math.abs(b.distance) < Math.abs(a.distance) ? b : a
|
||||
})
|
||||
|
||||
return {
|
||||
event: closestEvent.eventData,
|
||||
targetDate: closestEvent.eventData[closestEvent.targetKey]!
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* State for event modal edition
|
||||
*/
|
||||
const isEditEventModalOpen: Ref<boolean> = ref<boolean>(false)
|
||||
|
||||
function revealEditEventModal() {
|
||||
isEditEventModalOpen.value = true
|
||||
}
|
||||
|
||||
/**
|
||||
* State for event modal edition
|
||||
*/
|
||||
const isDeleteEventModalOpen: Ref<boolean> = ref<boolean>(false)
|
||||
|
||||
function revealDeleteEventModal() {
|
||||
isDeleteEventModalOpen.value = true
|
||||
}
|
||||
|
||||
/**
|
||||
* EVENT CREATION FUNCTIONS
|
||||
*/
|
||||
const lastActiveEvent = ref<CalendarEvent | null>()
|
||||
const isCreatingEvent = ref<boolean>(false)
|
||||
const isUpdatingEvent = ref<boolean>(false)
|
||||
const isDeletingEvent = ref<boolean>(false)
|
||||
const operationInProgress = computed(() => isCreatingEvent.value || isUpdatingEvent.value || isDeletingEvent.value)
|
||||
let abortController: AbortController | null = null
|
||||
|
||||
/**
|
||||
* Dummy event to hold creation data
|
||||
*/
|
||||
const eventSkeleton: Ref<CalendarEvent> = ref<CalendarEvent>({ title: "", startDate: defaultDate })
|
||||
|
||||
/**
|
||||
* Resets the dummy event data
|
||||
*/
|
||||
function resetSkeleton() {
|
||||
eventSkeleton.value = { title: "", startDate: defaultDate }
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the skeleton event and creates a real event from its data
|
||||
*
|
||||
* We assume it's been sanitized by the caller
|
||||
*/
|
||||
async function submitSkeleton() {
|
||||
abortController = new AbortController()
|
||||
isCreatingEvent.value = true
|
||||
|
||||
try {
|
||||
const res = await $fetch("/api/calendars/events/create", { method: "POST", body: { event : eventSkeleton.value, calendarId: activeCalendar?.id }, signal: abortController.signal })
|
||||
|
||||
baseEvents.value.push(res)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
} finally {
|
||||
abortController = null
|
||||
isCreatingEvent.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function updateEventFromSkeleton() {
|
||||
abortController = new AbortController()
|
||||
isUpdatingEvent.value = true
|
||||
|
||||
const res = await $fetch(`/api/calendars/events/${eventSkeleton.value.id}`, { method: "PATCH", body: { event : eventSkeleton.value, calendarId: activeCalendar?.id }, signal: abortController.signal })
|
||||
|
||||
const eventIndex = baseEvents.value.findIndex(e => e.id === eventSkeleton.value.id)
|
||||
baseEvents.value[eventIndex] = res
|
||||
|
||||
abortController = null
|
||||
isUpdatingEvent.value = false
|
||||
}
|
||||
|
||||
async function deleteEventFromSkeleton() {
|
||||
abortController = new AbortController()
|
||||
isDeletingEvent.value = true
|
||||
|
||||
try {
|
||||
await $fetch(`/api/calendars/events/${eventSkeleton.value.id}`, { method: "DELETE", signal: abortController.signal })
|
||||
|
||||
const eventIndex = baseEvents.value.findIndex(e => e.id === eventSkeleton.value.id)
|
||||
baseEvents.value.splice(eventIndex, 1)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
} finally {
|
||||
abortController = null
|
||||
isDeletingEvent.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function cancelLatestRequest() {
|
||||
if (abortController) {
|
||||
abortController.abort()
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
allEvents,
|
||||
fetchCalendarEvents,
|
||||
categories,
|
||||
setCategories,
|
||||
currentEvents,
|
||||
getRelativeEventFromDate,
|
||||
getRelativeEventFromEvent,
|
||||
cancelLatestRequest,
|
||||
isCreatingEvent,
|
||||
isUpdatingEvent,
|
||||
isDeletingEvent,
|
||||
operationInProgress,
|
||||
eventSkeleton,
|
||||
resetSkeleton,
|
||||
submitSkeleton,
|
||||
lastActiveEvent,
|
||||
updateEventFromSkeleton,
|
||||
deleteEventFromSkeleton,
|
||||
isEditEventModalOpen,
|
||||
revealEditEventModal,
|
||||
isDeleteEventModalOpen,
|
||||
revealDeleteEventModal
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user