feature: parish magazine
This commit is contained in:
parent
4c7825ce4e
commit
f85c50757d
9 changed files with 6978 additions and 12 deletions
47
src/collections/Magazine.ts
Normal file
47
src/collections/Magazine.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { CollectionConfig } from 'payload'
|
||||
import { isAdminOrEmployee } from '@/collections/access/admin'
|
||||
|
||||
export const Magazine: CollectionConfig = {
|
||||
slug: 'magazine',
|
||||
labels: {
|
||||
singular: {
|
||||
de: 'Nordlicht Ausgabe'
|
||||
},
|
||||
plural: {
|
||||
de: 'Nordlicht Ausgaben'
|
||||
}
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'cover',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
label: {
|
||||
de: 'Titelblatt'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'document',
|
||||
type: 'upload',
|
||||
relationTo: 'documents',
|
||||
label: {
|
||||
de: 'PDF-dokument'
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
type: 'date',
|
||||
label: {
|
||||
de: 'Datum'
|
||||
},
|
||||
required: true
|
||||
}
|
||||
],
|
||||
access: {
|
||||
read: () => true,
|
||||
update: isAdminOrEmployee(),
|
||||
delete: isAdminOrEmployee()
|
||||
},
|
||||
}
|
||||
|
|
@ -6,9 +6,9 @@ import { Title } from '@/components/Title/Title'
|
|||
import { NewsletterItem } from '@/compositions/PublicationAndNewsletter/NewsletterItem'
|
||||
import styles from "./styles.module.scss"
|
||||
import Image from 'next/image'
|
||||
import nordlicht from "./nordlicht.png"
|
||||
import envelope from "./envelope.svg"
|
||||
import Sandbox from '@nyariv/sandboxjs'
|
||||
import { fetchLastMagazine } from '@/fetch/magazine'
|
||||
|
||||
type NewsletterData = {
|
||||
guid: string,
|
||||
|
|
@ -40,25 +40,33 @@ export const PublicationAndNewsletter = async () => {
|
|||
console.error("Could not fetch newsletters. Please check PublicationAndNewsletter component")
|
||||
}
|
||||
|
||||
const magazine = await fetchLastMagazine();
|
||||
const magazine_url = magazine && typeof magazine.document === "object" ? magazine.document.url || undefined : undefined;
|
||||
const magazine_cover = magazine && typeof magazine.cover === "object" ? magazine.cover : undefined;
|
||||
|
||||
return (
|
||||
<Section backgroundColor={"off-white"}>
|
||||
<Container>
|
||||
<Row alignItems={"center"}>
|
||||
<Col>
|
||||
<a href={"https://storage.googleapis.com/dreikoenige/documents/nordlicht78-web-1.pdf"} target={"_blank"}>
|
||||
<Image
|
||||
className={styles.image}
|
||||
src={nordlicht}
|
||||
alt={"Pfarreimagazin Ausgabe 67"}
|
||||
/>
|
||||
</a>
|
||||
{magazine_url && magazine_cover && magazine_cover.url &&
|
||||
<a href={magazine_url} target={'_blank'}>
|
||||
<Image
|
||||
className={styles.image}
|
||||
src={magazine_cover.url}
|
||||
width={magazine_cover.width || 500}
|
||||
height={magazine_cover.height || 600}
|
||||
alt={'Pfarreimagazin Ausgabe'}
|
||||
/>
|
||||
</a>
|
||||
}
|
||||
</Col>
|
||||
<Col>
|
||||
<div className={styles.titleContainer}>
|
||||
<Image src={envelope} alt={"Newsletter icon"}/>
|
||||
<Image src={envelope} alt={'Newsletter icon'} />
|
||||
<Title
|
||||
title={"Newsletter aus dem Bistum"}
|
||||
size={"md"}
|
||||
title={'Newsletter aus dem Bistum'}
|
||||
size={'md'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 743 KiB |
27
src/fetch/magazine.ts
Normal file
27
src/fetch/magazine.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { stringify } from 'qs-esm'
|
||||
import { PaginatedDocs } from 'payload'
|
||||
import { Magazine } from '@/payload-types'
|
||||
|
||||
/**
|
||||
* Asynchronously fetches the last magazine entry from the specified API endpoint.
|
||||
*
|
||||
* This function sends a request to the specified API endpoint to fetch the last magazine based on the given sorting criteria.
|
||||
*
|
||||
* @returns {Promise<Magazine | undefined>} A Promise that resolves to the last fetched magazine entry if successful, or undefined if an error occurs.
|
||||
*/
|
||||
export const fetchLastMagazine = async (): Promise<Magazine | undefined> => {
|
||||
|
||||
const stringifiedQuery = stringify(
|
||||
{
|
||||
sort: "-date",
|
||||
limit: 1,
|
||||
},
|
||||
{ addQueryPrefix: true },
|
||||
)
|
||||
|
||||
const response = await fetch(`http://localhost:3000/api/magazine${stringifiedQuery}`)
|
||||
if (!response.ok) return undefined
|
||||
const announcements = await response.json() as PaginatedDocs<Magazine>
|
||||
return announcements.docs[0]
|
||||
|
||||
}
|
||||
6793
src/migrations/20250827_093559_magazine.json
Normal file
6793
src/migrations/20250827_093559_magazine.json
Normal file
File diff suppressed because it is too large
Load diff
54
src/migrations/20250827_093559_magazine.ts
Normal file
54
src/migrations/20250827_093559_magazine.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
|
||||
|
||||
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
|
||||
await db.execute(sql`
|
||||
CREATE TABLE IF NOT EXISTS "magazine" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"cover_id" uuid NOT NULL,
|
||||
"document_id" uuid NOT NULL,
|
||||
"date" timestamp(3) with time zone NOT NULL,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2025-08-31T09:35:59.090Z';
|
||||
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2025-08-31T09:35:59.222Z';
|
||||
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2025-09-26T09:35:59.313Z';
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD COLUMN "magazine_id" uuid;
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "magazine" ADD CONSTRAINT "magazine_cover_id_media_id_fk" FOREIGN KEY ("cover_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "magazine" ADD CONSTRAINT "magazine_document_id_documents_id_fk" FOREIGN KEY ("document_id") REFERENCES "public"."documents"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "magazine_cover_idx" ON "magazine" USING btree ("cover_id");
|
||||
CREATE INDEX IF NOT EXISTS "magazine_document_idx" ON "magazine" USING btree ("document_id");
|
||||
CREATE INDEX IF NOT EXISTS "magazine_updated_at_idx" ON "magazine" USING btree ("updated_at");
|
||||
CREATE INDEX IF NOT EXISTS "magazine_created_at_idx" ON "magazine" USING btree ("created_at");
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_magazine_fk" FOREIGN KEY ("magazine_id") REFERENCES "public"."magazine"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "payload_locked_documents_rels_magazine_id_idx" ON "payload_locked_documents_rels" USING btree ("magazine_id");`)
|
||||
}
|
||||
|
||||
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
|
||||
await db.execute(sql`
|
||||
ALTER TABLE "magazine" DISABLE ROW LEVEL SECURITY;
|
||||
DROP TABLE "magazine" CASCADE;
|
||||
ALTER TABLE "payload_locked_documents_rels" DROP CONSTRAINT "payload_locked_documents_rels_magazine_fk";
|
||||
|
||||
DROP INDEX IF EXISTS "payload_locked_documents_rels_magazine_id_idx";
|
||||
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2025-08-24T14:31:15.010Z';
|
||||
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2025-08-24T14:31:15.092Z';
|
||||
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2025-09-17T14:31:15.112Z';
|
||||
ALTER TABLE "payload_locked_documents_rels" DROP COLUMN IF EXISTS "magazine_id";`)
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import * as migration_20250319_101337_donationbox from './20250319_101337_donati
|
|||
import * as migration_20250322_134918_classifieds from './20250322_134918_classifieds';
|
||||
import * as migration_20250608_105124_new_blocks from './20250608_105124_new_blocks';
|
||||
import * as migration_20250818_143115_menu from './20250818_143115_menu';
|
||||
import * as migration_20250827_093559_magazine from './20250827_093559_magazine';
|
||||
|
||||
export const migrations = [
|
||||
{
|
||||
|
|
@ -58,6 +59,11 @@ export const migrations = [
|
|||
{
|
||||
up: migration_20250818_143115_menu.up,
|
||||
down: migration_20250818_143115_menu.down,
|
||||
name: '20250818_143115_menu'
|
||||
name: '20250818_143115_menu',
|
||||
},
|
||||
{
|
||||
up: migration_20250827_093559_magazine.up,
|
||||
down: migration_20250827_093559_magazine.down,
|
||||
name: '20250827_093559_magazine'
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export interface Config {
|
|||
contactPerson: ContactPerson;
|
||||
locations: Location;
|
||||
group: Group;
|
||||
magazine: Magazine;
|
||||
documents: Document;
|
||||
media: Media;
|
||||
users: User;
|
||||
|
|
@ -46,6 +47,7 @@ export interface Config {
|
|||
contactPerson: ContactPersonSelect<false> | ContactPersonSelect<true>;
|
||||
locations: LocationsSelect<false> | LocationsSelect<true>;
|
||||
group: GroupSelect<false> | GroupSelect<true>;
|
||||
magazine: MagazineSelect<false> | MagazineSelect<true>;
|
||||
documents: DocumentsSelect<false> | DocumentsSelect<true>;
|
||||
media: MediaSelect<false> | MediaSelect<true>;
|
||||
users: UsersSelect<false> | UsersSelect<true>;
|
||||
|
|
@ -532,6 +534,18 @@ export interface Classified {
|
|||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "magazine".
|
||||
*/
|
||||
export interface Magazine {
|
||||
id: string;
|
||||
cover: string | Media;
|
||||
document: string | Document;
|
||||
date: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "users".
|
||||
|
|
@ -611,6 +625,10 @@ export interface PayloadLockedDocument {
|
|||
relationTo: 'group';
|
||||
value: string | Group;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'magazine';
|
||||
value: string | Magazine;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'documents';
|
||||
value: string | Document;
|
||||
|
|
@ -961,6 +979,17 @@ export interface GroupSelect<T extends boolean = true> {
|
|||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "magazine_select".
|
||||
*/
|
||||
export interface MagazineSelect<T extends boolean = true> {
|
||||
cover?: T;
|
||||
document?: T;
|
||||
date?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "documents_select".
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import { PopesPrayerIntentions } from '@/collections/PopesPrayerIntentions'
|
|||
import { LiturgicalCalendar } from '@/collections/LiturgicalCalendar'
|
||||
import { Classifieds } from '@/collections/Classifieds'
|
||||
import { MenuGlobal } from '@/globals/Menu'
|
||||
import { Magazine } from '@/collections/Magazine'
|
||||
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
|
@ -89,6 +90,7 @@ export default buildConfig({
|
|||
ContactPerson,
|
||||
Locations,
|
||||
Groups,
|
||||
Magazine,
|
||||
Documents,
|
||||
Media,
|
||||
Users,
|
||||
|
|
|
|||
Loading…
Reference in a new issue