Skip to content

Commit

Permalink
Merge pull request #83 from webmardi/feature/event-seo-page
Browse files Browse the repository at this point in the history
  • Loading branch information
Yago authored Apr 1, 2023
2 parents aed8cdb + ef45c2d commit c2e7c05
Show file tree
Hide file tree
Showing 10 changed files with 807 additions and 391 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Event detail page - #81

## [1.1.8] - 2023-03-17
### Changed
- Update dependencies

## [1.1.8] - 2023-03-17
### Changed
Expand Down
30 changes: 15 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"axios": "1.3.4",
"clsx": "^1.2.1",
"date-fns": "^2.29.3",
"i18next": "^22.4.12",
"i18next": "^22.4.13",
"next": "13.2.4",
"next-pwa": "^5.6.0",
"postcss": "^8.4.21",
Expand All @@ -38,27 +38,27 @@
"react-i18next": "^12.2.0",
"react-indiana-drag-scroll": "^2.2.0",
"react-mailchimp-subscribe": "^2.1.3",
"slugify": "^1.6.5",
"slugify": "^1.6.6",
"tailwind-underline-utils": "^1.1.3",
"tailwindcss": "^3.2.7"
"tailwindcss": "^3.3.1"
},
"devDependencies": {
"@svgr/webpack": "^6.5.1",
"@svgr/webpack": "^7.0.0",
"@types/jest": "^29.5.0",
"@types/node": "^18.15.3",
"@types/react": "^18.0.28",
"@types/node": "^18.15.11",
"@types/react": "^18.0.31",
"@types/react-dom": "^18.0.11",
"@types/react-html-parser": "^2.0.2",
"@types/react-mailchimp-subscribe": "^2.1.1",
"@typescript-eslint/eslint-plugin": "^5.55.0",
"@typescript-eslint/parser": "^5.55.0",
"@typescript-eslint/eslint-plugin": "^5.57.0",
"@typescript-eslint/parser": "^5.57.0",
"babel-eslint": "^10.1.0",
"cypress": "^12.8.1",
"eslint": "^8.36.0",
"cypress": "^12.9.0",
"eslint": "^8.37.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-config-prettier": "^8.7.0",
"eslint-import-resolver-typescript": "^3.5.3",
"eslint-config-prettier": "^8.8.0",
"eslint-import-resolver-typescript": "^3.5.4",
"eslint-plugin-html": "^7.1.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsx-a11y": "^6.7.1",
Expand All @@ -70,9 +70,9 @@
"husky": "^8.0.3",
"jest": "^29.5.0",
"lint-staged": "^13.2.0",
"prettier": "^2.8.4",
"prettier": "^2.8.7",
"ts-jest": "^29.0.5",
"typescript": "^5.0.2"
"typescript": "^5.0.3"
},
"license": "MIT"
}
}
10 changes: 9 additions & 1 deletion src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,16 @@
"contact_us_link": "https://docs.google.com/document/d/1qjxg6l_nQ_ycgYwJAdXWSEqmB5D8uoWNs-hEtrO_stw/edit?usp=sharing"
}
},
"event": {
"speaker": "Speaker:",
"lang": "Language:",
"be_held": "Will be held in ",
"who": "Accessible:",
"where": "Location:",
"youtube": "If you can't make it, the event will be available on Youtube afterwards.\nThanks to our wonderful premium sponsors @liip_ch & @HidoraSwiss who help us make these journey possible \uD83D\uDE42"
},
"seo": {
"title": "Webmardi - Monthly events in western Switzerland",
"description": "Webmardi is a Swiss-based association that organises free monthly events in western Switzerland."
}
}
}
151 changes: 151 additions & 0 deletions src/pages/events/[slug].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import React, { ReactElement } from 'react';
import parse from 'react-html-parser';
import { useTranslation } from 'react-i18next';
import { GetStaticPaths, GetStaticProps } from 'next';
import { isNil } from 'ramda';

import Layout from 'components/Layout';
import SEO from 'components/SEO';
import Sponsors from 'components/Sponsors';
import { Event } from 'types';
import { getEvent, getEvents, getLangName } from 'utils';

type Props = {
event: Event;
};

