Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 182 additions & 0 deletions pages/hackathon/[id]/team/[tid].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { TableCellUser } from 'mobx-lark';
import { observer } from 'mobx-react';
import { cache, compose, errorLogger } from 'next-ssr-middleware';
import { FC, useContext } from 'react';
import { Badge, Card, Col, Container, Row, Tab, Tabs } from 'react-bootstrap';

import { LarkImage } from '../../../../components/LarkImage';
import { PageHead } from '../../../../components/Layout/PageHead';
import { Activity, ActivityModel } from '../../../../models/Activity';
import { Person, PersonModel, Project, ProjectModel } from '../../../../models/Hackathon';
import { I18nContext } from '../../../../models/Translation';

export const getServerSideProps = compose<{ id: string; tid: string }>(
cache(),
errorLogger,
async ({ params }) => {
const activityModel = new ActivityModel();
const activity = await activityModel.getOne(params!.id);

// @ts-expect-error Upstream compatibility
const { appId, tableIdMap } = activity.databaseSchema;

const projectModel = new ProjectModel(appId, tableIdMap.Project);
const team = await projectModel.getOne(params!.tid);

const personModel = new PersonModel(appId, tableIdMap.Person);
const allPeople = await personModel.getAll();

// Filter team members from all people based on the team's members field
const teamMemberNames = (team.members as string[]) || [];
const teamMembers = allPeople.filter((person) =>
teamMemberNames.includes(person.name as string),
);

return {
props: {
activity,
team,
teamMembers,
},
};
},
);

interface TeamPageProps {
activity: Activity;
team: Project;
teamMembers: Person[];
}

const TeamPage: FC<TeamPageProps> = observer(({ activity, team, teamMembers }) => {
const { t } = useContext(I18nContext);

const { name: activityName } = activity;
const { name: displayName, summary: description, createdBy, score } = team;

const currentRoute = [
{ title: activityName as string, href: `/hackathon/${activityName}` },
{ title: displayName as string },
];

return (
<Container as="main" className="mt-4">
<PageHead title={`${displayName} - ${activityName}`} />

<nav aria-label="breadcrumb">
<ol className="breadcrumb">
{currentRoute.map(({ title, href }) =>
href ? (
<li key={title} className="breadcrumb-item">
<a href={href}>{title}</a>
</li>
) : (
<li key={title} className="breadcrumb-item active" aria-current="page">
{title}
</li>
),
)}
</ol>
</nav>

<Row className="mt-4">
<Col xs={12} sm={4}>
<Card style={{ minWidth: '15rem' }}>
<Card.Header className="bg-white">
<h1 className="h3 my-2">{displayName as string}</h1>
<p className="text-muted">{description as string}</p>
{score !== undefined && (
<div className="text-center mt-3">
<Badge bg="primary" className="fs-5">
{t('score')}: {score as number}
</Badge>
</div>
)}
</Card.Header>
<Card.Body>
<h2 className="text-dark fw-bold h6 mb-3">
👥 {t('team_members')}
</h2>
<ul className="list-unstyled">
{teamMembers.map((member) => (
<li key={member.id as string} className="mb-3">
<div className="d-flex align-items-center">
<LarkImage
src={member.avatar}
alt={member.name as string}
className="rounded-circle me-2"
style={{ width: '40px', height: '40px' }}
/>
<div>
<div className="fw-bold">{member.name as string}</div>
{member.githubLink && (
<a
href={member.githubLink as string}
target="_blank"
rel="noreferrer"
className="text-muted small"
>
{t('view_github')}
</a>
)}
</div>
</div>
</li>
))}
</ul>
</Card.Body>
</Card>
</Col>
<Col xs={12} sm={8}>
<Tabs defaultActiveKey="update" id="team-detail-tabs">
<Tab className="pt-2" eventKey="update" title={t('latest_news')}>
<div className="h1 my-5 text-center text-muted">{t('no_news_yet')}</div>
</Tab>
<Tab eventKey="teamWork" title={t('team_works')} className="pt-2">
<div className="mt-3">
{team.products && (team.products as string[]).length > 0 ? (
<ul className="list-unstyled">
{(team.products as string[]).map((product, index) => (
<li key={index} className="mb-2">
<Card body>
<h5>{product}</h5>
</Card>
</li>
))}
</ul>
) : (
<div className="text-center text-muted my-5">
{t('no_news_yet')}
</div>
)}
</div>
</Tab>
</Tabs>
</Col>
</Row>

{createdBy && (
<Row className="mt-4">
<Col>
<Card>
<Card.Body>
<h3 className="h5">{t('created_by')}</h3>
<div className="mt-3">
<div className="fw-bold">{(createdBy as TableCellUser).name}</div>
<a
href={`mailto:${(createdBy as TableCellUser).email}`}
className="text-muted"
>
{(createdBy as TableCellUser).email}
</a>
</div>
</Card.Body>
</Card>
</Col>
</Row>
)}
</Container>
);
});

export default TeamPage;
14 changes: 14 additions & 0 deletions translation/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,18 @@ export default {
male: 'Male',
female: 'Female',
other: 'Other',

// Team detail page
team_members: 'Team Members',
team_works: 'Team Works',
latest_news: 'Latest News',
no_news_yet: 'No news yet',
join_team: 'Join Team',
leave_team: 'Leave Team',
manage_team: 'Manage Team',
cancel_application: 'Cancel Application',
please_make_sure: 'Please confirm',
success: 'Success',
team_description: 'Team Description',
team_details: 'Team Details',
};
14 changes: 14 additions & 0 deletions translation/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,18 @@ export default {
male: '男',
female: '女',
other: '其他',

// Team detail page
team_members: '团队成员',
team_works: '团队作品',
latest_news: '最新动态',
no_news_yet: '暂无动态',
join_team: '加入团队',
leave_team: '退出团队',
manage_team: '管理团队',
cancel_application: '取消申请',
please_make_sure: '请确认',
success: '成功',
team_description: '团队描述',
team_details: '团队详情',
};
14 changes: 14 additions & 0 deletions translation/zh-TW.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,18 @@ export default {
male: '男',
female: '女',
other: '其他',

// Team detail page
team_members: '團隊成員',
team_works: '團隊作品',
latest_news: '最新動態',
no_news_yet: '暫無動態',
join_team: '加入團隊',
leave_team: '退出團隊',
manage_team: '管理團隊',
cancel_application: '取消申請',
please_make_sure: '請確認',
success: '成功',
team_description: '團隊描述',
team_details: '團隊詳情',
};
Loading