({ default: "white" });
-
+
({
title: "Manage categories",
subtitle: "Add and change the categories of your calendar",
},
+ addedToast: {
+ title: "The category \"{category}\" has been added to the calendar.",
+ titleError: "An error has occured and the category \"{category}\" wasn't added to the calendar.",
+ },
updatedToast: {
title: "The category \"{category}\" has been successfuly updated.",
titleError: "An error has occured and the category \"{category}\" wasn't updated.",
@@ -409,6 +413,10 @@ export default defineI18nConfig(() => ({
title: "Gestion des catégories",
subtitle: "Créer et modifier les catégories de votre calendrier",
},
+ addedToast: {
+ title: "La catégorie \"{category}\" a été ajoutée au calendrier.",
+ titleError: "Une erreur s'est produite et la catégorie \"{category}\" n'a pas pu être ajoutée.",
+ },
updatedToast: {
title: "La catégorie \"{category}\" a été modifiée avec succès.",
titleError: "Une erreur s'est produite et la catégorie \"{category}\" n'a pas pu être modifiée.",
diff --git a/models/CalendarEvent.ts b/models/CalendarEvent.ts
index 65562fa..3ac68b1 100644
--- a/models/CalendarEvent.ts
+++ b/models/CalendarEvent.ts
@@ -1,5 +1,5 @@
import { z } from "zod"
-import { categorySchema, type Category } from "./Category"
+import type { Category } from "./Category"
import { dateSchema, type RPGDate } from "./Date"
export interface CalendarEvent {
@@ -26,7 +26,11 @@ export const postEventBodySchema = z.object({
startDate: dateSchema.required(),
endDate: dateSchema.optional().nullable(),
hidden: z.boolean().optional().nullable(),
- category: categorySchema.optional().nullable(),
+ category: z.object({
+ id: z.number().int(),
+ name: z.string(),
+ color: z.string().default("black")
+ }).optional().nullable(),
}),
calendarId: z.number({ coerce: true }).int().positive()
})
diff --git a/models/Category.ts b/models/Category.ts
index b099386..7ee0024 100644
--- a/models/Category.ts
+++ b/models/Category.ts
@@ -2,13 +2,15 @@ import { z } from "zod"
import type { RPGColor } from "./Color"
export interface Category {
- id: number
+ id?: number
name: string
color?: RPGColor
}
export const categorySchema = z.object({
- id: z.number().int(),
- name: z.string(),
- color: z.string().default("black"),
+ category: z.object({
+ name: z.string(),
+ color: z.string().default("black"),
+ }),
+ calendarId: z.number({ coerce: true }).int().positive()
})
diff --git a/server/api/calendars/categories/[id].patch.ts b/server/api/calendars/categories/[id].patch.ts
index 26d7131..d7926fb 100644
--- a/server/api/calendars/categories/[id].patch.ts
+++ b/server/api/calendars/categories/[id].patch.ts
@@ -46,8 +46,9 @@ export default defineEventHandler(async (event) => {
.from("calendar_event_categories")
.update(
{
- name: bodyData.name,
- color: bodyData.color,
+ name: bodyData.category.name,
+ color: bodyData.category.color,
+ calendar_id: bodyData.calendarId
} as never
)
.eq("id", params.id)
diff --git a/server/api/calendars/categories/create.post.ts b/server/api/calendars/categories/create.post.ts
new file mode 100644
index 0000000..b8e2479
--- /dev/null
+++ b/server/api/calendars/categories/create.post.ts
@@ -0,0 +1,56 @@
+import { serverSupabaseClient } from "#supabase/server";
+import { type Category, categorySchema } from "@/models/Category";
+
+export default defineEventHandler(async (event) => {
+ const client = await serverSupabaseClient(event)
+
+ const { data: bodyData, error: bodyError } = await readValidatedBody(event, body => categorySchema.safeParse(body))
+
+ if (bodyError) {
+ const error = createError({
+ cause: "Utilisateur",
+ fatal: false,
+ statusCode: 401,
+ statusMessage: "Validation Error",
+ message: "Erreur de validation du schéma, probablement dûe à une erreur utilisateur.",
+ data: {
+ errors: bodyError.issues.map(issue => ({
+ path: issue.path,
+ message: issue.message,
+ code: issue.code
+ }))
+ }
+ })
+
+ throw error
+ }
+
+ try {
+ const { data, error } = await client
+ .from("calendar_event_categories")
+ .insert(
+ {
+ name: bodyData.category.name,
+ color: bodyData.category.color,
+ calendar_id: bodyData.calendarId
+ } as never
+ )
+ .select(`
+ id,
+ name,
+ color
+ `)
+ .single()
+
+ 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/stores/CategoryStore.ts b/stores/CategoryStore.ts
index 70a00f3..e357294 100644
--- a/stores/CategoryStore.ts
+++ b/stores/CategoryStore.ts
@@ -1,7 +1,7 @@
import type { Category } from "~/models/Category";
export const useCategoryStore = defineStore("calendar-category", () => {
- const { categories } = storeToRefs(useCalendar())
+ const { activeCalendar, categories } = storeToRefs(useCalendar())
/**
* Dummy event to hold creation data
@@ -21,16 +21,38 @@ export const useCategoryStore = defineStore("calendar-category", () => {
categorySkeleton.value = null
}
+ async function addCategoryFromSkeleton() {
+ if (!categorySkeleton.value) return
+
+ abortController = new AbortController()
+
+ isCreatingCategory.value = true
+
+ const { data, error } = await tryCatch(
+ $fetch("/api/calendars/categories/create", { method: "POST", body: { category: categorySkeleton.value, calendarId: activeCalendar.value?.id }, signal: abortController.signal })
+ )
+
+ if (error) {
+ isCreatingCategory.value = false
+ throw error
+ }
+
+ // Update the category in the store
+ categories.value.push(data)
+
+ abortController = null
+ isCreatingCategory.value = false
+ resetSkeleton()
+ }
+
async function updateCategoryFromSkeleton() {
if (!categorySkeleton.value) return
abortController = new AbortController()
isUpdatingCategory.value = true
- const body = categorySkeleton.value
-
const { data, error } = await tryCatch(
- $fetch(`/api/calendars/categories/${categorySkeleton.value.id}`, { method: "PATCH", body, signal: abortController.signal })
+ $fetch(`/api/calendars/categories/${categorySkeleton.value.id}`, { method: "PATCH", body: { category: categorySkeleton.value, calendarId: activeCalendar.value?.id }, signal: abortController.signal })
)
if (error) {
@@ -48,6 +70,7 @@ export const useCategoryStore = defineStore("calendar-category", () => {
abortController = null
isUpdatingCategory.value = false
+ resetSkeleton()
}
return {
@@ -57,6 +80,7 @@ export const useCategoryStore = defineStore("calendar-category", () => {
operationInProgress,
categorySkeleton,
resetSkeleton,
+ addCategoryFromSkeleton,
updateCategoryFromSkeleton
}
})
diff --git a/supabase/migrations/202401_init.sql b/supabase/migrations/202401_init.sql
index 45f19a8..bc58698 100644
--- a/supabase/migrations/202401_init.sql
+++ b/supabase/migrations/202401_init.sql
@@ -440,6 +440,20 @@ create policy "Allow anonymous access to published event categories" on public.c
)
);
+create policy "Allow GMs to add new events categories"
+ on public.calendar_event_categories
+ for insert
+ with check (
+ exists (
+ select 1
+ from public.calendars c
+ join public.worlds w on w.id = c.world_id
+ where
+ c.id = calendar_event_categories.calendar_id
+ and w.gm_id = auth.uid()
+ )
+);
+
create policy "Allow GMs to update their events categories"
on public.calendar_event_categories
for update