From 09a23ade13c6570b14d76e177b1056b5fb88fceb Mon Sep 17 00:00:00 2001 From: Ferdinand Salis-Samaden Date: Tue, 14 Jan 2025 16:06:58 +0100 Subject: [PATCH] Add event schema type --- app/sanity/schema/event.tsx | 200 ++++++++++++++++++++++++++++++++++++ app/sanity/schema/index.ts | 2 + sanity.config.ts | 3 +- 3 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 app/sanity/schema/event.tsx diff --git a/app/sanity/schema/event.tsx b/app/sanity/schema/event.tsx new file mode 100644 index 0000000..9d4bafa --- /dev/null +++ b/app/sanity/schema/event.tsx @@ -0,0 +1,200 @@ +import { Calendar1Icon } from 'lucide-react' +import { defineField, defineType, ObjectInputProps } from 'sanity' +import { z } from 'zod' + +export const AttachmentSchema = z.object({ + _type: z.literal('file'), + asset: z.object({ + _type: z.literal('reference'), + _ref: z.string(), + }), +}) + +export const EventSchema = z.object({ + title: z.string(), + location: z.string().nullable(), + description: z.string().nullable(), + start: z.union([ + z.object({ + date: z.string(), + dateTime: z.string().nullable(), + }), + z.object({ + date: z.string().nullable(), + dateTime: z.string(), + }), + ]), + end: z.union([ + z.object({ + date: z.string(), + dateTime: z.string().nullable(), + }), + z.object({ + date: z.string().nullable(), + dateTime: z.string(), + }), + ]), + type: z.union([ + z.literal('general'), + z.literal('internal'), + z.literal('year'), + ]), + attachments: z.array(AttachmentSchema), +}) + +export type Event = z.infer + +function MyTimeInput(props: ObjectInputProps) { + return +} + +export default defineType({ + name: 'event', + title: 'Ereignis', + type: 'document', + icon: Calendar1Icon, + fields: [ + defineField({ + name: 'title', + type: 'string', + title: 'Titel', + validation: Rule => Rule.required(), + }), + defineField({ + name: 'description', + type: 'array', + title: 'Beschreibung', + of: [{ type: 'block' }], + }), + defineField({ + name: 'location', + type: 'string', + title: 'Ort', + }), + defineField({ + name: 'type', + type: 'string', + title: 'Typ', + options: { + list: [ + { title: 'Allgemein', value: 'general' }, + { title: 'Intern', value: 'internal' }, + { title: 'Jahrgang', value: 'year' }, + ], + }, + validation: Rule => Rule.required(), + }), + defineField({ + name: 'year', + type: 'reference', + title: 'Jahrgang', + to: [{ type: 'year' }], + weak: true, + hidden: ({ document }) => document?.type !== 'year', + }), + defineField({ + name: 'attachments', + type: 'array', + title: 'Anhänge', + of: [{ type: 'file' }], + options: { + layout: 'grid', + }, + }), + // timezone is constant for all events and for start and end + defineField({ + name: 'timeZone', + type: 'string', + title: 'Zeitzone', + hidden: true, + initialValue: 'Europe/Vienna', + }), + defineField({ + name: 'start', + type: 'object', + title: 'Start', + validation: rule => rule.required(), + fields: [ + defineField({ + name: 'date', + type: 'date', + title: 'Datum', + validation: rule => rule.required(), + }), + defineField({ + name: 'time', + type: 'string', + title: 'Uhrzeit', + components: { + // @ts-ignore + input: MyTimeInput, + }, + }), + ], + }), + defineField({ + name: 'end', + type: 'object', + title: 'Ende', + validation: rule => + rule.custom((end, context) => { + if (end?.date && end?.time) { + return true + } + if (!end?.date && end?.time) { + return 'Enddatum fehlt' + } + if (end?.date && context.document?.start) { + // @ts-ignore + const startDate = new Date(context.document.start.date) + // @ts-ignore + const endDate = new Date(end.date) + if (endDate < startDate) { + return 'Enddatum liegt vor dem Startdatum' + } + } + return true + }), + fields: [ + defineField({ + name: 'date', + type: 'date', + title: 'Datum', + }), + defineField({ + name: 'time', + type: 'string', + title: 'Uhrzeit', + components: { + // @ts-ignore + input: MyTimeInput, + }, + }), + ], + }), + ], + preview: { + select: { + title: 'title', + start: 'start', + end: 'end', + }, + prepare({ title, start, end }) { + const startString = new Date(start?.date).toLocaleDateString('de-AT') + const endString = end?.date + ? new Date(end.date).toLocaleDateString('de-AT') + : '' + return { + title: title, + subtitle: startString + (endString ? ' - ' + endString : ''), + } + }, + }, + orderings: [ + { + title: 'Startdatum, Absteigend', + name: 'start', + by: [{ field: 'start.date', direction: 'desc' }], + }, + ], +}) diff --git a/app/sanity/schema/index.ts b/app/sanity/schema/index.ts index 13bf524..8109135 100644 --- a/app/sanity/schema/index.ts +++ b/app/sanity/schema/index.ts @@ -1,5 +1,6 @@ import costs from './costs.ts' import { curriculum, project } from './curriculum.ts' +import event from './event.tsx' import homeHero from './home-hero.ts' import person from './person.ts' import post from './post.ts' @@ -8,6 +9,7 @@ import testimonial from './testimonial.ts' import year from './year.ts' export const schemaTypes = [ + event, homeHero, testimonial, schoolYear, diff --git a/sanity.config.ts b/sanity.config.ts index 8e1b197..af70877 100644 --- a/sanity.config.ts +++ b/sanity.config.ts @@ -21,11 +21,12 @@ export default defineConfig({ .title('Content') .items([ S.documentTypeListItem('post').title('Posts'), + S.documentTypeListItem('event').title('Ereignisse'), S.divider(), - S.documentTypeListItem('schoolYear').title('Schuljahr'), S.documentTypeListItem('costs').title('Kosten'), S.documentTypeListItem('person').title('Personen'), S.documentTypeListItem('year').title('Jahrgang'), + S.documentTypeListItem('schoolYear').title('Schuljahr'), S.documentTypeListItem('testimonial').title('Erfahrungsberichte'), S.divider(),