Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Article Routes #67

Merged
merged 17 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions components/news/article-date.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { styled } from '@mui/system'
import { formatDate } from '@/utils/date'

export const DateSpan = styled('span')({
fontSize: '95%',
fontWeight: 'bold',
margin: 0,
lineHeight: 2,
})

export const ArticleDate = ({ date }) => {
return <DateSpan>{ formatDate(date) }</DateSpan>
}
47 changes: 47 additions & 0 deletions components/news/time-grouping.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { dateToSlug } from "@/utils/slug"
import { Page } from "../layout"
import { Link } from "../link"
import { Typography } from "@mui/material"

const MONTHS = [ undefined, "Jan.", "Feb.", "Mar.", "Apr.", "May", "Jun.", "Jul.", "Aug.", "Sep.", "Oct.", "Nov.", "Dec."]
const DAYS =
[undefined, "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th","9th", "10th",
"11th", "12th", "13th", "14th", "15th", "16th", "17th", "18th", "19th", "20th",
"21st", "22nd", "23rd", "24th", "25th", "26th", "27th", "28th", "29th", "30th", "31st"]

export const TimeGrouping = ({
year,
month,
day,
posts,
}) => {
const title = `Articles during ${
month !== undefined ? `${MONTHS[Number(month)]} ` : ''
}${
day !== undefined ? `${DAYS[Number(day)]}, ` : ''
}${year}`

return <Page title={title}>
<Typography variant="subtitle2" sx={{ textTransform: 'uppercase' }}>
<Link to='/news'>← Back to news</Link>
</Typography>
{posts.length === 0 ? "No articles for this period." : (
<ul>
{
posts.map(({ title, publishDate, slug }, i) => {
const d = new Date(publishDate)
return (
<li key={i}>
<Link to={`/news/${dateToSlug(d)}/${slug}`}>
{`${d.getUTCMonth() + 1}/${d.getUTCDate()}/${d.getUTCFullYear()}`}
{" - "}
{title}
</Link>
</li>
)
})
}
</ul>
)}
</Page>
}
3 changes: 2 additions & 1 deletion lib/strapi/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export * from './groupsGraphQL'
export * from './peopleGraphQL'
export * from './fetchOurWorkTrayItems'
export * from './newsAppearancesGraphQL'
export * from './newsSWR'
export * from './newsSWR'
export * from './newsGraphQL'
118 changes: 118 additions & 0 deletions lib/strapi/newsGraphQL.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { fetchStrapiGraphQL } from "./fetchStrapiGraphQL";

export const fetchArticle = async (slug) => {
const articleGql = await fetchStrapiGraphQL(`
fragment PersonAttributes on PersonRelationResponseCollection {
data {
attributes {
firstName
lastName
slug
}
}
}

query {
posts(filters: { slug: { eq: "${slug}" }}) {
data {
attributes {
title
subtitle
slug
publishDate
newsOrBlog
renciAuthors {
...PersonAttributes
}
externalAuthors
metadata {
metaTitle
metaDescription
shareImage {
data {
attributes {
url
}
}
}
}
people {
...PersonAttributes
}
researchGroups {
data {
attributes {
name
slug
}
}
}
collaborations {
data {
attributes {
name
slug
}
}
}
projects {
data {
attributes {
name
slug
}
}
}
organizations {
data {
attributes {
name
slug
}
}
}
tags {
data {
attributes {
name
}
}
}
content {
__typename
...on ComponentPostSectionsImage {
caption
altText
image {
data {
attributes {
url
width
height
}
}
}
}
...on ComponentPostSectionsRichText{
content
}
}
}
}
}
}
`);

if (articleGql?.data?.posts?.data?.length !== 1) return null;

return articleGql.data.posts.data.map(({ attributes }) => ({
...attributes,
renciAuthors: attributes.renciAuthors.data.map(({ attributes }) => attributes),
people: attributes.people.data.map(({ attributes }) => ({ ...attributes, name: `${attributes.firstName} ${attributes.lastName}`})),
researchGroups: attributes.researchGroups.data.map(({ attributes }) => attributes),
collaborations: attributes.collaborations.data.map(({ attributes }) => attributes),
projects: attributes.projects.data.map(({ attributes }) => attributes),
organizations: attributes.organizations.data.map(({ attributes }) => attributes),
postTags: attributes.tags.data.map(({ attributes }) => attributes),
}))[0];
}
191 changes: 191 additions & 0 deletions pages/news/[year]/[month]/[day]/[slug].js
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import { Fragment } from "react"
import { Page, Section } from "@/components/layout";
import { fetchArticle, fetchStrapiGraphQL } from "@/lib/strapi";
import { Divider, Typography, Box, Stack } from "@mui/material";
import { Markdown } from "@/components/markdown";
import Image from "next/image";
import { ArticleDate } from "@/components/news/article-date"
import { Tag } from "@/components/news/tag"
import qs from "qs";
import { Link } from "@/components/link"

