Files
SkinbaseNova/resources/js/Pages/Profile/ProfileShow.jsx
2026-03-28 19:15:39 +01:00

262 lines
8.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState, useEffect, useCallback } from 'react'
import { usePage } from '@inertiajs/react'
import ProfileHero from '../../components/profile/ProfileHero'
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 = ['posts', 'artworks', 'stories', 'achievements', 'collections', 'about', 'stats', 'favourites', 'activity']
function getInitialTab(initialTab = 'posts') {
if (typeof window === 'undefined') {
return VALID_TABS.includes(initialTab) ? initialTab : 'posts'
}
try {
const pathname = window.location.pathname.replace(/\/+$/, '')
const segments = pathname.split('/').filter(Boolean)
const lastSegment = segments.at(-1)
if (VALID_TABS.includes(lastSegment)) {
return lastSegment
}
} catch {
return VALID_TABS.includes(initialTab) ? initialTab : 'posts'
}
return VALID_TABS.includes(initialTab) ? initialTab : 'posts'
}
/**
* 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,
followContext,
followAnalytics,
suggestedUsers,
viewerIsFollowing,
heroBgUrl,
profileComments,
creatorStories,
collections,
achievements,
leaderboardRank,
countryName,
isOwner,
auth,
initialTab,
profileUrl,
galleryUrl,
collectionCreateUrl,
collectionReorderUrl,
collectionsFeaturedUrl,
collectionFeatureLimit,
profileTabUrls,
} = props
const [activeTab, setActiveTab] = useState(() => getInitialTab(initialTab))
const handleTabChange = useCallback((tab) => {
if (!VALID_TABS.includes(tab)) return
setActiveTab(tab)
try {
const currentUrl = new URL(window.location.href)
const targetBase = profileTabUrls?.[tab] || `${profileUrl || `${window.location.origin}`}/${tab}`
const nextUrl = new URL(targetBase, window.location.origin)
const sharedPostId = currentUrl.searchParams.get('post')
if (sharedPostId) {
nextUrl.searchParams.set('post', sharedPostId)
}
window.history.pushState({}, '', nextUrl.toString())
} catch (_) {}
}, [profileTabUrls, profileUrl])
useEffect(() => {
const onPop = () => setActiveTab(getInitialTab(initialTab))
window.addEventListener('popstate', onPop)
return () => window.removeEventListener('popstate', onPop)
}, [initialTab])
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 ?? {})
const contentShellClassName = activeTab === 'artworks'
? 'w-full px-4 md:px-6'
: activeTab === 'posts'
? 'mx-auto max-w-7xl px-4 md:px-6'
: 'max-w-6xl mx-auto px-4'
return (
<div className="relative min-h-screen overflow-hidden pb-16">
<div
aria-hidden="true"
className="pointer-events-none absolute inset-x-0 top-0 -z-10 h-[34rem] opacity-90"
style={{
background: 'radial-gradient(circle at top left, rgba(56,189,248,0.18), transparent 32%), radial-gradient(circle at 82% 10%, rgba(249,115,22,0.16), transparent 28%), linear-gradient(180deg, #07101d 0%, #0a1220 42%, #0a1220 100%)',
}}
/>
<div
aria-hidden="true"
className="pointer-events-none absolute inset-0 -z-10 opacity-[0.06]"
style={{ backgroundImage: 'url(/gfx/noise.png)', backgroundSize: '180px' }}
/>
<ProfileHero
user={user}
profile={profile}
isOwner={isOwner}
viewerIsFollowing={viewerIsFollowing}
followerCount={followerCount}
recentFollowers={recentFollowers}
followContext={followContext}
heroBgUrl={heroBgUrl}
countryName={countryName}
leaderboardRank={leaderboardRank}
extraActions={galleryUrl ? (
<a
href={galleryUrl}
className="inline-flex shrink-0 items-center gap-2 whitespace-nowrap rounded-xl border border-white/15 px-3.5 py-2 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}
/>
<div className="mt-6">
<ProfileTabs
activeTab={activeTab}
onTabChange={handleTabChange}
/>
</div>
<div className={`${contentShellClassName} pt-6`}>
{activeTab === 'artworks' && (
<TabArtworks
artworks={{ data: artworkList, next_cursor: artworkNextCursor }}
featuredArtworks={featuredArtworks}
username={user.username || user.name}
galleryUrl={galleryUrl}
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}
suggestedUsers={suggestedUsers}
socialLinks={socialLinksObj}
countryName={countryName}
profileUrl={profileUrl}
onTabChange={handleTabChange}
/>
)}
{activeTab === 'stories' && (
<TabStories
stories={creatorStories}
username={user.username || user.name}
/>
)}
{activeTab === 'achievements' && (
<TabAchievements achievements={achievements} />
)}
{activeTab === 'collections' && (
<TabCollections
collections={collections}
isOwner={isOwner}
createUrl={collectionCreateUrl}
reorderUrl={collectionReorderUrl}
featuredUrl={collectionsFeaturedUrl}
featureLimit={collectionFeatureLimit}
/>
)}
{activeTab === 'about' && (
<TabAbout
user={user}
profile={profile}
stats={stats}
achievements={achievements}
artworks={artworkList}
creatorStories={creatorStories}
profileComments={profileComments}
socialLinks={socialLinksObj}
countryName={countryName}
followerCount={followerCount}
recentFollowers={recentFollowers}
leaderboardRank={leaderboardRank}
/>
)}
{activeTab === 'stats' && (
<TabStats
stats={stats}
followerCount={followerCount}
followAnalytics={followAnalytics}
/>
)}
{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}
stats={stats}
followerCount={followerCount}
creatorStories={creatorStories}
/>
)}
</div>
</div>
)
}