diff --git a/app/(authenticated)/sports/[id]/games/[gameId]/automatic-match-editor/page.tsx b/app/(authenticated)/sports/[id]/games/[gameId]/automatic-match-editor/page.tsx
index 767d2cc..1b89515 100644
--- a/app/(authenticated)/sports/[id]/games/[gameId]/automatic-match-editor/page.tsx
+++ b/app/(authenticated)/sports/[id]/games/[gameId]/automatic-match-editor/page.tsx
@@ -4,6 +4,7 @@ import {sportFactory} from "@/src/models/SportModel";
import {gameFactory} from "@/src/models/GameModel";
import {AutomaticMatchEditor} from "@/components/automation/AutomaticMatchEditor";
import NextLink from "next/link";
+import {AutomaticMatchEditorForImizu} from "@/components/automation/AutomaticMatchEditorForImizu";
export default async function AutomaticMatchEditorPage({params}: { params: { gameId:string, id: string } }) {
const gameId = parseInt(params.gameId, 10)
@@ -49,7 +50,8 @@ export default async function AutomaticMatchEditorPage({params}: { params: { gam
試合一括編集
-
+ {/**/}
+
)
diff --git a/app/(authenticated)/teams/page.tsx b/app/(authenticated)/teams/page.tsx
index f363a54..5dbc5f6 100644
--- a/app/(authenticated)/teams/page.tsx
+++ b/app/(authenticated)/teams/page.tsx
@@ -45,6 +45,14 @@ export default async function TeamPage() {
>
一括名前変更
+
+
+
+
+ 管理者のダッシュボード
+
+
+ チーム管理
+
+
+ 射水チーム作成
+
+
+
+
+
+
+ )
+}
diff --git a/app/(authenticated)/users/csv/page.tsx b/app/(authenticated)/users/csv/page.tsx
index 9572583..a8aee21 100644
--- a/app/(authenticated)/users/csv/page.tsx
+++ b/app/(authenticated)/users/csv/page.tsx
@@ -3,6 +3,8 @@ import CardBackground from "@/components/layout/cardBackground";
import {classFactory} from "@/src/models/ClassModel";
import UserCreatingAutomation from "@/components/users/csv/userCreatingAutomation";
import NextLink from "next/link";
+import UserCreatingAutomationWithoutClassSelection
+ from "@/components/users/csv/userCreatingAutomationWithoutClassSelection";
export default async function UsersCsv() {
const classes = await classFactory().index()
@@ -30,7 +32,8 @@ export default async function UsersCsv() {
-
+ {/**/}
+
);
diff --git a/components/automation/AutomaticMatchEditorForImizu.tsx b/components/automation/AutomaticMatchEditorForImizu.tsx
new file mode 100644
index 0000000..61b5cf6
--- /dev/null
+++ b/components/automation/AutomaticMatchEditorForImizu.tsx
@@ -0,0 +1,355 @@
+'use client'
+import {
+ Button, Checkbox,
+ FormControl,
+ InputLabel, LinearProgress, MenuItem,
+ Select, SelectChangeEvent, Stack, TextField,
+ TextFieldProps,
+ Typography
+} from "@mui/material";
+import React, {ChangeEvent, useRef, useState} from "react";
+import dayjs, {Dayjs} from "dayjs";
+import {Game, gameFactory} from "@/src/models/GameModel";
+import {Team} from "@/src/models/TeamModel";
+import {Location, locationFactory} from "@/src/models/LocationModel";
+import {Match, matchFactory} from "@/src/models/MatchModel";
+import {useAsync} from "react-use";
+import {useRouter} from "next/navigation";
+import Loading from "@/app/(authenticated)/loading";
+import {DateTimePicker} from "@mui/x-date-pickers";
+import {LocalizationProvider} from "@mui/x-date-pickers";
+import {AdapterDayjs} from "@mui/x-date-pickers/AdapterDayjs";
+import {HiArrowPath, HiCheck} from "react-icons/hi2";
+import MatchEditorStatus from "@/components/automation/matchEditorStatus";
+import NextLink from "next/link";
+
+export type AutomaticMatchEditorProps = {
+ game: Game
+}
+
+export type EditedMatch = {
+ id: number
+ leftTeamName: string
+ rightTeamName: string
+ judgeTeamName: string
+ startAt: string
+ status: "success" | "not_found_match" | "not_link_yet" | "team_invalid"
+}
+
+export function AutomaticMatchEditorForImizu(props: AutomaticMatchEditorProps) {
+ const router = useRouter()
+ // resources
+ const [isFetching, setIsFetching] = useState(true)
+ const [locations, setLocations] = useState([])
+ const [teams, setTeams] = useState([])
+ const [matches, setMatches] = useState([])
+ // ref
+ const csvDataRef = useRef(null)
+ // state
+ const [startDateTime, setStartDateTime] = useState(dayjs())
+ const [locationId, setLocationId] = useState("-1")
+ const [editedMatchesState, setEditedMatchesState] = useState([])
+ const [isDeleteUnlinkedMatch, setIsDeleteUnlinkedMatch] = useState(false)
+ const [progress, setProgress] = useState(0)
+ const [isExecuting, setIsExecuting] = useState(false)
+
+ useAsync(async () => {
+ const fetchedLocations = await locationFactory().index()
+ setLocations(fetchedLocations)
+
+ const fetchedTeams = await gameFactory().getGameEntries(props.game.id)
+ setTeams(fetchedTeams)
+
+ const fetchedMatches = await gameFactory().getGameMatches(props.game.id)
+ setMatches(fetchedMatches)
+
+ setIsFetching(false)
+ }, [props.game])
+
+ const handleSubmit = async () => {
+ if (isExecuting) {
+ alert("処理中です")
+ return
+ }
+
+ // validation
+ // exists location
+ if (!locations.some(location => location.id === parseInt(locationId))) {
+ alert("場所を選択してください")
+ return
+ }
+
+ handleCSVDataChange()
+
+ // execute
+ setIsExecuting(true)
+ setProgress(0)
+
+ let index = 0;
+ for (const match of editedMatchesState) {
+ // original
+ const originalMatch = matches.find(value => value.id === match.id)
+ const judgeTeam = teams.find(value => value.name === match.judgeTeamName)
+ if (originalMatch !== undefined) {
+ if (match.status == "success") {
+ // update match
+ await matchFactory().update(match.id, {
+ startAt: match.startAt,
+ locationId: parseInt(locationId),
+ judgeTeamId: judgeTeam?.id ?? null,
+ // original data
+ gameId: originalMatch.gameId,
+ sportId: originalMatch.sportId,
+ leftTeamId: originalMatch.leftTeamId,
+ rightTeamId: originalMatch.rightTeamId,
+ leftScore: originalMatch.leftScore,
+ rightScore: originalMatch.rightScore,
+ result: originalMatch.result,
+ status: originalMatch.status,
+ note: originalMatch.note,
+ })
+ } else if (match.status == "not_link_yet" && isDeleteUnlinkedMatch) {
+ // delete match
+ await matchFactory().delete(match.id)
+ }
+ }
+
+ // increment progress
+ index++
+ setProgress((index) / editedMatchesState.length * 100)
+
+ // delay for api server load
+ await timeout(100);
+ }
+
+ setIsExecuting(false)
+ // refresh
+ router.push(`/sports/${props.game.sportId}/games/${props.game.id}`)
+ }
+
+ const handleCSVDataChange = () => {
+ if (csvDataRef.current?.value === undefined) {
+ return
+ }
+
+ const csvData = csvDataRef.current.value as string
+ const rows = csvData.split("\n")
+ let currentDay = dayjs(startDateTime)
+
+ const editedMatches: EditedMatch[] = []
+
+ for (const row of rows) {
+ const data = row.split(",")
+ const leftTeamName = data[0]
+ const rightTeamName = data[1]
+ const judgeTeamName = data[2]
+ const startAtHHMM = data[3]
+ // current Day の日付を取得
+ const currentDayDate = currentDay.format("YYYY-MM-DD")
+ // startAtHHMMの日付をcurrentDayの日付に変換
+ const startAt = dayjs(`${currentDayDate} ${startAtHHMM}`, "YYYY-MM-DD HH:mm")
+
+ // team
+ const leftTeam = teams.find(team => team.name === leftTeamName)
+ const rightTeam = teams.find(team => team.name === rightTeamName)
+ const judge = teams.find(team => team.name === judgeTeamName)
+ // if team not found
+ if (leftTeam === undefined || rightTeam === undefined || (judgeTeamName !== "" && judge === undefined)) {
+ // failed
+ editedMatches.push({
+ id: -1,
+ leftTeamName: leftTeamName,
+ rightTeamName: rightTeamName,
+ judgeTeamName: judgeTeamName,
+ startAt: startAt.format("YYYY-MM-DDTHH:mm:ss.SSS"),
+ status: "team_invalid"
+ })
+ continue
+ }
+
+ // find match by team name
+ const match = matches.find(match => {
+ return (leftTeam.id === match.leftTeamId && rightTeam.id === match.rightTeamId)
+ || (leftTeam.id === match.rightTeamId && rightTeam.id === match.leftTeamId)
+ })
+
+ if (match === undefined) {
+ // failed
+ editedMatches.push({
+ id: -1,
+ leftTeamName: leftTeamName,
+ rightTeamName: rightTeamName,
+ judgeTeamName: judgeTeamName,
+ startAt: startAt.format("YYYY-MM-DDTHH:mm:ss.SSS"),
+ status: "not_found_match"
+ })
+ continue
+ }
+
+ // success
+ editedMatches.push({
+ id: match.id,
+ leftTeamName: leftTeamName,
+ rightTeamName: rightTeamName,
+ judgeTeamName: judgeTeamName,
+ startAt: startAt.format("YYYY-MM-DDTHH:mm:ss.SSS"),
+ status: "success"
+ })
+ }
+
+ // add matches not exist in csv
+ const notExistMatches = matches.filter(match => {
+ return !editedMatches.some(editedMatch => editedMatch.id === match.id)
+ }).map(match => {
+ const leftTeam = teams.find(team => team.id === match.leftTeamId)
+ const rightTeam = teams.find(team => team.id === match.rightTeamId)
+ const judgeTeam = teams.find(team => team.id === match.judgeTeamId)
+
+ return {
+ id: match.id,
+ leftTeamName: leftTeam?.name,
+ rightTeamName: rightTeam?.name,
+ judgeTeamName: judgeTeam?.name,
+ startAt: match.startAt,
+ status: "not_link_yet"
+ } as EditedMatch
+ })
+
+ const results = editedMatches.concat(notExistMatches)
+
+ setEditedMatchesState(results)
+ }
+
+ const handleLocationChange = (e: SelectChangeEvent) => {
+ setLocationId(e.target.value)
+ }
+
+ if (isFetching) {
+ return (
+
+ )
+ }
+
+
+ return (
+
+
+ {
+ setStartDateTime(newValue)
+ // calculate
+ handleCSVDataChange()
+ }}
+ sx={{
+ my: '20px',
+ width: "300px",
+ }}
+ />
+
+
+ 開催場所
+
+ 開催場所
+
+
+
+
+ 未リンクの試合を削除する
+ ) =>
+ setIsDeleteUnlinkedMatch(event.target.checked)
+ }
+ size="small"
+ />
+
+
+
+ CSVデータ
+
+ handleCSVDataChange()}
+ />
+
+
+
+
+
+
+
+
+ {isExecuting &&
+
+ }
+
+ )
+}
+
+function timeout(delay: number) {
+ return new Promise(res => setTimeout(res, delay));
+}
diff --git a/components/league/legacy/AddGameEntryAutomation.tsx b/components/league/legacy/AddGameEntryAutomation.tsx
index caaa85f..8fa5894 100644
--- a/components/league/legacy/AddGameEntryAutomation.tsx
+++ b/components/league/legacy/AddGameEntryAutomation.tsx
@@ -34,13 +34,24 @@ export default function AddGameEntryAutomation(props: AddGameEntryAutomationProp
// get data
const data = dataRef.current.value as string
- const splitData = data.split("\t")
+ // const splitData = data.split("\t")
+ // separate with space and \t
+ const splitData = data.split(/[\s\t]+/)
console.log(splitData)
// find teams
const selectedTeams = props.teams.filter((team) => splitData.includes(team.name))
+ // ファインドできなかった残りのチーム
+ const notFoundTeams = splitData
+ .filter((teamName) => !selectedTeams.some((team) => team.name === teamName))
+ .filter((teamName) => !props.entries.some((entry) => entry.name === teamName))
+ if (notFoundTeams.length > 0) {
+ alert(`${notFoundTeams.join(", ")} が見つかりませんでした`)
+ return
+ }
+
if (selectedTeams.length === 0
) {
alert("チームを選択してください")
diff --git a/components/teams/automatic-entry/teamCreatingAutomation.tsx b/components/teams/automatic-entry/teamCreatingAutomation.tsx
new file mode 100644
index 0000000..2899679
--- /dev/null
+++ b/components/teams/automatic-entry/teamCreatingAutomation.tsx
@@ -0,0 +1,214 @@
+'use client'
+import {Class, classFactory} from "@/src/models/ClassModel";
+import {Button, FormControl, InputLabel, MenuItem, Select, Stack, TextField, Typography} from "@mui/material";
+import {ChangeEvent, useState} from "react";
+import {TeamTag, teamTagFactory} from "@/src/models/TeamTagModel";
+import {User, userFactory} from "@/src/models/UserModel";
+import {useAsync} from "react-use";
+import {Team, teamFactory} from "@/src/models/TeamModel";
+import TeamCreatingStatus from "@/components/teams/automatic-entry/teamCreatingStatus";
+
+export type TeamCreatingState = "created" | "pending" | "error" | "team_not_found" | "invalid_class" | "invalid_user" | "invalid_csv"
+
+export type TeamCreatingData = {
+ name?: string,
+ email?: string,
+ className?: string,
+ state: TeamCreatingState
+}
+
+export default function TeamCreatingAutomation() {
+ const [selectedTeamTagId, setSelectedTeamTagId] = useState("")
+ const [csvInput, setCsvInput] = useState("")
+ const [teamCreatingDataList, setTeamCreatingDataList] = useState([])
+
+ const [classes, setClasses] = useState([])
+ const [teamTags, setTeamTags] = useState([])
+ const [users, setUsers] = useState([])
+
+ useAsync(async () => {
+ setClasses(await classFactory().index())
+ setTeamTags(await teamTagFactory().index())
+ setUsers(await userFactory().index())
+ }, [])
+
+ const handleCSVChange = (event: ChangeEvent) => {
+ const csv = event.target.value
+
+ // parse csv
+ const lines = csv.split("\n")
+ const newTeamCreatingDataList: TeamCreatingData[] = []
+
+ for (const line of lines) {
+ const elements = line.split(",")
+
+ let state: TeamCreatingState = "pending"
+
+ // invalid csv
+ if (elements.length !== 3) {
+ state = "invalid_csv"
+ }
+
+ // invalid class
+ if (!classes.some(v => v.name === elements[2])) {
+
+ }
+
+ newTeamCreatingDataList.push({
+ name: elements[0] === "" ? undefined : elements[0],
+ email: elements[1] === "" ? undefined : elements[1],
+ className: elements[2] === "" ? undefined : elements[2],
+ state: state
+ })
+ }
+
+ setTeamCreatingDataList(newTeamCreatingDataList)
+ setCsvInput(csv)
+ }
+
+ const handleCreateUsers = async () => {
+ // get team tags
+ const teamTag = teamTags.find((c) => c.id === +selectedTeamTagId)
+ if (teamTag === undefined) {
+ alert("チームタグを指定してください")
+ return
+ }
+
+ // get pending teams
+ const teams = teamCreatingDataList.filter((data) => data.state === "pending")
+
+ // チーム名を取得
+ type TeamForCreating = {
+ name: string,
+ classId: number,
+ }
+ const teamsForCreating: TeamForCreating[] = []
+ for (const team of teams) {
+ const teamName = team.name
+ if (teamName === undefined) {
+ team.state = "invalid_csv"
+ continue
+ }
+ const classModel = classes.find(v => v.name === team.className)
+ if (classModel === undefined) {
+ team.state = "invalid_class"
+ continue
+ }
+
+ // if team name is not exists in teamNamesForCreating, add
+ if (!teamsForCreating.some(v => v.name === teamName && v.classId === classModel.id)) {
+ teamsForCreating.push({
+ name: teamName,
+ classId: classModel.id
+ })
+ }
+ }
+
+ // チームを作成
+ const createdTeams: Team[] = []
+ for (const teamForCreating of teamsForCreating) {
+ const result = await teamFactory().create({
+ name: teamForCreating.name,
+ description: "",
+ classId: teamForCreating.classId,
+ teamTagId: teamTag.id
+ })
+ if (result !== undefined) {
+ createdTeams.push(result)
+ }
+ }
+
+ // メンバー追加
+ for (const team of teams) {
+ // add user
+ try {
+ const teamModel = createdTeams.find((c) => c.name === team?.name)
+ const userModel = users.find((c) => c.email === team?.email)
+ if (teamModel == undefined) {
+ team.state = "team_not_found"
+ continue
+ }
+
+ if (userModel === undefined) {
+ team.state = "invalid_user"
+ continue
+ }
+
+ const result = await teamFactory().addTeamUsers(teamModel.id, [userModel.id])
+
+ if (result === undefined) {
+ console.log("Error")
+ team.state = "error"
+ }
+ else {
+ console.log("Created")
+ team.state = "created"
+ }
+ } catch (e) {
+ console.error(e)
+ // duplicated
+ team.state = "error"
+ }
+ }
+
+ setTeamCreatingDataList([...teamCreatingDataList])
+ }
+
+ return (
+
+
+ エントリーのCSVファイルとチームタグを選択してください。
+
+
+
+ チームタグを指定してください。
+
+
+
+ TeamTag
+
+
+
+
+ CSVを入力してください
+
+
+
+
+
+
+
+ )
+}
diff --git a/components/teams/automatic-entry/teamCreatingStatus.tsx b/components/teams/automatic-entry/teamCreatingStatus.tsx
new file mode 100644
index 0000000..70100c2
--- /dev/null
+++ b/components/teams/automatic-entry/teamCreatingStatus.tsx
@@ -0,0 +1,85 @@
+'use client'
+import {UserCreatingData} from "@/components/users/csv/userCreatingAutomation";
+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, ModuleRegistry} from 'ag-grid-community';
+import {ClientSideRowModelModule} from 'ag-grid-community';
+import {TeamCreatingData} from "@/components/teams/automatic-entry/teamCreatingAutomation";
+
+ModuleRegistry.registerModules([ClientSideRowModelModule]);
+
+export type TeamCreatingStatusProps = {
+ dataList: TeamCreatingData[]
+}
+
+// Row Data Interface
+type IRow = {
+ name: string,
+ email: string,
+ className: string,
+ status: string
+}
+
+export default function TeamCreatingStatus(props: TeamCreatingStatusProps) {
+ const height = 'calc(100vh - 230px)';
+ // Column Definitions: Defines & controls grid columns.
+ const colDefs: ColDef[] = [
+ {field: "name", headerName: "チーム名"},
+ {field: "email", headerName: "メールアドレス"},
+ {field: "className", headerName: "クラス名"},
+ {field: "status", headerName: "ステータス"},
+ ]
+
+ const rowData: IRow[] = props.dataList.map((data) => {
+ // status
+ let status = ""
+ switch (data.state) {
+ case "created":
+ status = "✅作成済み"
+ break
+ case "pending":
+ status = "🕐作成待ち"
+ break
+ case "error":
+ status = "❌作成エラー"
+ break
+ case "invalid_class":
+ status = "❌クラスが見つかりません"
+ break
+ case "invalid_user":
+ status = "❌ユーザーが見つかりません"
+ break
+ case "team_not_found":
+ status = "❌チームの作成に失敗しました"
+ break
+ case "invalid_csv":
+ status = "❌CSVエラー"
+ break
+ }
+
+ return {
+ name: data.name ?? "未登録",
+ email: data.email ?? "未登録",
+ className: data.className ?? "未登録",
+ status: status
+ }
+ })
+
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/components/users/csv/userCreatingAutomation.tsx b/components/users/csv/userCreatingAutomation.tsx
index ddc4992..5a651de 100644
--- a/components/users/csv/userCreatingAutomation.tsx
+++ b/components/users/csv/userCreatingAutomation.tsx
@@ -83,7 +83,6 @@ export default function UserCreatingAutomation(props: UserCreatingAutomationProp
email: email,
gender: gender,
classId: classModel.id,
- pictureId: null,
})
if (result === undefined) {
diff --git a/components/users/csv/userCreatingAutomationWithoutClassSelection.tsx b/components/users/csv/userCreatingAutomationWithoutClassSelection.tsx
new file mode 100644
index 0000000..61bed9b
--- /dev/null
+++ b/components/users/csv/userCreatingAutomationWithoutClassSelection.tsx
@@ -0,0 +1,140 @@
+'use client'
+import {Class} from "@/src/models/ClassModel";
+import {Button, FormControl, InputLabel, MenuItem, Select, Stack, TextField, Typography} from "@mui/material";
+import {ChangeEvent, useState} from "react";
+import UserCreatingStatus from "./userCreatingStatus";
+import {Gender, userFactory} from "@/src/models/UserModel";
+import UserCreatingStatusWithoutClassSelection from "@/components/users/csv/userCreatingStatusWithoutClassSelection";
+
+export type UserCreatingAutomationProps = {
+ classes: Class[],
+}
+
+export type UserCreatingStateWithoutClassSelection = "created" | "pending" | "error" | "invalid_gender" | "invalid_csv" | "invalid_class"
+
+export type UserCreatingDataWithoutClassSelection = {
+ username?: string,
+ email?: string,
+ gender?: string,
+ className?: string,
+ state: UserCreatingStateWithoutClassSelection
+}
+
+export default function UserCreatingAutomationWithoutClassSelection(props: UserCreatingAutomationProps) {
+ const [csvInput, setCsvInput] = useState("")
+ const [userCreatingDataList, setUserCreatingDataList] = useState([])
+
+ const handleCSVChange = (event: ChangeEvent) => {
+ const csv = event.target.value
+
+ // parse csv
+ const lines = csv.split("\n")
+ const newUserCreatingDataList: UserCreatingDataWithoutClassSelection[] = []
+
+ for (const line of lines) {
+ const elements = line.split(",")
+
+ let state: UserCreatingStateWithoutClassSelection = "pending"
+
+ // invalid csv
+ if (elements.length !== 4) {
+ state = "invalid_csv"
+ }
+
+ // gender
+ if (!["male", "female"].includes(elements[2])) {
+ state = "invalid_gender"
+ }
+
+ // class name
+ if (!props.classes.some(v => v.name === elements[3])) {
+ state = "invalid_class"
+ }
+
+ newUserCreatingDataList.push({
+ username: elements[0] === "" ? undefined : elements[0],
+ email: elements[1] === "" ? undefined : elements[1],
+ gender: elements[2] === "" ? undefined : elements[2],
+ className: elements[3] === "" ? undefined : elements[3],
+ state: state
+ })
+ }
+
+ setUserCreatingDataList(newUserCreatingDataList)
+ setCsvInput(csv)
+ }
+
+ const handleCreateUsers = async () => {
+ // get pending users
+ const users = userCreatingDataList.filter((data) => data.state === "pending")
+
+ for (const user of users) {
+ // create user
+ try {
+ const gender: Gender = user.gender == "male" ? "male" : "female"
+ const username = user.username
+ const email = user.email
+ // class
+ const classModel = props.classes.find(v => v.name === user.className)
+ if (username === undefined || email === undefined || classModel === undefined) {
+ continue
+ }
+
+ const result = await userFactory().create({
+ name: username,
+ email: email,
+ gender: gender,
+ classId: classModel.id,
+ })
+
+ if (result === undefined) {
+ console.log("Error")
+ user.state = "error"
+ }
+ else {
+ console.log("Created")
+ user.state = "created"
+ }
+ } catch (e) {
+ console.error(e)
+ // duplicated
+ user.state = "error"
+ }
+ }
+
+ setUserCreatingDataList([...userCreatingDataList])
+ }
+
+ return (
+
+
+ 追加するユーザー一覧のCSVファイルと所属クラスを選択してください。
+
+
+
+ 所属クラスを指定してください。
+
+
+
+ CSVを入力してください
+
+
+
+
+
+
+
+ )
+}
diff --git a/components/users/csv/userCreatingStatusWithoutClassSelection.tsx b/components/users/csv/userCreatingStatusWithoutClassSelection.tsx
new file mode 100644
index 0000000..3565fb6
--- /dev/null
+++ b/components/users/csv/userCreatingStatusWithoutClassSelection.tsx
@@ -0,0 +1,100 @@
+'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, ModuleRegistry} from 'ag-grid-community';
+import {ClientSideRowModelModule} from 'ag-grid-community';
+import {
+ UserCreatingDataWithoutClassSelection
+} from "@/components/users/csv/userCreatingAutomationWithoutClassSelection";
+import {UserCreatingStatusProps} from "@/components/users/csv/userCreatingStatus";
+
+ModuleRegistry.registerModules([ClientSideRowModelModule]);
+
+export type UserCreatingStatusWithoutClassSelectionProps = {
+ dataList: UserCreatingDataWithoutClassSelection[]
+}
+
+// Row Data Interface
+type IRow = {
+ username: string,
+ email: string,
+ gender: string,
+ className: string,
+ status: string
+}
+
+export default function UserCreatingStatusWithoutClassSelection(props: UserCreatingStatusWithoutClassSelectionProps) {
+ const height = 'calc(100vh - 230px)';
+ // Column Definitions: Defines & controls grid columns.
+ const colDefs: ColDef[] = [
+ {field: "username", headerName: "ユーザー名"},
+ {field: "email", headerName: "メールアドレス"},
+ {field: "gender", headerName: "性別"},
+ {field: "className", headerName: "クラス"},
+ {field: "status", headerName: "ステータス"},
+ ]
+
+ const rowData: IRow[] = props.dataList.map((data) => {
+ let gender = "未登録";
+ if (data.gender !== undefined) {
+ if (data.gender === "male") {
+ gender = "男性"
+ }
+ else if (data.gender === "female") {
+ gender = "女性"
+ }
+ else {
+ gender = "エラー"
+ }
+ }
+
+ // status
+ let status = ""
+ switch (data.state) {
+ case "created":
+ status = "✅作成済み"
+ break
+ case "pending":
+ status = "🕐作成待ち"
+ break
+ case "error":
+ status = "❌作成に失敗しました"
+ break
+ case "invalid_gender":
+ status = "❌性別が不正です"
+ break
+ case "invalid_csv":
+ status = "❌形式が不正です"
+ break
+ case "invalid_class":
+ status = "❌クラスがありません"
+ break
+ }
+
+ return {
+ username: data.username ?? "未登録",
+ email: data.email ?? "未登録",
+ gender: data.gender !== "" ? gender : "未登録",
+ className: data.className ?? "未登録",
+ status: status
+ }
+ })
+
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/components/users/userEditor.tsx b/components/users/userEditor.tsx
index 95420ce..cb30b2c 100644
--- a/components/users/userEditor.tsx
+++ b/components/users/userEditor.tsx
@@ -8,7 +8,7 @@ import {
import {HiCheck, HiTrash} from "react-icons/hi2";
import React, {useState} from "react";
import {Gender, User, userFactory} from "@/src/models/UserModel";
-import { Class } from "@/src/models/ClassModel";
+import {Class} from "@/src/models/ClassModel";
import {Role} from "@/src/models/RoleModel";
import {useRouter} from "next/navigation";
@@ -31,7 +31,6 @@ export default function UserEditor(props: UserEditorProps) {
name: props.user.name,
email: props.user.email,
gender: gender as Gender,
- pictureId: props.user.pictureId,
classId: classId,
})
@@ -46,22 +45,9 @@ export default function UserEditor(props: UserEditorProps) {
return (
<>
-
-
-
-
-
- {props.user.name}
-
-
+
+ {props.user.name}
+
性別
diff --git a/src/models/UserModel.ts b/src/models/UserModel.ts
index 74175ec..a16e8fe 100644
--- a/src/models/UserModel.ts
+++ b/src/models/UserModel.ts
@@ -7,7 +7,6 @@ export type User = {
name: string,
email: string,
gender: Gender,
- pictureId: number | null,
classId: number,
teamIds: number[],
createdAt: string,