Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 試合結果のページを作成 #413

Merged
merged 31 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
28a8335
feat: 試合結果のページを作成
speak-mentaiko Oct 6, 2024
d7fd7e9
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 6, 2024
09b80d2
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 6, 2024
6ca0da0
fix: 部門でフィルタ
speak-mentaiko Oct 7, 2024
c6b5714
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 7, 2024
dd627ec
chore: フォーマット
speak-mentaiko Oct 7, 2024
c5275b6
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 8, 2024
a50a278
fix: 無限ループを修正
speak-mentaiko Oct 8, 2024
77aab55
chore: フォーマット
speak-mentaiko Oct 8, 2024
d6bd59b
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 8, 2024
9278232
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 9, 2024
463da86
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 9, 2024
3693147
fix: promiseチェーンの廃止
speak-mentaiko Oct 9, 2024
8b848bb
fix: コンポーネントを細分化
speak-mentaiko Oct 10, 2024
964939c
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 10, 2024
1828619
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 10, 2024
2295948
fix: useMemoの導入
speak-mentaiko Oct 10, 2024
e591bf5
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 10, 2024
bd402bf
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 10, 2024
1956eef
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 10, 2024
c4f8f6f
fix: 正しいuseMemo
speak-mentaiko Oct 11, 2024
8699011
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 11, 2024
7967d8a
fix: useMemoの修正
speak-mentaiko Oct 11, 2024
bcad126
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 11, 2024
61144ee
fix: mapをfilterに変更
speak-mentaiko Oct 11, 2024
19e9d48
fix: undefindに対応
speak-mentaiko Oct 11, 2024
6022048
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 11, 2024
d215f82
fix: parseSecondsの導入
speak-mentaiko Oct 11, 2024
4123224
fix: 型を合わせた
speak-mentaiko Oct 11, 2024
c6ad611
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 11, 2024
4ad1642
Merge branch 'main' into feat/58-run-result-page
speak-mentaiko Oct 11, 2024
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
248 changes: 248 additions & 0 deletions packages/kcmsf/src/pages/result.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
import { Flex, Select, Table, Title } from "@mantine/core";
import { DepartmentType, config } from "config";
import { useEffect, useMemo, useState } from "react";
import { parseSeconds } from "../utils/time";

type PreMatch = {
id: string;
matchCode: string;
departmentType: DepartmentType;
leftTeam?: {
id: string;
teamName: string;
};
rightTeam?: {
id: string;
teamName: string;
};
runResults: MatchResults;
};

type MainMatch = {
id: string;
matchCode: string;
departmentType: DepartmentType;
team1: {
id: string;
teamName: string;
};
team2: {
id: string;
teamName: string;
};
winnerID: string;
runResults: MatchResults;
};

type MatchResults = {
id: string;
teamID: string;
points: number;
goalTimeSeconds?: number;
finishState: "goal" | "finished";
}[];

export const Result = () => {
const [preMatchData, setPreMatchData] = useState<PreMatch[]>([]);
const [mainMatchData, setMainMatchData] = useState<MainMatch[]>([]);
const [department, setDepartment] = useState<DepartmentType>(
config.departments[0].type
);

useEffect(() => {
const getMatches = async () => {
const response = await fetch(`${import.meta.env.VITE_API_URL}/match`, {
method: "GET",
}).catch(() => undefined);

const matchResponse = (await response?.json()) as
| { pre: PreMatch[]; main: MainMatch[] }
| undefined;

setPreMatchData(matchResponse ? matchResponse.pre : []);
setMainMatchData(matchResponse ? matchResponse.main : []);
};
getMatches();
}, []);

const teamNames: Map<string, string> = useMemo(() => {
const team = new Map<string, string>();
mainMatchData.forEach((element) => {
if (element.team1) team.set(element.team1.id, element.team1.teamName);
if (element.team2) team.set(element.team2.id, element.team2.teamName);
});
return team;
}, [mainMatchData]);

const preMatches = useMemo(
() => mainMatchData.filter((match) => match.departmentType === department),
[mainMatchData]
);

const mainMatches = useMemo(
() => preMatchData.filter((match) => match.departmentType === department),
[preMatchData]
);

return (
<>
<Select
label="部門"
data={config.departments.map((element) => ({
value: element.type,
label: element.name,
}))}
value={department}
defaultValue={config.departments[0].type}
onChange={(value) => value && setDepartment(value as DepartmentType)}
/>
<Flex direction="column" gap={20}>
<Title order={3}>{config.department[department].name}</Title>
<MainResultTable matches={preMatches} teamNames={teamNames} />
<PreResultTable matches={mainMatches} />
</Flex>
</>
);
};

const MainResultTable = (props: {
matches: MainMatch[];
teamNames: Map<string, string>;
}) => {
if (props.matches.length === 0) {
return (
<div>
<Title order={3}>{"本戦"}</Title>
<p>結果がありません</p>
</div>
);
}
return (
<div>
<Title order={3}>{"本戦"}</Title>
<Table striped withTableBorder miw="40rem">
<Table.Thead>
<Table.Tr>
<Table.Th style={{ textAlign: "center" }}>勝ち</Table.Th>
<Table.Th style={{ textAlign: "center" }}>得点</Table.Th>
<Table.Th style={{ textAlign: "center" }}>負け</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{props.matches.map((element) => (
<Table.Tr key={element.id}>
<MainMatchColum match={element} teamData={props.teamNames} />
</Table.Tr>
))}
</Table.Tbody>
</Table>
</div>
);
};

