Fetch upcoming events and recent news on home page #162

Merged
a258wang merged 13 commits from feat/upcoming-events-recent-news into main 2021-08-23 14:56:12 -04:00
4 changed files with 136 additions and 30 deletions

View File

@ -62,3 +62,38 @@ export async function getEventsByTerm(
.filter((name) => name.endsWith(".md")) .filter((name) => name.endsWith(".md"))
.map((name) => name.slice(0, -".md".length)); .map((name) => name.slice(0, -".md".length));
} }
export async function getUpcomingEvents(): Promise<Event[]> {
const today = new Date();
const currentYear = today.getFullYear();
const currentTerm = Math.trunc(today.getMonth() / 4);
const nextYear = currentTerm < 2 ? currentYear : currentYear + 1;
const nextTerm = (currentTerm + 1) % 3;
const events: Event[] = (
await Promise.all(
[
{ year: currentYear.toString(), term: currentTerm },
{ year: nextYear.toString(), term: nextTerm },
].map(async ({ year, term }) => {
try {
const eventsInTerm = await getEventsByTerm(year, TERMS[term]);
return await Promise.all(
eventsInTerm.map((slug) => getEventBySlug(year, TERMS[term], slug))
);
} catch (error) {
return [];
}
})
)
).flat();
return events
.filter((ev) => new Date(ev.metadata.date).getTime() >= Date.now())
.sort((a, b) => {
return (
new Date(a.metadata.date).getTime() -
new Date(b.metadata.date).getTime()
);
});
}

View File

@ -65,3 +65,38 @@ export async function getNewsBySlug(
metadata: metadata as Metadata, metadata: metadata as Metadata,
}; };
} }
export async function getRecentNews(): Promise<News[]> {
const today = new Date();
const currentYear = today.getFullYear();
const currentTerm = Math.trunc(today.getMonth() / 4);
const prevYear = currentTerm > 0 ? currentYear : currentYear - 1;
const prevTerm = (currentTerm - 1 + 3) % 3;
const news: News[] = (
await Promise.all(
[
{ year: currentYear.toString(), term: currentTerm },
{ year: prevYear.toString(), term: prevTerm },
].map(async ({ year, term }) => {
try {
const newsInTerm = await getNewsByTerm(year, TERMS[term]);
return await Promise.all(
newsInTerm.map((slug) => getNewsBySlug(year, TERMS[term], slug))
);
} catch (error) {
return [];
}
})
)
).flat();
return news
.filter((news) => new Date(news.metadata.date).getTime() <= Date.now())
.sort((a, b) => {
return (
new Date(b.metadata.date).getTime() -
new Date(a.metadata.date).getTime()
);
});
}

View File

@ -119,6 +119,7 @@
} }
.cards > section { .cards > section {
width: calc(540rem / 16);
max-width: calc(540rem / 16); max-width: calc(540rem / 16);
} }
} }
@ -171,13 +172,14 @@
.cards { .cards {
flex-direction: column; flex-direction: column;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: stretch;
gap: calc(8rem / 16); gap: calc(8rem / 16);
padding: calc(36rem / 16) calc(20rem / 16) calc(20rem / 16); padding: calc(36rem / 16) calc(20rem / 16) calc(20rem / 16);
} }
.cards > section { .cards > section {
width: unset;
max-width: unset; max-width: unset;
} }

View File

