From a92edd62151cad8575a4c7fec841f326314b1583 Mon Sep 17 00:00:00 2001
From: Alexis <35.alexis.pele@gmail.com>
Date: Sat, 1 Jun 2024 11:07:07 +0200
Subject: [PATCH 1/6] Added post component for events
This needs RLS disabled, will work on that later, I don't like postgre
---
components/calendar/Calendar.vue | 15 +-
components/calendar/form/CreateEvent.vue | 126 +++++++++++++
components/calendar/input/RPGDate.vue | 166 ++++++++++++++++++
components/calendar/state/monthly/DayTile.vue | 113 +++++++-----
components/calendar/state/monthly/Layout.vue | 2 +-
models/CalendarEvent.ts | 18 +-
models/Date.ts | 27 +--
pages/calendar/[id].vue | 3 -
server/api/calendars/events/create.post.ts | 36 ++++
.../api/{ => calendars}/events/query.get.ts | 0
stores/CalendarStore.ts | 8 +-
stores/EventStore.ts | 60 ++++---
12 files changed, 474 insertions(+), 100 deletions(-)
create mode 100644 components/calendar/form/CreateEvent.vue
create mode 100644 components/calendar/input/RPGDate.vue
create mode 100644 server/api/calendars/events/create.post.ts
rename server/api/{ => calendars}/events/query.get.ts (100%)
diff --git a/components/calendar/Calendar.vue b/components/calendar/Calendar.vue
index 7c7c00c..5b420d8 100644
--- a/components/calendar/Calendar.vue
+++ b/components/calendar/Calendar.vue
@@ -7,10 +7,12 @@ import CenturyLayout from './state/centennially/Layout.vue'
import DecadeLayout from './state/decennially/Layout.vue'
import YearLayout from './state/yearly/Layout.vue'
+const { isAdvancedSearchOpen } = storeToRefs(useCalendar())
+
const route = useRoute()
const worldId = route.params.id
-const { setMonths, setDefaultDate, currentConfig, selectedDate, jumpToDate } = useCalendar()
+const { setCalendarId, setMonths, setDefaultDate, currentConfig, selectedDate, jumpToDate } = useCalendar()
const { setEvents } = useCalendarEvents()
const { setCharacters } = useCharacters()
@@ -20,6 +22,12 @@ const { data: characters, pending: charPending, refresh: charRefresh } = await u
if (!calendar.value) {
await calRefresh()
} else {
+ if (calendar.value?.data?.id) {
+ setCalendarId(calendar.value?.data?.id)
+ }
+ if (calendar.value?.data?.months) {
+ setMonths(calendar.value?.data?.months)
+ }
if (calendar.value?.data?.months) {
setMonths(calendar.value?.data?.months)
}
@@ -40,6 +48,9 @@ if (!characters.value) {
watch(calPending, (newStatus) => {
if (!newStatus) {
+ if (calendar.value?.data?.id) {
+ setCalendarId(calendar.value?.data?.id)
+ }
if (calendar.value?.data?.months) {
setMonths(calendar.value?.data?.months)
}
@@ -97,5 +108,7 @@ onMounted(() => {
+
+
diff --git a/components/calendar/form/CreateEvent.vue b/components/calendar/form/CreateEvent.vue
new file mode 100644
index 0000000..fe9d3c4
--- /dev/null
+++ b/components/calendar/form/CreateEvent.vue
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/calendar/input/RPGDate.vue b/components/calendar/input/RPGDate.vue
new file mode 100644
index 0000000..a46dccd
--- /dev/null
+++ b/components/calendar/input/RPGDate.vue
@@ -0,0 +1,166 @@
+
+
+
+
+
+
+
+ {{ inputPlaceholder }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ month.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/calendar/state/monthly/DayTile.vue b/components/calendar/state/monthly/DayTile.vue
index f26d456..4d2be2f 100644
--- a/components/calendar/state/monthly/DayTile.vue
+++ b/components/calendar/state/monthly/DayTile.vue
@@ -1,5 +1,6 @@
@@ -66,9 +82,6 @@ const eventsNotDisplayed = computed(
'text-slate-300': !props.faded
}"
>
-
-
-
-
- -
-
-
+
+
+ -
+
+
- -
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
+ {{ eventsNotDisplayed }} autre{{ eventsNotDisplayed > 1 ? 's' : '' }}
+
+
+
+
+
+ {{ date.day }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/calendar/state/monthly/Layout.vue b/components/calendar/state/monthly/Layout.vue
index ba7066b..06ce384 100644
--- a/components/calendar/state/monthly/Layout.vue
+++ b/components/calendar/state/monthly/Layout.vue
@@ -27,7 +27,7 @@ const moveCalendarRight = useThrottleFn(() => {
{
})
const { revealAdvancedSearch } = useCalendar()
-const { isAdvancedSearchOpen } = storeToRefs(useCalendar())
const sidebarMenu: MenuItem[] = [
{
@@ -34,7 +33,5 @@ const sidebarMenu: MenuItem[] = [
-
-
diff --git a/server/api/calendars/events/create.post.ts b/server/api/calendars/events/create.post.ts
new file mode 100644
index 0000000..8fdec86
--- /dev/null
+++ b/server/api/calendars/events/create.post.ts
@@ -0,0 +1,36 @@
+import { serverSupabaseClient } from "#supabase/server";
+import type { CalendarEvent } from "@/models/CalendarEvent";
+import { postEventBodySchema } from "@/models/CalendarEvent";
+
+export default defineEventHandler(async (event) => {
+ const client = await serverSupabaseClient(event)
+ const { data: bodyData, error: schemaError } = await readValidatedBody(event, body => postEventBodySchema.safeParse(body))
+
+ if (schemaError) {
+ throw createError({
+ cause: 'Utilisateur',
+ fatal: false,
+ message: "Le schéma de la requête n'est pas complet ou mal renseigné.",
+ status: 401,
+ })
+ }
+
+ try {
+ const { data, error } = await client
+ .from('calendar_events')
+ .insert({ start_date: bodyData?.event.startDate, end_date: bodyData.event.endDate, title: bodyData?.event.title, description: bodyData.event.description, calendar_id: bodyData?.calendarId } as never)
+ .select()
+ .returns()
+
+ if (error) throw error
+
+ return data
+ } catch (err) {
+ throw createError({
+ cause: 'Serveur',
+ status: 500,
+ fatal: false,
+ message: 'Une erreur inconnue est survenue.'
+ })
+ }
+})
diff --git a/server/api/events/query.get.ts b/server/api/calendars/events/query.get.ts
similarity index 100%
rename from server/api/events/query.get.ts
rename to server/api/calendars/events/query.get.ts
diff --git a/stores/CalendarStore.ts b/stores/CalendarStore.ts
index be8fd99..9d64f63 100644
--- a/stores/CalendarStore.ts
+++ b/stores/CalendarStore.ts
@@ -36,6 +36,11 @@ export const useCalendar = defineStore('calendar', () => {
'century'
])
+ const calendarId = ref(0)
+
+ function setCalendarId(data: number) {
+ calendarId.value = data
+ }
/**
* Month list (queried from API)
*/
@@ -178,7 +183,6 @@ export const useCalendar = defineStore('calendar', () => {
/**
* Moves the current date forward one month
*/
-
function incrementMonth(): void {
let newValue = Number(params.month) + 1
@@ -598,6 +602,8 @@ export const useCalendar = defineStore('calendar', () => {
}
return {
+ calendarId,
+ setCalendarId,
months,
setMonths,
sortedMonths,
diff --git a/stores/EventStore.ts b/stores/EventStore.ts
index 3ed9002..0fbd5aa 100644
--- a/stores/EventStore.ts
+++ b/stores/EventStore.ts
@@ -5,7 +5,8 @@ import { ref, watch, type Ref } from 'vue'
import { useCalendar } from './CalendarStore'
export const useCalendarEvents = defineStore('calendar-events', () => {
- const { currentDate, currentConfig, convertDateToDays, compareDates } = useCalendar()
+ const { currentDate, defaultDate, currentConfig, convertDateToDays, compareDates } = useCalendar()
+ const { calendarId } = storeToRefs(useCalendar())
const baseEvents = ref([])
@@ -97,8 +98,7 @@ export const useCalendarEvents = defineStore('calendar-events', () => {
}
/**
- * From a base event, gets the next or previous in the timeline
- * @todo **This should probably be extracted to function FIRST with dates only, as the initialIsEnd param is only used at the beggining to establish a pivot**
+ * 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
@@ -120,6 +120,13 @@ export const useCalendarEvents = defineStore('calendar-events', () => {
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'
@@ -156,27 +163,6 @@ export const useCalendarEvents = defineStore('calendar-events', () => {
}
}
- // // Special case : If we query the first one but it already is
- // if (position === 'prev' && t[0].distance === 0) {
- // const targetDate =
- // t[0].targetKey === 'startDate' ? t[0].eventData.startDate : t[0].eventData.endDate!
- // return {
- // event: t[0].eventData,
- // targetDate: targetDate
- // }
- // }
- // // Special case : If we query the last one but it already is
- // if (position === 'next' && t[t.length - 1].distance === 0) {
- // const targetDate =
- // t[t.length - 1].targetKey === 'startDate'
- // ? t[t.length - 1].eventData.startDate
- // : t[t.length - 1].eventData.endDate!
- // return {
- // event: t[t.length - 1].eventData,
- // targetDate: targetDate
- // }
- // }
-
// 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
@@ -199,5 +185,29 @@ export const useCalendarEvents = defineStore('calendar-events', () => {
}
}
- return { allEvents, setEvents, currentEvents, getRelativeEventFromDate, getRelativeEventFromEvent }
+ /**
+ * EVENT CREATION FUNCTIONS
+ */
+ /**
+ * Dummy event to hold creation data
+ */
+ const eventSkeleton: Ref = ref({ 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() {
+ return await $fetch(`/api/calendars/events/create`, { method: 'POST', body: { event : eventSkeleton.value, calendarId: calendarId.value }})
+ }
+
+ return { allEvents, setEvents, currentEvents, getRelativeEventFromDate, getRelativeEventFromEvent, eventSkeleton, resetSkeleton, submitSkeleton }
})
From 5332b4c9c4dddc32385bb70c1137502d0c06329b Mon Sep 17 00:00:00 2001
From: Alexis <35.alexis.pele@gmail.com>
Date: Sun, 2 Jun 2024 10:35:18 +0200
Subject: [PATCH 2/6] Updated form component
I'll need to refactor this to a Calendar level component
---
components/calendar/CalendarEventDetails.vue | 104 ++++++++++---------
components/calendar/form/UpdateEvent.vue | 100 ++++++++++++++++++
2 files changed, 153 insertions(+), 51 deletions(-)
create mode 100644 components/calendar/form/UpdateEvent.vue
diff --git a/components/calendar/CalendarEventDetails.vue b/components/calendar/CalendarEventDetails.vue
index 799f982..eb93c77 100644
--- a/components/calendar/CalendarEventDetails.vue
+++ b/components/calendar/CalendarEventDetails.vue
@@ -2,19 +2,16 @@
import type { RPGDate } from '@/models/Date'
import type { CalendarEvent } from '@/models/CalendarEvent'
import { useCalendar } from '@/stores/CalendarStore'
-import { useCalendarEvents } from '@/stores/EventStore'
import {
PhHourglassMedium,
PhAlarm,
PhHourglassHigh,
PhHourglassLow,
- PhArrowBendDoubleUpLeft,
- PhArrowBendDoubleUpRight
+ PhDotsThreeOutlineVertical
} from '@phosphor-icons/vue'
const { defaultDate, getFormattedDateTitle, jumpToDate } = useCalendar()
-const { getRelativeEventFromEvent } = useCalendarEvents()
const props = defineProps<{
event: CalendarEvent
@@ -23,9 +20,10 @@ const props = defineProps<{
isEndEvent?: boolean
}>()
-const emit = defineEmits<{
- (e: 'query:close-popover'): void
-}>()
+// Ref for the popover
+const eventDetails = ref()
+
+const emit = defineEmits(['query:close-popover'])
const { getRelativeString } = useCalendar()
@@ -39,14 +37,15 @@ function handleJumpToDate(date: RPGDate) {
emit('query:close-popover')
}
-function handleGotoRelativeEvent(position: 'next' | 'prev' = 'next') {
- try {
- const { targetDate } = getRelativeEventFromEvent(props.event, position, props.isEndEvent)
+/**
+ * Edit event
+ */
+const commandMenuOpened = ref(false)
+const editModelOpened = ref(false)
- handleJumpToDate(targetDate)
- } catch (err) {
- console.log(err)
- }
+function deployEditModal() {
+ commandMenuOpened.value = false
+ editModelOpened.value = true
}
@@ -80,22 +79,24 @@ function handleGotoRelativeEvent(position: 'next' | 'prev' = 'next') {
'border-yellow-600': event.category?.name === 'commerce'
}"
>
-
-
- {{ event.title }}
-
+
+
+
+ {{ event.title }}
+
-
-
- {{ getFormattedDateTitle(event.startDate, true) }}
-
-
-
- Du {{ getFormattedDateTitle(event.startDate, true) }} au
- {{ getFormattedDateTitle(event.endDate, true) }}
-
-
-
+
+
+ {{ getFormattedDateTitle(event.startDate, true) }}
+
+
+
+ Du {{ getFormattedDateTitle(event.startDate, true) }} au
+ {{ getFormattedDateTitle(event.endDate, true) }}
+
+
+
+
@@ -133,7 +134,29 @@ function handleGotoRelativeEvent(position: 'next' | 'prev' = 'next') {
-
diff --git a/components/calendar/CalendarEvent.vue b/components/calendar/CalendarEvent.vue
index a6d11da..bf08ba4 100644
--- a/components/calendar/CalendarEvent.vue
+++ b/components/calendar/CalendarEvent.vue
@@ -17,15 +17,15 @@ const isStartEvent = spansMultipleDays && areDatesIdentical(props.tileDate, prop
const isEndEvent =
spansMultipleDays && props.event.endDate && areDatesIdentical(props.tileDate, props.event.endDate)
-const isPopoverOpen = ref
(false)
+const isPopoverDetailsOpen = ref(false)
function handleClosePopover() {
- isPopoverOpen.value = false
+ isPopoverDetailsOpen.value = false
}
-
+
-
-