import { useState, useEffect } from 'react' import { useParams, Link } from 'react-router-dom' import { Loader2, Fingerprint, Zap, Music2, CloudSun, Heart, Layers, Globe, Drama, User } from 'lucide-react' import { getPublicProfile, type TasteProfileResponse } from '../lib/api' const personalityIcons: Record = { zap: Zap, cloud: CloudSun, heart: Heart, layers: Layers, globe: Globe, drama: Drama, music: Music2, } const genreBarColors = [ 'bg-[#7C3AED]', 'bg-[#8B5CF6]', 'bg-[#9F6FFB]', 'bg-[#A78BFA]', 'bg-[#B49BFC]', 'bg-[#C4ABFD]', 'bg-[#D3BCFE]', 'bg-[#DDD6FE]', 'bg-[#E8DFFE]', 'bg-[#F0EAFF]', ] type PublicProfileData = TasteProfileResponse & { name: string } function possessive(name: string): string { return name.endsWith('s') ? `${name}'` : `${name}'s` } export default function PublicProfile() { const { userId, token } = useParams<{ userId: string; token: string }>() const [profile, setProfile] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) useEffect(() => { if (!userId || !token) return setLoading(true) getPublicProfile(userId, token) .then(setProfile) .catch(() => setError('This profile link is invalid or has expired.')) .finally(() => setLoading(false)) }, [userId, token]) if (loading) { return (
) } if (error || !profile) { return (

Profile Not Found

{error || 'This taste profile could not be found.'}

Discover Your Taste on Vynl
) } const PersonalityIcon = personalityIcons[profile.personality.icon] || Music2 const maxGenrePercent = profile.genre_breakdown.length > 0 ? Math.max(...profile.genre_breakdown.map((g) => g.percentage)) : 100 return (
{/* Header */}

vynl

{/* Content */}
{/* Title */}

{possessive(profile.name)} Music DNA

Built from {profile.track_count} tracks across {profile.playlist_count} playlists

{/* Listening Personality */}

Listening Personality

{profile.personality.label}

{profile.personality.description}

{/* Genre DNA */} {profile.genre_breakdown.length > 0 && (

Genre DNA

{profile.genre_breakdown.map((genre, i) => (
{genre.name}
{genre.percentage}%
))}
)} {/* Audio Features */}

Audio Features

Avg Tempo
{profile.audio_features.avg_tempo} BPM
{/* Top Artists */} {profile.top_artists.length > 0 && (

Artists That Define Them

{profile.top_artists.map((artist) => (

{artist.name}

{artist.track_count} track{artist.track_count !== 1 ? 's' : ''} {artist.genre ? ` ยท ${artist.genre}` : ''}

))}
)} {/* CTA */}

Want to discover your own music DNA?

Discover Your Taste on Vynl
) } function PublicAudioMeter({ label, value }: { label: string; value: number }) { return (
{label}
0 ? '1.5rem' : '0' }} > {value > 10 && ( {value}% )}
{value <= 10 && ( {value}% )}
) }