feature: event page

This commit is contained in:
Benno Tielen 2024-12-03 14:33:14 +01:00
parent 5d808f6bd3
commit 388ab0b2e6
13 changed files with 298 additions and 72 deletions

View file

@ -1,11 +1,30 @@
import { notFound } from 'next/navigation'
import { Event } from '@/payload-types'
import { EventPage } from '@/pageComponents/Event/Event'
import { stringify } from 'qs-esm'
export default async function Page({ params }: { params: Promise<{id: string}>}) {
const id = (await params).id;
const res = await fetch(`http://localhost:3000/api/event/${id}?depth=0`);
const stringifiedQuery = stringify(
{
select: {
title: true,
date: true,
createdAt: true,
cancelled: true,
isRecurring: true,
location: true,
description: true,
shortDescription: true,
contact: true,
flyer: true,
photo: true
},
},
{ addQueryPrefix: true },
)
const res = await fetch(`http://localhost:3000/api/event/${id}${stringifiedQuery}`);
if (!res.ok) {
notFound()
@ -24,7 +43,6 @@ export default async function Page({ params }: { params: Promise<{id: string}>})
description={event.description}
shortDescription={event.shortDescription}
contact={event.contact || undefined}
address={event.address || undefined}
flyer={typeof event.flyer === 'object' ? event.flyer || undefined : undefined}
/>
)

View file

@ -0,0 +1,44 @@
import { CollectionConfig } from 'payload'
import { isAdminOrEmployee } from '@/collections/access/admin'
export const ContactPerson: CollectionConfig = {
slug: 'contactPerson',
labels: {
singular: {
de: 'Ansprechpartner'
},
plural: {
de: "Ansprechpartner"
}
},
fields: [
{
name: 'name',
type: 'text',
required: true,
label: {
de: "Name"
}
},
{
name: 'email',
type: 'email',
},
{
name: 'telephone',
type: 'text',
label: {
de: 'Telefon'
}
}
],
admin: {
useAsTitle: "name"
},
access: {
read: () => true,
create: isAdminOrEmployee(),
update: isAdminOrEmployee(),
delete: isAdminOrEmployee(),
},
}

View file

@ -43,19 +43,13 @@ export const Events: CollectionConfig = {
},
{
name: 'location',
type: 'text',
type: 'relationship',
relationTo: 'locations',
required: true,
label: {
de: 'Location'
},
},
{
name: 'address',
type: 'textarea',
label: {
de: 'Addresse'
},
},
{
name: 'parish',
type: 'relationship',
@ -104,7 +98,8 @@ export const Events: CollectionConfig = {
},
{
name: 'contact',
type: 'textarea',
type: 'relationship',
relationTo: 'contactPerson',
label: {
de: "Ansprechperson"
}

View file

@ -0,0 +1,62 @@
import { CollectionConfig } from 'payload'
import { isAdmin, isAdminOrEmployee } from '@/collections/access/admin'
export const Locations: CollectionConfig = {
slug: 'locations',
labels: {
singular: {
de: 'Standort'
},
plural: {
de: 'Standorte'
}
},
fields: [
{
name: 'name',
label: {
de: 'Name'
},
type: 'text',
unique: true,
required: true,
},
{
name: 'address',
label: {
de: 'Addresse'
},
type: 'textarea'
},
{
name: 'coordinates',
type: 'point',
label: {
de: 'Koordinaten'
}
},
{
name: 'notes',
type: 'textarea',
label: {
de: "Hinweise"
}
},
{
name: 'barrierFree',
type: 'checkbox',
label: {
de: "Barrierefrei"
},
defaultValue: false
}
],
admin: {
useAsTitle: 'name'
},
access: {
read: () => true,
update: isAdminOrEmployee(),
delete: isAdmin(),
},
}

View file

@ -45,7 +45,8 @@ export async function fetchEvents(parishId: string | undefined, groupId?: string
date: true,
title: true,
cancelled: true
}
},
depth: 1
},
{ addQueryPrefix: true },
)

View file

