diff --git a/assets/main.css b/assets/main.css index 71f25ec..ad39aa5 100644 --- a/assets/main.css +++ b/assets/main.css @@ -5,64 +5,64 @@ :root { --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; - + --muted: 210 40% 96.1%; --muted-foreground: 215.4 16.3% 46.9%; - + --popover: 0 0% 100%; --popover-foreground: 222.2 84% 4.9%; - + --card: 0 0% 100%; --card-foreground: 222.2 84% 4.9%; - + --border: 214.3 31.8% 91.4%; --input: 214.3 31.8% 91.4%; - + --primary: 222.2 47.4% 11.2%; --primary-foreground: 210 40% 98%; - + --secondary: 210 40% 96.1%; --secondary-foreground: 222.2 47.4% 11.2%; - + --accent: 210 40% 96.1%; --accent-foreground: 222.2 47.4% 11.2%; - + --destructive: 0 84.2% 60.2%; --destructive-foreground: 210 40% 98%; - + --ring: 222.2 84% 4.9%; - + --radius: 0.5rem; } - + :root.dark { --background: 222.2 84% 4.9%; --foreground: 210 40% 98%; - + --muted: 217.2 32.6% 17.5%; --muted-foreground: 215 20.2% 65.1%; - + --popover: 222.2 84% 4.9%; --popover-foreground: 210 40% 98%; - + --card: 222.2 84% 4.9%; --card-foreground: 210 40% 98%; - + --border: 217.2 32.6% 17.5%; --input: 217.2 32.6% 17.5%; - + --primary: 210 40% 98%; --primary-foreground: 222.2 47.4% 11.2%; - + --secondary: 217.2 32.6% 17.5%; --secondary-foreground: 210 40% 98%; - + --accent: 217.2 32.6% 17.5%; --accent-foreground: 210 40% 98%; - + --destructive: 0 62.8% 30.6%; --destructive-foreground: 210 40% 98%; - + --ring: 212.7 26.8% 83.9%; } @@ -73,4 +73,21 @@ body { @apply bg-background text-foreground; } -} \ No newline at end of file +} + +.fade-enter-active, +.fade-leave-active { + transition: all .5s ease; +} +.fade-delay-enter-active, +.fade-delay-leave-active { + transition: all .5s ease 1s; +} + +.fade-enter-from, +.fade-leave-to, +.fade-delay-enter-from, +.fade-delay-leave-to { + opacity: 0; + visibility: hidden; +} diff --git a/components/calendar/Calendar.vue b/components/calendar/Calendar.vue index 950b36b..9506e05 100644 --- a/components/calendar/Calendar.vue +++ b/components/calendar/Calendar.vue @@ -93,7 +93,7 @@ onMounted(() => { setCurrentMenu([ { - phIcon: PhMagnifyingGlass, + phIcon: shallowRef(PhMagnifyingGlass), tooltip: 'Recherche avancée', action: 'event-search' } @@ -116,10 +116,10 @@ onMounted(() => { - - - - + + + + diff --git a/components/calendar/form/CreateEvent.vue b/components/calendar/form/CreateEvent.vue index 7729509..524121f 100644 --- a/components/calendar/form/CreateEvent.vue +++ b/components/calendar/form/CreateEvent.vue @@ -1,11 +1,12 @@ @@ -52,7 +87,13 @@ async function handleSubmit() { :align="'center'" :side="'right'" :collision-padding="60" + :disable-outside-pointer-events="true" + :trap-focus="true" class="pl-3 min-w-96 bg-slate-900 border-slate-800" + @escape-key-down="handleClosing" + @focus-outside="handleClosing" + @interact-outside="handleClosing" + @pointer-down-outside="handleClosing" > @@ -118,8 +159,18 @@ async function handleSubmit() { - - + + + + Annuler + + + + + + + + Sauvegarder diff --git a/components/calendar/form/DeleteEvent.vue b/components/calendar/form/DeleteEvent.vue index 224d563..caeb0a0 100644 --- a/components/calendar/form/DeleteEvent.vue +++ b/components/calendar/form/DeleteEvent.vue @@ -1,9 +1,13 @@ Supprimer l'évènement @@ -46,7 +77,7 @@ async function handleAction() { Les données associés à cet évènement seront supprimées et vous ne pourrez plus les récupérer ! - + @@ -54,16 +85,23 @@ async function handleAction() { - - - - Annuler - - - Supprimer - - + + diff --git a/components/calendar/form/UpdateEvent.vue b/components/calendar/form/UpdateEvent.vue index 7350394..4e072f7 100644 --- a/components/calendar/form/UpdateEvent.vue +++ b/components/calendar/form/UpdateEvent.vue @@ -1,12 +1,14 @@ - - + e.preventDefault()" > - Modifier l'évènement + Modifier l'évènement - + Mettre à jour les données de l'évènement - + - + + + - - - Annuler - - - Sauvegarder - - - - + + diff --git a/components/calendar/state/monthly/DayTile.vue b/components/calendar/state/monthly/DayTile.vue index 0ae0b5d..bcd9b15 100644 --- a/components/calendar/state/monthly/DayTile.vue +++ b/components/calendar/state/monthly/DayTile.vue @@ -146,7 +146,7 @@ const eventsNotDisplayed: ComputedRef = computed(() => eventsFo - + diff --git a/components/global/sidebar/SidebarProps.ts b/components/global/sidebar/SidebarProps.ts index 4414df0..bb3cd9e 100644 --- a/components/global/sidebar/SidebarProps.ts +++ b/components/global/sidebar/SidebarProps.ts @@ -1,7 +1,9 @@ +import type { ShallowRef } from "vue" + export type SidebarMenuActionType = "event-search" export interface SidebarMenuItem { - phIcon: Component + phIcon: ShallowRef tooltip: string action?: SidebarMenuActionType to?: string diff --git a/stores/EventStore.ts b/stores/EventStore.ts index 454bd24..b3294e9 100644 --- a/stores/EventStore.ts +++ b/stores/EventStore.ts @@ -187,6 +187,12 @@ export const useCalendarEvents = defineStore('calendar-events', () => { * EVENT CREATION FUNCTIONS */ const lastActiveEvent = ref() + const isCreatingEvent = ref(false) + const isUpdatingEvent = ref(false) + const isDeletingEvent = ref(false) + const operationInProgress = computed(() => isCreatingEvent.value || isUpdatingEvent.value || isDeletingEvent.value) + let abortController: AbortController | null = null + /** * Dummy event to hold creation data */ @@ -205,31 +211,58 @@ export const useCalendarEvents = defineStore('calendar-events', () => { * 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: calendarId.value }}) + const res = await $fetch('/api/calendars/events/create', { method: 'POST', body: { event : eventSkeleton.value, calendarId: calendarId.value }, 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 + try { - const res = await $fetch(`/api/calendars/events/${eventSkeleton.value.id}`, { method: 'PATCH', body: { event : eventSkeleton.value, calendarId: calendarId.value }}) + const res = await $fetch(`/api/calendars/events/${eventSkeleton.value.id}`, { method: 'PATCH', body: { event : eventSkeleton.value, calendarId: calendarId.value }, signal: abortController.signal }) + const eventIndex = baseEvents.value.findIndex(e => e.id === eventSkeleton.value.id) baseEvents.value[eventIndex] = res } catch (err) { console.log(err) + } finally { + 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' }) + 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() } } @@ -239,6 +272,11 @@ export const useCalendarEvents = defineStore('calendar-events', () => { currentEvents, getRelativeEventFromDate, getRelativeEventFromEvent, + cancelLatestRequest, + isCreatingEvent, + isUpdatingEvent, + isDeletingEvent, + operationInProgress, eventSkeleton, resetSkeleton, submitSkeleton,