From e1a21d2bc40e73b926f8022de020f5b5ca2f6954 Mon Sep 17 00:00:00 2001 From: Jules Date: Fri, 17 May 2024 11:56:49 +0200 Subject: [PATCH 1/2] :construction: actions --- frontend-react/src/app/users/UserList.tsx | 8 +++++++- frontend-react/src/app/users/userComponents.tsx | 16 ++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/frontend-react/src/app/users/UserList.tsx b/frontend-react/src/app/users/UserList.tsx index 6606e6a..b106552 100644 --- a/frontend-react/src/app/users/UserList.tsx +++ b/frontend-react/src/app/users/UserList.tsx @@ -19,6 +19,11 @@ export default function UsersList() { }); }, []); + const handleDelete = async (id: number) => { + await apiRequest(`users/${id}`, 'DELETE'); + + }; + return (
@@ -41,7 +46,8 @@ export default function UsersList() { - diff --git a/frontend-react/src/app/users/userComponents.tsx b/frontend-react/src/app/users/userComponents.tsx index 1cb7395..8197507 100644 --- a/frontend-react/src/app/users/userComponents.tsx +++ b/frontend-react/src/app/users/userComponents.tsx @@ -4,15 +4,23 @@ 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"; export default function UserComponent() { const [user, setUser] = useState(null); + const [classgroup, setClassgroup] = useState(); + useEffect(() => { verifySession().then(session => { if (session) { getUser().then(fetchedUser => { setUser(fetchedUser); + if (fetchedUser.classGroupId) { + getClassGroupById(fetchedUser.classGroupId).then(fetchedClassgroup => { + setClassgroup(fetchedClassgroup); + }); + } }); } }); @@ -20,13 +28,13 @@ export default function UserComponent() { return (
- {user && ( + {user && classgroup && (

{user.firstname} {user.lastname}

{user.email}

-

{user.classGroupId}

+

{classgroup.name}

)}
); -}; +}; \ No newline at end of file From 4ddbc6cf0449f60c93e4ba1259b6e49b1cc5801d Mon Sep 17 00:00:00 2001 From: Jules Date: Fri, 17 May 2024 15:07:35 +0200 Subject: [PATCH 2/2] edit user --- backend-nest/src/api/users/users.service.ts | 6 +- frontend-react/src/app/api/apiService.ts | 2 +- frontend-react/src/app/users/UserList.tsx | 60 ------------- frontend-react/src/app/users/page.tsx | 1 - .../src/app/users/userComponents.tsx | 85 ++++++++++++++----- frontend-react/src/app/users/userTable.tsx | 45 ++++++---- 6 files changed, 99 insertions(+), 100 deletions(-) delete mode 100644 frontend-react/src/app/users/UserList.tsx 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)}}