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

リーグ編成およびリーグ作成機能 #48

Merged
merged 6 commits into from
May 20, 2024
Merged
Changes from all commits
Commits
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
14 changes: 8 additions & 6 deletions app/(authenticated)/sports/[id]/create-league/page.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
import {Breadcrumbs, Link, Stack, Typography} from "@mui/material";
import CardBackground from "@/components/layout/cardBackground";
import LeagueDnd from "@/components/league/create/leagueDnd";
import {sportFactory} from "@/src/models/SportModel";
import GameForm from "@/components/league/legacy/GameForm";
import {tagFactory} from "@/src/models/TagModel";

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}`
const tags = await tagFactory().index()

return (
<Stack spacing={2} mx={2} my={3}>
<Breadcrumbs aria-label="breadcrumb" sx={{pl:2}}>
<Breadcrumbs aria-label="breadcrumb" sx={{pl: 2}}>
<Link underline="hover" color="inherit" href="/public">
管理者のダッシュボード
</Link>
<Link underline="hover" color="inherit" href={"/sports"}>
競技管理
</Link>
<Link underline="hover" color="inherit" href={sportLink}>
<Link underline="hover" color="inherit" href={`/sports/${sportId}`}>
{sport.name}
</Link>
<Typography color="text.primary">リーグを作成・編集</Typography>
</Breadcrumbs>
<CardBackground title={`${sport.name}のリーグ`}>
<LeagueDnd sport={sport} sportId={sportId}/>
<CardBackground>
<GameForm formType={"create"} sportId={sportId} tags={tags}/>
</CardBackground>
</Stack>
);
50 changes: 44 additions & 6 deletions app/(authenticated)/sports/[id]/games/[gameId]/page.tsx
Original file line number Diff line number Diff line change
@@ -4,17 +4,32 @@ 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";
import {tagFactory} from "@/src/models/TagModel";
import GameForm from "@/components/league/legacy/GameForm";
import {teamTagFactory} from "@/src/models/TeamTagModel";
import {teamFactory} from "@/src/models/TeamModel";
import {GameEntryList} from "@/components/league/legacy/GameEntryList";
import AddGameEntryDialog from "@/components/league/legacy/AddGameEntryDialog";

export default async function GamePage({params}: { params: { gameId:string, id: string } }) {
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)
const matchList = await gameFactory().getGameMatches(gameId)
const tags = await tagFactory().index()

return(
// この突貫工事は修正してください。
const gameEntryTeams = await gameFactory().getGameEntries(gameId)
const teamTags = await teamTagFactory().index()
const linkedTeamTag = teamTags.find((teamTag) => teamTag.sportId === sport.id)
const teams = await teamFactory().index()
const filteredTeams = linkedTeamTag ? teams.filter((team) => team.teamTagId === linkedTeamTag.id) : []


return (
<Stack spacing={1} mx={2} my={3}>
<Breadcrumbs aria-label="breadcrumb" sx={{pl:2}}>
<Breadcrumbs aria-label="breadcrumb" sx={{pl: 2}}>
<Link underline="hover" color="inherit" href="/">
管理者のダッシュボード
</Link>
@@ -26,10 +41,33 @@ export default async function GamePage({params}: { params: { gameId:string, id:
</Link>
<Typography color="text.primary">{game.name}(ID:{gameId})</Typography>
</Breadcrumbs>
<CardBackground title={`${game.name}のリーグ表`} button={"試合を再生成"} link={`/sports/${sportId}/games/${gameId}/generate-league-matches`}>
<LeagueTable game={game} sport={sport} />
<CardBackground title={`${game.name}を編集`}>
<GameForm
formType={"edit"}
sportId={sportId}
game={game}
tags={tags}
/>
</CardBackground>
<CardBackground title={`${game.name}のエントリー`}>
<Stack>
<GameEntryList
game={game}
entries={gameEntryTeams}
/>
<AddGameEntryDialog
game={game}
teams={filteredTeams}
entries={gameEntryTeams}
/>
</Stack>
</CardBackground>
<CardBackground title={`${game.name}のリーグ表`} button={"試合を再生成"}
link={`/sports/${sportId}/games/${gameId}/generate-league-matches`}>
<LeagueTable game={game} sport={sport}/>
</CardBackground>
<CardBackground title={`${game.name}試合一覧`} button={"一括変更"} link={`/sports/${sportId}/games/${gameId}/automatic-match-editor`}>
<CardBackground title={`${game.name}試合一覧`} button={"一括変更"}
link={`/sports/${sportId}/games/${gameId}/automatic-match-editor`}>
<MatchList
matches={matchList}
/>
35 changes: 16 additions & 19 deletions app/(authenticated)/sports/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -10,12 +10,13 @@ export default async function SportPage({params}: { params: { id: string } }) {
const sportId = parseInt(params.id, 10)
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;
const filteredGames = games
.filter((game) => game.sportId == sportId)
.filter((game) => game.type === "league")

return(
return (
<Stack spacing={1} mx={2} my={3}>
<Breadcrumbs aria-label="breadcrumb" sx={{pl:2}}>
<Breadcrumbs aria-label="breadcrumb" sx={{pl: 2}}>
<Link underline="hover" color="inherit" href="/">
管理者のダッシュボード
</Link>
@@ -24,24 +25,20 @@ export default async function SportPage({params}: { params: { id: string } }) {
</Link>
<Typography color="text.primary">{sport.name}</Typography>
</Breadcrumbs>
{gameType === "league" && (
<CardBackground title={"リーグ一覧"} button={"リーグを作成・編集"} link={`/sports/${sport.id}/create-league`}>
<Grid container spacing={1}>
<LeagueList games={filteredGames} sportId={sportId}/>
</Grid>
</CardBackground>
)}
{gameType === "tournament" && (
<CardBackground title={"トーナメントビュー"} button={"トーナメントを作成・編集"} link={`/sports/${sport.id}/create-tournament`}>
<Grid container spacing={1}>

</Grid>
</CardBackground>
)}
<CardBackground
title={"リーグ一覧"}
button={"リーグを作成"}
link={`/sports/${sport.id}/create-league`}
>
<Grid container spacing={1}>
<LeagueList games={filteredGames} sportId={sportId}/>
</Grid>
</CardBackground>
<CardBackground title={`${sport.name}`}>
<SportEditor sport={sport}/>
</CardBackground>
<CardBackground title={`${sport.name}の進行中の試合`} button={"一括編集(Cross Game)"} link={`/sports/${sportId}/automatic-match-editor`}>
<CardBackground title={`${sport.name}の進行中の試合`} button={"一括編集(Cross Game)"}
link={`/sports/${sportId}/automatic-match-editor`}>
<SportInProgressMatchList sport={sport}/>
</CardBackground>
</Stack>
140 changes: 140 additions & 0 deletions components/league/legacy/AddGameEntryDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
'use client'
import {AgGridReact} from 'ag-grid-react';
import "ag-grid-community/styles/ag-grid.css"; // Mandatory CSS required by the grid
import "ag-grid-community/styles/ag-theme-quartz.css"; // Optional Theme applied to the grid
import {ColDef, GridApi, GridReadyEvent, ModuleRegistry} from 'ag-grid-community';
import {ClientSideRowModelModule} from 'ag-grid-community';
import {Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography} from "@mui/material";
import {Team} from "@/src/models/TeamModel";
import {useState} from "react";
import {useRouter} from "next/navigation";
import {Game, gameFactory} from "@/src/models/GameModel";

ModuleRegistry.registerModules([ClientSideRowModelModule]);

export type AddGameEntryDialogProps = {
game: Game
teams: Team[]
entries: Team[]
}

// Row Data Interface
type IRow = {
id: number,
name: string,
}

export default function AddGameEntryDialog(props: AddGameEntryDialogProps) {
const router = useRouter()
const height = 'calc(100vh - 230px)';
const [gridApi, setGridApi] = useState<GridApi<IRow> | null>(null)
const [isOpen, setIsOpen] = useState<boolean>(false)
// Column Definitions: Defines & controls grid columns.
const colDefs: ColDef<IRow>[] = [
{
field: "id",
headerName: "ID",
headerCheckboxSelection: true,
checkboxSelection: true,
showDisabledCheckboxes: true,
},
{
field: "name",
headerName: "チーム名",
filter: true
},
]

const rowData: IRow[] = props.teams
.filter((team) => !props.entries.some((entry) => entry.id === team.id))
.map((team) => {
return {
id: team.id,
name: team.name,
} as IRow
})

const handleGridReady = (params: GridReadyEvent) => {
setGridApi(params.api)
}

const handleSubmit = async () => {
if (!gridApi) {
alert("エラーが発生しました")
return
}

const selectedRowIds = gridApi
.getSelectedRows()
.map((row) => row.id)

if (selectedRowIds.length === 0) {
alert("チームを選択してください")
return
}

// add team user
await gameFactory().addGameEntries(props.game.id, selectedRowIds)

// refresh
router.refresh()
// close
setIsOpen(false)
}

return (
<>
<Button
variant={"contained"}
onClick={() => setIsOpen(true)}
>
エントリー追加
</Button>

<Dialog
open={isOpen}
onClose={() => setIsOpen(false)}
maxWidth={"md"}
fullWidth
>
<DialogTitle>
<Typography>
エントリーの追加
</Typography>
</DialogTitle>
<DialogContent>
<div
className={"ag-theme-quartz"}
style={{
width: '100%',
height: height,
borderRadius: "10px"
}}
>
<AgGridReact
rowData={rowData}
columnDefs={colDefs}
rowSelection={"multiple"}
onGridReady={handleGridReady}
/>
</div>
</DialogContent>
<DialogActions>
<Button
variant={"outlined"}
onClick={() => setIsOpen(false)}
>
キャンセル
</Button>
<Button
type={"submit"}
variant={"contained"}
onClick={handleSubmit}
>
追加
</Button>
</DialogActions>
</Dialog>
</>
)
}
49 changes: 49 additions & 0 deletions components/league/legacy/ConfirmDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use client'
import React from "react";
import {Button, Dialog, DialogActions, DialogContent} from "@mui/material";
import {OverridableStringUnion} from "@mui/types";
import {ButtonPropsColorOverrides} from "@mui/material/Button/Button";

type ConfirmDialogProps = {
open: boolean
onClose: VoidFunction
onConfirm: VoidFunction
confirmText: string
confirmColor: OverridableStringUnion<
'inherit' | 'primary' | 'secondary' | 'success' | 'error' | 'info' | 'warning',
ButtonPropsColorOverrides
>
children: React.ReactNode
}

export function ConfirmDialog(props: ConfirmDialogProps) {

return (
<Dialog
open={props.open}
onClose={props.onClose}
maxWidth={"sm"}
fullWidth
>
<DialogContent>
{props.children}
</DialogContent>
<DialogActions>
<Button
variant={"outlined"}
onClick={props.onClose}
>
キャンセル
</Button>
<Button
variant={"contained"}
onClick={props.onConfirm}
color={props.confirmColor}
>
{props.confirmText}
</Button>
</DialogActions>

</Dialog>
);
}
Loading