diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f1ae76f..f0e2488 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -41,6 +41,9 @@ importers:
lucide-vue-next:
specifier: ^0.475.0
version: 0.475.0(vue@3.5.13(typescript@5.7.3))
+ luxon:
+ specifier: ^3.5.0
+ version: 3.5.0
nuxt:
specifier: ^3.15.4
version: 3.15.4(@parcel/watcher@2.5.1)(@types/node@22.13.5)(db0@0.2.4)(encoding@0.1.13)(eslint@9.21.0(jiti@2.4.2))(ioredis@5.5.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.8)(sass@1.85.1)(terser@5.39.0)(typescript@5.7.3)(vite@6.2.0(@types/node@22.13.5)(jiti@2.4.2)(sass@1.85.1)(terser@5.39.0)(yaml@2.7.0))(yaml@2.7.0)
@@ -84,6 +87,9 @@ importers:
'@stylistic/eslint-plugin-js':
specifier: ^3.1.0
version: 3.1.0(eslint@9.21.0(jiti@2.4.2))
+ '@types/luxon':
+ specifier: ^3.4.2
+ version: 3.4.2
'@typescript-eslint/eslint-plugin':
specifier: ^8.25.0
version: 8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.21.0(jiti@2.4.2))(typescript@5.7.3)
@@ -1632,6 +1638,9 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+ '@types/luxon@3.4.2':
+ resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==}
+
'@types/node@22.13.5':
resolution: {integrity: sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==}
@@ -3411,6 +3420,10 @@ packages:
peerDependencies:
vue: '>=3.0.1'
+ luxon@3.5.0:
+ resolution: {integrity: sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==}
+ engines: {node: '>=12'}
+
magic-string-ast@0.7.0:
resolution: {integrity: sha512-686fgAHaJY7wLTFEq7nnKqeQrhqmXB19d1HnqT35Ci7BN6hbAYLZUezTQ062uUHM7ggZEQlqJ94Ftls+KDXU8Q==}
engines: {node: '>=16.14.0'}
@@ -6786,6 +6799,8 @@ snapshots:
'@types/json-schema@7.0.15': {}
+ '@types/luxon@3.4.2': {}
+
'@types/node@22.13.5':
dependencies:
undici-types: 6.20.0
@@ -8798,6 +8813,8 @@ snapshots:
dependencies:
vue: 3.5.13(typescript@5.7.3)
+ luxon@3.5.0: {}
+
magic-string-ast@0.7.0:
dependencies:
magic-string: 0.30.17
diff --git a/server/api/calendars/query.get.ts b/server/api/calendars/query.get.ts
index a438640..9430ec8 100644
--- a/server/api/calendars/query.get.ts
+++ b/server/api/calendars/query.get.ts
@@ -19,6 +19,8 @@ export default defineEventHandler(async (event) => {
today,
months:calendar_months (*),
state,
+ createdAt:created_at,
+ updatedAt:updated_at,
eventNb:calendar_events(count)
`
@@ -29,6 +31,8 @@ export default defineEventHandler(async (event) => {
today,
months:calendar_months (*),
state,
+ createdAt:created_at,
+ updatedAt:updated_at,
events:calendar_events (
id,
title,
@@ -64,5 +68,5 @@ export default defineEventHandler(async (event) => {
return output.eq("id", query.id).limit(1).single()
}
- return output.returns()
+ return output.overrideTypes()
})
diff --git a/server/api/worlds/query.get.ts b/server/api/worlds/query.get.ts
index e980f36..7d56ee2 100644
--- a/server/api/worlds/query.get.ts
+++ b/server/api/worlds/query.get.ts
@@ -4,15 +4,45 @@ import type { World } from "~/models/World";
const querySchema = z.object({
id: z.number({ coerce: true }).positive().int().optional(),
- full: z.boolean({ coerce: true }).optional()
+ full: z.boolean({ coerce: true }).optional(),
+ gmId: z.string().optional(),
})
export default defineEventHandler(async (event) => {
const client = await serverSupabaseClient(event)
const query = await getValidatedQuery(event, querySchema.parse)
- const fullFields = "id, name, description, color, calendars (id, name, color, today)"
- const partialFields = "id, name, description, color"
+ const fullFields = `
+ id,
+ name,
+ description,
+ color,
+ createdAt:created_at,
+ updatedAt:updated_at,
+ gmId:gm_id,
+ calendars (
+ id,
+ name,
+ color,
+ today,
+ createdAt:created_at,
+ updatedAt:updated_at,
+ eventNb:calendar_events(count)
+ )
+ `
+ const partialFields = `
+ id,
+ name,
+ description,
+ color,
+ createdAt:created_at,
+ updatedAt:updated_at,
+ calendars (
+ createdAt:created_at,
+ updatedAt:updated_at,
+ eventNb:calendar_events(count)
+ )
+ `
let output
@@ -23,10 +53,11 @@ export default defineEventHandler(async (event) => {
}
if (query.id) {
- // const eventNb = await client.from('worlds').select('events:calendars(calendar_events(id))').order('events_count')
-
return output.eq("id", query.id).single()
}
+ if (query.gmId) {
+ return output.eq("gm_id", query.gmId).overrideTypes()
+ }
- return output.returns()
+ return output.overrideTypes()
})
diff --git a/stores/CalendarStore.ts b/stores/CalendarStore.ts
index b76ebcd..b678d44 100644
--- a/stores/CalendarStore.ts
+++ b/stores/CalendarStore.ts
@@ -52,7 +52,7 @@ export const useCalendar = defineStore("calendar", () => {
function setReadStatus(gmId: string) {
// If the user is not logged in, or the calendar is not owned by the user, it's read-only
- isReadOnly.value = (!user) || (gmId !== user.value?.id)
+ isReadOnly.value = !user.value || gmId !== user.value.id
}
/**
diff --git a/supabase/migrations/202401_init.sql b/supabase/migrations/202401_init.sql
index f2aaee0..f10ac73 100644
--- a/supabase/migrations/202401_init.sql
+++ b/supabase/migrations/202401_init.sql
@@ -1,6 +1,7 @@
--
-- For use with https://github.com/supabase/supabase/tree/master/examples/slack-clone/nextjs-slack-clone
--
+create extension if not exists moddatetime schema extensions;
-- Custom types
create type public.app_permission as enum ('events.see.hidden', 'users.ban');
@@ -44,9 +45,13 @@ create table public.worlds (
description text,
color app_colors default 'black',
state world_state default 'draft',
+ created_at timestamptz default now(),
+ updated_at timestamptz,
gm_id uuid references public.users on delete cascade
);
comment on table public.worlds is 'Worlds belonging to a single user ; a game master.';
+create trigger handle_updated_at before update on public.worlds
+ for each row execute procedure moddatetime (updated_at);
-- World Players (join table)
create table public.world_players (
@@ -66,9 +71,13 @@ create table public.calendars (
today json not null,
color app_colors default 'black',
state calendar_state default 'draft',
+ created_at timestamptz default now(),
+ updated_at timestamptz,
world_id bigint references public.worlds on delete cascade not null
);
comment on table public.calendars is 'Calendar settings and configuration attached to a single world.';
+create trigger handle_updated_at before update on public.calendars
+ for each row execute procedure moddatetime (updated_at);
-- Calendar Months
create table public.calendar_months (
@@ -100,6 +109,8 @@ create table public.calendar_events (
category bigint references public.calendar_event_categories on delete cascade,
hidden boolean default false,
wiki text,
+ created_at timestamptz default now(),
+ updated_at timestamptz,
calendar_id bigint references public.calendars on delete cascade not null
);
comment on table public.calendar_events is 'Events linked to a world';
@@ -123,9 +134,11 @@ comment on table public.calendar_event_categories_links is 'Link tables for mult
-- Character categories
create table public.character_categories (
- id bigint generated by default as identity primary key,
- name text not null,
- color app_colors default 'black',
+ id bigint generated by default as identity primary key,
+ name text not null,
+ color app_colors default 'black',
+ created_at timestamptz default now(),
+ updated_at timestamptz,
unique (name)
);
comment on table public.character_categories is 'Categories describing characters';
@@ -141,6 +154,8 @@ create table public.characters (
hidden_birth boolean,
hidden_death boolean,
wiki text,
+ created_at timestamptz default now(),
+ updated_at timestamptz,
world_id bigint references public.worlds on delete cascade not null
);
comment on table public.characters is 'Characters linked to a world';