Skip to content

Commit

Permalink
Merge pull request #44 from Sports-day/feature/team-member-editor
Browse files Browse the repository at this point in the history
チームメンバー編集機能の実装
  • Loading branch information
testusuke authored May 20, 2024
2 parents 38fa6ed + 5f77e93 commit 60bfe31
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 20 deletions.
8 changes: 5 additions & 3 deletions app/(authenticated)/teams/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {classFactory} from "@/src/models/ClassModel";
export default async function TeamDetailPage({ params }: { params: { id: string } }) {
const teamId = parseInt(params.id, 10)
const teamInfo = await teamFactory().show(teamId)
const classes = await classFactory().show(teamInfo.classId)
const classModel = await classFactory().show(teamInfo.classId)
const classUsers = await classFactory().getUsers(teamInfo.classId)
const teamUsers = await teamFactory().getTeamUsers(teamId);

return (
Expand All @@ -17,7 +18,7 @@ export default async function TeamDetailPage({ params }: { params: { id: string
<Link underline="hover" color="inherit" href="/">
管理者のダッシュボード
</Link>
<Link underline="hover" color="inherit" href="/teams/">
<Link underline="hover" color="inherit" href={"/teams/"}>
チーム管理
</Link>
<Typography color="text.primary">{teamInfo.name}</Typography>
Expand All @@ -27,7 +28,8 @@ export default async function TeamDetailPage({ params }: { params: { id: string
<TeamEditor
team={teamInfo}
teamUser={teamUsers}
class={classes}
class={classModel}
classUsers={classUsers}
/>
</CardBackground>
</Stack>
Expand Down
131 changes: 131 additions & 0 deletions components/teams/addTeamMemberDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
'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 {User} from "@/src/models/UserModel";
import {Team, teamFactory} from "@/src/models/TeamModel";
import {useState} from "react";
import {useRouter} from "next/navigation";

ModuleRegistry.registerModules([ClientSideRowModelModule]);

export type AddTeamMemberDialogProps = {
isOpen: boolean
setClose: () => void
team: Team
users: User[]
}

// Row Data Interface
type IRow = {
id: number,
username: string,
gender: string,
emailAccountName: string,
}

export default function AddTeamMemberDialog(props: AddTeamMemberDialogProps) {
const router = useRouter()
const height = 'calc(100vh - 230px)';
const [gridApi, setGridApi] = useState<GridApi<IRow> | null>(null)
// Column Definitions: Defines & controls grid columns.
const colDefs: ColDef<IRow>[] = [
{
field: "id",
headerName: "ID",
headerCheckboxSelection: true,
checkboxSelection: true,
showDisabledCheckboxes: true,
},
{field: "username", headerName: "ユーザー名"},
{field: "gender", headerName: "性別"},
{field: "emailAccountName", headerName: "学籍番号"},
]

const rowData: IRow[] = props.users.map((user) => {
return {
id: user.id,
username: user.name,
gender: user.gender == "male" ? "男" : "女",
emailAccountName: user.email.split("@")[0]
} 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 teamFactory().addTeamUsers(props.team.id, selectedRowIds)

// refresh
router.refresh()
// close
props.setClose()
}

return (
<Dialog
open={props.isOpen}
onClose={props.setClose}
maxWidth={"lg"}
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={props.setClose}
>
キャンセル
</Button>
<Button
type={"submit"}
variant={"contained"}
onClick={handleSubmit}
>
追加
</Button>
</DialogActions>
</Dialog>
)
}
80 changes: 63 additions & 17 deletions components/teams/teamEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,30 @@
import {
Box,
Button,
FormControl, InputLabel, Paper,
FormControl, InputLabel, Paper,
Stack, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField,
Typography
} from "@mui/material";
import { HiCheck } from "react-icons/hi2";
import {HiCheck, HiMiniTrash, HiPlus} from "react-icons/hi2";
import React, {useState} from "react";
import {useRouter} from "next/navigation";
import {Team, teamFactory} from "@/src/models/TeamModel";
import {Class} from "@/src/models/ClassModel";
import {User} from "@/src/models/UserModel";
import TeamDelete from "@/components/teams/teamDelete";
import AddTeamMemberDialog from "@/components/teams/addTeamMemberDialog";

type TeamEditorProps = {
class : Class;
team : Team;
teamUser : User[];
class: Class;
team: Team;
teamUser: User[];
classUsers: User[];
}

export default function TeamEditor(props: TeamEditorProps) {
const router = useRouter()
const [teamName, setTeamName] = useState<string>(props.team.name)
const [isOpenTeamMemberAddDialog, setIsOpenTeamMemberAddDialog] = useState<boolean>(false)

const handleSubmit = async () => {
await teamFactory().update(props.team.id, {
Expand All @@ -37,6 +40,16 @@ export default function TeamEditor(props: TeamEditorProps) {

}

const removeUser = async (userId: number) => {
await teamFactory().removeTeamUser(props.team.id, userId)
// refresh
router.refresh()
}

const notTeamUsers = props.classUsers.filter((user) => {
return !props.teamUser.some((teamUser) => teamUser.id === user.id)
})

return (
<>
<Stack mx={0} my={2} spacing={2} direction={"column"}>
Expand All @@ -49,7 +62,7 @@ export default function TeamEditor(props: TeamEditorProps) {
<TextField
label="チーム名"
id="change-team-name"
InputLabelProps={{ shrink: true }}
InputLabelProps={{shrink: true}}
defaultValue={props.team.name}
value={teamName}
onChange={(t) => {
Expand Down Expand Up @@ -82,14 +95,14 @@ export default function TeamEditor(props: TeamEditorProps) {
>
所属クラス
</InputLabel>
<Typography variant="body1" >
<Typography variant="body1">
{props.class.name}
</Typography>
</Paper>
</FormControl>

<FormControl fullWidth>
<Box sx={{ position: 'relative' }}>
<Box sx={{position: 'relative'}}>
<InputLabel sx={{
position: 'absolute',
top: '-24px',
Expand All @@ -104,29 +117,41 @@ export default function TeamEditor(props: TeamEditorProps) {
<TableContainer
component={Paper}
elevation={0}
sx={{ border: '1px solid #adafbd' }}
sx={{border: '1px solid #adafbd'}}
>
<Table>
<TableHead sx={{ borderBottom: '1px solid #adafbd' }}>
<TableHead sx={{borderBottom: '1px solid #adafbd'}}>
<TableRow>
<TableCell sx={{ border: 0 }}>学籍番号</TableCell>
<TableCell sx={{ border: 0 }}>名前</TableCell>
<TableCell sx={{ border: 0 }}>性別</TableCell>
<TableCell sx={{border: 0}}>学籍番号</TableCell>
<TableCell sx={{border: 0}}>名前</TableCell>
<TableCell sx={{border: 0}}>性別</TableCell>
<TableCell sx={{border: 0}}>削除</TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.teamUser.map((member) => {
return (
<TableRow key={member.id}>
<TableCell sx={{ border: 0 }}>{member.id}</TableCell>
<TableCell sx={{ border: 0 }}>{member.name}</TableCell>
<TableCell sx={{ border: 0 }}>
<TableCell sx={{border: 0}}>{member.id}</TableCell>
<TableCell sx={{border: 0}}>{member.name}</TableCell>
<TableCell sx={{border: 0}}>
<Typography
sx={{ color: member.gender === "female" ? "red" : "inherit" }}
sx={{color: member.gender === "female" ? "red" : "inherit"}}
>
{member.gender === "male" ? "男性" : "女性"}
</Typography>
</TableCell>
<TableCell
sx={{border: 0}}
>
<Button
color={"error"}
startIcon={<HiMiniTrash/>}
onClick={() => removeUser(member.id)}
>
削除
</Button>
</TableCell>
</TableRow>
);
})}
Expand All @@ -135,6 +160,27 @@ export default function TeamEditor(props: TeamEditorProps) {
</TableContainer>
</FormControl>

<AddTeamMemberDialog
isOpen={isOpenTeamMemberAddDialog}
setClose={() => {
setIsOpenTeamMemberAddDialog(false)
}}
team={props.team}
users={notTeamUsers}
/>

<Button
variant={"contained"}
color={"primary"}
sx={{flexGrow: 3}}
startIcon={<HiPlus/>}
onClick={() => {
setIsOpenTeamMemberAddDialog(true)
}}
>
チームメンバー追加
</Button>

<Stack
direction={"row"}
my={0.5}
Expand Down

0 comments on commit 60bfe31

Please sign in to comment.