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,