|
|
|
@ -6,28 +6,33 @@ import matter from "gray-matter"; |
|
|
|
|
import { MDXRemoteSerializeResult } from "next-mdx-remote"; |
|
|
|
|
import { serialize } from "next-mdx-remote/serialize"; |
|
|
|
|
|
|
|
|
|
import type { Props } from "../pages/events/[year]/[term]/index"; |
|
|
|
|
// do not use alias "@/utils" as generate-calendar imports a function from this file and ts-node is not compatible
|
|
|
|
|
import { |
|
|
|
|
Term, |
|
|
|
|
TERMS, |
|
|
|
|
isTerm, |
|
|
|
|
DATE_FORMAT, |
|
|
|
|
getLocalDateFromEST, |
|
|
|
|
} from "../utils"; |
|
|
|
|
TermYear, |
|
|
|
|
getTermYear, |
|
|
|
|
getCurrentTermYear, |
|
|
|
|
} from "@/utils"; |
|
|
|
|
|
|
|
|
|
import type { Props } from "../pages/events/[year]/[term]"; |
|
|
|
|
|
|
|
|
|
const EVENTS_PATH = path.join("content", "events"); |
|
|
|
|
|
|
|
|
|
export async function getEventYears(): Promise<string[]> { |
|
|
|
|
export async function getEventYears(): Promise<number[]> { |
|
|
|
|
return (await fs.readdir(EVENTS_PATH, { withFileTypes: true })) |
|
|
|
|
.filter((dirent) => dirent.isDirectory()) |
|
|
|
|
.map((dirent) => dirent.name) |
|
|
|
|
.map((dirent) => parseInt(dirent.name)) |
|
|
|
|
.sort(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export async function getEventTermsByYear(year: string): Promise<Term[]> { |
|
|
|
|
export async function getEventTermsByYear(year: number): Promise<Term[]> { |
|
|
|
|
return ( |
|
|
|
|
await fs.readdir(path.join(EVENTS_PATH, year), { withFileTypes: true }) |
|
|
|
|
await fs.readdir(path.join(EVENTS_PATH, year.toString()), { |
|
|
|
|
withFileTypes: true, |
|
|
|
|
}) |
|
|
|
|
) |
|
|
|
|
.filter((dirent) => dirent.isDirectory() && isTerm(dirent.name)) |
|
|
|
|
.map((dirent) => dirent.name as Term) |
|
|
|
@ -55,7 +60,7 @@ interface Metadata { |
|
|
|
|
location: string; |
|
|
|
|
permaLink: string; |
|
|
|
|
registerLink?: string; |
|
|
|
|
year: string; |
|
|
|
|
year: number; |
|
|
|
|
term: string; |
|
|
|
|
slug: string; |
|
|
|
|
} |
|
|
|
@ -66,12 +71,12 @@ export interface Event { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export async function getEventBySlug( |
|
|
|
|
year: string, |
|
|
|
|
year: number, |
|
|
|
|
term: Term, |
|
|
|
|
slug: string |
|
|
|
|
): Promise<Event> { |
|
|
|
|
const file = await fs.readFile( |
|
|
|
|
path.join(EVENTS_PATH, year, term, `${slug}.md`), |
|
|
|
|
path.join(EVENTS_PATH, year.toString(), term, `${slug}.md`), |
|
|
|
|
"utf-8" |
|
|
|
|
); |
|
|
|
|
const { content, data } = matter(file); |
|
|
|
@ -95,11 +100,11 @@ export async function getEventBySlug( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export async function getEventsByTerm( |
|
|
|
|
year: string, |
|
|
|
|
year: number, |
|
|
|
|
term: Term |
|
|
|
|
): Promise<string[]> { |
|
|
|
|
try { |
|
|
|
|
return (await fs.readdir(path.join(EVENTS_PATH, year, term))) |
|
|
|
|
return (await fs.readdir(path.join(EVENTS_PATH, year.toString(), term))) |
|
|
|
|
.filter((name) => name.endsWith(".md")) |
|
|
|
|
.map((name) => name.slice(0, -".md".length)); |
|
|
|
|
} catch { |
|
|
|
@ -108,22 +113,24 @@ export async function getEventsByTerm( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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 terms: TermYear[] = []; |
|
|
|
|
|
|
|
|
|
// Get events for the next two terms
|
|
|
|
|
for (const termYear of getTermYear()) { |
|
|
|
|
if (terms.length >= 2) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
terms.push(termYear); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const events: Event[] = ( |
|
|
|
|
await Promise.all( |
|
|
|
|
[ |
|
|
|
|
{ year: currentYear.toString(), term: currentTerm }, |
|
|
|
|
{ year: nextYear.toString(), term: nextTerm }, |
|
|
|
|
].map(async ({ year, term }) => { |
|
|
|
|
terms.map(async ({ year, term }) => { |
|
|
|
|
try { |
|
|
|
|
const eventsInTerm = await getEventsByTerm(year, TERMS[term]); |
|
|
|
|
const eventsInTerm = await getEventsByTerm(year, term); |
|
|
|
|
return await Promise.all( |
|
|
|
|
eventsInTerm.map((slug) => getEventBySlug(year, TERMS[term], slug)) |
|
|
|
|
eventsInTerm.map((slug) => getEventBySlug(year, term, slug)) |
|
|
|
|
); |
|
|
|
|
} catch (error) { |
|
|
|
|
return []; |
|
|
|
@ -162,12 +169,9 @@ export async function getAllEvents(): Promise<Event[]> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export async function getEventsPageProps({ |
|
|
|
|
year, |
|
|
|
|
term, |
|
|
|
|
}: { |
|
|
|
|
year: string; |
|
|
|
|
term: Term; |
|
|
|
|
}): Promise<Props> { |
|
|
|
|
year, |
|
|
|
|
}: TermYear): Promise<Props> { |
|
|
|
|
const eventNames = await getEventsByTerm(year, term); |
|
|
|
|
|
|
|
|
|
const events: Event[] = ( |
|
|
|
@ -198,40 +202,43 @@ export async function getEventsPageProps({ |
|
|
|
|
currentDate |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
const current = getCurrentTerm(); |
|
|
|
|
|
|
|
|
|
const eventYears = await getEventYears(); |
|
|
|
|
|
|
|
|
|
const minYear = eventYears[0]; |
|
|
|
|
const pastTerms: { year: string; term: Term }[] = []; |
|
|
|
|
let curPastYear = year; |
|
|
|
|
let curPastTerm = term; |
|
|
|
|
while (parseInt(curPastYear) >= parseInt(minYear) && pastTerms.length < 2) { |
|
|
|
|
const pastTerm = getPastTerm(curPastYear, curPastTerm); |
|
|
|
|
curPastYear = pastTerm.year; |
|
|
|
|
curPastTerm = pastTerm.term; |
|
|
|
|
if ((await getEventsByTerm(curPastYear, curPastTerm)).length !== 0) { |
|
|
|
|
pastTerms.push(pastTerm); |
|
|
|
|
const pastTerms: TermYear[] = []; |
|
|
|
|
|
|
|
|
|
for (const current of getTermYear( |
|
|
|
|
{ year, term }, |
|
|
|
|
{ goBackwards: true, skipCurrent: true } |
|
|
|
|
)) { |
|
|
|
|
if (pastTerms.length >= 2 || current.year < minYear) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ((await getEventsByTerm(current.year, current.term)).length !== 0) { |
|
|
|
|
pastTerms.push(current); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
pastTerms.reverse(); |
|
|
|
|
|
|
|
|
|
const maxYear = eventYears[eventYears.length - 1]; |
|
|
|
|
const futureTerms: { year: string; term: Term }[] = []; |
|
|
|
|
let curFutureYear = year; |
|
|
|
|
let curFutureTerm = term; |
|
|
|
|
while ( |
|
|
|
|
parseInt(curFutureYear) <= parseInt(maxYear) && |
|
|
|
|
futureTerms.length < 2 |
|
|
|
|
) { |
|
|
|
|
const futureTerm = getFutureTerm(curFutureYear, curFutureTerm); |
|
|
|
|
curFutureYear = futureTerm.year; |
|
|
|
|
curFutureTerm = futureTerm.term; |
|
|
|
|
if ((await getEventsByTerm(curFutureYear, curFutureTerm)).length !== 0) { |
|
|
|
|
futureTerms.push(futureTerm); |
|
|
|
|
const futureTerms: TermYear[] = []; |
|
|
|
|
|
|
|
|
|
for (const current of getTermYear( |
|
|
|
|
{ year, term }, |
|
|
|
|
{ goBackwards: false, skipCurrent: true } |
|
|
|
|
)) { |
|
|
|
|
if (futureTerms.length >= 2 || maxYear < current.year) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ((await getEventsByTerm(current.year, current.term)).length !== 0) { |
|
|
|
|
futureTerms.push(current); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const current = getCurrentTermYear(); |
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
year: year, |
|
|
|
|
term: term, |
|
|
|
@ -242,70 +249,3 @@ export async function getEventsPageProps({ |
|
|
|
|
futureTerms: futureTerms, |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export function getCurrentTerm(): { year: string; term: Term } { |
|
|
|
|
const today = new Date().toLocaleDateString("en-CA", { |
|
|
|
|
timeZone: "EST", |
|
|
|
|
year: "numeric", |
|
|
|
|
month: "numeric", |
|
|
|
|
day: "numeric", |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const [year] = today.split("-"); |
|
|
|
|
|
|
|
|
|
let term = ""; |
|
|
|
|
|
|
|
|
|
if (`${year}-01-01` <= today) { |
|
|
|
|
term = "winter"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (`${year}-05-01` <= today) { |
|
|
|
|
term = "spring"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (`${year}-09-01` <= today) { |
|
|
|
|
term = "fall"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!isTerm(term)) { |
|
|
|
|
throw new Error("Error setting the current term"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return { year, term }; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function getPastTerm(year: string, term: Term): { year: string; term: Term } { |
|
|
|
|
const index = TERMS.indexOf(term); |
|
|
|
|
|
|
|
|
|
if (index === -1) { |
|
|
|
|
throw new Error(`[getPastTerm] Not a valid term: "${term}" "${year}"`); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return index === 0 |
|
|
|
|
? { |
|
|
|
|
year: (parseInt(year) - 1).toString(), |
|
|
|
|
term: TERMS[TERMS.length - 1], |
|
|
|
|
} |
|
|
|
|
: { |
|
|
|
|
year: year, |
|
|
|
|
term: TERMS[index - 1], |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function getFutureTerm(year: string, term: Term): { year: string; term: Term } { |
|
|
|
|
const index = TERMS.indexOf(term); |
|
|
|
|
|
|
|
|
|
if (index === -1) { |
|
|
|
|
throw new Error(`[getFutureTerm] Not a valid term: "${term}" "${year}"`); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return index === TERMS.length - 1 |
|
|
|
|
? { |
|
|
|
|
year: (parseInt(year) + 1).toString(), |
|
|
|
|
term: TERMS[0], |
|
|
|
|
} |
|
|
|
|
: { |
|
|
|
|
year: year, |
|
|
|
|
term: TERMS[index + 1], |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|