import React from 'react' const SOCIAL_ICONS = { twitter: { icon: 'fa-brands fa-x-twitter', label: 'X / Twitter' }, deviantart: { icon: 'fa-brands fa-deviantart', label: 'DeviantArt' }, instagram: { icon: 'fa-brands fa-instagram', label: 'Instagram' }, behance: { icon: 'fa-brands fa-behance', label: 'Behance' }, artstation: { icon: 'fa-solid fa-palette', label: 'ArtStation' }, youtube: { icon: 'fa-brands fa-youtube', label: 'YouTube' }, website: { icon: 'fa-solid fa-link', label: 'Website' }, } function formatNumber(value) { return Number(value ?? 0).toLocaleString() } function formatRelativeDate(value) { if (!value) return null try { const date = new Date(value) if (Number.isNaN(date.getTime())) return null const now = new Date() const diffSeconds = Math.round((date.getTime() - now.getTime()) / 1000) const absSeconds = Math.abs(diffSeconds) const formatter = new Intl.RelativeTimeFormat('en', { numeric: 'auto' }) if (absSeconds < 3600) { return formatter.format(Math.round(diffSeconds / 60), 'minute') } if (absSeconds < 86400) { return formatter.format(Math.round(diffSeconds / 3600), 'hour') } if (absSeconds < 604800) { return formatter.format(Math.round(diffSeconds / 86400), 'day') } if (absSeconds < 2629800) { return formatter.format(Math.round(diffSeconds / 604800), 'week') } return formatter.format(Math.round(diffSeconds / 2629800), 'month') } catch { return null } } function formatShortDate(value) { if (!value) return null try { const date = new Date(value) if (Number.isNaN(date.getTime())) return null return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) } catch { return null } } function truncateText(value, maxLength = 140) { const text = String(value ?? '').trim() if (!text) return '' if (text.length <= maxLength) return text return `${text.slice(0, maxLength).trimEnd()}...` } function buildInterestGroups(artworks = []) { const categoryMap = new Map() const contentTypeMap = new Map() artworks.forEach((artwork) => { const categoryKey = String(artwork?.category_slug || artwork?.category || '').trim().toLowerCase() const categoryLabel = String(artwork?.category || '').trim() const contentTypeKey = String(artwork?.content_type_slug || artwork?.content_type || '').trim().toLowerCase() const contentTypeLabel = String(artwork?.content_type || '').trim() if (categoryKey && categoryLabel) { categoryMap.set(categoryKey, { label: categoryLabel, count: (categoryMap.get(categoryKey)?.count ?? 0) + 1, }) } if (contentTypeKey && contentTypeLabel) { contentTypeMap.set(contentTypeKey, { label: contentTypeLabel, count: (contentTypeMap.get(contentTypeKey)?.count ?? 0) + 1, }) } }) const toSortedList = (source) => Array.from(source.values()) .sort((left, right) => right.count - left.count || left.label.localeCompare(right.label)) .slice(0, 5) return { categories: toSortedList(categoryMap), contentTypes: toSortedList(contentTypeMap), } } function InfoRow({ icon, label, children }) { return (
{label}
{children}
) } function StatCard({ icon, label, value, tone = 'sky' }) { const tones = { sky: 'text-sky-300 bg-sky-400/10 border-sky-300/15', amber: 'text-amber-200 bg-amber-300/10 border-amber-300/15', emerald: 'text-emerald-200 bg-emerald-400/10 border-emerald-300/15', violet: 'text-violet-200 bg-violet-400/10 border-violet-300/15', } return (
{label}
{value}
) } function SectionCard({ icon, eyebrow, title, children, className = '' }) { return (

{eyebrow}

{title}

{children}
) } /** * TabAbout * Bio, social links, metadata - replaces old sidebar profile card. */ export default function TabAbout({ user, profile, stats, achievements, artworks, creatorStories, profileComments, socialLinks, countryName, followerCount, recentFollowers, leaderboardRank }) { const uname = user.username || user.name const displayName = user.name || uname const about = profile?.about const website = profile?.website const joinDate = user.created_at ? new Date(user.created_at).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' }) : null const lastVisit = user.last_visit_at ? (() => { try { const d = new Date(user.last_visit_at) return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) } catch { return null } })() : null const genderMap = { M: 'Male', F: 'Female', X: 'Non-binary / N/A' } const genderLabel = genderMap[profile?.gender?.toUpperCase()] ?? null const birthDate = profile?.birthdate ? (() => { try { return new Date(profile.birthdate).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' }) } catch { return null } })() : null const lastSeenRelative = formatRelativeDate(user.last_visit_at) const socialEntries = socialLinks ? Object.entries(socialLinks).filter(([, link]) => link?.url) : [] const followers = recentFollowers ?? [] const recentAchievements = Array.isArray(achievements?.recent) ? achievements.recent : [] const stories = Array.isArray(creatorStories) ? creatorStories : [] const comments = Array.isArray(profileComments) ? profileComments : [] const interestGroups = buildInterestGroups(Array.isArray(artworks) ? artworks : []) const summaryCards = [ { icon: 'fa-user-group', label: 'Followers', value: formatNumber(followerCount), tone: 'sky' }, { icon: 'fa-images', label: 'Uploads', value: formatNumber(stats?.uploads_count ?? 0), tone: 'violet' }, { icon: 'fa-eye', label: 'Profile views', value: formatNumber(stats?.profile_views_count ?? 0), tone: 'emerald' }, { icon: 'fa-trophy', label: 'Weekly rank', value: leaderboardRank?.rank ? `#${formatNumber(leaderboardRank.rank)}` : 'Unranked', tone: 'amber' }, ] return (
{summaryCards.map((card) => ( ))}
{about ? (

{about}

) : (
This creator has not written a public bio yet.
)}
{displayName && displayName !== uname ? ( {displayName} ) : null} @{uname} {genderLabel ? {genderLabel} : null} {countryName ? ( {profile?.country_code ? ( {countryName} { e.target.style.display = 'none' }} /> ) : null} {countryName} ) : null} {website ? ( {(() => { try { const url = website.startsWith('http') ? website : `https://${website}` return new URL(url).hostname } catch { return website } })()} ) : null} {birthDate ? {birthDate} : null} {joinDate ? {joinDate} : null} {lastVisit ? {lastSeenRelative ? `${lastSeenRelative} ยท ${lastVisit}` : lastVisit} : null}
{followers.length > 0 ? (
{followers.slice(0, 6).map((follower) => ( {follower.username}
{follower.uname || follower.username}
@{follower.username}
))}
) : null} {recentAchievements.length > 0 ? (
{recentAchievements.slice(0, 4).map((achievement) => (
{achievement.name}
{achievement.description ? (
{achievement.description}
) : null}
{achievement.unlocked_at ? ( {formatShortDate(achievement.unlocked_at) || 'Unlocked'} ) : null} +{formatNumber(achievement.xp_reward ?? 0)} XP
))}
) : null} {stories.length > 0 || comments.length > 0 ? (
{stories.length > 0 ? (
Latest story
{formatShortDate(stories[0]?.published_at) || 'Published'}
{stories[0].title} {stories[0].excerpt ? (

{truncateText(stories[0].excerpt, 180)}

) : null}
{stories[0].reading_time ? ( {stories[0].reading_time} min read ) : null} {formatNumber(stories[0].views ?? 0)} views {formatNumber(stories[0].comments_count ?? 0)} comments
) : null} {comments.length > 0 ? (
Latest guestbook comment
{formatRelativeDate(comments[0]?.created_at) || 'Recently'}
{comments[0].author_name} { e.target.src = '/images/avatar_default.webp' }} />
{comments[0].author_name}

{truncateText(comments[0].body, 180)}

) : null}
) : null}
Creator level
Lv {formatNumber(user?.level ?? 1)}
{user?.rank || 'Creator'}
XP
{formatNumber(user?.xp ?? 0)}
Weekly rank
{leaderboardRank?.rank ? `#${formatNumber(leaderboardRank.rank)}` : 'Not ranked'}
{leaderboardRank?.score ?
Score {formatNumber(leaderboardRank.score)}
: null}
Community size
{formatNumber(followerCount)}
Followers
{formatNumber(stats?.uploads_count ?? 0)} {formatNumber(stats?.artwork_views_received_count ?? 0)} {formatNumber(stats?.downloads_received_count ?? 0)} {formatNumber(stats?.favourites_received_count ?? 0)} {formatNumber(stats?.comments_received_count ?? 0)}
{interestGroups.categories.length > 0 || interestGroups.contentTypes.length > 0 ? (
{interestGroups.categories.length > 0 ? (
Top categories
{interestGroups.categories.map((category) => ( {category.label} {formatNumber(category.count)} ))}
) : null} {interestGroups.contentTypes.length > 0 ? (
Preferred formats
{interestGroups.contentTypes.map((contentType) => ( {contentType.label} {formatNumber(contentType.count)} ))}
) : null}
) : null} {socialEntries.length > 0 ? (
{socialEntries.map(([platform, link]) => { const si = SOCIAL_ICONS[platform] ?? { icon: 'fa-solid fa-link', label: platform } const href = link.url.startsWith('http') ? link.url : `https://${link.url}` return ( {si.label} ) })}
) : null}
) }