Skip to content

Commit

Permalink
Merge pull request #13 from B3-3iL-DLW/actions-users
Browse files Browse the repository at this point in the history
Actions users
  • Loading branch information
julesartd authored May 17, 2024
2 parents a8bf473 + 4ddbc6c commit bdc3997
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 92 deletions.
6 changes: 2 additions & 4 deletions backend-nest/src/api/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@ export class UsersService {

async findOne(id: number): Promise<user | null> {
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');
Expand Down
2 changes: 1 addition & 1 deletion frontend-react/src/app/api/apiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface ApiResponse {

}

export async function apiRequest(endpoint: string, method: string, body?: any): Promise<ApiResponse> {
export async function apiRequest(endpoint: string, method: string, body?: any): Promise<ApiResponse> {
const session = await verifySession()
const bearer = session?.session

Expand Down
54 changes: 0 additions & 54 deletions frontend-react/src/app/users/UserList.tsx

This file was deleted.

1 change: 0 additions & 1 deletion frontend-react/src/app/users/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<string | null>(null);

Expand Down
89 changes: 72 additions & 17 deletions frontend-react/src/app/users/userComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,86 @@
"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<User | null>(null);
useEffect(() => {
verifySession().then(session => {
if (session) {
getUser().then(fetchedUser => {
setUser(fetchedUser);
});
const [classgroup, setClassgroup] = useState<Classgroup>();
const [editMode, setEditMode] = useState(false);
const [email, setEmail] = useState("");
const [firstname, setFirstname] = useState("");
const [lastname, setLastname] = useState("");
const [error, setError] = useState("");

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 (
<div>
{user && (
<div className="flex items-center justify-center min-h-screen">
<h1>{user.firstname} {user.lastname}</h1>
<p>{user.email}</p>
<p>{user.classGroupId}</p>
</div>
<div className="flex items-center justify-center pt-20">
{user && classgroup && (
<Card className="py-4">
<CardHeader className="pb-0 pt-2 px-4 flex-col items-start">
<Image src="/3il_logos_groupe.png" alt="Logo" width={200} height={200}/>
</CardHeader>
<CardBody className="overflow-visible py-2">
<h4 className="font-bold text-large">{user.firstname} {user.lastname}</h4>
{editMode ? (
<>
<Spacer y={8}/>
<Input label="First Name" value={firstname}
onChange={e => setFirstname(e.target.value)}/>
<Spacer y={8}/>
<Input label="Last Name" value={lastname} onChange={e => setLastname(e.target.value)}/>
<Spacer y={8}/>
<Input label="Email" value={email} onChange={e => setEmail(e.target.value)}/>
<Spacer y={8}/>
<Button onClick={handleEdit}>Save</Button>
</>
) : (
<>
<p className="text-default-500">{user.email}</p>
<p className="text-tiny uppercase font-bold">{classgroup.name}</p>
<Spacer y={8}/>
<Button onClick={() => setEditMode(true)}>Modifier</Button>
</>
)}
{error && <p className="error">{error}</p>}
</CardBody>
</Card>
)}
</div>
);
};
};
45 changes: 30 additions & 15 deletions frontend-react/src/app/users/userTable.tsx
Original file line number Diff line number Diff line change
@@ -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"},
Expand All @@ -15,7 +17,7 @@ const columns = [
];

export default function UserTable() {
const [users, setUsers] = useState([]);
const [users, setUsers] = useState<User[]>([]);

useEffect(() => {
apiRequest('users', 'GET').then(response => {
Expand All @@ -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":
Expand All @@ -39,24 +52,26 @@ export default function UserTable() {
return (
<div className="relative flex items-center gap-2">
<Tooltip content="Edit user">
<span className="text-lg text-default-400 cursor-pointer active:opacity-50">
<EditIcon />
</span>
<button className="text-lg text-default-400 cursor-pointer active:opacity-50">
<EditIcon/>
</button>
</Tooltip>
<Tooltip color="danger" content="Delete user">
<span className="text-lg text-danger cursor-pointer active:opacity-50">
<DeleteIcon />
</span>
<button className="text-lg text-danger cursor-pointer active:opacity-50"
onClick={() => handleDelete(user.id)}
onKeyDown={(event) => handleKeyDown(event, user.id)}>
<DeleteIcon/>
</button>
</Tooltip>
</div>
);
default:
return cellValue;
}
}, []);
}, [users]);

return (
<div style={{ padding: '20px', color: 'black' }}>
<div style={{padding: '20px', color: 'black'}}>
<Table aria-label="Example table with custom cells">
<TableHeader columns={columns}>
{(column) => (
Expand All @@ -66,7 +81,7 @@ export default function UserTable() {
)}
</TableHeader>
<TableBody items={users}>
{(item) => (
{(item: User) => (
<TableRow key={item.id}>
{(columnKey) => <TableCell>{renderCell(item, columnKey)}</TableCell>}
</TableRow>
Expand Down

0 comments on commit bdc3997

Please sign in to comment.