From e5fd9bfec91825df01da63ad98c934e41606c7a9 Mon Sep 17 00:00:00 2001 From: Jared He <66887902+jaredjhe@users.noreply.github.com> Date: Tue, 16 Nov 2021 20:20:40 -0600 Subject: [PATCH] Add Term type --- components/ArchivePage.tsx | 4 ++-- lib/events.ts | 33 +++++++++++--------------- lib/news.ts | 9 +++---- pages/events/[year]/[term]/[event].tsx | 6 ++--- pages/events/[year]/[term]/index.tsx | 14 +++++------ pages/events/[year]/index.tsx | 3 ++- pages/events/index.tsx | 4 ++-- pages/news/[year]/[term].tsx | 6 ++--- utils.ts | 8 +++++++ 9 files changed, 46 insertions(+), 41 deletions(-) diff --git a/components/ArchivePage.tsx b/components/ArchivePage.tsx index 522578a2..ed714184 100644 --- a/components/ArchivePage.tsx +++ b/components/ArchivePage.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { capitalize } from "@/utils"; +import { capitalize, Term } from "@/utils"; import { Link } from "./Link"; import { @@ -16,7 +16,7 @@ export interface Props { type: "news" | "events"; items: { year: string; - terms: string[]; + terms: Term[]; }[]; } diff --git a/lib/events.ts b/lib/events.ts index 8df6e449..41a7b9c8 100644 --- a/lib/events.ts +++ b/lib/events.ts @@ -7,10 +7,11 @@ import matter from "gray-matter"; import { MDXRemoteSerializeResult } from "next-mdx-remote"; import { serialize } from "next-mdx-remote/serialize"; +import { Term, TERMS, isTerm } from "@/utils"; + import type { Props } from "../pages/events/[year]/[term]/index"; const EVENTS_PATH = path.join("content", "events"); -export const TERMS = ["winter", "spring", "fall"]; export async function getEventYears(): Promise { return (await fs.readdir(EVENTS_PATH, { withFileTypes: true })) @@ -19,12 +20,12 @@ export async function getEventYears(): Promise { .sort(); } -export async function getEventTermsByYear(year: string): Promise { +export async function getEventTermsByYear(year: string): Promise { return ( await fs.readdir(path.join(EVENTS_PATH, year), { withFileTypes: true }) ) - .filter((dirent) => dirent.isDirectory() && TERMS.includes(dirent.name)) - .map((dirent) => dirent.name) + .filter((dirent) => dirent.isDirectory() && isTerm(dirent.name)) + .map((dirent) => dirent.name as Term) .sort((a, b) => TERMS.indexOf(a) - TERMS.indexOf(b)); } @@ -58,7 +59,7 @@ export const DATE_FORMAT = "MMMM dd yyyy HH:mm"; export async function getEventBySlug( year: string, - term: string, + term: Term, slug: string ): Promise { const file = await fs.readFile( @@ -84,7 +85,7 @@ export async function getEventBySlug( export async function getEventsByTerm( year: string, - term: string + term: Term ): Promise { try { return (await fs.readdir(path.join(EVENTS_PATH, year, term))) @@ -149,7 +150,7 @@ export async function getEventsPageProps({ term, }: { year: string; - term: string; + term: Term; }): Promise { const eventNames = await getEventsByTerm(year, term); @@ -177,7 +178,7 @@ export async function getEventsPageProps({ const eventYears = await getEventYears(); const minYear = eventYears[0]; - const pastTerms: { year: string; term: string }[] = []; + const pastTerms: { year: string; term: Term }[] = []; let curPastYear = year; let curPastTerm = term; while (parseInt(curPastYear) >= parseInt(minYear) && pastTerms.length < 2) { @@ -191,7 +192,7 @@ export async function getEventsPageProps({ pastTerms.reverse(); const maxYear = eventYears[eventYears.length - 1]; - const futureTerms: { year: string; term: string }[] = []; + const futureTerms: { year: string; term: Term }[] = []; let curFutureYear = year; let curFutureTerm = term; while ( @@ -217,7 +218,7 @@ export async function getEventsPageProps({ }; } -export function getCurrentTerm() { +export function getCurrentTerm(): { year: string; term: Term } { const today = new Date().toLocaleDateString("en-CA", { timeZone: "EST", year: "numeric", @@ -241,17 +242,14 @@ export function getCurrentTerm() { term = "fall"; } - if (term === "") { + if (!isTerm(term)) { throw new Error("Error setting the current term"); } return { year, term }; } -function getPastTerm( - year: string, - term: string -): { year: string; term: string } { +function getPastTerm(year: string, term: Term): { year: string; term: Term } { const index = TERMS.indexOf(term); if (index === -1) { @@ -269,10 +267,7 @@ function getPastTerm( }; } -function getFutureTerm( - year: string, - term: string -): { year: string; term: string } { +function getFutureTerm(year: string, term: Term): { year: string; term: Term } { const index = TERMS.indexOf(term); if (index === -1) { diff --git a/lib/news.ts b/lib/news.ts index 0ab30257..9a3f6496 100644 --- a/lib/news.ts +++ b/lib/news.ts @@ -6,10 +6,11 @@ import matter from "gray-matter"; import { MDXRemoteSerializeResult } from "next-mdx-remote"; import { serialize } from "next-mdx-remote/serialize"; +import { isTerm, Term, TERMS } from "@/utils"; + import { DATE_FORMAT, getLocalDateFromEST } from "./events"; export const NEWS_PATH = path.join("content", "news"); -const TERMS = ["winter", "spring", "fall"]; export interface Metadata { author: string; @@ -28,14 +29,14 @@ export async function getNewsYears(): Promise { .sort(); } -export async function getNewsTermsByYear(year: string): Promise { +export async function getNewsTermsByYear(year: string): Promise { return ( await fs.readdir(path.join(NEWS_PATH, year), { withFileTypes: true, }) ) - .filter((dirent) => dirent.isDirectory() && TERMS.includes(dirent.name)) - .map((dirent) => dirent.name) + .filter((dirent) => dirent.isDirectory() && isTerm(dirent.name)) + .map((dirent) => dirent.name as Term) .sort((a, b) => TERMS.indexOf(a) - TERMS.indexOf(b)); } diff --git a/pages/events/[year]/[term]/[event].tsx b/pages/events/[year]/[term]/[event].tsx index 4ab46a09..ef30a6a5 100644 --- a/pages/events/[year]/[term]/[event].tsx +++ b/pages/events/[year]/[term]/[event].tsx @@ -18,7 +18,7 @@ import { getEventsByTerm, getEventBySlug, } from "@/lib/events"; -import { capitalize } from "@/utils"; +import { capitalize, Term } from "@/utils"; export default function EventInfoPage({ year, term, event }: Props) { return ( @@ -43,13 +43,13 @@ EventInfoPage.getShapesConfig = ((width, height) => { interface Props { year: string; - term: string; + term: Term; event: Event; } interface Params extends ParsedUrlQuery { year: string; - term: string; + term: Term; event: string; } diff --git a/pages/events/[year]/[term]/index.tsx b/pages/events/[year]/[term]/index.tsx index bb7cc93f..8830d624 100644 --- a/pages/events/[year]/[term]/index.tsx +++ b/pages/events/[year]/[term]/index.tsx @@ -14,21 +14,21 @@ import { getEventYears, getEventTermsByYear, } from "@/lib/events"; -import { capitalize } from "@/utils"; +import { capitalize, Term } from "@/utils"; import styles from "./index.module.css"; export interface Props { year: string; - term: string; + term: Term; pastEvents: Event[]; futureEvents: Event[]; isCurrentTerm: boolean; - pastTerms: { year: string; term: string }[]; - futureTerms: { year: string; term: string }[]; + pastTerms: { year: string; term: Term }[]; + futureTerms: { year: string; term: Term }[]; } -export default function Term(props: Props) { +export default function TermPage(props: Props) { let headerTerms = [{ year: props.year, term: props.term }]; // p, Current, f @@ -120,7 +120,7 @@ export default function Term(props: Props) { function HeaderLink(props: { year: string; - term: string; + term: Term; isCurrentTerm?: boolean; }) { return ( @@ -134,7 +134,7 @@ function HeaderLink(props: { interface Params extends ParsedUrlQuery { year: string; - term: string; + term: Term; } export const getStaticProps: GetStaticProps = async ( diff --git a/pages/events/[year]/index.tsx b/pages/events/[year]/index.tsx index 07e29e05..23df88bf 100644 --- a/pages/events/[year]/index.tsx +++ b/pages/events/[year]/index.tsx @@ -6,12 +6,13 @@ import React from "react"; import { Link } from "@/components/Link"; import { Title } from "@/components/Title"; import { getEventYears, getEventTermsByYear } from "@/lib/events"; +import { Term } from "@/utils"; import styles from "./index.module.css"; interface Props { year: string; - terms: string[]; + terms: Term[]; } export default function Year(props: Props) { diff --git a/pages/events/index.tsx b/pages/events/index.tsx index 9d5b1796..c7b71293 100644 --- a/pages/events/index.tsx +++ b/pages/events/index.tsx @@ -2,9 +2,9 @@ import { GetStaticProps } from "next"; import { getCurrentTerm, getEventsPageProps } from "@/lib/events"; -import Term, { Props } from "./[year]/[term]"; +import TermEvent, { Props } from "./[year]/[term]"; -export default Term; +export default TermEvent; export const getStaticProps: GetStaticProps = async () => { return { props: await getEventsPageProps(getCurrentTerm()) }; diff --git a/pages/news/[year]/[term].tsx b/pages/news/[year]/[term].tsx index 06640a7e..e28fa908 100644 --- a/pages/news/[year]/[term].tsx +++ b/pages/news/[year]/[term].tsx @@ -18,13 +18,13 @@ import { getNewsYears, News, } from "@/lib/news"; -import { capitalize } from "@/utils"; +import { capitalize, Term } from "@/utils"; import styles from "./[term].module.css"; interface Props { year: string; - term: string; + term: Term; news: News[]; } @@ -75,7 +75,7 @@ export const getStaticProps: GetStaticProps = async ( interface Params extends ParsedUrlQuery { year: string; - term: string; + term: Term; } export const getStaticPaths: GetStaticPaths = async () => { diff --git a/utils.ts b/utils.ts index 40ef05aa..2ab7507e 100644 --- a/utils.ts +++ b/utils.ts @@ -1,3 +1,11 @@ +export const TERMS = ["winter", "spring", "fall"] as const; +export type Term = typeof TERMS[number]; + +// https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates +export function isTerm(x: string): x is Term { + return x === "winter" || x === "spring" || x === "fall"; +} + export function capitalize(str: string) { return str.slice(0, 1).toUpperCase() + str.slice(1); }