diff --git a/app/(authenticated)/page.tsx b/app/(authenticated)/page.tsx
index 204f1e0..63c263a 100644
--- a/app/(authenticated)/page.tsx
+++ b/app/(authenticated)/page.tsx
@@ -1,15 +1,15 @@
-import {Breadcrumbs, Grid, Stack, Typography} from "@mui/material";
-import CardBackground from "@/components/layout/cardBackground";
-import CardLarge from "@/components/layout/cardLarge";
-import CardList from "@/components/layout/cardList";
-import SportsList from "@/components/sports/sportsList";
-import {sportFactory} from "@/src/models/SportModel";
+import {Breadcrumbs, Grid, Stack, Typography} from "@mui/material"
+import CardBackground from "@/components/layout/cardBackground"
+import CardLarge from "@/components/layout/cardLarge"
+import SportsList from "@/components/sports/sportsList"
+import {sportFactory} from "@/src/models/SportModel"
+import InProgressMatchList from "@/components/match/inProgressMatchList"
export default async function Home() {
const sports = await sportFactory().index()
return (
-
+
管理者のダッシュボード
@@ -23,69 +23,8 @@ export default async function Home() {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
- );
+ )
}
diff --git a/app/(authenticated)/sports/[id]/games/[gameId]/page.tsx b/app/(authenticated)/sports/[id]/games/[gameId]/page.tsx
index b24ab32..de85203 100644
--- a/app/(authenticated)/sports/[id]/games/[gameId]/page.tsx
+++ b/app/(authenticated)/sports/[id]/games/[gameId]/page.tsx
@@ -1,8 +1,8 @@
import CardBackground from "@/components/layout/cardBackground";
-import {Stack, Grid, Link, Typography, Breadcrumbs} from "@mui/material";
-import CardList from "@/components/layout/cardList";
+import {Stack, Link, Typography, Breadcrumbs} from "@mui/material";
import {sportFactory} from "@/src/models/SportModel";
import {gameFactory} from "@/src/models/GameModel";
+import MatchList from "@/components/match/matchList";
import LeagueTable from "@/components/league/table/leagueTable";
export default async function GamePage({params}: { params: { gameId:string, id: string } }) {
@@ -10,6 +10,7 @@ export default async function GamePage({params}: { params: { gameId:string, id:
const game = await gameFactory().show(gameId)
const sportId = parseInt(params.id, 10)
const sport = await sportFactory().show(sportId)
+ const matchList = await gameFactory().getGameMatches(gameId)
return(
@@ -28,10 +29,10 @@ export default async function GamePage({params}: { params: { gameId:string, id:
-
-
-
-
+
+
)
diff --git a/app/(authenticated)/sports/[id]/page.tsx b/app/(authenticated)/sports/[id]/page.tsx
index 6c1dd25..ed4ba52 100644
--- a/app/(authenticated)/sports/[id]/page.tsx
+++ b/app/(authenticated)/sports/[id]/page.tsx
@@ -1,10 +1,10 @@
import CardBackground from "@/components/layout/cardBackground";
import {Stack, Grid, Link, Typography, Breadcrumbs} from "@mui/material";
-import CardList from "@/components/layout/cardList";
import {sportFactory} from "@/src/models/SportModel";
import SportEditor from "@/components/sports/sportEditor";
import LeagueList from "@/components/sports/leagueList";
import {gameFactory} from "@/src/models/GameModel";
+import SportInProgressMatchList from "@/components/match/sportInProgressMatchList";
export default async function SportPage({params}: { params: { id: string } }) {
const sportId = parseInt(params.id, 10)
@@ -42,9 +42,7 @@ export default async function SportPage({params}: { params: { id: string } }) {
-
-
-
+
)
diff --git a/components/match/inProgressMatchList.tsx b/components/match/inProgressMatchList.tsx
new file mode 100644
index 0000000..e334fff
--- /dev/null
+++ b/components/match/inProgressMatchList.tsx
@@ -0,0 +1,31 @@
+import {gameFactory} from "@/src/models/GameModel"
+import {Match, matchFactory} from "@/src/models/MatchModel"
+import MatchList from "@/components/match/matchList"
+
+export default async function InProgressMatchList() {
+ // get all games
+ const games = await gameFactory().index()
+ const matches = await matchFactory().index()
+
+ const matchList: Match[] = []
+ for (const game of games) {
+ // get all matches
+ const filteredMatches = matches.filter((match) => match.gameId == game.id)
+ // filter matches that are not finished
+ const inProgressMatches = filteredMatches.filter((match) => match.status == "standby" || match.status == "in_progress")
+
+ // sort by start time
+ inProgressMatches.sort((a, b) => {
+ return new Date(a.startAt).getTime() - new Date(b.startAt).getTime()
+ })
+
+ console.log(inProgressMatches[0])
+
+ // pick the first match
+ matchList.push(inProgressMatches[0])
+ }
+
+ return (
+
+ )
+}
diff --git a/components/layout/cardList.tsx b/components/match/matchCard.tsx
similarity index 56%
rename from components/layout/cardList.tsx
rename to components/match/matchCard.tsx
index 746b289..c7ab33e 100644
--- a/components/layout/cardList.tsx
+++ b/components/match/matchCard.tsx
@@ -1,22 +1,37 @@
import {Grid, Button, Avatar, Chip, Stack, Tooltip, Divider} from "@mui/material";
-import React, {ReactNode} from 'react';
import {HiClock, HiFlag, HiMapPin, HiTableCells, HiUserGroup} from "react-icons/hi2";
+import {Match} from "@/src/models/MatchModel";
+import {sportFactory} from "@/src/models/SportModel";
+import {gameFactory} from "@/src/models/GameModel";
+import {locationFactory} from "@/src/models/LocationModel";
+import {teamFactory} from "@/src/models/TeamModel";
-type CardProps = {
- link?: string;
- sport: string;
- league: string;
- judge: string;
- left: string;
- right: string;
- time: string;
- location: string;
+type MatchCardProps = {
+ match: Match
}
-const CardList: React.FC = ({link, location, sport, league, judge, left, right, time}) => {
+export default async function MatchCard(props: MatchCardProps) {
+ const sport = await sportFactory().show(props.match.sportId)
+ const game = await gameFactory().show(props.match.gameId)
+ const location = props.match.locationId == null ? undefined : await locationFactory().show(props.match.locationId)
+ const leftTeam = props.match.leftTeamId == null ? undefined : await teamFactory().show(props.match.leftTeamId)
+ const rightTeam = props.match.rightTeamId == null ? undefined : await teamFactory().show(props.match.rightTeamId)
+ const judgeTeam = props.match.judgeTeamId == null ? undefined : await teamFactory().show(props.match.judgeTeamId)
+
+ const date = new Date(props.match.startAt)
+ const formattedDate = `${date.getHours()}時${date.getMinutes() < 10 ? '0' : ''}${date.getMinutes()}分`
+
return (
-
);
};
-
-export default CardList;
diff --git a/components/match/matchEditor.tsx b/components/match/matchEditor.tsx
index daa9197..34a490e 100644
--- a/components/match/matchEditor.tsx
+++ b/components/match/matchEditor.tsx
@@ -1,7 +1,7 @@
'use client'
-import React, {useRef} from "react";
-import {useAsync} from "react-use";
-import {useRouter} from "next/navigation";
+import React, {useRef, useState} from "react"
+import {useAsync} from "react-use"
+import {useRouter} from "next/navigation"
import {
Accordion,
AccordionDetails,
@@ -19,17 +19,17 @@ import {
Typography,
ToggleButton,
ToggleButtonGroup, Chip, SvgIcon, Avatar
-} from "@mui/material";
-import CardBackground from "@/components/layout/cardBackground";
-import {HiCheck, HiChevronDown, HiArrowPath, HiFlag, HiMapPin, HiClock} from "react-icons/hi2";
-
-import {Sport} from "@/src/models/SportModel";
-import {Game} from "@/src/models/GameModel";
-import {Match, matchFactory, MatchResult, MatchStatus} from "@/src/models/MatchModel";
-import {Team, teamFactory} from "@/src/models/TeamModel";
-import {Location, locationFactory} from "@/src/models/LocationModel";
-import Loading from "@/app/(authenticated)/loading";
-import Link from "next/link";
+} from "@mui/material"
+import CardBackground from "@/components/layout/cardBackground"
+import {HiCheck, HiChevronDown, HiArrowPath, HiFlag, HiMapPin, HiClock, HiMiniNoSymbol} from "react-icons/hi2"
+
+import {Sport} from "@/src/models/SportModel"
+import {Game} from "@/src/models/GameModel"
+import {Match, matchFactory, MatchResult, MatchStatus} from "@/src/models/MatchModel"
+import {Team, teamFactory} from "@/src/models/TeamModel"
+import {Location, locationFactory} from "@/src/models/LocationModel"
+import Loading from "@/app/(authenticated)/loading"
+import Link from "next/link"
export type MatchEditorProps = {
sport: Sport
@@ -39,98 +39,92 @@ export type MatchEditorProps = {
export default function MatchEditor(props: MatchEditorProps) {
const router = useRouter()
- const useState = React.useState;
-
- const teamUndefined = {
- id: 0,
- name: "取得中",
- description: "取得中",
- classId: 0,
- teamTagId: 0,
- userIds: [],
- enteredGameIds: [],
- createdAt: "0",
- updatedAt: "0"
- };
-
- // state
+ // loading state
const [isFetching, setIsFetching] = useState(true)
- const [leftTeam, setLeftTeam] = useState(teamUndefined);
- const [rightTeam, setRightTeam] = useState(teamUndefined);
- const [judgeTeam, setJudgeTeam] = useState(teamUndefined);
- const [matchResult, setMatchResult] = useState(props.match.result);
- const [matchStatus, setMatchStatus] = useState(props.match.status);
- const [locations, setLocations] = useState([]);
- const [locationId, setLocationId] = useState(props.match.locationId);
- const [teams, setTeams] = useState([]);
- const [judgeTeamId, setJudgeTeamId] = useState(props.match.judgeTeamId);
- const [updateSnackOpen, setUpdateSnackOpen] = React.useState(false)
- const [cancelSnackOpen, setCancelSnackOpen] = React.useState(false)
- const [scoreError, setScoreError] = useState(false);
- const leftRef = useRef(null)
- const rightRef = useRef(null)
+ // index
+ const [teams, setTeams] = useState([])
+ const [locations, setLocations] = useState([])
+ // match result state
+ const [matchResult, setMatchResult] = useState(props.match.result)
+ const [matchStatus, setMatchStatus] = useState(props.match.status)
+ // location and team state
+ const [locationId, setLocationId] = useState(props.match.locationId)
+ const [judgeTeamId, setJudgeTeamId] = useState(props.match.judgeTeamId)
+ // UX state
+ const [updateSnackOpen, setUpdateSnackOpen] = useState(false)
+ const [cancelSnackOpen, setCancelSnackOpen] = useState(false)
+ const [scoreError, setScoreError] = useState(false)
+ const [matchStateError, setMatchStateError] = useState(false)
+ const leftScoreRef = useRef(null)
+ const rightScoreRef = useRef(null)
const noteRef = useRef(null)
// fetch data
useAsync(async () => {
- const fetchMatchEditor = async () => {
- const left = await teamFactory().show(Number(props.match.leftTeamId));
- const right = await teamFactory().show(Number(props.match.rightTeamId));
- const judge = await teamFactory().show(Number(props.match.judgeTeamId));
- const location = await locationFactory().index();
- const teams = await teamFactory().index();
- setLeftTeam(left);
- setRightTeam(right);
- setJudgeTeam(judge);
- setLocations(location);
- setTeams(teams);
- setIsFetching(false);
- };
-
- return fetchMatchEditor();
+ const fetchedLocations = await locationFactory().index()
+ setLocations(fetchedLocations)
+
+ const fetchedTeams = await teamFactory().index()
+ // filter by game id
+ const filteredTeams = fetchedTeams.filter(team => team.enteredGameIds.includes(props.game.id))
+ setTeams(filteredTeams)
+
+ // finish loading
+ setIsFetching(false)
})
// reformat data
- const locationName = locations.find(location => location.id === props.match.locationId)?.name;
- const date = new Date(props.match.startAt);
- const formattedDate = `${date.getMonth() + 1}月${date.getDate()}日 ${date.getHours()}時${date.getMinutes() < 10 ? '0' : ''}${date.getMinutes()}分`;
+ const locationName = locations.find(location => location.id === props.match.locationId)?.name
+ const date = new Date(props.match.startAt)
+ const formattedDate = `${date.getMonth() + 1}月${date.getDate()}日 ${date.getHours()}時${date.getMinutes() < 10 ? '0' : ''}${date.getMinutes()}分`
- // handler
+ // snack bar close handler
const handleUpdateSnackClose = () => {
setUpdateSnackOpen(false)
}
+ // snack bar close handler
const handleCancelSnackClose = () => {
setCancelSnackOpen(false)
}
+
+ // match result change handler
const handleResultChange = (
- event: React.MouseEvent,
+ _: React.MouseEvent,
newResult: string,
) => {
- setMatchResult(newResult as MatchResult);
- };
+ setMatchResult(newResult as MatchResult)
+ }
+
+ // match status change handler
const handleStatusChange = (
- event: React.MouseEvent,
+ _: React.MouseEvent,
newStatus: string,
) => {
- setMatchStatus(newStatus as MatchStatus);
- };
+ setMatchStatus(newStatus as MatchStatus)
+ }
+
+ const handleMatchStateErrorClose = () => {
+ setMatchStateError(false)
+ }
+
+ // auto compare
const handleCompare = () => {
- const leftScore = Number(leftRef.current?.value);
- const rightScore = Number(rightRef.current?.value);
+ const leftScore = Number(leftScoreRef.current?.value)
+ const rightScore = Number(rightScoreRef.current?.value)
if (leftScore !== 0 || rightScore !== 0) {
- setMatchStatus('finished');
+ setMatchStatus('finished')
} else {
- setMatchStatus('standby');
+ setMatchStatus('standby')
}
if (leftScore > rightScore) {
- setMatchResult('left_win');
+ setMatchResult('left_win')
} else if (leftScore < rightScore) {
- setMatchResult('right_win');
+ setMatchResult('right_win')
} else {
- setMatchResult('draw');
+ setMatchResult('draw')
}
setScoreError(false)
}
@@ -142,23 +136,28 @@ export default function MatchEditor(props: MatchEditorProps) {
setLocationId(props.match.locationId)
setJudgeTeamId(props.match.judgeTeamId)
noteRef.current!.value = props.match.note
- leftRef.current!.value = props.match.leftScore
- rightRef.current!.value = props.match.rightScore
+ leftScoreRef.current!.value = props.match.leftScore
+ rightScoreRef.current!.value = props.match.rightScore
setCancelSnackOpen(true)
}
// update data
const handleUpdate = async () => {
- const leftScoreValue = leftRef.current?.value;
- const rightScoreValue = rightRef.current?.value;
+ const leftScoreValue = leftScoreRef.current?.value
+ const rightScoreValue = rightScoreRef.current?.value
if (!leftScoreValue || !rightScoreValue || isNaN(Number(leftScoreValue)) || isNaN(Number(rightScoreValue || Number(leftScoreValue) < 0 || Number(rightScoreValue) < 0))) {
- setScoreError(true);
- return;
+ setScoreError(true)
+ return
}
- const leftScore = Number(leftScoreValue);
- const rightScore = Number(rightScoreValue);
+ const leftScore = Number(leftScoreValue)
+ const rightScore = Number(rightScoreValue)
+
+ if (!matchResult || !matchStatus) {
+ setMatchStateError(true)
+ return
+ }
await matchFactory().update(props.match.id, {
locationId: locationId,
@@ -178,322 +177,353 @@ export default function MatchEditor(props: MatchEditorProps) {
router.refresh()
setUpdateSnackOpen(true)
setScoreError(false)
+ setMatchStateError(false)
}
if (isFetching) {
return (
)
- } else {
- return (
-
-
-
-
-
-
- } color={"secondary"}
- />
- } color={"secondary"}
+ }
+
+ const leftTeamName = teams.find(team => team.id === props.match.leftTeamId)?.name ?? "未登録"
+ const rightTeamName = teams.find(team => team.id === props.match.rightTeamId)?.name ?? "未登録"
+ const judgeTeamName = teams.find(team => team.id === props.match.judgeTeamId)?.name ?? "未登録"
+
+ return (
+
+
+
+
+
+
+ } color={"secondary"}
+ />
+ } color={"secondary"}
+ />
+ } color={"secondary"}
+ />
+
+
+
+
+
+
+ {leftTeamName}のスコア
+
- } color={"secondary"}
+
+
+ VS
+
+
+ {rightTeamName}のスコア
+
+
-
+
-
-
+
+ 勝ったのは
+
- {leftTeam.name}のスコア
-
-
-
- VS
-
- {leftTeamName}
+ 引き分け
+ {rightTeamName}
+
+
+
+ 試合の状態
+
- {rightTeam.name}のスコア
-
-
+ 中止
+ スタンバイ
+ 進行中
+ 完了
+
+
-
-
-
-
- 勝ったのは
-
- {leftTeam.name}
- 引き分け
- {rightTeam.name}
-
-
-
- 試合の状態
-
- 中止
- スタンバイ
- 進行中
- 完了
-
-
-
+
+ }
+ onClick={handleCancel}
+ >
+ 元に戻す
+
+ }
+ onClick={handleUpdate}
+ >
+ 保存
+
+
+
+
+
+
+
+
+ }
+ aria-controls="panel-content"
+ id="panel-header"
+ >
+ 編集する
+
+
+
+
+ 補足
+
+
+ 審判
+
+ 審判
+
+
+
+ 試合の場所
+
+ 場所
+
+
}
onClick={handleCancel}
>
- 元に戻す
+ すべて元に戻す
}
onClick={handleUpdate}
>
- 保存
+ すべて保存
-
-
-
-
-
- }
- aria-controls="panel-content"
- id="panel-header"
- >
- 編集する
-
-
-
+
+
+
- 補足
-
-
- 審判
-
- 審判
-
-
-
- 試合の場所
-
- 場所
-
-
-
-
- }
- onClick={handleCancel}
- >
- すべて元に戻す
-
- }
- onClick={handleUpdate}
- >
- すべて保存
-
-
-
-
-
-
-
+
-
-
-
-
-
-
- 変更が保存されました
-
-
- リーグに戻る
-
-
-
-
-
+
+
+
+
+ 変更が保存されました
+
+
+ リーグに戻る
+
+
+
+
+ {/*Cancel Snack*/}
+
+
-
-
-
-
-
-
- 変更を元に戻しました
-
-
- リーグに戻る
-
-
-
-
-
- )
- }
-}
\ No newline at end of file
+
+
+
+
+
+ 変更を元に戻しました
+
+
+ リーグに戻る
+
+
+
+
+ {/*Match State Error*/}
+
+
+
+
+
+
+
+ 勝者、状態を選択してください。
+
+
+
+
+
+ )
+}
diff --git a/components/match/matchList.tsx b/components/match/matchList.tsx
new file mode 100644
index 0000000..ebc2e7a
--- /dev/null
+++ b/components/match/matchList.tsx
@@ -0,0 +1,24 @@
+import Grid from "@mui/material/Grid";
+import {Match} from "@/src/models/MatchModel";
+import MatchCard from "@/components/match/matchCard";
+
+export type MatchListProps = {
+ matches: Match[]
+}
+
+export default async function MatchList(props: MatchListProps) {
+ const components = props.matches.map((match) =>
+
+ )
+ return (
+
+ {components}
+
+ )
+}
\ No newline at end of file
diff --git a/components/match/sportInProgressMatchList.tsx b/components/match/sportInProgressMatchList.tsx
new file mode 100644
index 0000000..341b9a9
--- /dev/null
+++ b/components/match/sportInProgressMatchList.tsx
@@ -0,0 +1,36 @@
+import {Sport} from "@/src/models/SportModel";
+import {gameFactory} from "@/src/models/GameModel";
+import {Match} from "@/src/models/MatchModel";
+import MatchList from "@/components/match/matchList";
+
+export interface SportInProgressMatchListProps {
+ sport: Sport
+}
+
+export default async function SportInProgressMatchList(props: SportInProgressMatchListProps) {
+ // get all games
+ const games = await gameFactory().index()
+ const filteredGames = games.filter((game) => game.sportId == props.sport.id)
+
+ const matchList: Match[] = []
+ for (const game of filteredGames) {
+ // get all matches
+ const matches = await gameFactory().getGameMatches(game.id)
+ // filter matches that are not finished
+ const inProgressMatches = matches.filter((match) => match.status == "standby" || match.status == "in_progress")
+
+ // sort by start time
+ inProgressMatches.sort((a, b) => {
+ return new Date(a.startAt).getTime() - new Date(b.startAt).getTime()
+ })
+
+ console.log(inProgressMatches[0])
+
+ // pick the first match
+ matchList.push(inProgressMatches[0])
+ }
+
+ return (
+
+ )
+}
diff --git a/src/models/MatchModel.ts b/src/models/MatchModel.ts
index 8071c86..b950ca0 100644
--- a/src/models/MatchModel.ts
+++ b/src/models/MatchModel.ts
@@ -13,7 +13,7 @@ export type Match = {
result: MatchResult,
status: MatchStatus,
note: string | null,
- judgeTeamId: string | null,
+ judgeTeamId: number | null,
parents: number[],
children: number[],
createdAt: string,