Skip to content

Commit

Permalink
feat: added publicaties page
Browse files Browse the repository at this point in the history
  • Loading branch information
onursagir committed Dec 30, 2024
1 parent e212a6d commit 58bfc2f
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/olive-jeans-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"web": minor
---

Added `publicaties` page
15 changes: 15 additions & 0 deletions apps/web/src/app/publicaties/[slug]/copy-cite-to-clipboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use client';

import { Button } from '@/components/button';
import { IconClipboard } from '@tabler/icons-react';
import { CopyToClipboard } from 'react-copy-to-clipboard';

interface Props {
text: string;
}

export const CopyCiteToClipboard: React.FC<Props> = ({ text }) => (
<CopyToClipboard text={text}>
<Button startIcon={<IconClipboard />}>Kopiëren naar klembord</Button>
</CopyToClipboard>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { db } from '@/drizzle/db';
import { files, filesRelatedMorphs, publications } from '@/drizzle/schema';
import { and, eq } from 'drizzle-orm';

interface Args {
slug: string;
}

export async function getPublicationFileBySlug({ slug }: Args) {
const [result] = await db
.select({ file: files })
.from(publications)
.leftJoin(filesRelatedMorphs, eq(publications.id, filesRelatedMorphs.relatedId))
.leftJoin(files, eq(files.id, filesRelatedMorphs.fileId))
.where(and(eq(publications.slug, slug), eq(filesRelatedMorphs.relatedType, 'api::publication.publication')))
.limit(1);

return result.file;
}
22 changes: 22 additions & 0 deletions apps/web/src/app/publicaties/[slug]/download/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { resolveCmsImage } from '@/common/resolve-cms-image';
import slugify from '@sindresorhus/slugify';
import { NextRequest } from 'next/server';
import { getPublicationFileBySlug } from './get-publication-file-by-slug';

export async function GET(req: NextRequest, { params }: { params: { slug: string } }) {
const file = await getPublicationFileBySlug({ slug: params.slug });

const fetchResponse = await fetch(resolveCmsImage(file as any), {
method: 'GET',
});

const headers = new Headers();

headers.set('Content-Disposition', `attachment; filename="${slugify(params.slug)}${file?.ext}"`);
headers.set('Content-Type', file?.mime || '');

return new Response(fetchResponse.body, {
headers,
status: fetchResponse.status,
});
}
13 changes: 13 additions & 0 deletions apps/web/src/app/publicaties/[slug]/get-publication-by-slug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { db } from '@/drizzle/db';
import { publications } from '@/drizzle/schema';
import { eq } from 'drizzle-orm';

interface Args {
slug: string;
}

export async function getPublicationBySlug({ slug }: Args) {
const [publication] = await db.select().from(publications).where(eq(publications.slug, slug)).limit(1);

return publication;
}
120 changes: 120 additions & 0 deletions apps/web/src/app/publicaties/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { EnhanceMenuBreadcrumbs } from '@/app/menu-breadcrumbs';
import { Button } from '@/components/button';
import { Container } from '@/components/container';
import * as Dialog from '@/components/dialog';
import { Pill } from '@/components/pill';
import { RemoteMdx } from '@/components/remote-mdx';
import { Typography } from '@/components/typography';
import { IconArrowLeft, IconBlockquote, IconDownload, IconExternalLink, IconFileTypePdf } from '@tabler/icons-react';
import { format } from 'date-fns';
import Link from 'next/link';
import { CopyCiteToClipboard } from './copy-cite-to-clipboard';
import { getPublicationBySlug } from './get-publication-by-slug';

type Args = { params: { slug: string } };

export default async function PublicatiesSlugPage({ params }: Args) {
const publication = await getPublicationBySlug({ slug: params.slug });

return (
<>
<EnhanceMenuBreadcrumbs append={publication.title!} />
<Container component="header" className="-mt-14 bg-[#F7FBFD] py-12">
<Typography variant="h1">{publication.title}</Typography>
<section className="flex flex-col gap-y-1 pb-2 pt-12">
<Typography className="!mt-0 text-lg text-primary-dark">
Gepubliceerd op: {format(publication.updatedAt!, 'dd MMMM yyyy')}
</Typography>
<Typography className="!mt-0 text-lg text-primary-dark">Auteurs: {publication.authors}</Typography>
<Typography className="!mt-0 text-lg text-primary-dark">Locatie: {publication.location}</Typography>
</section>
<section>
<ul className="-ml-4 flex">
<li>
<Dialog.Root>
<Dialog.Trigger asChild>
<Button startIcon={<IconBlockquote />} variant="text">
Citeer dit artikel
</Button>
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Content>
<Dialog.Title>Citeer deze publicatie</Dialog.Title>
<Dialog.Description>
{publication.cite}
<div className="mt-4 flex justify-center">
<CopyCiteToClipboard text={publication.cite!} />
</div>
</Dialog.Description>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
</li>
<li>
<Button
component={Link}
href={`/publicaties/${params.slug}/download`}
startIcon={<IconFileTypePdf />}
variant="text"
>
Download dit artikel
</Button>
</li>
<li>
<Button
component="a"
variant="text"
target="_blank"
rel="noopener noreferrer"
startIcon={<IconExternalLink />}
href={publication.originalSource!}
>
Originele bron
</Button>
</li>
</ul>
</section>
</Container>
<Container component="main" className="pt-12">
<section>
<Typography variant="h2">Samenvatting</Typography>
<RemoteMdx content={publication.content!} />
</section>
<section>
<Typography variant="h3">Trefwoorden</Typography>
<ul className="mt-4 flex gap-x-6">
{publication.tags?.split(',').map((tag) => (
<Pill key={tag} component="li" label={tag} />
))}
</ul>
</section>
</Container>
<Container component="footer" className="pb-12">
<div className="mt-16 flex justify-between">
<Button component={Link} href="/publicaties" startIcon={<IconArrowLeft />}>
Overzicht
</Button>
<Button
component={Link}
color="primary-light"
href={`/publicaties/${params.slug}/download`}
startIcon={<IconDownload />}
>
Download
</Button>
</div>
</Container>
</>
);
}

export async function generateMetadata({ params }: Args) {
const publication = await getPublicationBySlug({ slug: params.slug });

return {
title: publication.title + ' - Regelregister van de Nederlandse Overheid',
keywords: publication.tags,
authors: publication.authors?.split(',').map((author) => ({ name: author.trim() })),
description: publication.summary,
};
}
26 changes: 26 additions & 0 deletions apps/web/src/app/publicaties/card-publication.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Pill } from '@/components/pill';
import { Typography } from '@/components/typography';
import { getPublications } from './get-publications';
import Link from 'next/link';

