diff --git a/backend-nest/src/api/users/users.service.ts b/backend-nest/src/api/users/users.service.ts index 7b3fd5b..7a02e3b 100644 --- a/backend-nest/src/api/users/users.service.ts +++ b/backend-nest/src/api/users/users.service.ts @@ -16,15 +16,13 @@ export class UsersService { async findOne(id: number): Promise { const existingUser = await this.prisma.user.findUnique({ - where: { id: id }, + where: { id: Number(id) }, }); if (!existingUser) { throw new NotFoundException('User not found'); } try { - return await this.prisma.user.findUnique({ - where: { id: id }, - }); + return existingUser } catch (error) { console.error(error); throw new InternalServerErrorException('Error finding user'); diff --git a/frontend-react/src/app/api/apiService.ts b/frontend-react/src/app/api/apiService.ts index 7dc4e02..98808dd 100644 --- a/frontend-react/src/app/api/apiService.ts +++ b/frontend-react/src/app/api/apiService.ts @@ -9,7 +9,7 @@ export interface ApiResponse { } -export async function apiRequest(endpoint: string, method: string, body?: any): Promise { +export async function apiRequest(endpoint: string, method: string, body?: any): Promise { const session = await verifySession() const bearer = session?.session diff --git a/frontend-react/src/app/users/UserList.tsx b/frontend-react/src/app/users/UserList.tsx deleted file mode 100644 index de22c70..0000000 --- a/frontend-react/src/app/users/UserList.tsx +++ /dev/null @@ -1,60 +0,0 @@ -// src/app/users/UsersList.tsx -"use client"; -import React, {useEffect, useState} from 'react'; -import {apiRequest} from '../api/apiService'; -import {User} from "@/app/models/user"; -import {FontAwesomeIcon} from '@fortawesome/react-fontawesome' -import {faEdit, faTrash} from '@fortawesome/free-solid-svg-icons' -import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow} from "@nextui-org/table"; - -export default function UsersList() { - const [users, setUsers] = useState([]); - - useEffect(() => { - apiRequest('users', 'GET').then(response => { - console.log(response) - if (response.ok) { - setUsers(response.data); - } - }); - }, []); - - const handleDelete = async (id: number) => { - await apiRequest(`users/${id}`, 'DELETE'); - - }; - - return ( -
- - - First Name - Last Name - Email - Class Group - Action - - - - {users.map(user => ( - - {user.firstname} - {user.lastname} - {user.email} - {user.classGroupId} - - - - - - ))} - -
-
- ); -} \ No newline at end of file diff --git a/frontend-react/src/app/users/page.tsx b/frontend-react/src/app/users/page.tsx index 311a7fe..62e0245 100644 --- a/frontend-react/src/app/users/page.tsx +++ b/frontend-react/src/app/users/page.tsx @@ -7,7 +7,6 @@ import UserTable from "@/app/users/userTable"; const UserComponent = dynamic(() => import('../users/userComponents'), { ssr: false }); -// This is a new client component that fetches the user's role const UserRoleComponent = () => { const [role, setRole] = React.useState(null); diff --git a/frontend-react/src/app/users/userComponents.tsx b/frontend-react/src/app/users/userComponents.tsx index 8197507..0a54060 100644 --- a/frontend-react/src/app/users/userComponents.tsx +++ b/frontend-react/src/app/users/userComponents.tsx @@ -2,38 +2,85 @@ "use client"; import React, {useEffect, useState} from 'react'; import {getUser, verifySession} from "@/app/lib/dal"; - import {User} from "@/app/models/user"; import {Classgroup} from "@/app/models/classgroup"; import {getClassGroupById} from "@/app/api/services/classgroupService"; +import {Button, Card, CardBody, CardHeader, Image, Input, Spacer} from "@nextui-org/react"; +import {apiRequest} from '../api/apiService'; export default function UserComponent() { const [user, setUser] = useState(null); const [classgroup, setClassgroup] = useState(); + const [editMode, setEditMode] = useState(false); + const [email, setEmail] = useState(""); + const [firstname, setFirstname] = useState(""); + const [lastname, setLastname] = useState(""); + const [error, setError] = useState(""); - useEffect(() => { - verifySession().then(session => { - if (session) { - getUser().then(fetchedUser => { - setUser(fetchedUser); - if (fetchedUser.classGroupId) { - getClassGroupById(fetchedUser.classGroupId).then(fetchedClassgroup => { - setClassgroup(fetchedClassgroup); - }); - } - }); + const fetchData = async () => { + const session = await verifySession(); + if (session) { + const fetchedUser = await getUser(); + setUser(fetchedUser); + setEmail(fetchedUser.email); + setFirstname(fetchedUser.firstname); + setLastname(fetchedUser.lastname); + if (fetchedUser.classGroupId) { + const fetchedClassgroup = await getClassGroupById(fetchedUser.classGroupId); + setClassgroup(fetchedClassgroup); } - }); + } + }; + + useEffect(() => { + fetchData().then(r => r); }, []); + const handleEdit = async () => { + if (user) { + const response = await apiRequest(`users/${user.id}`, 'PATCH', {id: user.id, email, firstname, lastname}); + if (response.ok) { + await fetchData(); + setEditMode(false); + setError(""); // clear any previous error + } else if (response.status === 409) { + setError("Email already in use"); + } + } + }; + return ( -
+
{user && classgroup && ( -
-

{user.firstname} {user.lastname}

-

{user.email}

-

{classgroup.name}

-
+ + + Logo + + +

{user.firstname} {user.lastname}

+ {editMode ? ( + <> + + setFirstname(e.target.value)}/> + + setLastname(e.target.value)}/> + + setEmail(e.target.value)}/> + + + + ) : ( + <> +

{user.email}

+

{classgroup.name}

+ + + + )} + {error &&

{error}

} +
+
)}
); diff --git a/frontend-react/src/app/users/userTable.tsx b/frontend-react/src/app/users/userTable.tsx index dff89fc..fa55a68 100644 --- a/frontend-react/src/app/users/userTable.tsx +++ b/frontend-react/src/app/users/userTable.tsx @@ -1,8 +1,10 @@ -import React, { useEffect, useState } from "react"; -import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Tooltip} from "@nextui-org/react"; +// src/app/users/userTable.tsx +import React, {useEffect, useState} from "react"; +import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow, Tooltip} from "@nextui-org/react"; import {EditIcon} from "./EditIcon"; import {DeleteIcon} from "./DeleteIcon"; -import { apiRequest } from '../api/apiService'; +import {apiRequest} from '../api/apiService'; +import {User} from "@/app/models/user"; const columns = [ {name: "ID", uid: "id"}, @@ -15,7 +17,7 @@ const columns = [ ]; export default function UserTable() { - const [users, setUsers] = useState([]); + const [users, setUsers] = useState([]); useEffect(() => { apiRequest('users', 'GET').then(response => { @@ -25,8 +27,19 @@ export default function UserTable() { }); }, []); - const renderCell = React.useCallback((user: { [x: string]: any; }, columnKey: string | number) => { - const cellValue = user[columnKey]; + const handleDelete = async (id: number) => { + await apiRequest(`users/${id}`, 'DELETE'); + setUsers(users.filter(user => user.id !== id)); + }; + + const handleKeyDown = (event: React.KeyboardEvent, id: number) => { + if (event.key === 'Enter') { + handleDelete(id).then(r => r); + } + }; + + const renderCell = React.useCallback((user: User, columnKey: string | number) => { + const cellValue = user[columnKey as keyof User]; switch (columnKey) { case "firstname": @@ -39,24 +52,26 @@ export default function UserTable() { return (
- - - + - - - +
); default: return cellValue; } - }, []); + }, [users]); return ( -
+
{(column) => ( @@ -66,7 +81,7 @@ export default function UserTable() { )} - {(item) => ( + {(item: User) => ( {(columnKey) => {renderCell(item, columnKey)}}