diff --git a/app/(authenticated)/league/page.tsx b/app/(authenticated)/league/page.tsx
deleted file mode 100644
index f39e61e..0000000
--- a/app/(authenticated)/league/page.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import {Stack, Grid, Typography, Link, Breadcrumbs} from "@mui/material";
-import CardBackground from "@/components/layout/cardBackground";
-import {sportFactory} from "@/src/models/SportModel";
-import LeagueSportsList from "@/components/league/leagueSportsList";
-
-
-export default async function LeaguePage() {
- const sports = await sportFactory().index()
- return (
-
-
-
- 管理者のダッシュボード
-
- リーグ管理
-
-
-
-
-
-
-
- );
-}
diff --git a/app/(authenticated)/locations/page.tsx b/app/(authenticated)/locations/page.tsx
index e8973bb..10f93c6 100644
--- a/app/(authenticated)/locations/page.tsx
+++ b/app/(authenticated)/locations/page.tsx
@@ -1,6 +1,5 @@
import {Breadcrumbs, Link, Stack, Typography} from "@mui/material";
import CardBackground from "@/components/layout/cardBackground";
-import TeamsAgGrid from "@/components/teams/teamsTable";
export default function LocationPage() {
return (
@@ -12,7 +11,7 @@ export default function LocationPage() {
場所管理
- none
+ この機能は開発中です。
)
diff --git a/app/(authenticated)/page.tsx b/app/(authenticated)/page.tsx
index 559ba9d..204f1e0 100644
--- a/app/(authenticated)/page.tsx
+++ b/app/(authenticated)/page.tsx
@@ -12,17 +12,17 @@ export default async function Home() {
管理者のダッシュボード
-
-
-
-
-
この機能は開発中です
-
+
+
+
+
+
+
+
+
+ 管理者のダッシュボード
+
+
+ 競技管理
+
+
+ {sport.name}
+
+
+ {game.name}(ID:{gameId})
+
+ 試合(ID:{match.id})
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/app/(authenticated)/sports/[id]/[gameId]/page.tsx b/app/(authenticated)/sports/[id]/[gameId]/page.tsx
new file mode 100644
index 0000000..bde3291
--- /dev/null
+++ b/app/(authenticated)/sports/[id]/[gameId]/page.tsx
@@ -0,0 +1,36 @@
+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 {gameFactory} from "@/src/models/GameModel";
+
+export default async function GamePage({params}: { params: { gameId:string, id: string } }) {
+ const gameId = parseInt(params.gameId, 10)
+ const game = await gameFactory().show(gameId)
+ const sportId = parseInt(params.id, 10)
+ const sport = await sportFactory().show(sportId)
+
+ return(
+
+
+
+ 管理者のダッシュボード
+
+
+ 競技管理
+
+
+ {sport.name}
+
+ {game.name}(ID:{gameId})
+
+
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/app/(authenticated)/league/[id]/page.tsx b/app/(authenticated)/sports/[id]/league/page.tsx
similarity index 64%
rename from app/(authenticated)/league/[id]/page.tsx
rename to app/(authenticated)/sports/[id]/league/page.tsx
index 4347fa5..2806e9e 100644
--- a/app/(authenticated)/league/[id]/page.tsx
+++ b/app/(authenticated)/sports/[id]/league/page.tsx
@@ -3,19 +3,23 @@ import CardBackground from "@/components/layout/cardBackground";
import LeagueDnd from "@/components/league/leagueDnd";
import {sportFactory} from "@/src/models/SportModel";
-export default async function LeagueTestPage({params}: { params: { id: string } }) {
+export default async function LeaguePage({params}: { params: { id: string } }) {
const sportId = parseInt(params.id, 10)
const sport = await sportFactory().show(sportId)
+ const sportLink = `/sports/${sportId}`
return (
管理者のダッシュボード
-
- リーグ管理
+
+ 競技管理
- {sport.name}
+
+ {sport.name}
+
+ リーグを作成・編集
diff --git a/app/(authenticated)/sports/[id]/page.tsx b/app/(authenticated)/sports/[id]/page.tsx
index 468a3bb..bc57aec 100644
--- a/app/(authenticated)/sports/[id]/page.tsx
+++ b/app/(authenticated)/sports/[id]/page.tsx
@@ -1,6 +1,5 @@
import CardBackground from "@/components/layout/cardBackground";
import {Stack, Grid, Link, Typography, Breadcrumbs} from "@mui/material";
-import {ButtonLarge} from "@/components/layout/buttonLarge";
import CardList from "@/components/layout/cardList";
import {sportFactory} from "@/src/models/SportModel";
import SportEditor from "@/components/sports/sportEditor";
@@ -12,6 +11,7 @@ export default async function SportPage({params}: { params: { id: string } }) {
const sport = await sportFactory().show(sportId)
const games = await gameFactory().index()
const filteredGames = games.filter((game) => game.sportId == sportId)
+ const gameType = filteredGames.find(game => game)?.type;
return(
@@ -24,15 +24,24 @@ export default async function SportPage({params}: { params: { id: string } }) {
{sport.name}
+ {gameType === "league" && (
+
+
+
+
+
+ )}
+ {gameType === "tournament" && (
+
+
+
+
+
+ )}
-
-
-
-
-
-
+
diff --git a/app/(authenticated)/tournament/[id]/page.tsx b/app/(authenticated)/sports/[id]/tournament/page.tsx
similarity index 100%
rename from app/(authenticated)/tournament/[id]/page.tsx
rename to app/(authenticated)/sports/[id]/tournament/page.tsx
diff --git a/app/(authenticated)/tournament/page.tsx b/app/(authenticated)/tournament/page.tsx
deleted file mode 100644
index 98e6c58..0000000
--- a/app/(authenticated)/tournament/page.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import {Stack, Grid, Typography, Link, Breadcrumbs} from "@mui/material";
-import CardBackground from "@/components/layout/cardBackground";
-import CardLarge from "@/components/layout/cardLarge";
-import {ButtonLarge} from "@/components/layout/buttonLarge";
-
-export default function LeaguePage() {
- return (
-
-
-
- 管理者のダッシュボード
-
- トーナメント管理
-
-
-
-
- フットサル
-
-
-
-
- );
-}
diff --git a/components/layout/navigation.tsx b/components/layout/navigation.tsx
index 9674d2b..0b9ca9f 100644
--- a/components/layout/navigation.tsx
+++ b/components/layout/navigation.tsx
@@ -8,8 +8,6 @@ import {
HiMiniNewspaper,
HiUser,
HiUserGroup,
- HiTableCells,
- HiRectangleGroup,
HiTrophy,
HiMapPin, HiIdentification
} from "react-icons/hi2";
@@ -101,107 +99,78 @@ export const Navigation = () => {
- ユーザー
+ スポーツ
-
- 競技
+ 情報
-
-
-
-
- 編成
+
diff --git a/components/league/leagueSportsList.tsx b/components/league/leagueSportsList.tsx
deleted file mode 100644
index 0e180f7..0000000
--- a/components/league/leagueSportsList.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import {ButtonLarge} from "@/components/layout/buttonLarge";
-import {Sport} from "@/src/models/SportModel";
-
-export type SportsListProps = {
- sports: Sport[]
-}
-
-export default function LeagueSportsList(props: SportsListProps) {
- props.sports.sort((a, b) => b.weight - a.weight);
- return (
- <>
- {props.sports.map((sport) => (
-
- {sport.name}
-
- ))}
- >
- )
-}
\ No newline at end of file
diff --git a/components/match/matchEditor.tsx b/components/match/matchEditor.tsx
new file mode 100644
index 0000000..daa9197
--- /dev/null
+++ b/components/match/matchEditor.tsx
@@ -0,0 +1,499 @@
+'use client'
+import React, {useRef} from "react";
+import {useAsync} from "react-use";
+import {useRouter} from "next/navigation";
+import {
+ Accordion,
+ AccordionDetails,
+ AccordionSummary,
+ Alert,
+ Button,
+ Card, Divider, FormControl,
+ InputLabel,
+ MenuItem,
+ Select,
+ Snackbar,
+ Stack,
+ TextField,
+ TextFieldProps,
+ 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";
+
+export type MatchEditorProps = {
+ sport: Sport
+ game: Game
+ match: Match
+}
+
+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
+ 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)
+ 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();
+ })
+
+ // 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()}分`;
+
+ // handler
+ const handleUpdateSnackClose = () => {
+ setUpdateSnackOpen(false)
+ }
+ const handleCancelSnackClose = () => {
+ setCancelSnackOpen(false)
+ }
+ const handleResultChange = (
+ event: React.MouseEvent,
+ newResult: string,
+ ) => {
+ setMatchResult(newResult as MatchResult);
+ };
+ const handleStatusChange = (
+ event: React.MouseEvent,
+ newStatus: string,
+ ) => {
+ setMatchStatus(newStatus as MatchStatus);
+ };
+ const handleCompare = () => {
+ const leftScore = Number(leftRef.current?.value);
+ const rightScore = Number(rightRef.current?.value);
+
+ if (leftScore !== 0 || rightScore !== 0) {
+ setMatchStatus('finished');
+ } else {
+ setMatchStatus('standby');
+ }
+
+ if (leftScore > rightScore) {
+ setMatchResult('left_win');
+ } else if (leftScore < rightScore) {
+ setMatchResult('right_win');
+ } else {
+ setMatchResult('draw');
+ }
+ setScoreError(false)
+ }
+
+ // cancel
+ const handleCancel = () => {
+ setMatchResult(props.match.result)
+ setMatchStatus(props.match.status)
+ 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
+ setCancelSnackOpen(true)
+ }
+
+ // update data
+ const handleUpdate = async () => {
+ const leftScoreValue = leftRef.current?.value;
+ const rightScoreValue = rightRef.current?.value;
+
+ if (!leftScoreValue || !rightScoreValue || isNaN(Number(leftScoreValue)) || isNaN(Number(rightScoreValue || Number(leftScoreValue) < 0 || Number(rightScoreValue) < 0))) {
+ setScoreError(true);
+ return;
+ }
+
+ const leftScore = Number(leftScoreValue);
+ const rightScore = Number(rightScoreValue);
+
+ await matchFactory().update(props.match.id, {
+ locationId: locationId,
+ gameId: props.match.gameId,
+ sportId: props.match.sportId,
+ startAt: props.match.startAt,
+ leftTeamId: props.match.leftTeamId,
+ rightTeamId: props.match.rightTeamId,
+ leftScore: leftScore,
+ rightScore: rightScore,
+ result: matchResult,
+ status: matchStatus,
+ note: noteRef.current?.value as string,
+ judgeTeamId: judgeTeamId
+ })
+
+ router.refresh()
+ setUpdateSnackOpen(true)
+ setScoreError(false)
+ }
+
+ if (isFetching) {
+ return (
+
+ )
+ } else {
+ return (
+
+
+
+
+
+
+ } color={"secondary"}
+ />
+ } color={"secondary"}
+ />
+ } color={"secondary"}
+ />
+
+
+
+
+
+
+ {leftTeam.name}のスコア
+
+
+
+ VS
+
+
+ {rightTeam.name}のスコア
+
+
+
+
+
+
+
+
+ 勝ったのは
+
+ {leftTeam.name}
+ 引き分け
+ {rightTeam.name}
+
+
+
+ 試合の状態
+
+ 中止
+ スタンバイ
+ 進行中
+ 完了
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ aria-controls="panel-content"
+ id="panel-header"
+ >
+ 編集する
+
+
+
+
+ 補足
+
+
+ 審判
+
+ 審判
+
+
+
+ 試合の場所
+
+ 場所
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 変更が保存されました
+
+
+
+
+
+
+
+
+
+
+
+
+ 変更を元に戻しました
+
+
+
+
+
+
+ )
+ }
+}
\ No newline at end of file
diff --git a/components/sports/leagueList.tsx b/components/sports/leagueList.tsx
index bb27b74..298fd11 100644
--- a/components/sports/leagueList.tsx
+++ b/components/sports/leagueList.tsx
@@ -3,9 +3,11 @@ import {Game} from "@/src/models/GameModel";
export type LeagueListProps = {
games: Game[]
+ sportId: number
}
export default function LeagueList(props: LeagueListProps) {
+ const sportId = props.sportId
return (
@@ -14,7 +16,7 @@ export default function LeagueList(props: LeagueListProps) {
{game.name}
diff --git a/components/sports/sportEditor.tsx b/components/sports/sportEditor.tsx
index 1386b7e..efce5ae 100644
--- a/components/sports/sportEditor.tsx
+++ b/components/sports/sportEditor.tsx
@@ -67,7 +67,7 @@ export default function SportEditor(props: SportEditorProps) {
<>
- 競技の情報
+ 競技を編集する