Refactor: Remove server state files and update server log handling

- Deleted server-stopped, server.log, and server.pid files to clean up unused state.
- Updated game-page-client.tsx to enhance button accessibility with cursor-pointer class.
- Modified not-found.tsx, page.tsx, and profile/page.tsx for consistent cursor-pointer usage on links.
- Adjusted search/page.tsx and components/auth/*.tsx for improved button interactions with cursor-pointer.
- Refined navbar.tsx for better user experience with cursor-pointer on navigation links.
- Updated settings-security-tab.tsx for passkey management API endpoints and improved error handling.
- Enhanced saved-games components for better user interaction with cursor-pointer on buttons.
- General code cleanup and consistency improvements across various components.
This commit is contained in:
2026-04-26 12:09:37 -05:00
parent 18b9e5d0db
commit b0688f8f2a
35 changed files with 323 additions and 1631 deletions
+5 -5
View File
@@ -367,7 +367,7 @@ export function GamePageClient({
{session && (
<Link
href={`/game/${game.id}/submit`}
className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-primary text-white text-sm font-semibold hover:bg-primary/90 transition-colors"
className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-primary text-white text-sm font-semibold hover:bg-primary/90 transition-colors cursor-pointer"
>
<Plus className="h-4 w-4" />
Add Benchmark
@@ -382,7 +382,7 @@ export function GamePageClient({
href={game.storeUrl}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 text-xs text-text/60 hover:text-primary transition-colors"
className="inline-flex items-center gap-1 text-xs text-text/60 hover:text-primary transition-colors cursor-pointer"
>
<FaSteam className="h-3.5 w-3.5" />
Steam
@@ -394,7 +394,7 @@ export function GamePageClient({
href={protonDbUrl}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 text-xs text-text/60 hover:text-primary transition-colors"
className="inline-flex items-center gap-1 text-xs text-text/60 hover:text-primary transition-colors cursor-pointer"
>
ProtonDB
<ExternalLinkIcon className="h-3 w-3" />
@@ -405,7 +405,7 @@ export function GamePageClient({
href={steamDbUrl}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 text-xs text-text/60 hover:text-primary transition-colors"
className="inline-flex items-center gap-1 text-xs text-text/60 hover:text-primary transition-colors cursor-pointer"
>
SteamDB
<ExternalLinkIcon className="h-3 w-3" />
@@ -537,7 +537,7 @@ export function GamePageClient({
<button
key={device.hardwareSlug}
onClick={() => toggleDevice(device.hardwareSlug)}
className={`shrink-0 px-3 py-1.5 rounded-full text-xs font-medium border transition-colors ${
className={`shrink-0 px-3 py-1.5 rounded-full text-xs font-medium border transition-colors cursor-pointer ${
active
? "bg-primary/20 border-primary text-primary"
: "bg-transparent border-border text-text/60 hover:text-text/80"
+1 -1
View File
@@ -35,7 +35,7 @@ export default function NotFound() {
>
<Link
href="/"
className="px-6 py-3 rounded-full bg-primary text-background font-semibold hover:bg-primary/80 transition-colors"
className="px-6 py-3 rounded-full bg-primary text-background font-semibold hover:bg-primary/80 transition-colors cursor-pointer"
>
Back to Home
</Link>
+1 -1
View File
@@ -111,7 +111,7 @@ export default function Landing() {
<Link
title="Visit our Github Repository"
href="https://github.com/AdrianBonpin/deckyvault"
className="text-accent opacity-60 hover:opacity-100 transition-opacity"
className="text-accent opacity-60 hover:opacity-100 transition-opacity cursor-pointer"
>
Github.
</Link>
+201 -165
View File
@@ -18,179 +18,215 @@ type Tab = "overview" | "saved" | "settings"
type SettingsTab = "profile" | "security" | "accounts"
export default function ProfilePage() {
const router = useRouter()
const { data: session, isPending: isSessionLoading } = useSession()
const [activeTab, setActiveTab] = useState<Tab>("overview")
const [settingsSubTab, setSettingsSubTab] = useState<SettingsTab>("profile")
const [profile, setProfile] = useState<{
id: string
name: string
email: string
image: string | null
role: string | null
createdAt: string
contributions: number
verifiedEntries: number
reputation: number
verified: boolean
} | null>(null)
const [contributions, setContributions] = useState<ContributionEntry[]>([])
const [isLoading, setIsLoading] = useState(true)
const router = useRouter()
const { data: session, isPending: isSessionLoading } = useSession()
const [activeTab, setActiveTab] = useState<Tab>("overview")
const [settingsSubTab, setSettingsSubTab] = useState<SettingsTab>("profile")
const [profile, setProfile] = useState<{
id: string
name: string
email: string
image: string | null
role: string | null
createdAt: string
contributions: number
verifiedEntries: number
reputation: number
verified: boolean
} | null>(null)
const [contributions, setContributions] = useState<ContributionEntry[]>([])
const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
if (!isSessionLoading && !session) {
router.push("/login")
}
}, [session, isSessionLoading, router])
useEffect(() => {
if (!session) return
async function fetchProfile() {
try {
const [profileRes, contribRes] = await Promise.all([
fetch("/api/user/me"),
fetch("/api/user/profile/" + session!.user.id + "/contributions?limit=10"),
])
if (profileRes.ok) {
setProfile(await profileRes.json())
useEffect(() => {
if (!isSessionLoading && !session) {
router.push("/login")
}
if (contribRes.ok) {
const data = await contribRes.json()
setContributions(data.data)
}, [session, isSessionLoading, router])
useEffect(() => {
if (!session) return
async function fetchProfile() {
try {
const [profileRes, contribRes] = await Promise.all([
fetch("/api/user/me"),
fetch(
"/api/user/profile/" +
session!.user.id +
"/contributions?limit=10",
),
])
if (profileRes.ok) {
setProfile(await profileRes.json())
}
if (contribRes.ok) {
const data = await contribRes.json()
setContributions(data.data)
}
} catch (err) {
console.error("Failed to fetch profile:", err)
} finally {
setIsLoading(false)
}
}
} catch (err) {
console.error("Failed to fetch profile:", err)
} finally {
setIsLoading(false)
}
fetchProfile()
}, [session])
if (isSessionLoading || isLoading) {
return (
<div className='flex items-center justify-center min-h-[50vh]'>
<Loader2 className='h-8 w-8 animate-spin text-primary' />
</div>
)
}
fetchProfile()
}, [session])
if (!session || !profile) {
return null
}
const tabs: { id: Tab; label: string; icon: typeof Bookmark }[] = [
{ id: "overview", label: "Overview", icon: TrendingUp },
{ id: "saved", label: "Saved Games", icon: Bookmark },
{ id: "settings", label: "Settings", icon: Settings },
]
if (isSessionLoading || isLoading) {
return (
<div className="flex items-center justify-center min-h-[50vh]">
<Loader2 className="h-8 w-8 animate-spin text-primary" />
</div>
)
}
if (!session || !profile) {
return null
}
const tabs: { id: Tab; label: string; icon: typeof Bookmark }[] = [
{ id: "overview", label: "Overview", icon: TrendingUp },
{ id: "saved", label: "Saved Games", icon: Bookmark },
{ id: "settings", label: "Settings", icon: Settings },
]
return (
<div className="w-full flex flex-col gap-8 pb-16">
{/* Profile header section */}
<motion.div initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4 }} className="px-4 md:px-[10svw]">
<div className="max-w-7xl mx-auto">
<ProfileHeader
name={profile.name}
email={profile.email}
role={profile.role}
verified={profile.verified}
createdAt={profile.createdAt}
/>
</div>
</motion.div>
{/* Stats section */}
<motion.div initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4, delay: 0.1 }} className="px-4 md:px-[10svw]">
<div className="max-w-7xl mx-auto">
<StatsRow
contributions={profile.contributions}
verifiedEntries={profile.verifiedEntries}
reputation={profile.reputation}
/>
</div>
</motion.div>
{/* Tabs + content section */}
<motion.div initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4, delay: 0.15 }} className="px-4 md:px-[10svw]">
<div className="max-w-7xl mx-auto">
{/* Tabs */}
<div className="flex gap-1 border-b border-border">
{tabs.map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`flex items-center gap-2 px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${
activeTab === tab.id
? "border-primary text-primary"
: "border-transparent text-text/50 hover:text-text/70"
}`}
>
<tab.icon className="h-4 w-4" />
{tab.label}
</button>
))}
</div>
{/* Tab Content */}
<motion.div
key={activeTab}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.2 }}
className="pt-6"
>
{activeTab === "overview" && (
<div>
<h2 className="text-lg font-semibold mb-4">Recent Contributions</h2>
<ContributionList entries={contributions} />
</div>
)}
{activeTab === "saved" && <SavedGamesGrid />}
{activeTab === "settings" && (
<div className="space-y-4">
{/* Settings sub-tabs */}
<div className="flex gap-1 border-b border-border">
{([
{ id: "profile" as SettingsTab, label: "Profile" },
{ id: "security" as SettingsTab, label: "Security" },
{ id: "accounts" as SettingsTab, label: "Linked Accounts" },
]).map((subTab) => (
<button
key={subTab.id}
onClick={() => setSettingsSubTab(subTab.id)}
className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${
settingsSubTab === subTab.id
? "border-primary text-primary"
: "border-transparent text-text/50 hover:text-text/70"
}`}
>
{subTab.label}
</button>
))}
<div className='w-full flex flex-col gap-8 pt-4'>
{/* Profile header section */}
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4 }}
className='px-4 md:px-[10svw]'
>
<div className='max-w-7xl mx-auto'>
<ProfileHeader
name={profile.name}
email={profile.email}
role={profile.role}
verified={profile.verified}
createdAt={profile.createdAt}
/>
</div>
</motion.div>
{/* Settings sub-tab content */}
{settingsSubTab === "profile" && (
<SettingsProfileTab
name={profile.name}
email={profile.email}
role={profile.role}
createdAt={profile.createdAt}
/>
)}
{settingsSubTab === "security" && <SettingsSecurityTab />}
{settingsSubTab === "accounts" && <SettingsAccountsTab />}
</div>
)}
</motion.div>
{/* Stats section */}
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, delay: 0.1 }}
className='px-4 md:px-[10svw]'
>
<div className='max-w-7xl mx-auto'>
<StatsRow
contributions={profile.contributions}
verifiedEntries={profile.verifiedEntries}
reputation={profile.reputation}
/>
</div>
</motion.div>
{/* Tabs + content section */}
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, delay: 0.15 }}
className='px-4 md:px-[10svw]'
>
<div className='max-w-7xl mx-auto'>
{/* Tabs */}
<div className='flex gap-1 border-b border-border'>
{tabs.map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`flex items-center gap-2 px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px cursor-pointer ${
activeTab === tab.id
? "border-primary text-primary"
: "border-transparent text-text/50 hover:text-text/70"
}`}
>
<tab.icon className='h-4 w-4' />
{tab.label}
</button>
))}
</div>
{/* Tab Content */}
<motion.div
key={activeTab}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.2 }}
className='pt-6'
>
{activeTab === "overview" && (
<div>
<h2 className='text-lg font-semibold mb-4'>
Recent Contributions
</h2>
<ContributionList entries={contributions} />
</div>
)}
{activeTab === "saved" && <SavedGamesGrid />}
{activeTab === "settings" && (
<div className='space-y-4'>
{/* Settings sub-tabs */}
<div className='flex gap-1 border-b border-border'>
{[
{
id: "profile" as SettingsTab,
label: "Profile",
},
{
id: "security" as SettingsTab,
label: "Security",
},
{
id: "accounts" as SettingsTab,
label: "Linked Accounts",
},
].map((subTab) => (
<button
key={subTab.id}
onClick={() =>
setSettingsSubTab(subTab.id)
}
className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px cursor-pointer ${
settingsSubTab === subTab.id
? "border-primary text-primary"
: "border-transparent text-text/50 hover:text-text/70"
}`}
>
{subTab.label}
</button>
))}
</div>
{/* Settings sub-tab content */}
{settingsSubTab === "profile" && (
<SettingsProfileTab
name={profile.name}
email={profile.email}
role={profile.role}
createdAt={profile.createdAt}
/>
)}
{settingsSubTab === "security" && (
<SettingsSecurityTab />
)}
{settingsSubTab === "accounts" && (
<SettingsAccountsTab />
)}
</div>
)}
</motion.div>
</div>
</motion.div>
</div>
</motion.div>
</div>
)
)
}
+3 -3
View File
@@ -374,7 +374,7 @@ function SearchResultCard({
href={`https://store.steampowered.com/app/${result.appId}`}
target="_blank"
rel="noopener noreferrer"
className="relative z-10 inline-flex items-center justify-center gap-1.5 px-2.5 py-1 rounded-md bg-[#1b2838] border border-[#2a475e] text-[#c6d4df] text-[11px] hover:bg-[#2a475e] transition-colors w-full"
className="relative z-10 inline-flex items-center justify-center gap-1.5 px-2.5 py-1 rounded-md bg-[#1b2838] border border-[#2a475e] text-[#c6d4df] text-[11px] hover:bg-[#2a475e] transition-colors w-full cursor-pointer"
onClick={(e) => e.stopPropagation()}
title="Open store page on Steam"
>
@@ -386,7 +386,7 @@ function SearchResultCard({
href={`https://www.protondb.com/app/${result.appId}`}
target="_blank"
rel="noopener noreferrer"
className="relative z-10 inline-flex items-center justify-center gap-1.5 px-2.5 py-1 rounded-md bg-purple-500/10 border border-purple-500/20 text-purple-400 text-[11px] hover:bg-purple-500/20 transition-colors w-full"
className="relative z-10 inline-flex items-center justify-center gap-1.5 px-2.5 py-1 rounded-md bg-purple-500/10 border border-purple-500/20 text-purple-400 text-[11px] hover:bg-purple-500/20 transition-colors w-full cursor-pointer"
onClick={(e) => e.stopPropagation()}
title="View Proton compatibility on ProtonDB"
>
@@ -398,7 +398,7 @@ function SearchResultCard({
href={`https://steamdb.info/app/${result.appId}`}
target="_blank"
rel="noopener noreferrer"
className="relative z-10 inline-flex items-center justify-center gap-1.5 px-2.5 py-1 rounded-md bg-blue-500/10 border border-blue-500/20 text-blue-400 text-[11px] hover:bg-blue-500/20 transition-colors w-full"
className="relative z-10 inline-flex items-center justify-center gap-1.5 px-2.5 py-1 rounded-md bg-blue-500/10 border border-blue-500/20 text-blue-400 text-[11px] hover:bg-blue-500/20 transition-colors w-full cursor-pointer"
onClick={(e) => e.stopPropagation()}
title="View app details on SteamDB"
>