@ -1,3 +1,5 @@
import { GetStaticProps } from "next";
import { MDXRemote } from "next-mdx-remote";
import React from "react"; import React from "react";
import { ConnectWithUs } from "@/components/ConnectWithUs"; import { ConnectWithUs } from "@/components/ConnectWithUs";
@ -5,29 +7,21 @@ import { DefaultLayout } from "@/components/DefaultLayout";
import { EmailSignup } from "@/components/EmailSignup"; import { EmailSignup } from "@/components/EmailSignup";
import { EventDescriptionCard } from "@/components/EventDescriptionCard"; import { EventDescriptionCard } from "@/components/EventDescriptionCard";
import { Image } from "@/components/Image"; import { Image } from "@/components/Image";
import { Link } from "@/components/Link";
import { NewsCard } from "@/components/NewsCard"; import { NewsCard } from "@/components/NewsCard";
import { SocialLinks } from "@/components/SocialLinks"; import { SocialLinks } from "@/components/SocialLinks";
import { Event, getUpcomingEvents } from "@/lib/events";
import AltTab, { import { News, getRecentNews } from "@/lib/news";
metadata as altTabEventMetadata,
} from "../content/playground/alt-tab.event.mdx";
import OOTBReact, {
metadata as OOTBReactEventMetadata,
} from "../content/playground/ootb-react.event.mdx";
import UnavailableContent, {
metadata as unavailableMetadata,
} from "../content/playground/unavailable.news.mdx";
import styles from "./index.module.css"; import styles from "./index.module.css";
// temporary event and news imports interface Props {
moreEvents: boolean; // true if there are more than 2 upcoming events
export default function Home() { events: Event[]; // array of 0 - 2 events
const events = [ news: News;
{ Content: OOTBReact, metadata: OOTBReactEventMetadata }, }
{ Content: AltTab, metadata: altTabEventMetadata },
];
export default function Home(props: Props) {
return ( return (
<> <>
<DefaultLayout> <DefaultLayout>
@ -54,30 +48,58 @@ export default function Home() {
</DefaultLayout> </DefaultLayout>
<div className={styles.cardsBackground}> <div className={styles.cardsBackground}>
<div className={styles.cards}> <div className={styles.cards}>
{/* TODO: add links to past events and past news */}
<section className={styles.events}> <section className={styles.events}>
<h1 className={styles.cardsHeading}>Upcoming Events</h1> <h1 className={styles.cardsHeading}>Upcoming Events</h1>
<p className={styles.cardsDescription}>See past events here</p> <p className={styles.cardsDescription}>
See past events{" "}
<Link href="/events/archive">
<a title="Events Archive">here</a>
</Link>
</p>
<hr className={styles.cardsDividingLine} /> <hr className={styles.cardsDividingLine} />
{props.events.length === 0 ? (
<p>
There are no upcoming events right now. Please check back later!
</p>
) : null}
<div className={styles.eventCards}> <div className={styles.eventCards}>
{events.map(({ metadata }) => ( {props.events.length > 0
<EventDescriptionCard ? props.events.map((event) => (
{...metadata} <EventDescriptionCard
key={metadata.name + metadata.date.toString()} {...event.metadata}
/> date={new Date(event.metadata.date)}
))} key={event.metadata.name + event.metadata.date.toString()}
/>
))
: null}
</div> </div>
{props.moreEvents ? (
<p>
See more upcoming events{" "}
<Link href="/events">
<a title="Events">here</a>
</Link>
</p>
) : null}
</section> </section>
<section className={styles.news} id="news"> <section className={styles.news} id="news">
<h1 className={styles.cardsHeading}>News</h1> <h1 className={styles.cardsHeading}>News</h1>
<p className={styles.cardsDescription}> <p className={styles.cardsDescription}>
Updates from our execs! <br /> Updates from our execs! <br />
See past news here See past news{" "}
<Link href="/news/archive">
<a title="News Archive">here</a>
</Link>
</p> </p>
<hr className={styles.cardsDividingLine} /> <hr className={styles.cardsDividingLine} />
<NewsCard {...unavailableMetadata}> {
<UnavailableContent /> <NewsCard
</NewsCard> {...props.news.metadata}
date={new Date(props.news.metadata.date)}
>
<MDXRemote {...props.news.content} />
</NewsCard>
}
</section> </section>
</div> </div>
</div> </div>
@ -92,3 +114,15 @@ export default function Home() {
Home.Layout = function HomeLayout(props: { children: React.ReactNode }) { Home.Layout = function HomeLayout(props: { children: React.ReactNode }) {
return <div className={styles.page}>{props.children}</div>; return <div className={styles.page}>{props.children}</div>;
}; };
export const getStaticProps: GetStaticProps<Props> = async () => {
const upcomingEvents = await getUpcomingEvents();
const recentNews = await getRecentNews();
return {
props: {
moreEvents: upcomingEvents.length > 2,
events: upcomingEvents.slice(0, 2),
news: recentNews[0],
},
};
};