|
| 1 | +import { SongPreviewDto } from '@shared/validation/song/dto/SongPreview.dto'; |
1 | 2 | import { UserProfileViewDto } from '@shared/validation/user/dto/UserProfileView.dto';
|
2 | 3 | import Image from 'next/image';
|
3 | 4 |
|
| 5 | +import { EarlySupporterBadge } from './UserBadges'; |
| 6 | +import UserSocialIcon from './UserSocialIcon'; |
| 7 | +import SongCard from '../../browse/components/SongCard'; |
| 8 | +import SongCardGroup from '../../browse/components/SongCardGroup'; |
| 9 | +import { formatTimeAgo } from '../../shared/util/format'; |
| 10 | + |
4 | 11 | type UserProfileProps = {
|
5 | 12 | userData: UserProfileViewDto;
|
| 13 | + songData: SongPreviewDto[] | null; |
6 | 14 | };
|
7 | 15 |
|
8 |
| -const UserProfile = ({ userData }: UserProfileProps) => { |
9 |
| - const { |
10 |
| - lastSeen, |
11 |
| - loginStreak, |
12 |
| - playCount, |
13 |
| - publicName, |
14 |
| - description, |
15 |
| - profileImage, |
16 |
| - // socialLinks, |
17 |
| - } = userData; |
| 16 | +const UserProfile = ({ userData, songData }: UserProfileProps) => { |
| 17 | + const { lastSeen, username, description, profileImage } = userData; |
18 | 18 |
|
19 | 19 | return (
|
20 |
| - <section className='w-full h-full'> |
21 |
| - <Image |
22 |
| - src={profileImage} |
23 |
| - alt={publicName} |
24 |
| - className='w-32 h-32 rounded-full' |
25 |
| - width={128} |
26 |
| - height={128} |
27 |
| - /> |
28 |
| - <h1 className='text-2xl font-bold'>{publicName}</h1> |
29 |
| - <p className='text-gray-500'>{description}</p> |
30 |
| - <p className='text-gray-500'>Last Login: {lastSeen.toLocaleString()}</p> |
31 |
| - <p className='text-gray-500'>Login Streak: {loginStreak}</p> |
32 |
| - <p className='text-gray-500'>Play Count: {playCount}</p> |
33 |
| - {/* <ul className='mt-4'> |
34 |
| - {Object.keys(socialLinks).map((key, index) => { |
35 |
| - const link = socialLinks[key as keyof UserLinks]; |
36 |
| - if (!link) return null; |
37 |
| -
|
38 |
| - return ( |
39 |
| - <li key={index}> |
40 |
| - <a href={link} className='text-blue-500 hover:underline'> |
41 |
| - {key} |
42 |
| - </a> |
43 |
| - </li> |
44 |
| - ); |
45 |
| - })} |
46 |
| - </ul> */} |
47 |
| - </section> |
| 20 | + <div className='max-w-screen-lg mx-auto'> |
| 21 | + {/* HEADER */} |
| 22 | + <section> |
| 23 | + <div className='flex items-center gap-8'> |
| 24 | + <Image |
| 25 | + src={profileImage} |
| 26 | + alt={username} |
| 27 | + className='w-32 h-32 rounded-full' |
| 28 | + width={128} |
| 29 | + height={128} |
| 30 | + /> |
| 31 | + <div> |
| 32 | + {/* Display name */} |
| 33 | + <div className='flex items-center gap-8'> |
| 34 | + <h1 className='text-3xl font-bold mb-1 relative'>{username}</h1> |
| 35 | + <EarlySupporterBadge /> |
| 36 | + </div> |
| 37 | + |
| 38 | + {/* Username/handle */} |
| 39 | + <p className='text-zinc-400 my-1'> |
| 40 | + <span className='font-black text-zinc-200'>{`@${username}`}</span> |
| 41 | + {` • 5 songs • 2,534 plays`} |
| 42 | + </p> |
| 43 | + |
| 44 | + {/* Description */} |
| 45 | + <p className='text-zinc-400 my-1 line-clamp-3'> |
| 46 | + Hello! This is my user description. |
| 47 | + </p> |
| 48 | + |
| 49 | + {/* Social links */} |
| 50 | + <div className='flex-grow flex flex-row gap-1.5 mt-4'> |
| 51 | + <UserSocialIcon icon='twitter' href='#' /> |
| 52 | + <UserSocialIcon icon='youtube' href='#' /> |
| 53 | + <UserSocialIcon icon='github' href='#' /> |
| 54 | + <UserSocialIcon icon='discord' href='#' /> |
| 55 | + <UserSocialIcon icon='patreon' href='#' /> |
| 56 | + </div> |
| 57 | + </div> |
| 58 | + <div className='flex-grow'></div> |
| 59 | + <div> |
| 60 | + {/* Joined */} |
| 61 | + <p className='text-zinc-500'>Joined</p> |
| 62 | + <p className='font-bold text-zinc-400 mb-4'> |
| 63 | + {/* TODO: lastSeen is supposed to be a date, but it's a string */} |
| 64 | + {new Date(lastSeen).toLocaleDateString('en-UK')} |
| 65 | + <span className='font-normal text-zinc-400'>{` (${formatTimeAgo( |
| 66 | + new Date(lastSeen), |
| 67 | + )})`}</span> |
| 68 | + </p> |
| 69 | + |
| 70 | + {/* Last seen */} |
| 71 | + <p className='text-zinc-500'>Last seen</p> |
| 72 | + <p className='font-bold text-zinc-400'> |
| 73 | + {/* TODO: lastSeen is supposed to be a date, but it's a string */} |
| 74 | + {new Date(lastSeen).toLocaleDateString('en-UK')} |
| 75 | + <span className='font-normal text-zinc-400'>{` (${formatTimeAgo( |
| 76 | + new Date(lastSeen), |
| 77 | + )})`}</span> |
| 78 | + </p> |
| 79 | + </div> |
| 80 | + </div> |
| 81 | + </section> |
| 82 | + |
| 83 | + <hr className='my-8 border-none bg-zinc-700 h-[3px]' /> |
| 84 | + |
| 85 | + {/* UPLOADED SONGS */} |
| 86 | + <section> |
| 87 | + <h2 className='flex-1 text-xl uppercase mb-4 text-zinc-200'>Songs</h2> |
| 88 | + <SongCardGroup> |
| 89 | + {songData?.map((song, i) => ( |
| 90 | + <SongCard key={i} song={song} /> |
| 91 | + ))} |
| 92 | + </SongCardGroup> |
| 93 | + </section> |
| 94 | + </div> |
48 | 95 | );
|
49 | 96 | };
|
50 | 97 |
|
|
0 commit comments