import React, { useState, useEffect } from 'react' import axios from 'axios' // ───────────────────────────────────────────────────────────────────────────── // Helpers // ───────────────────────────────────────────────────────────────────────────── function fmt(n) { if (n === null || n === undefined) return '0' if (n >= 1_000_000) return (n / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'M' if (n >= 1_000) return (n / 1_000).toFixed(1).replace(/\.0$/, '') + 'k' return String(n) } const SOCIAL_META = { twitter: { icon: 'fa-brands fa-x-twitter', label: 'Twitter / X', prefix: 'https://x.com/' }, instagram: { icon: 'fa-brands fa-instagram', label: 'Instagram', prefix: 'https://instagram.com/' }, deviantart: { icon: 'fa-brands fa-deviantart', label: 'DeviantArt', prefix: 'https://deviantart.com/' }, artstation: { icon: 'fa-brands fa-artstation', label: 'ArtStation', prefix: 'https://artstation.com/' }, behance: { icon: 'fa-brands fa-behance', label: 'Behance', prefix: 'https://behance.net/' }, website: { icon: 'fa-solid fa-globe', label: 'Website', prefix: '' }, youtube: { icon: 'fa-brands fa-youtube', label: 'YouTube', prefix: '' }, twitch: { icon: 'fa-brands fa-twitch', label: 'Twitch', prefix: '' }, } function SideCard({ title, icon, children, className = '' }) { return (
{title && (
{icon && } {title}
)} {children}
) } // ───────────────────────────────────────────────────────────────────────────── // Stats card // ───────────────────────────────────────────────────────────────────────────── function StatsCard({ stats, followerCount, user, onTabChange }) { const items = [ { label: 'Artworks', value: fmt(stats?.uploads_count ?? 0), icon: 'fa-solid fa-image', color: 'text-sky-400', tab: 'artworks', }, { label: 'Followers', value: fmt(followerCount ?? stats?.followers_count ?? 0), icon: 'fa-solid fa-user-group', color: 'text-violet-400', tab: null, }, { label: 'Following', value: fmt(stats?.following_count ?? 0), icon: 'fa-solid fa-user-plus', color: 'text-emerald-400', tab: null, }, { label: 'Awards', value: fmt(stats?.awards_received_count ?? 0), icon: 'fa-solid fa-trophy', color: 'text-amber-400', tab: 'stats', }, ] return (
{items.map((item) => ( ))}
) } // ───────────────────────────────────────────────────────────────────────────── // About card // ───────────────────────────────────────────────────────────────────────────── function AboutCard({ user, profile, socialLinks, countryName }) { const bio = profile?.bio || profile?.about || profile?.description const website = profile?.website || user?.website const hasSocials = socialLinks && Object.keys(socialLinks).length > 0 const hasContent = bio || countryName || website || hasSocials if (!hasContent) return null return (
{bio && (

{bio}

)}
{countryName && (
{countryName}
)} {website && ( )}
{hasSocials && (
{Object.entries(socialLinks).map(([platform, link]) => { const meta = SOCIAL_META[platform] ?? SOCIAL_META.website const url = link.url || (meta.prefix ? meta.prefix + link.handle : null) if (!url) return null return ( ) })}
)}
) } // ───────────────────────────────────────────────────────────────────────────── // Recent followers card // ───────────────────────────────────────────────────────────────────────────── function RecentFollowersCard({ recentFollowers, followerCount, onTabChange }) { const followers = recentFollowers ?? [] if (followers.length === 0) return null return (
{followers.slice(0, 6).map((f) => ( {f.username}

{f.name || f.uname || f.username}

@{f.username}

))} {followerCount > 6 && ( )}
) } // ───────────────────────────────────────────────────────────────────────────── // Trending hashtags card // ───────────────────────────────────────────────────────────────────────────── function TrendingHashtagsCard() { const [tags, setTags] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { axios.get('/api/feed/hashtags/trending', { params: { limit: 8 } }) .then(({ data }) => setTags(Array.isArray(data.hashtags) ? data.hashtags : [])) .catch(() => {}) .finally(() => setLoading(false)) }, []) if (!loading && tags.length === 0) return null return (
{loading ? [1, 2, 3, 4].map((i) => (
) } // ───────────────────────────────────────────────────────────────────────────── // Suggested to follow card // ───────────────────────────────────────────────────────────────────────────── function SuggestionsCard({ excludeUsername, isLoggedIn }) { const [users, setUsers] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { if (!isLoggedIn) { setLoading(false); return } axios.get('/api/search/users', { params: { q: '', per_page: 5 } }) .then(({ data }) => { const list = (data.data ?? []).filter((u) => u.username !== excludeUsername).slice(0, 4) setUsers(list) }) .catch(() => {}) .finally(() => setLoading(false)) }, [excludeUsername, isLoggedIn]) if (!isLoggedIn) return null if (!loading && users.length === 0) return null return (
{loading ? ( [1, 2, 3, 4].map((i) => (
)) ) : ( users.map((u) => ( {u.username}

{u.name || u.username}

@{u.username}

View
)) )}
) } // ───────────────────────────────────────────────────────────────────────────── // Main export // ───────────────────────────────────────────────────────────────────────────── /** * FeedSidebar * * Props: * user object { id, username, name, uploads_count, ...} * profile object { bio, about, country, website, ... } * stats object from user_statistics * followerCount number * recentFollowers array [{ id, username, name, avatar_url, profile_url }] * socialLinks object keyed by platform * countryName string|null * isLoggedIn boolean * onTabChange function(tab) */ export default function FeedSidebar({ user, profile, stats, followerCount, recentFollowers, socialLinks, countryName, isLoggedIn, onTabChange, }) { return (
) }