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))
);
a3thakra marked this conversation as resolved Outdated

no need to use async and await if the thing you're returning from your function is a promise.

so:

async (slug) => await getEventBySlug(year, TERMS[term], slug)

is the same as

(slug) => getEventBySlug(year, TERMS[term], slug)

no need to use async and await if the thing you're returning from your function is a promise. so: `async (slug) => await getEventBySlug(year, TERMS[term], slug)` is the same as `(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
a258wang marked this conversation as resolved Outdated

this seems redundant, why can't we just use events.length?

this seems redundant, why can't we just use events.length?

Currently, we're displaying a link to the upcoming events page iff there are more than 2 upcoming events, however we are only passing up to 2 events in the events array (that is, 0 <= events.length <= 2).

Currently, we're displaying a link to the upcoming events page iff there are more than 2 upcoming events, however we are only passing up to 2 events in the events array (that is, 0 <= events.length <= 2).

oh, I see. In that case, you should pass in a boolean prop (eg moreUpcomingEvents) instead of numberOfEvents.

oh, I see. In that case, you should pass in a boolean prop (eg `moreUpcomingEvents`) instead of `numberOfEvents`.
export default function Home() { events: Event[]; // array of 0 - 2 events
const events = [ news: News;
a3thakra marked this conversation as resolved Outdated

We only need the first news, so we should only pass 1 news item, instead of an array.

We only need the first news, so we should only pass 1 news item, instead of an array.
{ 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}>
a3thakra marked this conversation as resolved Outdated

links:

  • upcoming events: /events
  • past events: /events/archive
  • past news: /news/archive

note that we will never have upcoming news.

links: - upcoming events: `/events` - past events: `/events/archive` - past news: `/news/archive` note that we will never have upcoming news.
<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 ? (
a3thakra marked this conversation as resolved Outdated

Use ===. Only use == for null checks.

Use `===`. Only use `==` for null checks.
<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 }) {
a3thakra marked this conversation as resolved Outdated

Just GetStaticProps<Props> is fine, you can omit Params here.

Just `GetStaticProps<Props>` is fine, you can omit Params here.
return <div className={styles.page}>{props.children}</div>; return <div className={styles.page}>{props.children}</div>;
}; };
a3thakra marked this conversation as resolved Outdated

You should slice these arrays here, if you don't that will make the HTML pages gigantic, as all the events and news will be serialized in HTML.

You should slice these arrays here, if you don't that will make the HTML pages gigantic, as all the events and news will be serialized in HTML.
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],
},
};
};