-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #165 from nr2f1/publications
publications page
- Loading branch information
Showing
15 changed files
with
830 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
.publications { | ||
ul { | ||
margin: 0; | ||
padding: 0; | ||
padding-inline-start: var(--spacing-8); | ||
} | ||
|
||
&__by-year:not(:last-of-type) { | ||
margin-block-end: var(--spacing-6); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import styles from './page-body.module.scss'; | ||
|
||
import PageBody from '@components/page-body'; | ||
import { documentToReactComponents } from '@contentful/rich-text-react-renderer'; | ||
import { getClient } from '@graphql/client'; | ||
import { | ||
GetPublicationsPageDocument, | ||
type GetPublicationsPageQuery, | ||
} from '@graphql/queries/publications-page/index.generated'; | ||
import type { AvailableLocale } from '@i18n/locales'; | ||
import { | ||
geneResearchHeadingId, | ||
patientResearchHeadingId, | ||
} from '@models/headings'; | ||
import { | ||
geneResearchContentId, | ||
patientResearchContentId, | ||
} from '@models/paragraphs'; | ||
import { createHashLink } from '@shared/utils/hash-links'; | ||
|
||
interface RegisterPageBodyProps { | ||
lang: AvailableLocale; | ||
} | ||
|
||
const { query } = getClient(); | ||
|
||
interface CleanedPublication { | ||
__typename: 'Publication'; | ||
title: string; | ||
dateOfPublication: string; | ||
link: string | null; | ||
asset: { | ||
__typename: 'Asset'; | ||
url: string; | ||
} | null; | ||
} | ||
|
||
interface PublicationWithLink { | ||
title: string; | ||
year: number; | ||
link: string; | ||
} | ||
|
||
interface PublicationsByYear { | ||
year: number; | ||
publications: PublicationWithLink[]; | ||
} | ||
|
||
const getPublicationWithLink = ( | ||
publication: CleanedPublication, | ||
): PublicationWithLink => { | ||
const { title, dateOfPublication, link, asset } = publication; | ||
return { | ||
title: title, | ||
year: new Date(dateOfPublication).getFullYear(), | ||
link: link ?? asset?.url ?? '', | ||
}; | ||
}; | ||
|
||
const getPublicationsByYear = ( | ||
acc: PublicationsByYear[], | ||
{ title, year, link }: PublicationWithLink, | ||
) => { | ||
const existingYear = acc.find((publication) => publication.year === year); | ||
|
||
if (existingYear) { | ||
existingYear.publications.push({ title, link, year }); | ||
} else { | ||
acc.push({ year, publications: [{ title, link, year }] }); | ||
} | ||
|
||
return acc; | ||
}; | ||
|
||
const sortByYear = ( | ||
{ year: yearA }: PublicationsByYear, | ||
{ year: yearB }: PublicationsByYear, | ||
) => { | ||
return yearB - yearA; | ||
}; | ||
|
||
interface PublicationsByYearProps { | ||
publications: CleanedPublication[]; | ||
} | ||
|
||
const PublicationsByYear: React.FC<PublicationsByYearProps> = ({ | ||
publications, | ||
}) => { | ||
const publicationsByYear = publications | ||
.map(getPublicationWithLink) | ||
.reduce(getPublicationsByYear, [] as PublicationsByYear[]) | ||
.sort(sortByYear); | ||
|
||
return publicationsByYear.map(({ year, publications }) => ( | ||
<div className={styles['publications__by-year']} key={crypto.randomUUID()}> | ||
<h3>{year}</h3> | ||
<ul> | ||
{publications.map(({ title, link }) => ( | ||
<li key={crypto.randomUUID()}> | ||
<a href={link}>{title}</a> | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
)); | ||
}; | ||
|
||
const RegisterPageBody: React.FC<RegisterPageBodyProps> = async ({ lang }) => { | ||
const { | ||
data: { | ||
patientResearchHeading, | ||
patientResearchContent, | ||
patientPublications, | ||
geneResearchHeading, | ||
geneResearchContent, | ||
genePublications, | ||
}, | ||
error, | ||
} = await query<GetPublicationsPageQuery>({ | ||
query: GetPublicationsPageDocument, | ||
variables: { | ||
locale: lang, | ||
patientResearchHeadingId, | ||
patientResearchContentId, | ||
geneResearchHeadingId, | ||
geneResearchContentId, | ||
}, | ||
}); | ||
|
||
if (error) { | ||
return null; | ||
} | ||
|
||
const headings = [ | ||
patientResearchHeading?.content ?? '', | ||
geneResearchHeading?.content ?? '', | ||
]; | ||
|
||
return ( | ||
<PageBody lang={lang} headings={headings} className={styles.publications}> | ||
<section> | ||
<h2 id={createHashLink(patientResearchHeading?.content ?? '')}> | ||
{patientResearchHeading?.content} | ||
</h2> | ||
{documentToReactComponents(patientResearchContent?.content?.json)} | ||
<PublicationsByYear | ||
publications={patientPublications?.items as CleanedPublication[]} | ||
/> | ||
</section> | ||
<section> | ||
<h2 id={createHashLink(geneResearchHeading?.content ?? '')}> | ||
{geneResearchHeading?.content} | ||
</h2> | ||
{documentToReactComponents(geneResearchContent?.content?.json)} | ||
<PublicationsByYear | ||
publications={genePublications?.items as CleanedPublication[]} | ||
/> | ||
</section> | ||
</PageBody> | ||
); | ||
}; | ||
|
||
export default RegisterPageBody; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import PageHeader from '@components/page-header'; | ||
import { getClient } from '@graphql/client'; | ||
import { | ||
GetPageHeaderDocument, | ||
type GetPageHeaderQuery, | ||
} from '@graphql/queries/page-header/index.generated'; | ||
import type { AvailableLocale } from '@i18n/locales'; | ||
import { publicationsPageHeaderId } from '@models/page-header'; | ||
|
||
interface RegisterPageHeaderProps { | ||
lang: AvailableLocale; | ||
} | ||
|
||
const PublicationsPageHeader: React.FC<RegisterPageHeaderProps> = async ({ | ||
lang, | ||
}) => { | ||
const { query } = getClient(); | ||
|
||
// TODO: Change query | ||
const { data, error } = await query<GetPageHeaderQuery>({ | ||
query: GetPageHeaderDocument, | ||
variables: { | ||
locale: lang, | ||
id: publicationsPageHeaderId, | ||
}, | ||
}); | ||
|
||
if ( | ||
error || | ||
!data.pageHeader || | ||
!data.pageHeader.title || | ||
!data.pageHeader.sectionTitle || | ||
!data.pageHeader.lastUpdated || | ||
!data.pageHeader.image | ||
) { | ||
return null; | ||
} | ||
|
||
const { | ||
title, | ||
sectionTitle, | ||
lastUpdated, | ||
image: { url }, | ||
} = data.pageHeader; | ||
|
||
return ( | ||
<PageHeader | ||
lang={lang} | ||
pageTitle={title} | ||
sectionTitle={sectionTitle} | ||
lastUpdated={lastUpdated} | ||
imageUrl={url ?? ''} | ||
/> | ||
); | ||
}; | ||
|
||
export default PublicationsPageHeader; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import SupportBanner from '@components/support-banner'; | ||
import { getClient } from '@graphql/client'; | ||
import { | ||
GetMetadataDocument, | ||
type GetMetadataQuery, | ||
} from '@graphql/queries/metadata/index.generated'; | ||
import { registerPatientPageMetadataId } from '@models/metadata'; | ||
import type { PagePropsWithLocale } from '@shared/types/page-with-locale-params'; | ||
import type { Metadata, NextPage } from 'next'; | ||
import type { Graph, MedicalStudy, WebPage, WithContext } from 'schema-dts'; | ||
import RegisterPageBody from './page-body'; | ||
import PublicationsPageHeader from './page-header'; | ||
|
||
const { query } = getClient(); | ||
|
||
const Page: NextPage<PagePropsWithLocale> = async ({ params }) => { | ||
const { lang } = await params; | ||
|
||
// TODO: Change query | ||
const { | ||
data: { | ||
// @ts-ignore | ||
htmlHeadMetadata: { title, description }, | ||
}, | ||
} = await query<GetMetadataQuery>({ | ||
query: GetMetadataDocument, | ||
variables: { | ||
locale: lang, | ||
id: registerPatientPageMetadataId, | ||
}, | ||
}); | ||
|
||
const medicalStudy: WithContext<MedicalStudy> = { | ||
'@context': 'https://schema.org', | ||
'@type': 'MedicalStudy', | ||
name: title, | ||
description, | ||
potentialAction: [ | ||
{ | ||
'@type': 'RegisterAction', | ||
target: `https://nr2f1.org/${lang}/register-patient`, | ||
name: title, | ||
}, | ||
], | ||
}; | ||
|
||
// TODO: Change schema | ||
const webPage: WithContext<WebPage> = { | ||
'@context': 'https://schema.org', | ||
'@type': 'WebPage', | ||
url: `https://nr2f1.org/${lang}/register-a-patient`, | ||
name: title, | ||
inLanguage: lang, | ||
}; | ||
|
||
const jsonLd: Graph = { | ||
'@context': 'https://schema.org', | ||
'@graph': [medicalStudy, webPage], | ||
}; | ||
|
||
return ( | ||
<> | ||
<script | ||
type="application/ld+json" | ||
// biome-ignore lint/security/noDangerouslySetInnerHtml: this is a safe usage | ||
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} | ||
/> | ||
<PublicationsPageHeader lang={lang} /> | ||
<RegisterPageBody lang={lang} /> | ||
<SupportBanner lang={lang} /> | ||
</> | ||
); | ||
}; | ||
|
||
export default Page; | ||
|
||
export async function generateMetadata({ | ||
params, | ||
}: PagePropsWithLocale): Promise<Metadata> { | ||
const { lang } = await params; | ||
|
||
// TODO: Change query | ||
const { | ||
data: { | ||
// @ts-ignore | ||
htmlHeadMetadata: { title, description, keywords }, | ||
}, | ||
error, | ||
} = await query<GetMetadataQuery>({ | ||
query: GetMetadataDocument, | ||
variables: { | ||
locale: lang, | ||
id: registerPatientPageMetadataId, | ||
}, | ||
}); | ||
|
||
return { | ||
title: `NR2F1 Foundation | ${title}`, | ||
description, | ||
keywords, | ||
}; | ||
} |
Oops, something went wrong.