fix(layout+pages): default user=null + page audit sweep (P0 #7) #15

Merged
varutasu merged 4 commits from convoy/fix-layout-default-user into main 2026-05-24 15:31:37 -04:00
7 changed files with 45 additions and 57 deletions
Showing only changes of commit 0f6bfbb7df - Show all commits

View file

@ -2,6 +2,7 @@ import { useState, useEffect } from 'react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import Layout from '../../components/Layout'; import Layout from '../../components/Layout';
import { useIsAdmin } from '../../lib/admin-auth'; import { useIsAdmin } from '../../lib/admin-auth';
import { useAuth } from '../../lib/use-auth';
import CollectionSelectionModal from '../../components/CollectionSelectionModal'; import CollectionSelectionModal from '../../components/CollectionSelectionModal';
import { ManaCost, ColorIdentity, AdvancedManaCost } from '../../components/ManaSymbols'; import { ManaCost, ColorIdentity, AdvancedManaCost } from '../../components/ManaSymbols';
import ManaSymbolSettings from '../../components/ManaSymbolSettings'; import ManaSymbolSettings from '../../components/ManaSymbolSettings';
@ -9,11 +10,7 @@ import ManaSymbolSettings from '../../components/ManaSymbolSettings';
export default function CardDetail() { export default function CardDetail() {
const router = useRouter(); const router = useRouter();
const { id } = router.query; const { id } = router.query;
const { user } = useAuth();
const user = {
email: 'me@randallstillwell.com',
role: 'user'
};
const [card, setCard] = useState(null); const [card, setCard] = useState(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);

View file

@ -259,7 +259,7 @@ export default function DeckBuilder() {
if (!user) { if (!user) {
return ( return (
<Layout> <Layout user={user}>
<div className="flex items-center justify-center min-h-screen"> <div className="flex items-center justify-center min-h-screen">
<div className="text-center"> <div className="text-center">
<h1 className="text-2xl font-bold mb-4">Please log in to use the deck builder</h1> <h1 className="text-2xl font-bold mb-4">Please log in to use the deck builder</h1>
@ -274,7 +274,7 @@ export default function DeckBuilder() {
if (loading) { if (loading) {
return ( return (
<Layout> <Layout user={user}>
<div className="flex items-center justify-center min-h-screen"> <div className="flex items-center justify-center min-h-screen">
<div className="animate-spin rounded-full h-32 w-32 border-b-2 border-accent-ember"></div> <div className="animate-spin rounded-full h-32 w-32 border-b-2 border-accent-ember"></div>
</div> </div>
@ -284,7 +284,7 @@ export default function DeckBuilder() {
if (!deck) { if (!deck) {
return ( return (
<Layout> <Layout user={user}>
<div className="flex items-center justify-center min-h-screen"> <div className="flex items-center justify-center min-h-screen">
<div className="text-center"> <div className="text-center">
<h1 className="text-2xl font-bold mb-4">Deck not found</h1> <h1 className="text-2xl font-bold mb-4">Deck not found</h1>
@ -300,7 +300,7 @@ export default function DeckBuilder() {
const stats = getDeckStats(); const stats = getDeckStats();
return ( return (
<Layout> <Layout user={user}>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{/* Header */} {/* Header */}
<div className="flex justify-between items-center mb-6"> <div className="flex justify-between items-center mb-6">

View file

@ -129,7 +129,7 @@ export default function DeckDetail() {
if (loading) { if (loading) {
return ( return (
<Layout> <Layout user={user}>
<div className="flex items-center justify-center min-h-screen"> <div className="flex items-center justify-center min-h-screen">
<div className="animate-spin rounded-full h-32 w-32 border-b-2 border-accent-ember"></div> <div className="animate-spin rounded-full h-32 w-32 border-b-2 border-accent-ember"></div>
</div> </div>
@ -139,7 +139,7 @@ export default function DeckDetail() {
if (!deck) { if (!deck) {
return ( return (
<Layout> <Layout user={user}>
<div className="flex items-center justify-center min-h-screen"> <div className="flex items-center justify-center min-h-screen">
<div className="text-center"> <div className="text-center">
<h1 className="text-2xl font-bold mb-4">Deck not found</h1> <h1 className="text-2xl font-bold mb-4">Deck not found</h1>
@ -157,7 +157,7 @@ export default function DeckDetail() {
const isOwner = user && deck.user_id === user.userId; const isOwner = user && deck.user_id === user.userId;
return ( return (
<Layout> <Layout user={user}>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{/* Header */} {/* Header */}
<div className="flex justify-between items-start mb-8"> <div className="flex justify-between items-start mb-8">

View file

@ -158,7 +158,7 @@ export default function Decks() {
if (!user) { if (!user) {
return ( return (
<Layout> <Layout user={user}>
<div className="flex items-center justify-center min-h-screen"> <div className="flex items-center justify-center min-h-screen">
<div className="text-center"> <div className="text-center">
<h1 className="text-2xl font-bold mb-4">Please log in to view your decks</h1> <h1 className="text-2xl font-bold mb-4">Please log in to view your decks</h1>
@ -173,7 +173,7 @@ export default function Decks() {
if (loading) { if (loading) {
return ( return (
<Layout> <Layout user={user}>
<div className="flex items-center justify-center min-h-screen"> <div className="flex items-center justify-center min-h-screen">
<div className="animate-spin rounded-full h-32 w-32 border-b-2 border-accent-ember"></div> <div className="animate-spin rounded-full h-32 w-32 border-b-2 border-accent-ember"></div>
</div> </div>
@ -182,7 +182,7 @@ export default function Decks() {
} }
return ( return (
<Layout> <Layout user={user}>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{/* Header */} {/* Header */}
<div className="flex justify-between items-center mb-8"> <div className="flex justify-between items-center mb-8">

View file

@ -7,17 +7,7 @@ export default function Profile() {
const fileInputRef = useRef(null); const fileInputRef = useRef(null);
// User state // User state
const [user, setUser] = useState({ const [user, setUser] = useState(null);
email: 'me@randallstillwell.com',
role: 'admin',
first_name: '',
last_name: '',
username: '',
bio: '',
avatar_url: '',
favorite_games: ['MTG'],
created_at: new Date().toISOString()
});
// UI state // UI state
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@ -236,6 +226,7 @@ export default function Profile() {
}; };
const getDisplayName = () => { const getDisplayName = () => {
if (!user) return '';
if (user.first_name || user.last_name) { if (user.first_name || user.last_name) {
return `${user.first_name} ${user.last_name}`.trim(); return `${user.first_name} ${user.last_name}`.trim();
} }
@ -243,6 +234,7 @@ export default function Profile() {
}; };
const getInitials = () => { const getInitials = () => {
if (!user) return '';
if (user.first_name || user.last_name) { if (user.first_name || user.last_name) {
return `${user.first_name?.charAt(0) || ''}${user.last_name?.charAt(0) || ''}`.toUpperCase(); return `${user.first_name?.charAt(0) || ''}${user.last_name?.charAt(0) || ''}`.toUpperCase();
} }
@ -296,7 +288,7 @@ export default function Profile() {
{/* Avatar */} {/* Avatar */}
<div className="mb-6"> <div className="mb-6">
<div className="relative inline-block"> <div className="relative inline-block">
{user.avatar_url ? ( {user?.avatar_url ? (
<img <img
src={user.avatar_url} src={user.avatar_url}
alt="Profile" alt="Profile"
@ -358,29 +350,29 @@ export default function Profile() {
<h2 className="text-2xl font-bold mb-1" style={{ color: 'var(--text-primary)' }}> <h2 className="text-2xl font-bold mb-1" style={{ color: 'var(--text-primary)' }}>
{getDisplayName()} {getDisplayName()}
</h2> </h2>
{user.username && ( {user?.username && (
<p className="text-lg mb-2" style={{ color: 'var(--text-secondary)' }}> <p className="text-lg mb-2" style={{ color: 'var(--text-secondary)' }}>
@{user.username} @{user.username}
</p> </p>
)} )}
<p className="text-sm" style={{ color: 'var(--text-secondary)' }}> <p className="text-sm" style={{ color: 'var(--text-secondary)' }}>
{user.email} {user?.email}
</p> </p>
<div className="flex items-center justify-center mt-2"> <div className="flex items-center justify-center mt-2">
<span <span
className="px-3 py-1 text-xs rounded-full font-medium" className="px-3 py-1 text-xs rounded-full font-medium"
style={{ style={{
backgroundColor: user.role === 'admin' ? 'var(--accent-ember)' : 'var(--accent-gold)', backgroundColor: user?.role === 'admin' ? 'var(--accent-ember)' : 'var(--accent-gold)',
color: 'white' color: 'white'
}} }}
> >
{user.role?.toUpperCase()} {user?.role?.toUpperCase()}
</span> </span>
</div> </div>
</div> </div>
{/* Bio */} {/* Bio */}
{user.bio && ( {user?.bio && (
<div className="mb-6"> <div className="mb-6">
<p className="text-sm leading-relaxed" style={{ color: 'var(--text-secondary)' }}> <p className="text-sm leading-relaxed" style={{ color: 'var(--text-secondary)' }}>
{user.bio} {user.bio}
@ -389,11 +381,13 @@ export default function Profile() {
)} )}
{/* Member Since */} {/* Member Since */}
<div className="text-center"> {user?.created_at && (
<p className="text-sm" style={{ color: 'var(--text-secondary)' }}> <div className="text-center">
Member since {formatDate(user.created_at)} <p className="text-sm" style={{ color: 'var(--text-secondary)' }}>
</p> Member since {formatDate(user.created_at)}
</div> </p>
</div>
)}
</div> </div>
{/* Stats Card */} {/* Stats Card */}
@ -468,7 +462,7 @@ export default function Profile() {
/> />
) : ( ) : (
<p className="py-2 text-sm" style={{ color: 'var(--text-secondary)' }}> <p className="py-2 text-sm" style={{ color: 'var(--text-secondary)' }}>
{user.first_name || 'Not set'} {user?.first_name || 'Not set'}
</p> </p>
)} )}
</div> </div>
@ -486,7 +480,7 @@ export default function Profile() {
/> />
) : ( ) : (
<p className="py-2 text-sm" style={{ color: 'var(--text-secondary)' }}> <p className="py-2 text-sm" style={{ color: 'var(--text-secondary)' }}>
{user.last_name || 'Not set'} {user?.last_name || 'Not set'}
</p> </p>
)} )}
</div> </div>
@ -507,7 +501,7 @@ export default function Profile() {
/> />
) : ( ) : (
<p className="py-2 text-sm" style={{ color: 'var(--text-secondary)' }}> <p className="py-2 text-sm" style={{ color: 'var(--text-secondary)' }}>
{user.username || 'Not set'} {user?.username || 'Not set'}
</p> </p>
)} )}
</div> </div>
@ -527,7 +521,7 @@ export default function Profile() {
/> />
) : ( ) : (
<p className="py-2 text-sm leading-relaxed" style={{ color: 'var(--text-secondary)' }}> <p className="py-2 text-sm leading-relaxed" style={{ color: 'var(--text-secondary)' }}>
{user.bio || 'No bio set'} {user?.bio || 'No bio set'}
</p> </p>
)} )}
</div> </div>
@ -546,19 +540,19 @@ export default function Profile() {
className={`px-4 py-2 rounded-xl font-medium transition-all duration-200 flex items-center gap-2 ${ className={`px-4 py-2 rounded-xl font-medium transition-all duration-200 flex items-center gap-2 ${
editMode ? 'cursor-pointer hover:shadow-md' : 'cursor-default' editMode ? 'cursor-pointer hover:shadow-md' : 'cursor-default'
} ${ } ${
(editMode ? formData.favorite_games : user.favorite_games)?.includes(game.value) (editMode ? formData.favorite_games : user?.favorite_games)?.includes(game.value)
? 'shadow-lg' ? 'shadow-lg'
: 'hover:shadow-md' : 'hover:shadow-md'
}`} }`}
style={{ style={{
backgroundColor: (editMode ? formData.favorite_games : user.favorite_games)?.includes(game.value) backgroundColor: (editMode ? formData.favorite_games : user?.favorite_games)?.includes(game.value)
? 'var(--accent-ember)' ? 'var(--accent-ember)'
: 'var(--bg-tertiary)', : 'var(--bg-tertiary)',
color: (editMode ? formData.favorite_games : user.favorite_games)?.includes(game.value) color: (editMode ? formData.favorite_games : user?.favorite_games)?.includes(game.value)
? 'white' ? 'white'
: 'var(--text-primary)', : 'var(--text-primary)',
border: `1px solid ${ border: `1px solid ${
(editMode ? formData.favorite_games : user.favorite_games)?.includes(game.value) (editMode ? formData.favorite_games : user?.favorite_games)?.includes(game.value)
? 'var(--accent-ember)' ? 'var(--accent-ember)'
: 'var(--border)' : 'var(--border)'
}` }`
@ -578,7 +572,7 @@ export default function Profile() {
</label> </label>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<p className="py-2 text-sm" style={{ color: 'var(--text-secondary)' }}> <p className="py-2 text-sm" style={{ color: 'var(--text-secondary)' }}>
{user.email} {user?.email}
</p> </p>
<span className="px-2 py-1 text-xs rounded-full bg-green-100 dark:bg-green-900/20 text-green-800 dark:text-green-200"> <span className="px-2 py-1 text-xs rounded-full bg-green-100 dark:bg-green-900/20 text-green-800 dark:text-green-200">
Verified Verified
@ -596,11 +590,11 @@ export default function Profile() {
onClick={() => { onClick={() => {
setEditMode(false); setEditMode(false);
setFormData({ setFormData({
first_name: user.first_name || '', first_name: user?.first_name || '',
last_name: user.last_name || '', last_name: user?.last_name || '',
username: user.username || '', username: user?.username || '',
bio: user.bio || '', bio: user?.bio || '',
favorite_games: user.favorite_games || [] favorite_games: user?.favorite_games || []
}); });
setMessage({ type: '', text: '' }); setMessage({ type: '', text: '' });
}} }}

View file

@ -330,7 +330,7 @@ export default function Scanner() {
} }
return ( return (
<Layout> <Layout user={user}>
<div className="h-full flex flex-col"> <div className="h-full flex flex-col">
{/* Header */} {/* Header */}
<div className="px-6 pt-6 pb-4"> <div className="px-6 pt-6 pb-4">

View file

@ -6,10 +6,7 @@ export default function Settings() {
const router = useRouter(); const router = useRouter();
// User state // User state
const [user, setUser] = useState({ const [user, setUser] = useState(null);
email: 'me@randallstillwell.com',
role: 'admin'
});
// Settings state // Settings state
const [settings, setSettings] = useState({ const [settings, setSettings] = useState({
@ -303,7 +300,7 @@ export default function Settings() {
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<input <input
type="email" type="email"
value={user.email} value={user?.email || ''}
disabled disabled
className="input-field flex-1 opacity-50 cursor-not-allowed" className="input-field flex-1 opacity-50 cursor-not-allowed"
/> />