source: frontend/src/pages/UserDetailView.tsx@ 98992cf

main
Last change on this file since 98992cf was 98992cf, checked in by Dimitar Arsov <dimitararsov04@…>, 5 months ago

refactor NonAdminUser dtos

  • Property mode set to 100644
File size: 4.6 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 MusicalEntity,
8 Playlist,
9 ArtistContribution,
10} from "../utils/types";
11
12interface BaseUser {
13 id: number;
14 fullName: string;
15 userType: string;
16 followers: number;
17 following: number;
18 isFollowedByCurrentUser: boolean;
19}
20
21interface Artist extends BaseUser {
22 userType: "ARTIST";
23 contributions: ArtistContribution[];
24}
25interface Listener extends BaseUser {
26 userType: "LISTENER";
27 likedEntities: MusicalEntity[];
28 createdPlaylists: Playlist[];
29}
30
31type UserProfile = Artist | Listener;
32
33const UserDetail = () => {
34 // user refers to the selected user NOT to the user from context
35 const { userId } = useParams();
36 const navigate = useNavigate();
37 const [user, setUser] = useState<UserProfile | null>(null);
38 const [error, setError] = useState<string | null>(null);
39 const [isFollowing, setIsFollowing] = useState(false);
40
41 const handleFollow = async () => {
42 if (!user) return;
43
44 setIsFollowing(true);
45 try {
46 const response = await axiosInstance.post<UserProfile>(
47 `/users/follow/${userId}`,
48 );
49 } catch (err: any) {
50 console.error(err.response?.data?.error);
51 } finally {
52 setIsFollowing(false);
53 }
54 };
55
56 useEffect(() => {
57 const fetchUser = async () => {
58 setError(null);
59 try {
60 const response = await axiosInstance.get(`/users/${userId}`);
61 console.log(response.data);
62
63 setUser(response.data);
64 } catch (err: any) {
65 const errorMessage =
66 err.response?.data?.error || "Failed to fetch user";
67 setError(errorMessage);
68 }
69 };
70 fetchUser();
71 }, [userId]);
72
73 if (error) {
74 return (
75 <div className="p-6 bg-red-50 border border-red-200 text-red-700 rounded-lg">
76 <h2 className="font-bold">Error</h2>
77 <p>{error}</p>
78 </div>
79 );
80 }
81
82 if (!user) return <div className="p-6">Loading...</div>;
83
84 return (
85 <div className="container mx-auto p-6">
86 <button
87 onClick={() => navigate(-1)}
88 className="mb-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors duration-200"
89 >
90 ← Back
91 </button>
92
93 <div className="bg-white shadow-lg rounded-lg p-8">
94 <div className="flex items-start gap-6 mb-8">
95 <div className="shrink-0">
96 <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">
97 {user.fullName.charAt(0).toUpperCase()}
98 </div>
99 </div>
100
101 <div className="flex-1">
102 <h1 className="text-4xl font-bold mb-2">{user.fullName}</h1>
103 <span className="inline-block px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm font-medium mb-4">
104 {user.userType}
105 </span>
106
107 <div className="flex gap-6 mb-4 text-gray-700">
108 <div className="flex flex-col">
109 <span className="text-2xl font-bold">{user.followers}</span>
110 <span className="text-sm text-gray-500">Followers</span>
111 </div>
112 <div className="flex flex-col">
113 <span className="text-2xl font-bold">{user.following}</span>
114 <span className="text-sm text-gray-500">Following</span>
115 </div>
116 </div>
117
118 <button
119 onClick={handleFollow}
120 disabled={isFollowing}
121 className={`
122 px-6 py-2 font-semibold rounded-lg shadow-md
123 transition-colors duration-200
124 ${
125 isFollowing
126 ? "bg-gray-400 text-gray-200 cursor-not-allowed"
127 : user.isFollowedByCurrentUser
128 ? "bg-gray-200 text-gray-700 hover:bg-gray-300 cursor-pointer"
129 : "bg-blue-500 text-white hover:bg-blue-600 cursor-pointer"
130 }
131 `}
132 >
133 {user.isFollowedByCurrentUser ? "Unfollow" : "Follow"}
134 </button>
135 </div>
136 </div>
137
138 {user.userType === "ARTIST" ? (
139 <ArtistView contributions={user.contributions} />
140 ) : (
141 <ListenerView
142 likedEntities={user.likedEntities}
143 playlists={user.createdPlaylists}
144 />
145 )}
146 </div>
147 </div>
148 );
149};
150
151export default UserDetail;
Note: See TracBrowser for help on using the repository browser.