-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Team Profile page (for other teams) (#803)
- Loading branch information
Showing
8 changed files
with
182 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
REACT_APP_THIS_URL=http://localhost:3000 | ||
REACT_APP_BACKEND_URL=http://localhost:8000 | ||
REACT_APP_BACKEND_URL=http://api.staging.battlecode.org/ | ||
REACT_APP_REPLAY_URL=https://play.battlecode.org |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import type { QueryClient } from "@tanstack/react-query"; | ||
import type { LoaderFunction } from "react-router-dom"; | ||
import { matchListFactory } from "../compete/competeFactories"; | ||
import { buildKey } from "../helpers"; | ||
import { | ||
otherTeamInfoFactory, | ||
searchTeamsFactory, | ||
} from "../team/teamFactories"; | ||
|
||
// loader for other team's public profile pages | ||
export const teamProfileLoader = | ||
(queryClient: QueryClient): LoaderFunction => | ||
({ params }) => { | ||
const episodeId = params.episodeId; | ||
const teamId = params.teamId; | ||
if (teamId === undefined || episodeId === undefined) return null; | ||
|
||
// All teams | ||
void queryClient.ensureQueryData({ | ||
queryKey: buildKey(otherTeamInfoFactory.queryKey, { | ||
episodeId, | ||
id: teamId, | ||
}), | ||
queryFn: async () => | ||
await otherTeamInfoFactory.queryFn({ episodeId, id: teamId }), | ||
}); | ||
return null; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import React, { useMemo } from "react"; | ||
import { useEpisodeId } from "contexts/EpisodeContext"; | ||
import { useParams } from "react-router-dom"; | ||
import { useQueryClient } from "@tanstack/react-query"; | ||
import { useTeam } from "api/team/useTeam"; | ||
import { isNil } from "lodash"; | ||
import SectionCard from "components/SectionCard"; | ||
import { PageTitle } from "components/elements/BattlecodeStyle"; | ||
import MemberList from "components/team/MemberList"; | ||
import Loading from "components/Loading"; | ||
import { Status526Enum } from "api/_autogen"; | ||
import { useEpisodeInfo } from "api/episode/useEpisode"; | ||
|
||
const isNilOrEmptyStr = (str: string | undefined | null): boolean => { | ||
return isNil(str) || str === ""; | ||
}; | ||
|
||
// rendered at /:episodeId/team/:teamId | ||
const TeamProfile: React.FC = () => { | ||
const { episodeId } = useEpisodeId(); | ||
const { teamId } = useParams(); | ||
const episode = useEpisodeInfo({ id: episodeId }); | ||
const team = useTeam({ episodeId, id: teamId ?? "" }); | ||
const membersList = useMemo(() => { | ||
return ( | ||
<div className="flex flex-col gap-8"> | ||
{!team.isSuccess ? ( | ||
<Loading /> | ||
) : ( | ||
<MemberList members={team.data.members} /> | ||
)} | ||
</div> | ||
); | ||
}, [team]); | ||
const eligibles = useMemo( | ||
() => | ||
episode.data?.eligibility_criteria.filter( | ||
(criterion) => | ||
team.data?.profile?.eligible_for?.find( | ||
(id) => id === criterion.id, | ||
) !== undefined, | ||
) ?? [], | ||
[episode, team], | ||
); | ||
if (isNil(team.data)) { | ||
return <TeamNotFound />; | ||
} | ||
|
||
return ( | ||
<div className="p-6"> | ||
<PageTitle>Team Profile</PageTitle> | ||
<div className="flex flex-col gap-8 xl:flex-row"> | ||
<div className="flex flex-1 flex-col gap-8 xl:max-w-4xl"> | ||
<SectionCard title="Profile" className=""> | ||
<div className="flex flex-col md:flex-row md:gap-8"> | ||
<div className="flex flex-col items-center p-4"> | ||
<img | ||
className="h-24 w-24 rounded-full bg-gray-400 md:h-48 md:w-48" | ||
src={team.data.profile?.avatar_url} | ||
// TODO: open add avatar modal on click! With hover effect! | ||
/> | ||
<div className="mt-6 text-center text-xl font-semibold"> | ||
{team.data.name} | ||
</div> | ||
{team.data.status === Status526Enum.S && ( | ||
<div className="text-sm font-light text-gray-500"> | ||
(staff team) | ||
</div> | ||
)} | ||
</div> | ||
<div className="flex flex-1 flex-col gap-4"> | ||
<div> | ||
<div className="font-medium">Team quote</div> | ||
<div className="text-sm text-gray-800"> | ||
{isNilOrEmptyStr(team.data.profile?.quote) ? ( | ||
<span className="italic text-gray-500"> | ||
This team does not have a quote | ||
</span> | ||
) : ( | ||
team.data.profile?.quote | ||
)} | ||
</div> | ||
</div> | ||
<div> | ||
<div className="font-medium">Team biography</div> | ||
<div className="text-sm text-gray-800"> | ||
{isNilOrEmptyStr(team.data.profile?.biography) ? ( | ||
<span className="italic text-gray-500"> | ||
This team does not have a biography | ||
</span> | ||
) : ( | ||
team.data.profile?.biography | ||
)} | ||
</div> | ||
</div> | ||
<div> | ||
<div className="font-medium">Eligibility</div> | ||
<div className="text-sm text-gray-800"> | ||
{eligibles.length !== 0 ? ( | ||
eligibles?.map((criterion) => ( | ||
<div key={criterion.id}> | ||
{criterion.title} | ||
{" "} | ||
{criterion.icon} | ||
</div> | ||
)) | ||
) : ( | ||
<span className="italic text-gray-500"> | ||
This team did not select any eligibility criteria. | ||
</span> | ||
)} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</SectionCard> | ||
<SectionCard title="Rating"></SectionCard> | ||
{/* The members list that displays when on a smaller screen */} | ||
<SectionCard className="shrink xl:hidden" title="Members"> | ||
{membersList} | ||
</SectionCard> | ||
</div> | ||
|
||
{/* The members list that displays to the right side when on a big screen. */} | ||
<SectionCard className="hidden w-1/3 shrink xl:block" title="Members"> | ||
{membersList} | ||
</SectionCard> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
const TeamNotFound: React.FC = () => { | ||
const { teamId } = useParams(); | ||
return <div>Team {teamId} was not found.</div>; | ||
}; | ||
|
||
export default TeamProfile; |