const Home = ({ event }: Props): JSX.Element => {
const { t } = useTranslation();

return (
<Layout>
<SEO />
<h1 className="sr-only">{t('homepage.events.title')}</h1>

<main
className="max-w-3xl px-4 mx-auto my-20"
itemScope
itemType="https://schema.org/Event"
>
<h1
className="text-xl font-bold col-span-2 md:text-xl lg:text-2xl"
itemProp="name"
>
{event.title}
</h1>
<p className="mt-12">
{
parse(
event.seoBody.replace(/\n/gm, '<br /><br />')
) as React.ReactNode
}
</p>
<div className="mt-8 space-y-2">
{!isNil(event.speakerName) && (
<div
itemScope
itemProp="performer"
itemType="https://schema.org/Person"
className="flex items-baseline link space-x-4"
>
<h3 className="font-bold">{t('event.speaker')}</h3>
{!isNil(event.speakerName) && isNil(event.speakerLink) && (
<span itemProp="name">
{parse(event.speakerName) as ReactElement[]}
</span>
)}
{!isNil(event.speakerName) && !isNil(event.speakerLink) && (
<a
href={event.speakerLink}
target="_blank"
itemProp="name"
rel="noopener noreferrer"
>
{parse(event.speakerName) as ReactElement[]}
</a>
)}
{!isNil(event.speakerJob) && (
<span itemProp="jobTitle" className="mt-1">
{parse(event.speakerJob) as ReactElement[]}
</span>
)}
</div>
)}
{!isNil(event.language) && (
<div
itemProp="inLanguage"
className="flex items-baseline space-x-4"
>
<h3 className="font-bold">{t('event.lang')}</h3>
<p>
{t('event.be_held')}
{getLangName(event.language)}
</p>
</div>
)}
{!isNil(event.types) && (
<div
itemProp="inLanguage"
className="flex items-baseline space-x-4"
>
<h3 className="font-bold">{t('event.who')}</h3>
<p>
{event.types?.map(type => (
<span key={`event-type-${event.title}-${type}`}>
{t(`homepage.events.types.${type}`)}
</span>
))}
</p>
</div>
)}
{!isNil(event.location) && (
<div
itemProp="inLanguage"
className="flex items-baseline space-x-4"
>
<h3 className="font-bold">{t('event.where')}</h3>
<p itemProp="location">
{parse(event.location) as ReactElement[]}
</p>
</div>
)}
</div>

<p className="mt-8">{t('event.youtube')}</p>

<p className="mt-8">
{
parse(
event.seoHashtags.replace(/\n/gm, '<br /><br />')
) as React.ReactNode
}
</p>
</main>

<Sponsors />
</Layout>
);
};

export const getStaticProps: GetStaticProps = async ({ params }) => {
const event = await getEvent(params?.slug as string);
return isNil(event)
? { notFound: true }
: {
props: {
event,
},
};
};

export const getStaticPaths: GetStaticPaths = async () => {
const events: Event[] = await getEvents();
return {
paths: events
.filter(({ slug }) => !isNil(slug))
.map(({ slug }) => ({ params: { slug: slug as string } })),
fallback: false,
};
};

export default Home;
21 changes: 21 additions & 0 deletions src/types/api-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ export type Properties = {
speaker_name: Location;
subscription_link: ApplyLinkClass;
speaker_job: Location;
seo_body: SeoBody;
seo_hashtags: SeoHashtags;
slug: Slug;
published: Published;
Name: Name;
};
Expand Down Expand Up @@ -106,6 +109,24 @@ interface Location {
rich_text: Title[];
}

interface SeoBody {
id: string;
type: string;
rich_text: Title[];
}

interface SeoHashtags {
id: string;
type: string;
rich_text: Title[];
}

interface Slug {
id: string;
type: string;
rich_text: Title[];
}

interface Published {
id: string;
type: string;
Expand Down
3 changes: 3 additions & 0 deletions src/types/event.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
export type Event = {
title: string | null;
slug: string | null;
date: string | null;
types: string[] | null;
speakerName: string | null;
speakerJob: string | null;
speakerLink: string | null;
seoBody: string;
seoHashtags: string;
location: string | null;
language: string | null;
subscriptionLink: string | null;
Expand Down
47 changes: 47 additions & 0 deletions src/utils/getEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* eslint-disable @typescript-eslint/naming-convention */
import axios from 'axios';

import { ApiEvents, Event } from 'types';
import sanitizeEvents from 'utils/sanitizeEvents';

const getEvent = async (slug: string): Promise<Event | null> => {
let event: Event | null = null;

try {
const { results } = await axios
.request({
method: 'POST',
url: `https://api.notion.com/v1/databases/${process.env.NEXT_PUBLIC_DATABASE_ID}/query`,
headers: {
'Notion-Version': '2021-08-16',
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.NEXT_PUBLIC_TOKEN}`,
},
data: {
page_size: 1,
filter: {
property: 'slug',
rich_text: {
equals: slug,
},
},
},
})
.then(res => {
const data = res.data as unknown as ApiEvents;
return {
results: sanitizeEvents(data.results),
next_cursor: data.next_cursor,
has_more: data.has_more,
};
});

if (results.length > 0) [event] = results;
} catch (error) {
console.log('error', error);
}

return event;
};

export default getEvent;
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as getEvents } from './getEvents';
export { default as getEvent } from './getEvent';
export { default as sanitizeEvents } from './sanitizeEvents';
export { default as formatDate } from './formatDate';
export { default as getLangName } from './getLangName';
3 changes: 3 additions & 0 deletions src/utils/sanitizeEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ const getRichContent = (
const sanitizeEvents = (results: ApiEvents['results']): Event[] =>
results.map(({ properties }) => ({
title: properties.Name.title[0]?.plain_text ?? null,
slug: properties.slug.rich_text[0]?.plain_text ?? null,
date: (properties.date.date.start as unknown as string) ?? null,
types: properties.types.multi_select.map(i => i.name) ?? null,
language: properties.language.select?.name ?? null,
speakerName: getRichContent(properties.speaker_name.rich_text),
speakerJob: getRichContent(properties.speaker_job.rich_text),
seoBody: getRichContent(properties.seo_body.rich_text) ?? '',
seoHashtags: getRichContent(properties.seo_hashtags.rich_text) ?? '',
speakerLink: properties.speaker_link.url ?? null,
location: getRichContent(properties.location.rich_text),
subscriptionLink: properties.subscription_link.url ?? null,
Expand Down
Loading

0 comments on commit c2e7c05

Please sign in to comment.