Added profile view

This commit is contained in:
Marcin-Ramotowski 2025-04-13 18:26:23 +02:00
parent 749a5529f2
commit e374df55de
6 changed files with 122 additions and 2 deletions

View File

@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"axios": "^1.8.3", "axios": "^1.8.3",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"lucide-react": "^0.488.0",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-router-dom": "^7.3.0" "react-router-dom": "^7.3.0"
@ -2814,6 +2815,15 @@
"yallist": "^3.0.2" "yallist": "^3.0.2"
} }
}, },
"node_modules/lucide-react": {
"version": "0.488.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.488.0.tgz",
"integrity": "sha512-ronlL0MyKut4CEzBY/ai2ZpKPxyWO4jUqdAkm2GNK5Zn3Rj+swDz+3lvyAUXN0PNqPKIX6XM9Xadwz/skLs/pQ==",
"license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",

View File

@ -12,6 +12,7 @@
"dependencies": { "dependencies": {
"axios": "^1.8.3", "axios": "^1.8.3",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"lucide-react": "^0.488.0",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-router-dom": "^7.3.0" "react-router-dom": "^7.3.0"

View File

@ -1,6 +1,7 @@
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Login from "./pages/Login"; import Login from "./pages/Login";
import Tasks from "./pages/Tasks"; import Tasks from "./pages/Tasks";
import Profile from "./pages/Profile";
const App = () => { const App = () => {
return ( return (
@ -8,6 +9,7 @@ const App = () => {
<Routes> <Routes>
<Route path="/login" element={<Login />} /> <Route path="/login" element={<Login />} />
<Route path="/tasks" element={<Tasks />} /> <Route path="/tasks" element={<Tasks />} />
<Route path="/profile" element={<Profile />} />
</Routes> </Routes>
</Router> </Router>
); );

24
frontend/src/api/user.ts Normal file
View File

@ -0,0 +1,24 @@
import api from "./api";
export const getUser = async (userId: number) => {
const response = await api.get(`/users/${userId}`);
return response.data;
};
export const updateUser = async (
userId: number,
data: {
username: string;
email: string;
password?: string;
oldPassword?: string;
}
) => {
const response = await api.patch(`/users/${userId}`, data);
return response.data;
};
export const deleteUser = async (userId: number) => {
const response = await api.delete(`/users/${userId}`);
return response.data;
};

View File

@ -0,0 +1,77 @@
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { getUser, deleteUser } from "../api/user";
import Cookies from "js-cookie";
interface User {
id: number;
username: string;
email: string;
role: string;
}
const Profile = () => {
const id = Cookies.get("user_id")
const navigate = useNavigate();
if (!id) {
navigate("/login")
}
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
const fetchUser = async () => {
try {
const userData = await getUser(Number(id));
setUser(userData);
} catch (error) {
console.error("Błąd podczas pobierania danych użytkownika:", error);
}
};
fetchUser();
}, [id]);
const handleDeleteAccount = async () => {
if (!window.confirm("Na pewno chcesz usunąć konto? Tej operacji nie da się cofnąć.")) return;
try {
await deleteUser(Number(id));
Cookies.remove("user_id");
navigate("/login");
} catch (error) {
console.error("Błąd podczas usuwania konta:", error);
}
};
if (!user) return <div className="p-6">Ładowanie danych użytkownika...</div>;
return (
<div className="p-6 max-w-md mx-auto">
<h1 className="text-2xl font-bold mb-4">Twój profil</h1>
<div className="bg-white shadow rounded p-4 mb-4">
<p><strong>Nazwa użytkownika:</strong> {user.username}</p>
<p><strong>Email:</strong> {user.email}</p>
<p><strong>Rola:</strong> {user.role}</p>
</div>
<div className="flex flex-col gap-2">
<button
onClick={() => navigate(`/profile/${user.id}/change-password`)}
className="bg-blue-500 text-white p-2 rounded hover:bg-blue-600"
>
🔐 Zmień hasło
</button>
<button
onClick={handleDeleteAccount}
className="bg-red-500 text-white p-2 rounded hover:bg-red-600"
>
🗑 Usuń konto
</button>
</div>
</div>
);
};
export default Profile;

View File

@ -4,6 +4,7 @@ import { getUserTasks, createTask, deleteTask } from "../api/tasks";
import { logout } from "../api/auth"; import { logout } from "../api/auth";
import api from "../api/api"; import api from "../api/api";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { User } from "lucide-react";
// Define Task type // Define Task type
interface Task { interface Task {
@ -82,9 +83,14 @@ const Tasks = () => {
}; };
return ( return (
<div className="p-6"> <div className="p-6 relative min-h-screen">
<button
onClick={() => navigate(`/profile`)}
className="text-gray-600 hover:text-black mb-4 flex items-center">
<User className="w-5 h-5 mr-1" />
Profil
</button>
<h1 className="text-2xl font-bold mb-4">Twoje zadania</h1> <h1 className="text-2xl font-bold mb-4">Twoje zadania</h1>
<button <button
onClick={handleLogout} onClick={handleLogout}
className="bg-red-500 text-white p-2 rounded hover:bg-red-600 mb-4" className="bg-red-500 text-white p-2 rounded hover:bg-red-600 mb-4"