Skip to content

Commit 81ec3de

Browse files
authored
Merge pull request #4161 from Northeastern-Electric-Racing/#4088-individual-subteam-page
#4088 Individual subteam page
2 parents 559d5a2 + d87a426 commit 81ec3de

2 files changed

Lines changed: 120 additions & 2 deletions

File tree

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { Box, Stack, Typography } from '@mui/material';
2+
import { useMediaQuery } from '@mui/system';
3+
import { useSingleTeam } from '../../hooks/teams.hooks';
4+
import { useParams } from 'react-router-dom';
5+
import LoadingIndicator from '../../components/LoadingIndicator';
6+
import ErrorPage from '../ErrorPage';
7+
import PageLayout from '../../components/PageLayout';
8+
import { WbsElementStatus } from 'shared';
9+
import { routes } from '../../utils/routes';
10+
import PersonOutlineOutlinedIcon from '@mui/icons-material/PersonOutlineOutlined';
11+
import GroupOutlinedIcon from '@mui/icons-material/GroupOutlined';
12+
import GroupsOutlinedIcon from '@mui/icons-material/GroupsOutlined';
13+
import GuestProjectsCard from '../GuestProjectsPage/GuestProjectsCard';
14+
import NERMarkdown from '../../components/NERMarkdown';
15+
16+
interface ParamTypes {
17+
teamId: string;
18+
}
19+
20+
const GuestTeamSpecificPage: React.FC = () => {
21+
const { teamId } = useParams<ParamTypes>();
22+
const { isLoading, isError, data, error } = useSingleTeam(teamId);
23+
const isMobilePortrait = useMediaQuery('(max-width:480px)');
24+
25+
if (isError) return <ErrorPage message={error?.message} />;
26+
if (isLoading || !data) return <LoadingIndicator />;
27+
28+
const activeProjects = data.projects.filter((project) => project.status === WbsElementStatus.Active);
29+
30+
const formatNames = (members: { firstName: string; lastName: string }[]) =>
31+
members.map((m) => `${m.firstName} ${m.lastName}`).join(', ');
32+
33+
return (
34+
<PageLayout
35+
title={`${data.teamName}`}
36+
previousPages={
37+
data.teamType
38+
? [
39+
{ name: 'Divisions', route: routes.TEAMS },
40+
{ name: data.teamType.name, route: `${routes.TEAMS}/${data.teamType.teamTypeId}` }
41+
]
42+
: [{ name: 'Divisions', route: routes.TEAMS }]
43+
}
44+
>
45+
<Box sx={{ mb: 3 }}>
46+
<NERMarkdown markdown={data.description} />
47+
</Box>
48+
<Box sx={{ mb: 3 }}>
49+
<Typography variant="h5" fontWeight={700} sx={{ mb: 2 }}>
50+
People
51+
</Typography>
52+
<Stack spacing={3}>
53+
<Box display="flex" alignItems="flex-start" gap={1.5}>
54+
<PersonOutlineOutlinedIcon sx={{ color: 'text.secondary', mt: 0.25 }} />
55+
<Box>
56+
<Typography variant="subtitle1" fontWeight={700}>
57+
Head
58+
</Typography>
59+
<Typography variant="body2" color="text.secondary">
60+
{data.head.firstName} {data.head.lastName}
61+
</Typography>
62+
</Box>
63+
</Box>
64+
{data.leads && data.leads.length > 0 && (
65+
<Box display="flex" alignItems="flex-start" gap={1.5}>
66+
<GroupOutlinedIcon sx={{ color: 'text.secondary', mt: 0.25 }} />
67+
<Box>
68+
<Typography variant="subtitle1" fontWeight={700}>
69+
Leads
70+
</Typography>
71+
<Typography variant="body2" color="text.secondary">
72+
{formatNames(data.leads)}
73+
</Typography>
74+
</Box>
75+
</Box>
76+
)}
77+
{data.members && data.members.length > 0 && (
78+
<Box display="flex" alignItems="flex-start" gap={1.5}>
79+
<GroupsOutlinedIcon sx={{ color: 'text.secondary', mt: 0.25 }} />
80+
<Box>
81+
<Typography variant="subtitle1" fontWeight={700}>
82+
Members
83+
</Typography>
84+
<Typography variant="body2" color="text.secondary">
85+
{formatNames(data.members)}
86+
</Typography>
87+
</Box>
88+
</Box>
89+
)}
90+
</Stack>
91+
</Box>
92+
<Box sx={{ mb: 3 }}>
93+
<Typography variant="h5" fontWeight={700} sx={{ mb: 2 }}>
94+
Active Projects
95+
</Typography>
96+
<Box
97+
sx={{
98+
display: 'grid',
99+
gridTemplateColumns: isMobilePortrait ? '1fr' : 'repeat(3, 1fr)',
100+
gap: isMobilePortrait ? 2 : 3,
101+
width: '100%',
102+
px: isMobilePortrait ? 1 : 0
103+
}}
104+
>
105+
{activeProjects.map((project) => (
106+
<GuestProjectsCard key={project.id} project={{ ...project, teamTypes: [] }} />
107+
))}
108+
</Box>
109+
</Box>
110+
</PageLayout>
111+
);
112+
};
113+
114+
export default GuestTeamSpecificPage;

src/frontend/src/pages/TeamsPage/Teams.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { isGuest } from 'shared';
1313
import { useAllTeamTypes } from '../../hooks/team-types.hooks';
1414
import GuestTeamPage from '../GuestTeamsPage/GuestTeamPage';
1515
import GuestDivisionPage from '../GuestDivisionsPage/GuestDivisionPage';
16+
import GuestTeamSpecificPage from '../GuestTeamsPage/GuestTeamSpecificPage';
1617
import LoadingIndicator from '../../components/LoadingIndicator';
1718
import ErrorPage from '../ErrorPage';
1819

@@ -24,8 +25,11 @@ const TeamOrDivisionPage: React.FC = () => {
2425
if (isTeamsError) return <ErrorPage message={teamsError.message} />;
2526
if (teamsLoading || !teamTypes) return <LoadingIndicator />;
2627

27-
if (isGuest(user.role) && teamTypes?.some((t) => t.teamTypeId === teamId)) {
28-
return <GuestTeamPage teamTypeId={teamId} />;
28+
if (isGuest(user.role)) {
29+
if (teamTypes?.some((t) => t.teamTypeId === teamId)) {
30+
return <GuestTeamPage teamTypeId={teamId} />;
31+
}
32+
return <GuestTeamSpecificPage />;
2933
}
3034
return <TeamSpecificPage />;
3135
};

0 commit comments

Comments
 (0)