From 81614e4449b66a153502bf058eafbd328dbe0f73 Mon Sep 17 00:00:00 2001 From: Benno Tielen Date: Mon, 10 Feb 2025 14:54:43 +0100 Subject: [PATCH] feature: admin menu --- src/app/blog/[id]/page.tsx | 8 ++++ .../[year]/[month]/page.tsx | 9 +++++ src/app/gemeinde/[slug]/page.tsx | 39 ++++++++++++------- src/app/gottesdienst/[id]/page.tsx | 14 ++++++- src/app/gottesdienst/page.tsx | 7 ++++ src/app/gruppe/[slug]/page.tsx | 9 +++++ src/app/layout.tsx | 16 ++++---- src/app/veranstaltungen/[id]/page.tsx | 6 +++ src/app/veranstaltungen/page.tsx | 7 ++++ src/components/AdminMenu/AdminMenu.tsx | 26 +++++++++++++ src/components/AdminMenu/styles.module.scss | 19 +++++++++ src/compositions/Footer/Footer.tsx | 2 +- src/pageComponents/Event/Event.stories.tsx | 1 + src/pageComponents/Event/Event.tsx | 14 ++++++- src/utils/auth.ts | 18 +++++++++ 15 files changed, 169 insertions(+), 26 deletions(-) create mode 100644 src/components/AdminMenu/AdminMenu.tsx create mode 100644 src/components/AdminMenu/styles.module.scss create mode 100644 src/utils/auth.ts diff --git a/src/app/blog/[id]/page.tsx b/src/app/blog/[id]/page.tsx index 0133bee..c36edad 100644 --- a/src/app/blog/[id]/page.tsx +++ b/src/app/blog/[id]/page.tsx @@ -9,6 +9,8 @@ import { HR } from '@/components/HorizontalRule/HorizontalRule' import Image from 'next/image' import styles from "./styles.module.scss" import { Blocks } from '@/compositions/Blocks/Blocks' +import { isAuthenticated } from '@/utils/auth' +import { AdminMenu } from '@/components/AdminMenu/AdminMenu' async function fetchBlog(id: string) { const res = await fetch(`http://localhost:3000/api/blog/${id}`) @@ -21,6 +23,7 @@ export default async function BlogPage({ params }: { params: Promise<{id: string const id = (await params).id; const data = await fetchBlog(id) as Blog; const url = typeof data.photo === 'object' && data.photo?.sizes?.banner?.url; + const authenticated = await isAuthenticated(); if(!data) { notFound(); @@ -51,6 +54,11 @@ export default async function BlogPage({ params }: { params: Promise<{id: string + ) diff --git a/src/app/gebetsanliegen-des-papstes/[year]/[month]/page.tsx b/src/app/gebetsanliegen-des-papstes/[year]/[month]/page.tsx index bb01bca..1497c17 100644 --- a/src/app/gebetsanliegen-des-papstes/[year]/[month]/page.tsx +++ b/src/app/gebetsanliegen-des-papstes/[year]/[month]/page.tsx @@ -6,6 +6,8 @@ import { P } from '@/components/Text/Paragraph' import { PageHeader } from '@/compositions/PageHeader/PageHeader' import { NextPrevButtons } from '@/components/NextPrevButtons/NextPrevButtons' import { notFound } from 'next/navigation' +import { isAuthenticated } from '@/utils/auth' +import { AdminMenu } from '@/components/AdminMenu/AdminMenu' const months: Record = { "01": "Januar", @@ -105,6 +107,8 @@ export default async function PrayerIntentionPage({ params }: { params: Promise< notFound(); } + const authenticated = await isAuthenticated() + return ( <> + ) diff --git a/src/app/gemeinde/[slug]/page.tsx b/src/app/gemeinde/[slug]/page.tsx index 00b5073..05eaf67 100644 --- a/src/app/gemeinde/[slug]/page.tsx +++ b/src/app/gemeinde/[slug]/page.tsx @@ -6,6 +6,8 @@ import { fetchParish } from '@/fetch/parish' import { fetchLastAnnouncement } from '@/fetch/announcement' import { transformGallery } from '@/utils/dto/gallery' import { fetchLastCalendar } from '@/fetch/calendar' +import { isAuthenticated } from '@/utils/auth' +import { AdminMenu } from '@/components/AdminMenu/AdminMenu' export default async function ParishPage ({ params }: { params: Promise<{slug: string}>}) { @@ -32,20 +34,29 @@ export default async function ParishPage ({ params }: { params: Promise<{slug: s const worship = await fetchWorship({ locations: churchIds }) const announcement = await fetchLastAnnouncement(id); const calendar = await fetchLastCalendar(id); + const authenticated = await isAuthenticated(); return ( - + <> + + + + ) } \ No newline at end of file diff --git a/src/app/gottesdienst/[id]/page.tsx b/src/app/gottesdienst/[id]/page.tsx index 6705058..1d12ec7 100644 --- a/src/app/gottesdienst/[id]/page.tsx +++ b/src/app/gottesdienst/[id]/page.tsx @@ -1,6 +1,8 @@ import { notFound } from 'next/navigation' import { Worship as WorshipType } from '@/payload-types' import { Worship } from '@/pageComponents/Worship/Worship' +import { isAuthenticated } from '@/utils/auth' +import { AdminMenu } from '@/components/AdminMenu/AdminMenu' export default async function WorshipPage({ params }: { params: Promise<{id: string}>}) { @@ -9,10 +11,20 @@ export default async function WorshipPage({ params }: { params: Promise<{id: str if (!res.ok) { notFound() } + const authenticated = await isAuthenticated(); const worship = await res.json() as WorshipType; return ( - + <> + + + ) } \ No newline at end of file diff --git a/src/app/gottesdienst/page.tsx b/src/app/gottesdienst/page.tsx index d4ebf71..0656be1 100644 --- a/src/app/gottesdienst/page.tsx +++ b/src/app/gottesdienst/page.tsx @@ -9,6 +9,8 @@ import { EventRow } from '@/components/EventRow/EventRow' import Error from '@/pages/_error' import { fetchWorship } from '@/fetch/worship' import { tranformWorship } from '@/utils/dto/worship' +import { AdminMenu } from '@/components/AdminMenu/AdminMenu' +import { isAuthenticated } from '@/utils/auth' export default async function WorshipPage({searchParams}: { @@ -20,6 +22,7 @@ export default async function WorshipPage({searchParams}: { if (!week) { week = weekNumber(moment()); } + const authenticated = await isAuthenticated(); const fromDate = moment(week, true); @@ -76,6 +79,10 @@ export default async function WorshipPage({searchParams}: { } + {events.length > 0 &&
diff --git a/src/app/gruppe/[slug]/page.tsx b/src/app/gruppe/[slug]/page.tsx index 5e47c1d..e1c536f 100644 --- a/src/app/gruppe/[slug]/page.tsx +++ b/src/app/gruppe/[slug]/page.tsx @@ -15,6 +15,8 @@ import { Row } from '@/components/Flex/Row' import { RawHTML } from '@/components/RawHTML/RawHTML' import { Blocks } from '@/compositions/Blocks/Blocks' import { getPhoto } from '@/utils/dto/gallery' +import { isAuthenticated } from '@/utils/auth' +import { AdminMenu } from '@/components/AdminMenu/AdminMenu' export default async function GroupPage({ params }: { params: Promise<{slug: string}>}) { @@ -29,6 +31,7 @@ export default async function GroupPage({ params }: { params: Promise<{slug: str const media = getPhoto("tablet", photo) const events = await fetchEvents({groupId: id}) + const authenticated = await isAuthenticated(); return ( <> @@ -90,6 +93,12 @@ export default async function GroupPage({ params }: { params: Promise<{slug: str { content && content.length > 0 && } + + ) } \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 832425f..2e2bae5 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -60,7 +60,7 @@ export default function RootLayout({ items: [ { title: "Kathoccino", - description: "Brunchgruppe für Jungerwachsene", + description: "Brunchgruppe für junge Erwachsene", href: "/gruppe/kathocchino" }, { @@ -127,7 +127,7 @@ export default function RootLayout({ }, groups: [ { - title: "Sakramenten", + title: "Sakramente", items: [ { title: "Taufe", @@ -146,7 +146,7 @@ export default function RootLayout({ }, { title: "Ehe", - description: "Bund in Liebe, Treue", + description: "Bund in Liebe und Treue", href: "/sakramente/ehe" }, { @@ -196,7 +196,7 @@ export default function RootLayout({ items: [ { title: "Alphakurs", - description: "Freude am glauben entdecken", + description: "Freude am Glauben entdecken", href: "/gruppe/alphakurs" }, { @@ -228,11 +228,11 @@ export default function RootLayout({ { href: '/gruppe/waermestube', title: 'Wärmestube', - description: 'Kälteschutz für Bedurftigen', + description: 'Kälteschutz für Bedurftige', }, { href: '/gruppe/essen-ist-fertig', - title: 'Essen ist Fertig', + title: 'Essen ist fertig', description: 'Essensausgabe Neukölln', }, { @@ -252,8 +252,8 @@ export default function RootLayout({ }, { href: '/gruppe/die-unterstuetzer', - title: 'Anpacken & gutes tun', - description: 'Kinderbertreuung, Hilfe bei.., Kirchenreinigung', + title: 'Anpacken & Gutes tun', + description: 'Hilfe bei Kirchenreinigung und anderem', }, ] } diff --git a/src/app/veranstaltungen/[id]/page.tsx b/src/app/veranstaltungen/[id]/page.tsx index 864c3bd..712e4b3 100644 --- a/src/app/veranstaltungen/[id]/page.tsx +++ b/src/app/veranstaltungen/[id]/page.tsx @@ -3,6 +3,8 @@ import { Event } from '@/payload-types' import { EventPage } from '@/pageComponents/Event/Event' import { stringify } from 'qs-esm' import { getPhoto } from '@/utils/dto/gallery' +import { cookies } from 'next/headers' +import { isAuthenticated } from '@/utils/auth' export default async function Page({ params }: { params: Promise<{id: string}>}) { @@ -33,12 +35,15 @@ export default async function Page({ params }: { params: Promise<{id: string}>}) notFound() } + const authenticated = await isAuthenticated(); + const event = await res.json() as Event; const group = Array.isArray(event.group) && event.group.length > 0 && typeof event.group[0] == "object" ? event.group[0].slug : undefined; const photo = getPhoto("tablet", event.photo); return ( }) rsvpLink={event.rsvpLink || undefined} flyer={typeof event.flyer === 'object' ? event.flyer || undefined : undefined} photo={photo} + isAuthenticated={authenticated} /> ) } \ No newline at end of file diff --git a/src/app/veranstaltungen/page.tsx b/src/app/veranstaltungen/page.tsx index 61af9e3..b3a5064 100644 --- a/src/app/veranstaltungen/page.tsx +++ b/src/app/veranstaltungen/page.tsx @@ -13,12 +13,15 @@ import { Row } from '@/components/Flex/Row' import { Col } from '@/components/Flex/Col' import { highlightLink } from '@/utils/dto/highlight' import Error from '@/pages/_error' +import { AdminMenu } from '@/components/AdminMenu/AdminMenu' +import { isAuthenticated } from '@/utils/auth' export default async function EventsPage({searchParams}: { searchParams: Promise<{ week: string | undefined }> }) { + const authenticated = await isAuthenticated(); const query = await searchParams; const limit = 100; let week = query.week; @@ -116,6 +119,10 @@ export default async function EventsPage({searchParams}: {
+ {/*prevents bots indexing till infinity*/} { events.length > 0 && diff --git a/src/components/AdminMenu/AdminMenu.tsx b/src/components/AdminMenu/AdminMenu.tsx new file mode 100644 index 0000000..da6234b --- /dev/null +++ b/src/components/AdminMenu/AdminMenu.tsx @@ -0,0 +1,26 @@ +import styles from "./styles.module.scss" + +type AdminEditButtonProps = { + collection: string, + id?: string, + isAuthenticated: boolean, +} + +export const AdminMenu = ({ collection, id, isAuthenticated}: AdminEditButtonProps) => { + + if(!isAuthenticated) + return null; + + return ( +
+ Admin + Neu erstellen + {id && + Bearbeiten + + } + Abmelden +
+ + ) +} \ No newline at end of file diff --git a/src/components/AdminMenu/styles.module.scss b/src/components/AdminMenu/styles.module.scss new file mode 100644 index 0000000..f0f9a58 --- /dev/null +++ b/src/components/AdminMenu/styles.module.scss @@ -0,0 +1,19 @@ +.menu { + position: fixed; + bottom: 0; + width: 100%; + box-sizing: border-box; + left: 0; + background-color: rgba(238, 238, 238, 0.60); + backdrop-filter: blur(8px); + display: flex; + gap: 20px; + justify-content: flex-end; + padding-right: 20px; +} + +.menu a { + padding: 10px 0; + font-size: 14px; + color: #23362c; +} \ No newline at end of file diff --git a/src/compositions/Footer/Footer.tsx b/src/compositions/Footer/Footer.tsx index 9b0daf0..f5bc3df 100644 --- a/src/compositions/Footer/Footer.tsx +++ b/src/compositions/Footer/Footer.tsx @@ -31,7 +31,7 @@ export const Footer = () => {

  • Kontakt
  • -
  • Gottesdiensten
  • +
  • Gottesdienste
  • Datenschutz
  • Schutzkonzept
  • Impressum
  • diff --git a/src/pageComponents/Event/Event.stories.tsx b/src/pageComponents/Event/Event.stories.tsx index dcbb9d4..b889e1e 100644 --- a/src/pageComponents/Event/Event.stories.tsx +++ b/src/pageComponents/Event/Event.stories.tsx @@ -11,6 +11,7 @@ export default meta export const Default: Story = { args: { + id: "testid", title: "Sing & Pray", date: "2024-12-02T09:21:19Z", createdAt: "2024-12-02T09:21:19Z", diff --git a/src/pageComponents/Event/Event.tsx b/src/pageComponents/Event/Event.tsx index 45a5ca2..1e13861 100644 --- a/src/pageComponents/Event/Event.tsx +++ b/src/pageComponents/Event/Event.tsx @@ -15,8 +15,10 @@ import { StaticImageData } from 'next/image' import { locationString } from '@/utils/dto/location' import { ContactPerson2 } from '@/components/ContactPerson2/ContactPerson2' import { getPhoto } from '@/utils/dto/gallery' +import { AdminMenu } from '@/components/AdminMenu/AdminMenu' type EventProps = { + id: string, title: string, date: string, createdAt: string, @@ -29,11 +31,13 @@ type EventProps = { group?: string, flyer?: Document, photo?: StaticImageData, - rsvpLink?: string + rsvpLink?: string, + isAuthenticated: boolean } export function EventPage( { + id, title, date, createdAt, @@ -46,7 +50,8 @@ export function EventPage( flyer, group, photo, - rsvpLink + rsvpLink, + isAuthenticated }: EventProps ) { const published = useDate(createdAt) @@ -165,6 +170,11 @@ export function EventPage(
    + ) } \ No newline at end of file diff --git a/src/utils/auth.ts b/src/utils/auth.ts new file mode 100644 index 0000000..1db3b39 --- /dev/null +++ b/src/utils/auth.ts @@ -0,0 +1,18 @@ +import { cookies } from 'next/headers' + +/** + * Check if the current user is (trying to be) authenticated by + * checking if the `payload-token` is present. + * + * Warning: DO NOT USE THIS FUNCTION TO SECURE PARTS OF THE APPLICATION + */ +export const isAuthenticated = async (): Promise => { + const cookieStore = await cookies(); + const token = cookieStore.get("payload-token"); + + if(typeof token === "undefined") { + return false; + } + + return true; +} \ No newline at end of file