source: frontend/src/components/userProfile/UserDetailView.tsx@ 0f71490

main
Last change on this file since 0f71490 was 0f71490, checked in by Dimitar Arsov <dimitararsov04@…>, 6 months ago

show follow/following button

  • Property mode set to 100644
File size: 3.7 KB
Line 
1import { useEffect, useState } from "react";
2import { useParams, useNavigate } from "react-router-dom";
3import ArtistView from "./ArtistView";
4import ListenerView from "./ListenerView";
5import axiosInstance from "../../api/axiosInstance";
6import type { ArtistContributionDTO } from "../../types";
7import type { MusicalEntityDTO } from "../../types";
8import type { Playlist } from "../../types";
9
10interface User {
11 id: number;
12 username: string;
13 fullName: string;
14 userType: string;
15 followers: number;
16 following: number;
17 isFollowedByCurrentUser: boolean;
18
19 musicalEntities?: {
20 contributions: ArtistContributionDTO[];
21 };
22
23 likes?: {
24 likedEntities: MusicalEntityDTO[];
25 };
26
27 createdPlaylists?: Playlist[];
28}
29
30const UserDetail = () => {
31 // user refers to the selected user NOT to the user from context
32 const { userId } = useParams();
33 const navigate = useNavigate();
34 const [user, setUser] = useState<User | null>(null);
35 const [error, setError] = useState<string | null>(null);
36
37 useEffect(() => {
38 const fetchUser = async () => {
39 setError(null);
40 try {
41 const response = await axiosInstance.get(`/users/${userId}`);
42
43 setUser(response.data);
44 } catch (err: any) {
45 const errorMessage =
46 err.response?.data?.error || "Failed to fetch user";
47 setError(errorMessage);
48 }
49 };
50 fetchUser();
51 }, [userId]);
52
53 if (error) {
54 return (
55 <div className="p-6 bg-red-50 border border-red-200 text-red-700 rounded-lg">
56 <h2 className="font-bold">Error</h2>
57 <p>{error}</p>
58 </div>
59 );
60 }
61
62 if (!user) return <div className="p-6">Loading...</div>;
63
64 return (
65 <div className="container mx-auto p-6">
66 <button
67 onClick={() => navigate(-1)}
68 className="mb-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
69 >
70 ← Back
71 </button>
72
73 <div className="bg-white shadow-lg rounded-lg p-8">
74 <div className="flex items-start gap-6 mb-8">
75 <div className="shrink-0">
76 <div className="w-32 h-32 rounded-full bg-linear-to-br from-blue-400 to-purple-500 flex items-center justify-center text-white text-4xl font-bold shadow-lg">
77 {user.fullName.charAt(0).toUpperCase()}
78 </div>
79 </div>
80
81 <div className="flex-1">
82 <h1 className="text-4xl font-bold mb-2">{user.fullName}</h1>
83 <span className="inline-block px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm font-medium mb-4">
84 {user.userType}
85 </span>
86
87 <div className="flex gap-6 mb-4 text-gray-700">
88 <div className="flex flex-col">
89 <span className="text-2xl font-bold">{user.followers}</span>
90 <span className="text-sm text-gray-500">Followers</span>
91 </div>
92 <div className="flex flex-col">
93 <span className="text-2xl font-bold">{user.following}</span>
94 <span className="text-sm text-gray-500">Following</span>
95 </div>
96 </div>
97
98 <button className="px-6 py-2 bg-blue-500 hover:bg-blue-600 text-white font-semibold rounded-lg shadow-md transition-colors duration-200 cursor-pointer">
99 {user.isFollowedByCurrentUser ? "Unfollow" : "Follow"}
100 </button>
101 </div>
102 </div>
103
104 {user.userType === "ARTIST" && user.musicalEntities?.contributions && (
105 <ArtistView contributions={user.musicalEntities.contributions} />
106 )}
107
108 {user.userType === "LISTENER" && user.likes?.likedEntities && (
109 <ListenerView
110 likedEntities={user.likes.likedEntities}
111 playlists={user.createdPlaylists}
112 />
113 )}
114 </div>
115 </div>
116 );
117};
118
119export default UserDetail;
Note: See TracBrowser for help on using the repository browser.