Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion components/ChatClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1365,7 +1365,7 @@ export default function ChatClient() {
</div>

{/* Conditional guidance based on whether they have Math Brain data */}
{hasMathBrainSession === false && (
{hasMathBrainSession === false && !canRecoverStoredPayload && (
<div className="mt-5 rounded-lg border border-amber-500/30 bg-amber-500/10 px-4 py-4">
<div className="flex items-start gap-3">
<span className="text-lg">✨</span>
Expand Down Expand Up @@ -1418,6 +1418,29 @@ export default function ChatClient() {
</div>
)}

{hasMathBrainSession !== true && canRecoverStoredPayload && (
<div className="mt-5 rounded-lg border border-emerald-500/30 bg-emerald-500/10 px-4 py-4">
<div className="flex items-start gap-3">
<span className="text-lg">📂</span>
<div>
<p className="text-sm font-medium text-emerald-200">Saved Math Brain report detected</p>
<p className="mt-1 text-xs text-emerald-200/80">
I can restore your last export even though I couldn&apos;t automatically confirm Math Brain is active in this tab.
Load it below to start the structured Poetic Brain reading.
</p>
<button
type="button"
onClick={recoverLastStoredPayload}
className="mt-3 inline-flex items-center gap-2 rounded-lg border border-emerald-500/40 bg-emerald-500/20 px-4 py-2 text-sm font-medium text-emerald-100 transition hover:bg-emerald-500/30"
>
<span>📊</span>
Load last report
</button>
</div>
</div>
</div>
)}

{/* Always available actions */}
<div className="mt-5 border-t border-slate-700/50 pt-5">
<p className="text-xs text-slate-400 mb-3">Or explore without chart data:</p>
Expand Down
51 changes: 51 additions & 0 deletions hooks/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ export function useAuth() {
if (!client) {
// Fallback to stored token if client not ready
return typeof window !== 'undefined'

? window.localStorage.getItem(AUTH_TOKEN_KEY)

? window.localStorage.getItem(AUTH_TOKEN_KEY)

: null;
}

Expand All @@ -107,11 +111,34 @@ export function useAuth() {
} catch (error) {
console.warn('[useAuth] Failed to get token silently:', error);


// Clear any stale token so we do not keep sending invalid credentials
if (typeof window !== 'undefined') {
window.localStorage.removeItem(AUTH_TOKEN_KEY);
}

// If login is required, force a redirect so the user can re-authenticate cleanly
const requiresLogin = (error as any)?.error === 'login_required' || (error as any)?.error === 'consent_required';
if (requiresLogin) {
try {
await client.loginWithRedirect({
authorizationParams: {
redirect_uri: getRedirectUri(),
}
});
} catch (redirectError) {
console.warn('[useAuth] Redirect for re-auth failed:', redirectError);
}
}

return null;

// If refresh fails, try to return cached token as last resort
// (it might still work if the error was transient)
return typeof window !== 'undefined'
? window.localStorage.getItem(AUTH_TOKEN_KEY)
: null;

}
}, []);

Expand All @@ -129,7 +156,10 @@ export async function getAccessTokenAsync(): Promise<string | null> {
const client = await getAuth0Client();

if (!client) {

=======
// No client = auth not configured. Return stored token if exists.

return typeof window !== 'undefined'
? window.localStorage.getItem(AUTH_TOKEN_KEY)
: null;
Expand All @@ -148,6 +178,26 @@ export async function getAccessTokenAsync(): Promise<string | null> {
}

return token;

} catch (error) {
console.warn('[getAccessTokenAsync] Failed to get token:', error);

// Clear stale token to avoid repeated invalid-session failures
if (typeof window !== 'undefined') {
window.localStorage.removeItem(AUTH_TOKEN_KEY);
}

const requiresLogin = (error as any)?.error === 'login_required' || (error as any)?.error === 'consent_required';
if (requiresLogin) {
try {
await client.loginWithRedirect({
authorizationParams: {
redirect_uri: getRedirectUri(),
}
});
} catch (redirectError) {
console.warn('[getAccessTokenAsync] Redirect for re-auth failed:', redirectError);

} catch (error: any) {
console.warn('[getAccessTokenAsync] Failed to get token:', error?.message || error);

Expand All @@ -164,6 +214,7 @@ export async function getAccessTokenAsync(): Promise<string | null> {
errorMsg.includes('invalid')) {
console.log('[getAccessTokenAsync] Clearing stale token - reauth required');
window.localStorage.removeItem(AUTH_TOKEN_KEY);

}
}

Expand Down
Loading