export default function Article({ article }) {

const tags = [
article.projects.map((x) => ({ ...x, type: 'projects' })),
article.people.map((x) => ({ ...x, type: 'people' })),
article.collaborations.map((x) => ({ ...x, type: 'collaborations' })),
article.researchGroups.map((x) => ({ ...x, type: 'researchGroups' })),
article.organizations.map((x) => ({ ...x, type: 'organizations' })),
article.postTags.map((x) => ({ ...x, type: 'postTags' }))
].flat();

const createTagLinkURL = (id, type) => {
return `/news?${qs.stringify({[type]: id})}`
}

return (
<Page hideTitle title={article.title} description={article.subtitle}>

{/* Defines the article width, does not include next/previous article buttons */}
<Section>

{/* container that holds the date and label on the same line */}
<Stack
direction="row"
justifyContent="space-between"
>
<ArticleDate date={article.publishDate}/>

<div>
<Typography sx={{textTransform: "capitalize", fontWeight: "500", padding: "0.25rem 0.5rem", backgroundColor:"#D9D9D9"}}>{article.newsOrBlog}</Typography>
</div>
</Stack>

{/*title moved down here below the date/label line*/}
<Typography variant="h1">
{ article.title }
</Typography>

{/*Subheading/subtitle if one exists*/}
{
article.subtitle && (
<Typography variant="subtitle1">
{article.subtitle}
</Typography>
)
}
<Stack direction="row" flexWrap="wrap" gap={1}>
{tags.map(({ name, slug, type }, i) => {
const id = type === 'postTags' ? name : slug;

return (
<Link key={i} to={createTagLinkURL(id, type)}>
<Tag
type={type}
contents={name}
sx={{ minWidth: 'fit-content', maxWidth: 'revert' }}
/>
</Link>
)
})}
</Stack>

<Divider sx={{ margin: '1rem 0'}}/>


{/*Article content is mapped over because each section is grouped by content type, separating rich text from images*/}
{
article.content.map((item)=> {
return item.__typename == "ComponentPostSectionsImage" ? (
<Image
priority
src={item.image.data.attributes.url}
alt={item.altText}
width= {item.image.data.attributes.width}
height={item.image.data.attributes.height}
layout="responsive"
objectFit='cover'
/>
) : (
<Markdown>{item.content}</Markdown>
)
})
}

</Section>

<Divider sx={{ margin: '1rem 0'}}/>

<Section title="Read More">
{article.researchGroups[0] && (
<Fragment>
<Typography variant="h3">Research Groups:</Typography>
<ul>
{
article.researchGroups.map((item, i) => (
<li key={i}><Link to={`/groups/${item.slug}`}>{item.name}</Link></li>
))
}
</ul>
<br/>
</Fragment>
)}
{article.collaborations[0] && (
<Fragment>
<Typography variant="h3">Collaborations:</Typography>
<ul>
{
article.collaborations.map((item, i) => (
<li key={i}><Link to={`/collaborations/${item.slug}`}>{item.name}</Link></li>
))
}
</ul>
<br/>
</Fragment>
)}
{article.projects[0] && (
<Fragment>
<Typography variant="h3">Projects:</Typography>
{
article.projects.map((item, i) => (
<li key={i}><Link to={`/projects/${item.slug}`}>{item.name}</Link></li>
))
}
<br/>
</Fragment>
)}
{article.people[0] && (
<Fragment>
<Typography variant="h3">People:</Typography>
<ul>
{
article.people.map((item, i) => (
<li key={i}><Link to={`/people/${item.slug}`}>{item.name}</Link></li>
))
}
</ul>
<br/>
</Fragment>
)}
</Section>
</Page>
)
}

export async function getStaticPaths() {
const postsGql = await fetchStrapiGraphQL(`query {
posts(pagination: { limit: 1000 }, sort: "publishDate:desc") {
data {
attributes {
slug
publishDate
}
}
}
}`);

const paths = postsGql.data.posts.data.map(({ attributes: { publishDate, slug } }) => {
const date = new Date(publishDate);

return {
params: {
year: date.getUTCFullYear().toString(),
month: (date.getUTCMonth() + 1).toString(),
day: date.getUTCDate().toString(),
slug,
}
}
});

return {
paths,
fallback: 'blocking',
};
}

export async function getStaticProps({ params: { slug } }) {
const article = await fetchArticle(slug);
if (article === null || article.length) return { notFound: true };
return { props: { article } }
}
Loading