diff --git a/src/app/gemeinde/[slug]/page.tsx b/src/app/gemeinde/[slug]/page.tsx index 51632c3..3bbb4c9 100644 --- a/src/app/gemeinde/[slug]/page.tsx +++ b/src/app/gemeinde/[slug]/page.tsx @@ -1,42 +1,35 @@ -import { PaginatedDocs } from 'payload' -import { Parish as ParishType } from '@/payload-types' import { notFound } from 'next/navigation' -import { Parish } from "@/pageComponents/Parish/Parish" -import { stringify } from 'qs-esm' +import { Parish } from '@/pageComponents/Parish/Parish' import { fetchEvents } from '@/fetch/events' import { fetchWorship } from '@/fetch/worship' - -async function fetchParish(slug: string) { - const query = { - slug: { - equals: slug - } - } - - const stringifiedQuery = stringify( - { - where: query, - }, - { addQueryPrefix: true }, - ) - - const res = await fetch(`http://localhost:3000/api/parish${stringifiedQuery}`) - if (!res.ok) return undefined - return res.json(); -} +import { fetchParish } from '@/fetch/parish' +import { fetchLastAnnouncement } from '@/fetch/announcement' +import { transformGallery } from '@/utils/dto/gallery' export default async function ParishPage ({ params }: { params: Promise<{slug: string}>}) { const slug = (await params).slug; - const parish = await fetchParish(slug) as PaginatedDocs + const parish = await fetchParish(slug); - if(!parish.docs[0]) { + if(!parish || !parish.docs[0]) { notFound(); } - const { id, name, description, history, contactPersons, contact, photo, churches } = parish.docs[0] + const { + id, + name, + description, + history, + contactPersons, + contact, + photo, + churches, + gallery + } = parish.docs[0] const events = await fetchEvents(id) const worship = await fetchWorship(churches.map(c => typeof c === "string" ? c : c.id)) + const announcement = await fetchLastAnnouncement(id); + console.log(gallery) return ( ) } \ No newline at end of file diff --git a/src/collections/Announcements.ts b/src/collections/Announcements.ts index 2d9463e..98cc91a 100644 --- a/src/collections/Announcements.ts +++ b/src/collections/Announcements.ts @@ -2,7 +2,7 @@ import { CollectionConfig } from 'payload' import { isAdminOrEmployee } from '@/collections/access/admin' export const Announcements: CollectionConfig = { - slug: 'vermeldungen', + slug: 'announcement', labels: { singular: { de: 'Vermeldung' @@ -30,9 +30,19 @@ export const Announcements: CollectionConfig = { de: "Gemeinde" }, admin: { - allowCreate: false + allowCreate: false, + allowEdit: false } }, + { + name: 'document', + label: { + de: "PDF-Dokument" + }, + type: 'upload', + relationTo: 'documents', + required: true + } ], access: { read: () => true, diff --git a/src/collections/Parish.ts b/src/collections/Parish.ts index 0ec3201..aedf86b 100644 --- a/src/collections/Parish.ts +++ b/src/collections/Parish.ts @@ -110,10 +110,33 @@ export const Parish: CollectionConfig = { }, { name: 'photo', + label: { + de: "Hauptbild" + }, type: 'upload', relationTo: 'media', required: true }, + { + name: 'gallery', + label: { + de: 'Weitere Bilder' + }, + type: 'array', + fields: [ + { + name: 'photo', + label: { + de: 'Bild' + }, + type: 'upload', + relationTo: 'media', + required: true + }, + ], + minRows: 3, + maxRows: 12 + } ], admin: { useAsTitle: 'name', diff --git a/src/components/Gallery/Gallery.tsx b/src/components/Gallery/Gallery.tsx index 48528b1..5f6dbc2 100644 --- a/src/components/Gallery/Gallery.tsx +++ b/src/components/Gallery/Gallery.tsx @@ -36,7 +36,6 @@ const GalleryItem = ({ thumbnail, alt, onClick }: GalleryItemProps) => { export const Gallery = ({ items }: GalleryProps) => { const [display, setDisplay] = useState(false) const [idx, setIdx] = useState(0) - const { image, alt } = items[idx] const displayImage = useCallback((n: number) => { setIdx(n); setDisplay(true); @@ -46,6 +45,11 @@ export const Gallery = ({ items }: GalleryProps) => { setIdx((idx + 1) % items.length) }, [idx, setIdx, items]) + if(items.length == 0) { + return null; + } + + const { image, alt } = items[idx] return ( <>
diff --git a/src/fetch/announcement.ts b/src/fetch/announcement.ts new file mode 100644 index 0000000..3607c15 --- /dev/null +++ b/src/fetch/announcement.ts @@ -0,0 +1,41 @@ +import { stringify } from 'qs-esm' +import { Announcement } from '@/payload-types' +import { PaginatedDocs } from 'payload' + +/** + * Fetch last announcement for a parish + */ +export const fetchLastAnnouncement = async (parishId: string): Promise => { + const date = new Date(); + date.setDate(date.getDate() - 14) + + const query: any = { + and: [ + { + parish: { + equals: parishId + } + }, + { + date: { + greater_than_equal: date.toISOString(), + } + } + ] + + } + + const stringifiedQuery = stringify( + { + sort: "-date", + where: query, + limit: 1, + }, + { addQueryPrefix: true }, + ) + + const response = await fetch(`http://localhost:3000/api/announcement${stringifiedQuery}`) + if (!response.ok) return undefined + const announcements = await response.json() as PaginatedDocs + return announcements.docs[0] +} \ No newline at end of file diff --git a/src/fetch/parish.ts b/src/fetch/parish.ts new file mode 100644 index 0000000..00da845 --- /dev/null +++ b/src/fetch/parish.ts @@ -0,0 +1,22 @@ +import { stringify } from 'qs-esm' +import { PaginatedDocs } from 'payload' +import { Parish } from '@/payload-types' + +export async function fetchParish(slug: string): Promise | undefined> { + const query = { + slug: { + equals: slug, + }, + } + + const stringifiedQuery = stringify( + { + where: query, + }, + { addQueryPrefix: true }, + ) + + const res = await fetch(`http://localhost:3000/api/parish${stringifiedQuery}`) + if (!res.ok) return undefined + return res.json() +} \ No newline at end of file diff --git a/src/pageComponents/Parish/Parish.tsx b/src/pageComponents/Parish/Parish.tsx index 1043fc2..0a5a56e 100644 --- a/src/pageComponents/Parish/Parish.tsx +++ b/src/pageComponents/Parish/Parish.tsx @@ -11,8 +11,10 @@ import { MarginBottom } from '@/components/Margin/MarbinBottom' import { ContactPersonList } from '@/components/ContactPerson/ContactPersonList' import { Event, Worship } from '@/payload-types' import { transformEvents } from '@/utils/dto/events' -import { ChurchWithContact } from '@/compositions/ChurchWithContact/ChurchWithContact' import { tranformWorship } from '@/utils/dto/worship' +import { Button } from '@/components/Button/Button' +import { TextDiv } from '@/components/Text/TextDiv' +import { Gallery, GalleryItem } from '@/components/Gallery/Gallery' type ParishProps = { title: string, @@ -27,11 +29,28 @@ type ParishProps = { contact: string events: Event[], worship: Worship[] + announcement?: string + gallery?: GalleryItem[] } -export const Parish = ({title, slug, image, description, history, contactPersons, contact, events, worship}: ParishProps) => { +export const Parish = ( + { + title, + slug, + image, + description, + history, + contactPersons, + contact, + events, + worship, + announcement, + gallery + } + : ParishProps +) => { return ( <> @@ -53,6 +72,12 @@ export const Parish = ({title, slug, image, description, history, contactPersons <ContactPersonList persons={contactPersons} /> + + <Section padding={"small"}> + { announcement && + <Button href={announcement} size={"md"}>Aktuelle Vermeldungen</Button> + } + </Section> </Col> </Row> </Container> @@ -65,9 +90,17 @@ export const Parish = ({title, slug, image, description, history, contactPersons </Container> </Section> + { gallery && gallery.length > 0 && + <Section> + <Gallery items={gallery} /> + </Section> + } + + <Section> - <Container> - <ChurchWithContact church={title} contact={contact} /> + <Container textAlign={"center"}> + <Title title={"Kontakt"} size={"md"} align={"center"} /> + <TextDiv text={contact} /> </Container> </Section> </> diff --git a/src/payload-types.ts b/src/payload-types.ts index a869a3c..0dc88cf 100644 --- a/src/payload-types.ts +++ b/src/payload-types.ts @@ -14,7 +14,7 @@ export interface Config { parish: Parish; church: Church; worship: Worship; - vermeldungen: Vermeldungen; + announcement: Announcement; blog: Blog; highlight: Highlight; event: Event; @@ -34,7 +34,7 @@ export interface Config { parish: ParishSelect<false> | ParishSelect<true>; church: ChurchSelect<false> | ChurchSelect<true>; worship: WorshipSelect<false> | WorshipSelect<true>; - vermeldungen: VermeldungenSelect<false> | VermeldungenSelect<true>; + announcement: AnnouncementSelect<false> | AnnouncementSelect<true>; blog: BlogSelect<false> | BlogSelect<true>; highlight: HighlightSelect<false> | HighlightSelect<true>; event: EventSelect<false> | EventSelect<true>; @@ -102,6 +102,12 @@ export interface Parish { history: string; contact: string; photo: string | Media; + gallery?: + | { + photo: string | Media; + id?: string | null; + }[] + | null; updatedAt: string; createdAt: string; } @@ -202,15 +208,35 @@ export interface Worship { } /** * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "vermeldungen". + * via the `definition` "announcement". */ -export interface Vermeldungen { +export interface Announcement { id: string; date: string; parish: (string | Parish)[]; + document: string | Document; updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "documents". + */ +export interface Document { + id: string; + name: string; + updatedAt: string; + createdAt: string; + url?: string | null; + thumbnailURL?: string | null; + filename?: string | null; + mimeType?: string | null; + filesize?: number | null; + width?: number | null; + height?: number | null; + focalX?: number | null; + focalY?: number | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "blog". @@ -272,25 +298,6 @@ export interface Blog { updatedAt: string; createdAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "documents". - */ -export interface Document { - id: string; - name: string; - updatedAt: string; - createdAt: string; - url?: string | null; - thumbnailURL?: string | null; - filename?: string | null; - mimeType?: string | null; - filesize?: number | null; - width?: number | null; - height?: number | null; - focalX?: number | null; - focalY?: number | null; -} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "highlight". @@ -459,8 +466,8 @@ export interface PayloadLockedDocument { value: string | Worship; } | null) | ({ - relationTo: 'vermeldungen'; - value: string | Vermeldungen; + relationTo: 'announcement'; + value: string | Announcement; } | null) | ({ relationTo: 'blog'; @@ -564,6 +571,12 @@ export interface ParishSelect<T extends boolean = true> { history?: T; contact?: T; photo?: T; + gallery?: + | T + | { + photo?: T; + id?: T; + }; updatedAt?: T; createdAt?: T; } @@ -595,11 +608,12 @@ export interface WorshipSelect<T extends boolean = true> { } /** * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "vermeldungen_select". + * via the `definition` "announcement_select". */ -export interface VermeldungenSelect<T extends boolean = true> { +export interface AnnouncementSelect<T extends boolean = true> { date?: T; parish?: T; + document?: T; updatedAt?: T; createdAt?: T; } diff --git a/src/payload.config.ts b/src/payload.config.ts index cbbf33a..0f5e17c 100644 --- a/src/payload.config.ts +++ b/src/payload.config.ts @@ -33,7 +33,6 @@ import { Blog } from '@/collections/Blog' import { Highlight } from '@/collections/Highlight' import { Pages } from '@/collections/Pages' import { Documents } from '@/collections/Documents' -import { Underdog } from 'next/dist/compiled/@next/font/dist/google' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename)