www-new/pages/about/team.tsx

224 lines
6.0 KiB
TypeScript

import { GetStaticProps } from "next";
import { MDXRemote, MDXRemoteSerializeResult } from "next-mdx-remote";
import React from "react";
import { Bubble } from "@/components/Bubble";
import { DefaultLayout } from "@/components/DefaultLayout";
import { Image } from "@/components/Image";
import { Link } from "@/components/Link";
import { TeamMember } from "@/components/TeamMember";
import { TeamMemberCard } from "@/components/TeamMemberCard";
import { Title } from "@/components/Title";
import {
getExecs,
Metadata as TeamMemberData,
getMemberImagePath,
} from "@/lib/team";
import designData from "../../content/team/design-team.json";
import discordData from "../../content/team/discord-team.json";
import eventsData from "../../content/team/events-team.json";
import externalData from "../../content/team/external-affairs-team.json";
import marketingData from "../../content/team/marketing-team.json";
import photographyData from "../../content/team/photography-team.json";
import repsData from "../../content/team/representatives-team.json";
import systemsData from "../../content/team/systems-committee.json";
import terminalData from "../../content/team/terminal-committee.json";
import webData from "../../content/team/web-committee.json";
import styles from "./team.module.css";
interface SerializedExec {
content: MDXRemoteSerializeResult;
metadata: TeamMemberData;
}
interface Team {
id: string;
name: string;
members: TeamMemberData[];
}
interface Props {
execs: SerializedExec[];
teams: Team[];
}
export default function Team({ execs, teams }: Props) {
return (
<>
<Title>Team</Title>
<DefaultLayout>
<div className={styles.headerContainer}>
<div className={styles.headerTextContainer}>
<h1 className={styles.header}>Meet the Team!</h1>
<div className={styles.nav}>
<Link href="#execs">The Executives</Link>
{teams.map((team) => (
<Link href={`#${team.id}`} key={team.id}>
{team.name}
</Link>
))}
</div>
<h2
className={styles.subheading}
style={{ borderBottom: "none", margin: 0, padding: 0 }}
>
The Executives
</h2>
</div>
<Image src="images/team/team-codey.svg" className={styles.codey} />
</div>
<div className={styles.execs} id="execs">
{execs.map((exec) => {
return (
<div key={exec.metadata.name}>
<TeamMemberCard {...exec.metadata}>
<MDXRemote {...exec.content} />
</TeamMemberCard>
</div>
);
})}
</div>
{teams.map((team) => {
return (
<div id={team.id} key={team.id}>
<h2 className={styles.subheading}>{team.name}</h2>
<MembersList team={team.members} />
</div>
);
})}
</DefaultLayout>
<div className={styles.elections}>
<Bubble>
<h2 className={styles.electionSubheading}>Elections</h2>
To find out when and where the next elections will be held, keep an
eye on on the <Link href="/#news">News</Link>. <br />
For details on the elections, read our
<Link href="/about/constitution"> Constitution</Link>.
</Bubble>
</div>
</>
);
}
Team.Layout = function TeamLayout(props: { children: React.ReactNode }) {
return <div>{props.children}</div>;
};
interface MembersProps {
team: TeamMemberData[];
}
function MembersList(props: MembersProps) {
return (
<div className={styles.members}>
{props.team.map((member) => (
<TeamMember {...member} key={member.name} />
))}
</div>
);
}
async function getTeamWithImages(team: Team): Promise<Team> {
return {
...team,
members: await Promise.all(
team.members.map(async (member) => {
const image = member.image ?? (await getMemberImagePath(member.name));
return {
...member,
image,
};
})
),
};
}
function memberComparer(a: TeamMemberData, b: TeamMemberData) {
return a.name.localeCompare(b.name);
}
function sortTeamMembers(team: Team): Team {
const leads = team.members
.filter(({ role }) => role === "Team Lead")
.sort(memberComparer);
const general = team.members.filter(({ role }) => !role).sort(memberComparer);
const others = team.members
.filter(({ role }) => !!role && role !== "Team Lead")
.sort(memberComparer);
return { ...team, members: [...leads, ...general, ...others] };
}
export const getStaticProps: GetStaticProps<Props> = async () => {
const execs = await getExecs();
// Note that rawTeams do not contain image paths of members, even though
// TypeScript thinks that it does. It's just to simplify some code.
const rawTeams = [
{
id: "reps",
name: "Community Representatives",
members: repsData,
},
{
id: "design",
name: "Design",
members: designData,
},
{
id: "discord",
name: "Discord Bot (CodeyBot) Developers",
members: discordData,
},
{
id: "events",
name: "Events",
members: eventsData,
},
{
id: "external",
name: "External Affairs",
members: externalData,
},
{
id: "marketing",
name: "Marketing",
members: marketingData,
},
{
id: "photography",
name: "Photography",
members: photographyData,
},
{
id: "website",
name: "Web Committee",
members: webData,
},
{
id: "system",
name: "Systems Committee",
members: systemsData,
},
{
id: "terminal",
name: "Terminal Committee",
members: terminalData,
},
] as Team[];
const teamsWithImages = await Promise.all(rawTeams.map(getTeamWithImages));
const teamsAfterSorting = teamsWithImages.map(sortTeamMembers);
return {
props: {
execs,
teams: teamsAfterSorting,
},
};
};