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 18f0719..cab1f7a 100644
--- a/components/teams/teamEditor.tsx
+++ b/components/teams/teamEditor.tsx
@@ -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(props.team.name)
+ const [isOpenTeamMemberAddDialog, setIsOpenTeamMemberAddDialog] = useState(false)
const handleSubmit = async () => {
await teamFactory().update(props.team.id, {
@@ -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 (
<>
@@ -49,7 +62,7 @@ export default function TeamEditor(props: TeamEditorProps) {
{
@@ -82,14 +95,14 @@ export default function TeamEditor(props: TeamEditorProps) {
>
所属クラス
-
+
{props.class.name}
-
+
-
+
- 学籍番号
- 名前
- 性別
+ 学籍番号
+ 名前
+ 性別
+ 削除
{props.teamUser.map((member) => {
return (
- {member.id}
- {member.name}
-
+ {member.id}
+ {member.name}
+
{member.gender === "male" ? "男性" : "女性"}
+
+
+
);
})}
@@ -135,6 +160,27 @@ export default function TeamEditor(props: TeamEditorProps) {
+ {
+ setIsOpenTeamMemberAddDialog(false)
+ }}
+ team={props.team}
+ users={notTeamUsers}
+ />
+
+
+