Merge pull request #68 from christianlouis/copilot/fix-content-loading-issue
Fix infinite spinner on home page caused by isLoading always initialising as true
This commit is contained in:
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
- Fixed infinite spinning wheel on the home page: `authStore` no longer initialises `isLoading` as `true` unconditionally — it is now `false` when no access token exists in `localStorage`, so unauthenticated users see the landing page immediately instead of an endless spinner
|
||||||
|
- Home page now performs an auth check when a token is present in `localStorage`, redirecting authenticated users to the dashboard and clearing stale tokens on failure
|
||||||
- Wrapped `useSearchParams()` in a `Suspense` boundary in `frontend/src/app/auth/callback/page.tsx` to fix the Next.js build error: "useSearchParams() should be wrapped in a suspense boundary at page /auth/callback"
|
- Wrapped `useSearchParams()` in a `Suspense` boundary in `frontend/src/app/auth/callback/page.tsx` to fix the Next.js build error: "useSearchParams() should be wrapped in a suspense boundary at page /auth/callback"
|
||||||
- Fixed TypeScript build error in `frontend/src/app/accounts/page.tsx`: replaced non-existent `account.username` with `account.email_address`, `account.last_checked_at` with `account.last_check_at`, and `account.last_error` with `account.last_error_message` (the backend intentionally excludes `username` from API responses for security)
|
- Fixed TypeScript build error in `frontend/src/app/accounts/page.tsx`: replaced non-existent `account.username` with `account.email_address`, `account.last_checked_at` with `account.last_check_at`, and `account.last_error` with `account.last_error_message` (the backend intentionally excludes `username` from API responses for security)
|
||||||
- Fixed TypeScript error in `frontend/src/app/auth/callback/page.tsx`: `TokenResponse` doesn't include `user`; now fetches user via `userApi.getCurrentUser()` after OAuth token exchange
|
- Fixed TypeScript error in `frontend/src/app/auth/callback/page.tsx`: `TokenResponse` doesn't include `user`; now fetches user via `userApi.getCurrentUser()` after OAuth token exchange
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ because the API client layer is missing.
|
|||||||
- Exports: `authApi`, `mailAccountsApi`, `processingRunsApi`, `userApi`
|
- Exports: `authApi`, `mailAccountsApi`, `processingRunsApi`, `userApi`
|
||||||
- Exports types: `User`, `MailAccount`, `MailAccountCreate`, `ProcessingRun`
|
- Exports types: `User`, `MailAccount`, `MailAccountCreate`, `ProcessingRun`
|
||||||
- 8 files import from `@/lib/api` — all compilation errors resolved
|
- 8 files import from `@/lib/api` — all compilation errors resolved
|
||||||
|
- [x] Fix infinite spinner on home page: `isLoading` now initialises based on token presence; home page performs auth check when token exists
|
||||||
|
|
||||||
### Existing Pages (UI done, need API wiring) 🔨
|
### Existing Pages (UI done, need API wiring) 🔨
|
||||||
- [x] Landing page (`app/page.tsx`)
|
- [x] Landing page (`app/page.tsx`)
|
||||||
|
|||||||
@@ -4,17 +4,30 @@ import { useEffect } from 'react';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useAuthStore } from '@/store/authStore';
|
import { useAuthStore } from '@/store/authStore';
|
||||||
|
import { userApi } from '@/lib/api';
|
||||||
import { Mail, ArrowRight, Shield, Zap, Clock } from 'lucide-react';
|
import { Mail, ArrowRight, Shield, Zap, Clock } from 'lucide-react';
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { user, isLoading } = useAuthStore();
|
const { isLoading, setUser, setLoading } = useAuthStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isLoading && user) {
|
const token =
|
||||||
router.push('/dashboard');
|
typeof window !== 'undefined' ? localStorage.getItem('access_token') : null;
|
||||||
}
|
if (!token) return;
|
||||||
}, [user, isLoading, router]);
|
|
||||||
|
userApi
|
||||||
|
.getCurrentUser()
|
||||||
|
.then((userData) => {
|
||||||
|
setUser(userData);
|
||||||
|
router.push('/dashboard');
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error('Auth check failed on home page:', err);
|
||||||
|
localStorage.removeItem('access_token');
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, [router, setUser, setLoading]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const useAuthStore = create<AuthState>((set) => ({
|
|||||||
user: null,
|
user: null,
|
||||||
token: typeof window !== 'undefined' ? localStorage.getItem('access_token') : null,
|
token: typeof window !== 'undefined' ? localStorage.getItem('access_token') : null,
|
||||||
isAuthenticated: typeof window !== 'undefined' ? !!localStorage.getItem('access_token') : false,
|
isAuthenticated: typeof window !== 'undefined' ? !!localStorage.getItem('access_token') : false,
|
||||||
isLoading: true,
|
isLoading: typeof window !== 'undefined' ? !!localStorage.getItem('access_token') : false,
|
||||||
|
|
||||||
setUser: (user) => set({
|
setUser: (user) => set({
|
||||||
user,
|
user,
|
||||||
|
|||||||
Reference in New Issue
Block a user