interface Props {
publication: Awaited<ReturnType<typeof getPublications>>[number];
}

export const CardPublication: React.FC<Props> = ({ publication }) => {
if (!publication.slug || !publication.title || !publication.summary) return null;

return (
<Link href={'/publicaties/' + publication.slug} className="rounded-md border border-grey-lighter p-6">
<Typography variant="h3" className="mt-0 text-xl text-grey-dark">
{publication.title}
</Typography>
<Typography className="mb-4 mt-2 text-grey-dark">{publication.summary}</Typography>
<div className="flex items-start gap-x-4">
{publication.tags?.split(',').map((tag) => (
<Pill key={tag} label={tag.trim()} />
))}
</div>
</Link>
);
};
11 changes: 11 additions & 0 deletions apps/web/src/app/publicaties/get-publications.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { db } from '@/drizzle/db';
import { publications } from '@/drizzle/schema';
import { and, desc, lte } from 'drizzle-orm';

export function getPublications() {
return db
.select()
.from(publications)
.orderBy(desc(publications.publicationDate))
.where(and(lte(publications.publishedAt, new Date().toISOString())));
}
28 changes: 28 additions & 0 deletions apps/web/src/app/publicaties/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Container } from '@/components/container';
import { RemotePage } from '@/components/remote-page';
import { Typography } from '@/components/typography';
import { Metadata } from 'next';
import { CardPublication } from './card-publication';
import { getPublications } from './get-publications';

export default async function PublicatiesPage() {
const publications = await getPublications();

return (
<>
<Container className="mb-16">
<Typography variant="h1">Publicaties</Typography>
<RemotePage page="publicaties" />
<div className="mt-28 flex flex-col gap-y-4">
{publications.map((publication) => (
<CardPublication key={publication.id} publication={publication} />
))}
</div>
</Container>
</>
);
}

export const metadata: Metadata = {
title: 'Regelregister van de Nederlandse Overheid - Publicaties',
};

0 comments on commit 58bfc2f

Please sign in to comment.