208 lines
6.3 KiB
JavaScript
208 lines
6.3 KiB
JavaScript
import React, { useState, useEffect, useCallback } from 'react'
|
||
import { usePage } from '@inertiajs/react'
|
||
import ProfileHero from '../../components/profile/ProfileHero'
|
||
import ProfileStatsRow from '../../components/profile/ProfileStatsRow'
|
||
import ProfileTabs from '../../components/profile/ProfileTabs'
|
||
import TabArtworks from '../../components/profile/tabs/TabArtworks'
|
||
import TabAchievements from '../../components/profile/tabs/TabAchievements'
|
||
import TabAbout from '../../components/profile/tabs/TabAbout'
|
||
import TabStats from '../../components/profile/tabs/TabStats'
|
||
import TabFavourites from '../../components/profile/tabs/TabFavourites'
|
||
import TabCollections from '../../components/profile/tabs/TabCollections'
|
||
import TabActivity from '../../components/profile/tabs/TabActivity'
|
||
import TabPosts from '../../components/profile/tabs/TabPosts'
|
||
import TabStories from '../../components/profile/tabs/TabStories'
|
||
|
||
const VALID_TABS = ['artworks', 'stories', 'achievements', 'posts', 'collections', 'about', 'stats', 'favourites', 'activity']
|
||
|
||
function getInitialTab() {
|
||
try {
|
||
const sp = new URLSearchParams(window.location.search)
|
||
const t = sp.get('tab')
|
||
return VALID_TABS.includes(t) ? t : 'artworks'
|
||
} catch {
|
||
return 'artworks'
|
||
}
|
||
}
|
||
|
||
/**
|
||
* ProfileShow – Inertia page for /@username
|
||
*
|
||
* Props injected by ProfileController::renderUserProfile()
|
||
*/
|
||
export default function ProfileShow() {
|
||
const { props } = usePage()
|
||
|
||
const {
|
||
user,
|
||
profile,
|
||
artworks,
|
||
featuredArtworks,
|
||
favourites,
|
||
stats,
|
||
socialLinks,
|
||
followerCount,
|
||
recentFollowers,
|
||
viewerIsFollowing,
|
||
heroBgUrl,
|
||
profileComments,
|
||
creatorStories,
|
||
achievements,
|
||
leaderboardRank,
|
||
countryName,
|
||
isOwner,
|
||
auth,
|
||
profileUrl,
|
||
galleryUrl,
|
||
} = props
|
||
|
||
const [activeTab, setActiveTab] = useState(getInitialTab)
|
||
|
||
const handleTabChange = useCallback((tab) => {
|
||
if (!VALID_TABS.includes(tab)) return
|
||
setActiveTab(tab)
|
||
|
||
// Update URL query param without full navigation
|
||
try {
|
||
const url = new URL(window.location.href)
|
||
if (tab === 'artworks') {
|
||
url.searchParams.delete('tab')
|
||
} else {
|
||
url.searchParams.set('tab', tab)
|
||
}
|
||
window.history.pushState({}, '', url.toString())
|
||
} catch (_) {}
|
||
}, [])
|
||
|
||
// Handle browser back/forward
|
||
useEffect(() => {
|
||
const onPop = () => setActiveTab(getInitialTab())
|
||
window.addEventListener('popstate', onPop)
|
||
return () => window.removeEventListener('popstate', onPop)
|
||
}, [])
|
||
|
||
const isLoggedIn = !!(auth?.user)
|
||
|
||
// Normalise artwork list (SSR may send cursor-paginated object)
|
||
const artworkList = Array.isArray(artworks)
|
||
? artworks
|
||
: (artworks?.data ?? [])
|
||
const artworkNextCursor = artworks?.next_cursor ?? null
|
||
const favouriteList = Array.isArray(favourites)
|
||
? favourites
|
||
: (favourites?.data ?? [])
|
||
const favouriteNextCursor = favourites?.next_cursor ?? null
|
||
|
||
// Normalise social links (may be object keyed by platform, or array)
|
||
const socialLinksObj = Array.isArray(socialLinks)
|
||
? socialLinks.reduce((acc, l) => { acc[l.platform] = l; return acc }, {})
|
||
: (socialLinks ?? {})
|
||
|
||
return (
|
||
<div className="min-h-screen pb-16">
|
||
{/* Hero section */}
|
||
<ProfileHero
|
||
user={user}
|
||
profile={profile}
|
||
isOwner={isOwner}
|
||
viewerIsFollowing={viewerIsFollowing}
|
||
followerCount={followerCount}
|
||
heroBgUrl={heroBgUrl}
|
||
countryName={countryName}
|
||
leaderboardRank={leaderboardRank}
|
||
extraActions={galleryUrl ? (
|
||
<a
|
||
href={galleryUrl}
|
||
className="inline-flex items-center gap-2 rounded-xl border border-white/15 px-4 py-2.5 text-sm font-medium text-slate-300 transition-all hover:bg-white/5 hover:text-white"
|
||
>
|
||
<i className="fa-solid fa-images fa-fw" />
|
||
View Gallery
|
||
</a>
|
||
) : null}
|
||
/>
|
||
|
||
{/* Stats pills row */}
|
||
<ProfileStatsRow
|
||
stats={stats}
|
||
followerCount={followerCount}
|
||
onTabChange={handleTabChange}
|
||
/>
|
||
|
||
{/* Sticky tabs */}
|
||
<ProfileTabs
|
||
activeTab={activeTab}
|
||
onTabChange={handleTabChange}
|
||
/>
|
||
|
||
{/* Tab content area */}
|
||
<div className={activeTab === 'artworks' ? 'w-full px-4 md:px-6' : 'max-w-6xl mx-auto px-4'}>
|
||
{activeTab === 'artworks' && (
|
||
<TabArtworks
|
||
artworks={{ data: artworkList, next_cursor: artworkNextCursor }}
|
||
featuredArtworks={featuredArtworks}
|
||
username={user.username || user.name}
|
||
isActive
|
||
/>
|
||
)}
|
||
{activeTab === 'posts' && (
|
||
<TabPosts
|
||
username={user.username || user.name}
|
||
isOwner={isOwner}
|
||
authUser={auth?.user ?? null}
|
||
user={user}
|
||
profile={profile}
|
||
stats={stats}
|
||
followerCount={followerCount}
|
||
recentFollowers={recentFollowers}
|
||
socialLinks={socialLinksObj}
|
||
countryName={countryName}
|
||
onTabChange={handleTabChange}
|
||
/>
|
||
)}
|
||
{activeTab === 'stories' && (
|
||
<TabStories
|
||
stories={creatorStories}
|
||
username={user.username || user.name}
|
||
/>
|
||
)}
|
||
{activeTab === 'achievements' && (
|
||
<TabAchievements achievements={achievements} />
|
||
)}
|
||
{activeTab === 'collections' && (
|
||
<TabCollections collections={[]} />
|
||
)}
|
||
{activeTab === 'about' && (
|
||
<TabAbout
|
||
user={user}
|
||
profile={profile}
|
||
socialLinks={socialLinksObj}
|
||
countryName={countryName}
|
||
followerCount={followerCount}
|
||
/>
|
||
)}
|
||
{activeTab === 'stats' && (
|
||
<TabStats
|
||
stats={stats}
|
||
followerCount={followerCount}
|
||
/>
|
||
)}
|
||
{activeTab === 'favourites' && (
|
||
<TabFavourites
|
||
favourites={{ data: favouriteList, next_cursor: favouriteNextCursor }}
|
||
isOwner={isOwner}
|
||
username={user.username || user.name}
|
||
/>
|
||
)}
|
||
{activeTab === 'activity' && (
|
||
<TabActivity
|
||
profileComments={profileComments}
|
||
user={user}
|
||
isOwner={isOwner}
|
||
isLoggedIn={isLoggedIn}
|
||
/>
|
||
)}
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|