const MainMatchColum = (props: {
match: MainMatch;
teamData: Map<string, string>;
}) => {
const loserID =
props.match.winnerID === props.match.team1.id
? props.match.team2.id
: props.match.team1.id;
return (
<>
<Table.Td className="td">
{props.teamData.get(props.match.winnerID)}
</Table.Td>
<Table.Td className="td">
{props.match.runResults
.filter((result) => result.teamID === props.match.winnerID)
.reduce((sum, result) => sum + result.points, 0)}
-
{props.match.runResults
.filter((result) => result.teamID !== props.match.winnerID)
.reduce((sum, result) => sum + result.points, 0)}
</Table.Td>
<Table.Td className="td">{props.teamData.get(loserID)}</Table.Td>
</>
);
};

const PreResultTable = (props: { matches: PreMatch[] }) => {
if (props.matches.length === 0) {
return (
<div>
<Title order={3}>{"予選"}</Title>
<p>結果がありません</p>
</div>
);
}
return (
<div>
<Title order={3}>{"予選"}</Title>
<Table striped withTableBorder miw="40rem">
<Table.Thead>
<Table.Tr>
<Table.Th style={{ textAlign: "center" }}>左チーム</Table.Th>
<Table.Th style={{ textAlign: "center" }}>得点</Table.Th>
<Table.Th style={{ textAlign: "center" }}>時間</Table.Th>
<Table.Th style={{ textAlign: "center" }}>右チーム</Table.Th>
<Table.Th style={{ textAlign: "center" }}>得点</Table.Th>
<Table.Th style={{ textAlign: "center" }}>時間</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{props.matches.map((element) => (
<Table.Tr key={element.id}>
<PreResultColum match={element} />
</Table.Tr>
))}
</Table.Tbody>
</Table>
</div>
);
};

const PreResultColum = (props: { match: PreMatch }) => {
const leftResult = useMemo(
() =>
props.match.runResults.find(
(result) => result.teamID === props.match.leftTeam?.id
),
[props.match]
);
const rightResult = useMemo(
() =>
props.match.runResults.find(
(result) => result.teamID === props.match.rightTeam?.id
),
[props.match]
);
const leftGoalTimeSeconds = useMemo(() => {
if (!leftResult) {
return "";
} else {
if (leftResult.goalTimeSeconds)
return parseSeconds(leftResult.goalTimeSeconds);
return "フィニッシュ";
}
}, [leftResult]);
const rightGoalTimeSeconds = useMemo(() => {
if (!rightResult) {
return "";
} else {
if (rightResult.goalTimeSeconds)
return parseSeconds(rightResult.goalTimeSeconds);
return "フィニッシュ";
}
}, [leftResult]);
return (
<>
<Table.Td className="td">{props.match.leftTeam?.teamName}</Table.Td>
<Table.Td className="td">{leftResult?.points}</Table.Td>
<Table.Td className="td">{leftGoalTimeSeconds}</Table.Td>
<Table.Td className="td">{props.match.rightTeam?.teamName}</Table.Td>
<Table.Td className="td">{rightResult?.points}</Table.Td>
<Table.Td className="td">{rightGoalTimeSeconds}</Table.Td>
</>
);
};
5 changes: 5 additions & 0 deletions packages/kcmsf/src/routes/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Match } from "../pages/match.tsx";
import { MatchList } from "../pages/matchList.tsx";
import { Register } from "../pages/register.tsx";
import { RegisterBulk } from "../pages/registerBulk.tsx";
import { Result } from "../pages/result.tsx";
import { Teams } from "../pages/teams.tsx";
import { Layout } from "./layout.tsx";

Expand Down Expand Up @@ -46,6 +47,10 @@ export const router = createBrowserRouter(
path: "matchlist",
element: <MatchList />,
},
{
path: "result",
element: <Result />,
},
],
},
],
Expand Down
38 changes: 31 additions & 7 deletions packages/mock/src/data/match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ export const preMatches: PreMatch[] = [
{
id: "3548129",
teamID: "1392387",
points: 4,
goalTimeSeconds: 130,
points: 5,
finishState: "finished",
},
{
id: "13847917",
teamID: "7549586",
points: 4,
goalTimeSeconds: 130,
finishState: "goal",
},
],
Expand All @@ -81,7 +81,6 @@ export const preMatches: PreMatch[] = [
id: "983156",
teamID: "4578932",
points: 8,
goalTimeSeconds: 120,
finishState: "finished",
},
],
Expand All @@ -108,15 +107,28 @@ export const mainMatches: MainMatch[] = [
teamID: "1392387",
points: 5,
goalTimeSeconds: 150,
finishState: "finished",
finishState: "goal",
},
{
id: "987326732",
teamID: "7549586",
points: 4,
goalTimeSeconds: 130,
finishState: "goal",
},
{
id: "68963290",
teamID: "7549586",
points: 6,
finishState: "finished",
},
{
id: "5640890",
teamID: "1392387",
points: 5,
goalTimeSeconds: 120,
finishState: "goal",
},
],
},
{
Expand All @@ -125,7 +137,7 @@ export const mainMatches: MainMatch[] = [
departmentType: config.departmentTypes[0],
team1: {
id: "1392387",
teamName: "かに1",
teamName: "かに3",
},
team2: {
id: "7549586",
Expand All @@ -138,15 +150,27 @@ export const mainMatches: MainMatch[] = [
teamID: "1392387",
points: 5,
goalTimeSeconds: 150,
finishState: "goal",
},
{
id: "987326732",
teamID: "1392387",
points: 4,
finishState: "finished",
},
{
id: "987326732",
teamID: "7549586",
points: 4,
goalTimeSeconds: 130,
points: 3,
finishState: "finished",
},
{
id: "4279861",
teamID: "7549586",
points: 5,
goalTimeSeconds: 150,
finishState: "goal",
},
],
},
];
Expand Down