From 5f77e93248efbb36984b380995eb54b7b12b9d2f Mon Sep 17 00:00:00 2001 From: testusuke Date: Mon, 20 May 2024 21:29:12 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E6=A9=9F=E8=83=BD=E3=81=AE=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(authenticated)/teams/[id]/page.tsx | 8 +- components/teams/addTeamMemberDialog.tsx | 131 +++++++++++++++++++++++ components/teams/teamEditor.tsx | 30 +++++- 3 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 components/teams/addTeamMemberDialog.tsx diff --git a/app/(authenticated)/teams/[id]/page.tsx b/app/(authenticated)/teams/[id]/page.tsx index 4da4fba..361ce10 100644 --- a/app/(authenticated)/teams/[id]/page.tsx +++ b/app/(authenticated)/teams/[id]/page.tsx @@ -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 ( @@ -17,7 +18,7 @@ export default async function TeamDetailPage({ params }: { params: { id: string 管理者のダッシュボード - + チーム管理 {teamInfo.name} @@ -27,7 +28,8 @@ export default async function TeamDetailPage({ params }: { params: { id: string diff --git a/components/teams/addTeamMemberDialog.tsx b/components/teams/addTeamMemberDialog.tsx new file mode 100644 index 0000000..2908d91 --- /dev/null +++ b/components/teams/addTeamMemberDialog.tsx @@ -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 | null>(null) + // Column Definitions: Defines & controls grid columns. + const colDefs: ColDef[] = [ + { + 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 ( + + + + チームメンバーの追加 + + + +
+ +
+
+ + + + +
+ ) +} \ No newline at end of file diff --git a/components/teams/teamEditor.tsx b/components/teams/teamEditor.tsx index 6766f95..cab1f7a 100644 --- a/components/teams/teamEditor.tsx +++ b/components/teams/teamEditor.tsx @@ -6,23 +6,26 @@ import { Stack, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography } from "@mui/material"; -import {HiCheck, HiMiniTrash} 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[]; + classUsers: User[]; } export default function TeamEditor(props: TeamEditorProps) { const router = useRouter() const [teamName, setTeamName] = useState(props.team.name) + const [isOpenTeamMemberAddDialog, setIsOpenTeamMemberAddDialog] = useState(false) const handleSubmit = async () => { await teamFactory().update(props.team.id, { @@ -43,6 +46,10 @@ export default function TeamEditor(props: TeamEditorProps) { router.refresh() } + const notTeamUsers = props.classUsers.filter((user) => { + return !props.teamUser.some((teamUser) => teamUser.id === user.id) + }) + return ( <> @@ -153,6 +160,27 @@ export default function TeamEditor(props: TeamEditorProps) { + { + setIsOpenTeamMemberAddDialog(false) + }} + team={props.team} + users={notTeamUsers} + /> + + +