feature: event page
This commit is contained in:
parent
5d808f6bd3
commit
388ab0b2e6
13 changed files with 298 additions and 72 deletions
|
|
@ -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}
|
||||
/>
|
||||
)
|
||||
|
|
|
|||
44
src/collections/ContactPerson.ts
Normal file
44
src/collections/ContactPerson.ts
Normal 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(),
|
||||
},
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
62
src/collections/Locations.ts
Normal file
62
src/collections/Locations.ts
Normal 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(),
|
||||
},
|
||||
}
|
||||
|
|
@ -45,7 +45,8 @@ export async function fetchEvents(parishId: string | undefined, groupId?: string
|
|||
date: true,
|
||||
title: true,
|
||||
cancelled: true
|
||||
}
|
||||
},
|
||||
depth: 1
|
||||
},
|
||||
{ addQueryPrefix: true },
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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: [
|
||||
|
|
|
|||
|
|
@ -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".
|
||||
|
|
|
|||
|
|
@ -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
29
src/utils/dto/contact.ts
Normal 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
|
||||
}
|
||||
|
|
@ -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
22
src/utils/dto/location.ts
Normal 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;
|
||||
}
|
||||
Loading…
Reference in a new issue