diff --git a/frontend2/.env.development b/frontend2/.env.development index 4bfb5fa98..d1d6ea9d8 100644 --- a/frontend2/.env.development +++ b/frontend2/.env.development @@ -1,3 +1,3 @@ REACT_APP_THIS_URL=http://localhost:3000 -REACT_APP_BACKEND_URL=http://api.staging.battlecode.org/ +REACT_APP_BACKEND_URL=http://localhost:8000 REACT_APP_REPLAY_URL=https://play.battlecode.org diff --git a/frontend2/src/api/loaders/myTeamLoader.ts b/frontend2/src/api/loaders/myTeamLoader.ts index aefd6aa44..c848efbd5 100644 --- a/frontend2/src/api/loaders/myTeamLoader.ts +++ b/frontend2/src/api/loaders/myTeamLoader.ts @@ -2,6 +2,12 @@ import type { QueryClient } from "@tanstack/react-query"; import type { LoaderFunction } from "react-router-dom"; import { myTeamFactory } from "../team/teamFactories"; import { buildKey } from "../helpers"; +import { isNil } from "lodash"; +import { scrimmagingRecordFactory } from "api/compete/competeFactories"; +import { + CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum, + type TeamPrivate, +} from "api/_autogen"; export const myTeamLoader = (queryClient: QueryClient): LoaderFunction => @@ -16,5 +22,39 @@ export const myTeamLoader = queryFn: async () => await myTeamFactory.queryFn({ episodeId }), }); + // Win/loss/tie + const teamDataCached = queryClient.getQueryData( + buildKey(myTeamFactory.queryKey, { episodeId }), + ); + + if (!isNil(teamDataCached)) { + void queryClient.ensureQueryData({ + queryKey: buildKey(scrimmagingRecordFactory.queryKey, { + episodeId, + teamId: teamDataCached.id, + scrimmageType: + CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.Ranked, + }), + }); + + void queryClient.ensureQueryData({ + queryKey: buildKey(scrimmagingRecordFactory.queryKey, { + episodeId, + teamId: teamDataCached.id, + scrimmageType: + CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.Unranked, + }), + }); + + void queryClient.ensureQueryData({ + queryKey: buildKey(scrimmagingRecordFactory.queryKey, { + episodeId, + teamId: teamDataCached.id, + scrimmageType: + CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.All, + }), + }); + } + return null; }; diff --git a/frontend2/src/components/compete/ScrimmagingRecord.tsx b/frontend2/src/components/compete/ScrimmagingRecord.tsx index 00a3122c2..b620fcef6 100644 --- a/frontend2/src/components/compete/ScrimmagingRecord.tsx +++ b/frontend2/src/components/compete/ScrimmagingRecord.tsx @@ -6,7 +6,6 @@ import { import { useScrimmagingRecord } from "api/compete/useCompete"; import { useEpisodeId } from "contexts/EpisodeContext"; import WinLossTie from "./WinLossTie"; -import Spinner from "components/Spinner"; interface ScrimmagingRecordProps { team: Pick; @@ -57,11 +56,11 @@ const ScrimmagingRecord: React.FC = ({
{team.name}
)} - {!scrimmagingRecordAll.isSuccess || - !scrimmagingRecordUnranked.isSuccess || - !scrimmagingRecordRanked.isSuccess ? ( + {scrimmagingRecordAll.isError || + scrimmagingRecordUnranked.isError || + scrimmagingRecordRanked.isError ? (
- Loading... + Error fetching scrimmaging record.
) : (
@@ -70,9 +69,10 @@ const ScrimmagingRecord: React.FC = ({ scrimmageType={ CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.All } - wins={scrimmagingRecordAll.data.wins ?? 0} - losses={scrimmagingRecordAll.data.losses ?? 0} - ties={scrimmagingRecordAll.data.ties ?? 0} + loading={scrimmagingRecordAll.isFetching} + wins={scrimmagingRecordAll.data?.wins ?? 0} + losses={scrimmagingRecordAll.data?.losses ?? 0} + ties={scrimmagingRecordAll.data?.ties ?? 0} /> )} {!hideUnranked && ( @@ -80,9 +80,10 @@ const ScrimmagingRecord: React.FC = ({ scrimmageType={ CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.Unranked } - wins={scrimmagingRecordUnranked.data.wins ?? 0} - losses={scrimmagingRecordUnranked.data.losses ?? 0} - ties={scrimmagingRecordUnranked.data.ties ?? 0} + loading={scrimmagingRecordUnranked.isFetching} + wins={scrimmagingRecordUnranked.data?.wins ?? 0} + losses={scrimmagingRecordUnranked.data?.losses ?? 0} + ties={scrimmagingRecordUnranked.data?.ties ?? 0} /> )} {!hideRanked && ( @@ -90,9 +91,10 @@ const ScrimmagingRecord: React.FC = ({ scrimmageType={ CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.Ranked } - wins={scrimmagingRecordRanked.data.wins ?? 0} - losses={scrimmagingRecordRanked.data.losses ?? 0} - ties={scrimmagingRecordRanked.data.ties ?? 0} + loading={scrimmagingRecordRanked.isFetching} + wins={scrimmagingRecordRanked.data?.wins ?? 0} + losses={scrimmagingRecordRanked.data?.losses ?? 0} + ties={scrimmagingRecordRanked.data?.ties ?? 0} /> )}
diff --git a/frontend2/src/components/compete/WinLossTie.tsx b/frontend2/src/components/compete/WinLossTie.tsx index b5bc94520..2de044c5f 100644 --- a/frontend2/src/components/compete/WinLossTie.tsx +++ b/frontend2/src/components/compete/WinLossTie.tsx @@ -1,11 +1,14 @@ -import React from "react"; +import React, { useMemo } from "react"; import { CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum } from "api/_autogen"; +import Spinner from "components/Spinner"; +import { isNil } from "lodash"; interface WinLossTieProps { scrimmageType: CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum; wins: number; losses: number; ties: number; + loading?: boolean; className?: string; } @@ -21,8 +24,29 @@ const WinLossTie: React.FC = ({ wins, losses, ties, + loading, className = "", }) => { + const HEADER = + "w-full border-t-2 border-b-2 border-solid border-cyan-600 text-center"; + + const dataClassName = useMemo(() => { + const baseClassName = "w-full p-1"; + if (!isNil(loading) && loading) { + return `${baseClassName} flex flex-row items-center justify-center`; + } else { + return `${baseClassName} text-center font-semibold`; + } + }, [loading]); + + const dataOrLoading = (count: number): JSX.Element => { + if (!isNil(loading) && loading) { + return ; + } else { + return <>{count}; + } + }; + return (
= ({
{scrimmageTypeToName[scrimmageType]}
- + Wins - - Losses - - + Losses + Ties -
- {wins} +
+ {dataOrLoading(wins)}
-
- {losses} +
+ {dataOrLoading(losses)}
-
- {ties} +
+ {dataOrLoading(ties)}
); diff --git a/frontend2/src/components/tables/RankingsTable.tsx b/frontend2/src/components/tables/RankingsTable.tsx index b9776fa0e..960d2455b 100644 --- a/frontend2/src/components/tables/RankingsTable.tsx +++ b/frontend2/src/components/tables/RankingsTable.tsx @@ -76,7 +76,7 @@ const RankingsTable: React.FC = ({ <> {trimString(member.username, 13)} diff --git a/frontend2/src/views/MyTeam.tsx b/frontend2/src/views/MyTeam.tsx index 208d45b48..dbb495c53 100644 --- a/frontend2/src/views/MyTeam.tsx +++ b/frontend2/src/views/MyTeam.tsx @@ -21,6 +21,7 @@ import Loading from "components/Loading"; import { type SubmitHandler, useForm } from "react-hook-form"; import { FIELD_REQUIRED_ERROR_MSG } from "utils/constants"; import FormLabel from "components/elements/FormLabel"; +import ScrimmagingRecord from "components/compete/ScrimmagingRecord"; interface InfoFormInput { quote: string; @@ -61,9 +62,9 @@ const MyTeam: React.FC = () => { }, ); - const onInfoSubmit: SubmitHandler = async (data) => { + const onInfoSubmit: SubmitHandler = (data) => { if (updateTeam.isPending) return; - await updateTeam.mutateAsync({ + updateTeam.mutate({ profile: { quote: data.quote, biography: data.biography, @@ -72,13 +73,13 @@ const MyTeam: React.FC = () => { resetInfo(); }; - // eslint-disable-next-line @typescript-eslint/no-misused-promises - const onLeaveTeam: EventHandler> = async ( + const onLeaveTeam: EventHandler> = ( event, ) => { if (leaveTeam.isPending) return; event.preventDefault(); - await leaveTeam.mutateAsync(); + event.stopPropagation(); + leaveTeam.mutate(); setIsLeaveModalOpen(false); }; @@ -154,19 +155,25 @@ const MyTeam: React.FC = () => {
- {/* The members list and file upload that display when on a smaller screen */} + {/* The members list, file upload, and win/loss that display when on a smaller screen */} {membersList} + + +
- {/* Display the members list and file upload to the right when on a big screen. */} + {/* Display the members list, file upload, and win/loss to the right when on a big screen. */}
{membersList} + + + @@ -188,7 +195,6 @@ const MyTeam: React.FC = () => {