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] 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 }
})