Refactor: Centralized Supabase Auth and implemented Auth Guards to prevent 401 errors

This commit is contained in:
2026-01-04 23:00:18 +01:00
parent 9d6a8b358f
commit 71586fd6a8
15 changed files with 18678 additions and 576 deletions

View File

@@ -12,6 +12,7 @@ import DramOfTheDay from "@/components/DramOfTheDay";
import LanguageSwitcher from "@/components/LanguageSwitcher";
import OfflineIndicator from "@/components/OfflineIndicator";
import { useI18n } from "@/i18n/I18nContext";
import { useAuth } from "@/context/AuthContext";
import { useSession } from "@/context/SessionContext";
import TastingHub from "@/components/TastingHub";
import { Sparkles, X, Loader2 } from "lucide-react";
@@ -25,8 +26,8 @@ export default function Home() {
const supabase = createClient();
const router = useRouter();
const [bottles, setBottles] = useState<any[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [user, setUser] = useState<any>(null);
const { user, isLoading: isAuthLoading } = useAuth();
const [isInternalLoading, setIsInternalLoading] = useState(false);
const [fetchError, setFetchError] = useState<string | null>(null);
const { t } = useI18n();
const { activeSession } = useSession();
@@ -46,39 +47,15 @@ export default function Home() {
};
useEffect(() => {
// Check session
const checkUser = async () => {
try {
// Proactively get session - this will trigger a refresh if needed
const { data: { session }, error } = await supabase.auth.getSession();
if (session) {
console.log('[Auth] Valid session found:', {
userId: session.user.id,
expiry: new Date(session.expires_at! * 1000).toLocaleString()
});
} else {
console.log('[Auth] No active session found.');
}
if (error) {
console.error('[Auth] Session check error:', error);
}
setUser(session?.user ?? null);
if (session?.user) {
fetchCollection();
}
} catch (err) {
console.error('[Auth] Unexpected error during session check:', err);
setUser(null);
} finally {
setIsLoading(false);
}
};
checkUser();
// Only fetch if auth is ready and user exists
if (!isAuthLoading && user) {
fetchCollection();
} else if (!isAuthLoading && !user) {
setBottles([]);
}
}, [user, isAuthLoading]);
useEffect(() => {
// Fetch public splits if guest
getActiveSplits().then(res => {
if (res.success && res.splits) {
@@ -86,33 +63,6 @@ export default function Home() {
}
});
// Listen for visibility change (wake up from sleep)
const handleVisibilityChange = () => {
if (document.visibilityState === 'visible') {
console.log('[Auth] App became visible, refreshing session...');
checkUser();
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
// Listen for auth changes
const { data: { subscription } } = supabase.auth.onAuthStateChange((event: string, session: any) => {
console.log('[Auth] State change event:', event, {
hasSession: !!session,
userId: session?.user?.id,
email: session?.user?.email
});
setUser(session?.user ?? null);
if (session?.user) {
if (event === 'SIGNED_IN' || event === 'INITIAL_SESSION' || event === 'TOKEN_REFRESHED') {
fetchCollection();
}
} else {
setBottles([]);
}
});
// Listen for collection updates (e.g., after offline sync completes)
const handleCollectionUpdated = () => {
console.log('[Home] Collection update event received, refreshing...');
@@ -121,14 +71,12 @@ export default function Home() {
window.addEventListener('collection-updated', handleCollectionUpdated);
return () => {
subscription.unsubscribe();
document.removeEventListener('visibilitychange', handleVisibilityChange);
window.removeEventListener('collection-updated', handleCollectionUpdated);
};
}, []);
const fetchCollection = async () => {
setIsLoading(true);
setIsInternalLoading(true);
try {
// Fetch bottles with their latest tasting date
const { data, error } = await supabase
@@ -194,7 +142,7 @@ export default function Home() {
setFetchError(errorMessage);
}
} finally {
setIsLoading(false);
setIsInternalLoading(false);
}
};
@@ -249,6 +197,8 @@ export default function Home() {
);
}
const isLoading = isAuthLoading || isInternalLoading;
return (
<main className="flex min-h-screen flex-col items-center gap-6 md:gap-12 p-4 md:p-24 bg-[var(--background)] pb-32">
<div className="z-10 max-w-5xl w-full flex flex-col items-center gap-12">