source: frontend/src/pages/UserDetailView.tsx@ 4e5cf92

main
Last change on this file since 4e5cf92 was 4e5cf92, checked in by Filip Gavrilovski <filipgavrilovski28@…>, 6 months ago

refactor frontend file structure

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