Changeset 1579b4f for frontend/src/pages/UserDetail.tsx
- Timestamp:
- 02/10/26 21:58:39 (5 months ago)
- Branches:
- main
- Children:
- 92db381
- Parents:
- 0808ef2
- File:
-
- 1 edited
-
frontend/src/pages/UserDetail.tsx (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
-
frontend/src/pages/UserDetail.tsx
r0808ef2 r1579b4f 1 1 import { useEffect, useState } from "react"; 2 import { useNavigate, useParams } from "react-router-dom";3 import axiosInstance from "../api/axiosInstance";2 import { Link, useNavigate, useParams } from "react-router-dom"; 3 import axiosInstance, { baseURL } from "../api/axiosInstance"; 4 4 import LoadingSpinner from "../components/LoadingSpinner"; 5 5 import ArtistView from "../components/userProfile/ArtistView"; … … 35 35 36 36 const UserDetail = () => { 37 // user refers to the selected user NOT to the user from context38 const baseURL = import.meta.env.VITE_API_BASE_URL;39 37 const { username: usernameParam } = useParams(); 40 // sintaksava dole znaci zemi go user od auth context i preimenuvaj go vo currentUser, za da ne se izmesa so user-ot dole41 38 const { user: currentUser } = useAuth(); 42 39 const navigate = useNavigate(); … … 49 46 const [isFollowing, setIsFollowing] = useState(false); 50 47 51 // determine which username to use: URL param or current user's username52 48 const username = usernameParam || currentUser?.username; 53 54 // if we're on /me route and no user is logged in, show error 49 const isOwnProfile = currentUser?.username === username; 50 55 51 if (!usernameParam && !currentUser) { 56 52 return ( 57 <div className="p-6 bg-red-50 border border-red-200 text-red-700 rounded-lg"> 58 <h2 className="font-bold">Authentication Required</h2> 59 <p>You must be logged in to view your profile.</p> 60 <button 61 onClick={() => navigate("/login")} 62 className="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors duration-200 cursor-pointer" 63 > 64 Go to Login 65 </button> 53 <div className="min-h-screen bg-linear-to-br from-[#1e1e2e] to-[#0f0f1e] flex items-center justify-center"> 54 <div className="text-center"> 55 <p className="text-red-400 text-xl mb-4"> 56 You must be logged in to view your profile. 57 </p> 58 <button 59 onClick={() => navigate("/login")} 60 className="text-[#1db954] hover:underline text-sm cursor-pointer" 61 > 62 Go to Login 63 </button> 64 </div> 66 65 </div> 67 66 ); … … 95 94 try { 96 95 const response = await axiosInstance.post<FollowStatus>( 97 `/users/na/${ username}/follow`,96 `/users/na/${targetUsername}/follow`, 98 97 ); 99 98 … … 105 104 ), 106 105 ); 107 108 // if (user && user.id === targetId) {109 // setUser((prev) => {110 // if (!prev) return null;111 // return {112 // ...prev,113 // isFollowedByCurrentUser: response.data.isFollowing,114 // followers: response.data.followerCount,115 // };116 // });117 // }118 106 } catch (err: any) { 119 107 setError(handleError(err)); … … 157 145 try { 158 146 const response = await axiosInstance.get(`/users/na/${username}`); 159 console.log(response.data);160 147 setUser(response.data); 161 148 } catch (err: any) { … … 168 155 if (error) { 169 156 return ( 170 <div className="p-6 bg-red-50 border border-red-200 text-red-700 rounded-lg"> 171 <h2 className="font-bold">Error</h2> 172 <p>{error}</p> 157 <div className="min-h-screen bg-linear-to-br from-[#1e1e2e] to-[#0f0f1e] flex items-center justify-center"> 158 <div className="text-center"> 159 <p className="text-red-400 text-xl mb-4">{error}</p> 160 <Link to="/" className="text-[#1db954] hover:underline text-sm"> 161 ← Back to Home 162 </Link> 163 </div> 173 164 </div> 174 165 ); … … 180 171 181 172 return ( 182 <div className=" container mx-auto p-6">173 <div className="min-h-screen bg-linear-to-br from-[#1e1e2e] to-[#0f0f1e] text-white"> 183 174 {isLoadingModal && ( 184 <div className="fixed inset-0 z-40 bg-black/30 backdrop-blur-sm flex items-center justify-center"> 185 <div className="flex items-center gap-3"> 186 <div className="w-6 h-6 border-3 border-blue-500 border-t-transparent rounded-full animate-spin"></div> 187 </div> 175 <div className="fixed inset-0 z-40 bg-black/50 backdrop-blur-sm flex items-center justify-center"> 176 <div className="w-10 h-10 border-4 border-white/10 border-t-[#1db954] rounded-full animate-spin" /> 188 177 </div> 189 178 )} 190 <button 191 onClick={() => navigate(-1)} 192 className="mb-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors duration-200 cursor-pointer" 193 > 194 ← Back 195 </button> 196 197 <div className="bg-white shadow-lg rounded-lg p-8"> 198 <div className="flex items-start gap-6 mb-8"> 199 <div className="shrink-0"> 200 <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 overflow-hidden"> 179 180 <div className="max-w-5xl mx-auto px-6 py-10"> 181 {/* Back link */} 182 <Link 183 to="/" 184 className="inline-flex items-center gap-1 text-gray-400 hover:text-white text-sm mb-8 transition-colors" 185 > 186 <svg 187 className="w-4 h-4" 188 fill="none" 189 stroke="currentColor" 190 viewBox="0 0 24 24" 191 > 192 <path 193 strokeLinecap="round" 194 strokeLinejoin="round" 195 strokeWidth={2} 196 d="M15 19l-7-7 7-7" 197 /> 198 </svg> 199 Back to Home 200 </Link> 201 202 {/* Hero section */} 203 <div className="flex flex-col md:flex-row gap-8 mb-10"> 204 {/* Profile photo */} 205 <div className="w-full md:w-48 shrink-0"> 206 <div className="relative w-48 h-48 rounded-full overflow-hidden shadow-2xl bg-[#181818] mx-auto md:mx-0"> 201 207 {user.profilePhoto ? ( 202 208 <img … … 206 212 /> 207 213 ) : ( 208 user.fullName.charAt(0).toUpperCase() 214 <div className="w-full h-full bg-linear-to-br from-[#1db954] to-[#1ed760] flex items-center justify-center text-white text-5xl font-bold"> 215 {user.fullName.charAt(0).toUpperCase()} 216 </div> 209 217 )} 210 218 </div> 211 219 </div> 212 220 213 <div className="flex-1">214 <h1 className="text-4xl font-bold mb-2">{user.fullName}</h1>215 <span className=" inline-block px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm font-medium mb-4">216 {user.userType }221 {/* User info */} 222 <div className="flex flex-col justify-end gap-3 min-w-0"> 223 <span className="text-xs uppercase tracking-widest text-gray-400 font-medium"> 224 {user.userType === "ARTIST" ? "Artist" : "Listener"} • Profile 217 225 </span> 218 219 <div className="flex gap-6 mb-4 text-gray-700"> 226 <h1 className="text-4xl md:text-5xl font-extrabold leading-tight"> 227 {user.fullName} 228 </h1> 229 <p className="text-gray-400">@{user.username}</p> 230 231 {/* Stats */} 232 <div className="flex items-center gap-6 mt-2"> 220 233 <div 221 className={` flex flex-col ${user.userType == "LISTENER" ? "cursor-pointer" : "cursor-default"}`}234 className={`${user.userType === "LISTENER" ? "cursor-pointer hover:text-white" : ""} transition-colors`} 222 235 onClick={ 223 236 user.userType === "LISTENER" ? displayFollowers : undefined 224 237 } 225 238 > 226 <span className="text-2xl font-bold">{user.followers}</span> 227 <span className="text-sm text-gray-500">Followers</span> 239 <span className="text-xl font-bold text-white"> 240 {user.followers} 241 </span> 242 <span className="text-sm text-gray-400 ml-1">Followers</span> 228 243 </div> 229 244 <div 230 className={` flex flex-col ${user.userType == "LISTENER" ? "cursor-pointer" : "cursor-default"}`}245 className={`${user.userType === "LISTENER" ? "cursor-pointer hover:text-white" : ""} transition-colors`} 231 246 onClick={ 232 247 user.userType === "LISTENER" ? displayFollowing : undefined 233 248 } 234 249 > 235 <span className="text-2xl font-bold">{user.following}</span> 236 <span className="text-sm text-gray-500">Following</span> 250 <span className="text-xl font-bold text-white"> 251 {user.following} 252 </span> 253 <span className="text-sm text-gray-400 ml-1">Following</span> 237 254 </div> 238 255 </div> 239 256 240 <button 241 onClick={handleFollow} 242 disabled={isFollowing} 243 className={` 244 px-6 py-2 font-semibold rounded-lg shadow-md 245 transition-colors duration-200 246 ${ 247 isFollowing 248 ? "bg-gray-400 text-gray-200 cursor-not-allowed" 249 : user.isFollowedByCurrentUser 250 ? "bg-gray-200 text-gray-700 hover:bg-gray-300 cursor-pointer" 251 : "bg-blue-500 text-white hover:bg-blue-600 cursor-pointer" 252 } 253 `} 254 > 255 {user.isFollowedByCurrentUser ? "Unfollow" : "Follow"} 256 </button> 257 {/* Follow button - hidden on own profile */} 258 {!isOwnProfile && ( 259 <div className="mt-4"> 260 <button 261 onClick={handleFollow} 262 disabled={isFollowing} 263 className={`flex items-center gap-2 px-6 py-3 rounded-full text-sm font-semibold transition-all cursor-pointer ${ 264 isFollowing 265 ? "bg-gray-700 text-gray-400 cursor-not-allowed" 266 : user.isFollowedByCurrentUser 267 ? "bg-white/10 text-white hover:bg-white/20" 268 : "bg-[#1db954] text-black hover:bg-[#1ed760] hover:scale-105" 269 }`} 270 > 271 {user.isFollowedByCurrentUser ? ( 272 <> 273 <svg 274 className="w-5 h-5" 275 fill="none" 276 stroke="currentColor" 277 viewBox="0 0 24 24" 278 > 279 <path 280 strokeLinecap="round" 281 strokeLinejoin="round" 282 strokeWidth={2} 283 d="M5 13l4 4L19 7" 284 /> 285 </svg> 286 Following 287 </> 288 ) : ( 289 <> 290 <svg 291 className="w-5 h-5" 292 fill="none" 293 stroke="currentColor" 294 viewBox="0 0 24 24" 295 > 296 <path 297 strokeLinecap="round" 298 strokeLinejoin="round" 299 strokeWidth={2} 300 d="M12 4v16m8-8H4" 301 /> 302 </svg> 303 Follow 304 </> 305 )} 306 </button> 307 </div> 308 )} 257 309 </div> 258 310 </div> 259 311 312 {/* Content */} 260 313 {user.userType === "ARTIST" ? ( 261 314 <ArtistView contributions={user.contributions} />
Note:
See TracChangeset
for help on using the changeset viewer.