@ -23,8 +23,6 @@ export const Default: Story = {
contact: 'Pfarrei Ulrich Kotzur\n' +
'pfarrer@sankt-clara.de\n' +
'+4930 6851042',
address: 'Braunschweiger Str. 18, 12055 Berlin \n' +
'Anfahrt über S-Sonnenallee oder Mareschtraße',
flyer: {
id: "1",
name: "some flyer",

View file

@ -1,5 +1,5 @@
import styles from "./styles.module.scss"
import { Document } from '@/payload-types'
import { ContactPerson, Document, Location } from '@/payload-types'
import { Section } from '@/components/Section/Section'
import { Title } from '@/components/Title/Title'
import { Container } from '@/components/Container/Container'
@ -13,6 +13,8 @@ import { TextDiv } from '@/components/Text/TextDiv'
import { EventExcerpt } from '@/components/EventExcerpt/EventExcerpt'
import { Button } from '@/components/Button/Button'
import { StaticImageData } from 'next/image'
import { locationString } from '@/utils/dto/location'
import { contactPersonString } from '@/utils/dto/contact'
type EventProps = {
title: string,
@ -20,11 +22,10 @@ type EventProps = {
createdAt: string,
cancelled: boolean,
isRecurring?: boolean,
location: string,
location: string | Location,
description: string,
shortDescription: string,
contact?: string,
address?: string,
contact?: string | ContactPerson,
flyer?: Document,
photo?: StaticImageData
}
@ -40,19 +41,14 @@ export function EventPage(
description,
shortDescription,
contact,
address,
flyer,
photo
}: EventProps
) {
const published = useDate(createdAt)
const readableDate = readableDateTime(date)
let where = location;
if (address) {
where += '\n' + address;
}
const where = locationString(location);
const who = contactPersonString(contact)
return (
<>
@ -98,12 +94,16 @@ export function EventPage(
fontStyle={"sans-serif"}
align={"center"}
/>
<Title
size={"md"}
title={location}
fontStyle={"sans-serif"}
align={"center"}
/>
{typeof location === "object" &&
<Title
size={"md"}
title={location.name}
fontStyle={"sans-serif"}
align={"center"}
/>
}
<Section padding={"medium"}>
<div className={styles.description}>
@ -121,7 +121,7 @@ export function EventPage(
<EventExcerpt
what={shortDescription}
where={where}
who={contact}
who={who}
/>
</Section>

View file

@ -16,61 +16,52 @@ export const Default: Story = {
id: '1',
title: 'Event 1',
date: '2024-12-02T09:21:24Z',
location: 'St. Richard',
shortDescription: '',
description: {
root: {
type: '',
children: [],
direction: null,
format: '',
indent: 0,
version: 0,
},
location: {
id: 'l1',
name: "St. Richard",
updatedAt: "",
createdAt: ""
},
shortDescription: '',
description: "Some descripton",
cancelled: false,
updatedAt: '2024-12-02T09:21:24Z',
createdAt: '2024-12-02T09:21:24Z',
isRecurring: false
},
{
id: '2',
title: 'Event 2',
date: '2024-12-05T09:21:24Z',
location: 'St. Clara',
shortDescription: '',
description: {
root: {
type: '',
children: [],
direction: null,
format: '',
indent: 0,
version: 0,
},
location: {
id: 'l1',
name: "St. Richard",
updatedAt: "",
createdAt: ""
},
shortDescription: '',
description: "",
cancelled: false,
updatedAt: '2024-12-02T09:21:24Z',
createdAt: '2024-12-02T09:21:24Z',
isRecurring: false
},
{
id: '2',
title: 'Event 2',
date: '2024-12-08T09:21:24Z',
location: 'St. Hedwig',
shortDescription: '',
description: {
root: {
type: '',
children: [],
direction: null,
format: '',
indent: 0,
version: 0,
},
location: {
id: 'l2',
name: "St. Hedwig",
updatedAt: "",
createdAt: ""
},
shortDescription: '',
description: "",
cancelled: true,
updatedAt: '2024-12-02T09:21:24Z',
createdAt: '2024-12-02T09:21:24Z',
isRecurring: false
},
],
blog: [

View file

@ -18,6 +18,8 @@ export interface Config {
blog: Blog;
highlight: Highlight;
event: Event;
contactPerson: ContactPerson;
locations: Location;
group: Group;
employees: Employee;
testimony: Testimony;
@ -38,6 +40,8 @@ export interface Config {
blog: BlogSelect<false> | BlogSelect<true>;
highlight: HighlightSelect<false> | HighlightSelect<true>;
event: EventSelect<false> | EventSelect<true>;
contactPerson: ContactPersonSelect<false> | ContactPersonSelect<true>;
locations: LocationsSelect<false> | LocationsSelect<true>;
group: GroupSelect<false> | GroupSelect<true>;
employees: EmployeesSelect<false> | EmployeesSelect<true>;
testimony: TestimonySelect<false> | TestimonySelect<true>;
@ -333,11 +337,10 @@ export interface Event {
photo?: (string | null) | Media;
title: string;
date: string;
location: string;
address?: string | null;
location: string | Location;
parish?: (string | Parish)[] | null;
group?: (string | Group)[] | null;
contact?: string | null;
contact?: (string | null) | ContactPerson;
shortDescription: string;
description: string;
flyer?: (string | null) | Document;
@ -346,6 +349,24 @@ export interface Event {
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "locations".
*/
export interface Location {
id: string;
name: string;
address?: string | null;
/**
* @minItems 2
* @maxItems 2
*/
coordinates?: [number, number] | null;
notes?: string | null;
barrierFree?: boolean | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "group".
@ -359,6 +380,18 @@ export interface Group {
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "contactPerson".
*/
export interface ContactPerson {
id: string;
name: string;
email?: string | null;
telephone?: string | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "testimony".
@ -472,6 +505,14 @@ export interface PayloadLockedDocument {
relationTo: 'event';
value: string | Event;
} | null)
| ({
relationTo: 'contactPerson';
value: string | ContactPerson;
} | null)
| ({
relationTo: 'locations';
value: string | Location;
} | null)
| ({
relationTo: 'group';
value: string | Group;
@ -684,7 +725,6 @@ export interface EventSelect<T extends boolean = true> {
title?: T;
date?: T;
location?: T;
address?: T;
parish?: T;
group?: T;
contact?: T;
@ -696,6 +736,30 @@ export interface EventSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "contactPerson_select".
*/
export interface ContactPersonSelect<T extends boolean = true> {
name?: T;
email?: T;
telephone?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "locations_select".
*/
export interface LocationsSelect<T extends boolean = true> {
name?: T;
address?: T;
coordinates?: T;
notes?: T;
barrierFree?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "group_select".

View file

@ -33,7 +33,8 @@ import { Blog } from '@/collections/Blog'
import { Highlight } from '@/collections/Highlight'
import { Pages } from '@/collections/Pages'
import { Documents } from '@/collections/Documents'
import { payloadCloud } from '@payloadcms/plugin-cloud'
import { Locations } from '@/collections/Locations'
import { ContactPerson } from '@/collections/ContactPerson'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
@ -50,6 +51,8 @@ export default buildConfig({
Blog,
Highlight,
Events,
ContactPerson,
Locations,
Groups,
Employees,
Testimony,
@ -87,6 +90,5 @@ export default buildConfig({
sharp,
plugins: [
// storage-adapter-placeholder
payloadCloud()
],
})

29
src/utils/dto/contact.ts Normal file
View file

@ -0,0 +1,29 @@
import { ContactPerson } from '@/payload-types'
/**
* Return contact person as a readable string
*
* e.G
*
* Hans Mustermann
* hans@mustermann.com
* 030-65625885
*/
export const contactPersonString = (c: string | ContactPerson | undefined) => {
if(typeof c === "string" || !c) {
return "Unbekannt"
}
let s = c.name
if (c.email) {
s += '\n' + c.email;
}
if (c.telephone) {
s += '\n' + c.telephone;
}
return s
}

View file

@ -8,7 +8,7 @@ export const transformEvents = (events: Event[]): EventRowProps[] => {
title: e.title,
date: e.date,
href: `/veranstaltungen/${e.id}`,
location: e.location,
location: typeof e.location === "object" ? e.location.name : "Unbekannt",
cancelled: e.cancelled,
}
})

22
src/utils/dto/location.ts Normal file
View file

@ -0,0 +1,22 @@
import {Location} from '@/payload-types'
/**
* Return location as readable string
*/
export const locationString = (location: Location | string) => {
if (typeof location === 'string') {
return "Unbekannt";
}
let s = location.name;
if(location.address) {
s += '\n' + location.address;
}
if(location.notes) {
s += '\n' + location.notes;
}
return s;
}