diff --git a/code/backend/src/controllers/profileController.ts b/code/backend/src/controllers/profileController.ts index 3ce1644..4f8d017 100644 --- a/code/backend/src/controllers/profileController.ts +++ b/code/backend/src/controllers/profileController.ts @@ -202,6 +202,7 @@ export const updateBio = async (req: Request, res: Response) => { // Endpoint to get user data export const getProfile = async (req: Request, res: Response) => { const username: string = req.params.username as string; + const requestingUser: JwtPayload | undefined = req.user; if (!username) { res.status(StatusCodes.BAD_REQUEST).json({ error: "no username", @@ -227,9 +228,22 @@ export const getProfile = async (req: Request, res: Response) => { const publicUser: PublicUser | undefined = await getUser(user.id); + let isFollowing : boolean = false; + if(requestingUser) { + const followingData = await prisma.follow.findFirst({ + where: { + followedUserId: user.id, + followingUserId: requestingUser.id, + } + }) + if(followingData) { + isFollowing = true; + } + } + res.status(StatusCodes.OK).json({ message: "User found", - data: publicUser, + data: {...publicUser, isFollowing}, }); } catch (err) { console.error(err); diff --git a/code/backend/src/routes/profileRoutes.ts b/code/backend/src/routes/profileRoutes.ts index 61ff87a..f1915a7 100644 --- a/code/backend/src/routes/profileRoutes.ts +++ b/code/backend/src/routes/profileRoutes.ts @@ -10,6 +10,7 @@ const profileRouter = express.Router(); import { upload } from "../middleware/uploadSingle"; import { updateBioSchema } from "../schemas/profileSchemas"; import { validateData } from "../middleware/validationMiddleware"; +import { optionalAuthenticateToken } from "../middleware/optionalAuthenticateToken"; /** * @swagger * /api/profile/uploadProfilePicture: @@ -124,5 +125,5 @@ profileRouter.put( * 401: * description: Ungültige Anmeldedaten */ -profileRouter.get("/:username", getProfile); +profileRouter.get("/:username", optionalAuthenticateToken, getProfile); export default profileRouter; diff --git a/code/frontend/src/api/axios.ts b/code/frontend/src/api/axios.ts index 4deee55..358f9da 100644 --- a/code/frontend/src/api/axios.ts +++ b/code/frontend/src/api/axios.ts @@ -10,7 +10,6 @@ const api = axios.create({ // get token from local storage const getAccessToken = () => localStorage.getItem("token"); -const getRefreshToken = () => localStorage.getItem("refreshToken"); //redirects the page to the login and back export const redirectToLogin = (returnToPage = true) => { diff --git a/code/frontend/src/components/ChangeAvatarDialog.tsx b/code/frontend/src/components/ChangeAvatarDialog.tsx index e7d17ba..bfb1c36 100644 --- a/code/frontend/src/components/ChangeAvatarDialog.tsx +++ b/code/frontend/src/components/ChangeAvatarDialog.tsx @@ -87,11 +87,9 @@ export default function AvatarDialog({ - U + {username && username[0].toUpperCase() || ""} diff --git a/code/frontend/src/components/changeAvatarDialog.css b/code/frontend/src/components/changeAvatarDialog.css index 6f75c41..5f2b68d 100644 --- a/code/frontend/src/components/changeAvatarDialog.css +++ b/code/frontend/src/components/changeAvatarDialog.css @@ -19,8 +19,8 @@ } .profile-avatar { - width: 40px; - height: 40px; + width: 50px; + height: 50px; background-color: var(--Rotkehlchen-yellow-default); } @@ -46,8 +46,8 @@ @media screen and (min-width: 768px) { .profile-avatar { - width: 5rem; - height: 5rem; + width: 4.5rem; + height: 4.5rem; background-color: var(--Rotkehlchen-yellow-default); } diff --git a/code/frontend/src/components/username.css b/code/frontend/src/components/username.css index 39650ff..7be6bfb 100644 --- a/code/frontend/src/components/username.css +++ b/code/frontend/src/components/username.css @@ -1,10 +1,21 @@ .profile-username { color: var(--Rotkehlchen-orange-default); - max-width: 10rem; + width: 15rem; overflow: hidden; text-overflow: ellipsis; cursor: pointer; + text-align: start; } .profile-popover { padding: 1rem; } + +@media screen and (min-width: 768px) { + .profile-username { + width: 10rem; + } + .profile-popover { + padding: 2rem; + } + +} diff --git a/code/frontend/src/pages/Profile.tsx b/code/frontend/src/pages/Profile.tsx index b14df9a..eb1cee0 100644 --- a/code/frontend/src/pages/Profile.tsx +++ b/code/frontend/src/pages/Profile.tsx @@ -8,7 +8,7 @@ import { StyledEngineProvider, Divider } from "@mui/material"; import ChangeAvatarDialog from "../components/ChangeAvatarDialog"; import Bio from "../components/Bio"; import RotkehlchenButton from "../components/ButtonRotkehlchen"; -import api from "../api/axios"; +import api, { redirectToLogin } from "../api/axios"; import { useAuth } from "../api/Auth"; import { useNavigate, useParams } from "react-router-dom"; import { useEffect, useState } from "react"; @@ -27,11 +27,12 @@ function Profile() { followers: 0, following: 0, posts: 0, + isFollowing: false, }); const userProfile = async () => { try { - const response = await api.get(`/profile/get/${username}`); + const response = await api.get(`/profile/${username}`); setUserData(response.data.data); return; } catch (error) { @@ -54,12 +55,20 @@ function Profile() { return prevData; }); }; - function handleFollowUser() { - // TODO: implement follow user functionality - if (user) { - api.post(`follower/follow/${username}`) + const handleFollowUser = async () => { + try { + if (userData?.isFollowing === false) { + await api.post(`/follower/follow/${username}`); + } else if (userData?.isFollowing === true) { + await api.delete(`/follower/unfollow/${username}`); + } else { + redirectToLogin(); + } + userProfile(); // Refresh user data after unfollowing + } catch (error) { + console.error("Error following/unfollowing user:", error); } - } + }; return ( @@ -97,7 +106,12 @@ function Profile() { {!ownAccount && ( - + )} {userData && } diff --git a/code/frontend/src/types/UserProfile.ts b/code/frontend/src/types/UserProfile.ts index 2e4e824..ca438de 100644 --- a/code/frontend/src/types/UserProfile.ts +++ b/code/frontend/src/types/UserProfile.ts @@ -6,4 +6,5 @@ export type UserProfile = { followers: number; following: number; posts: number; + isFollowing: boolean; } \ No newline at end of file