mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-20 20:29:06 +00:00
fix: resolve authentication race condition with React Query
Previously, API calls were being made before the auth token was configured, causing initial 401 errors that would retry with 200 after token setup. Changes: - Add global auth readiness tracking in apiClient - Create useAuthReady hook that checks both session and token state - Update all API hooks to use isAuthReady instead of just session status - Add AuthWrapper component at layout level for consistent loading UX - Show spinner while authentication initializes across all pages This ensures API calls only fire after authentication is fully configured, eliminating the 401/retry pattern and improving user experience.
This commit is contained in:
28
www/app/(app)/AuthWrapper.tsx
Normal file
28
www/app/(app)/AuthWrapper.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
"use client";
|
||||
|
||||
import { Flex, Spinner } from "@chakra-ui/react";
|
||||
import useAuthReady from "../lib/useAuthReady";
|
||||
|
||||
export default function AuthWrapper({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const { isAuthReady, isLoading } = useAuthReady();
|
||||
|
||||
// Show spinner while auth is loading
|
||||
if (isLoading || !isAuthReady) {
|
||||
return (
|
||||
<Flex
|
||||
flexDir="column"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
h="calc(100vh - 80px)" // Account for header height
|
||||
>
|
||||
<Spinner size="xl" color="blue.500" thickness="4px" />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import Image from "next/image";
|
||||
import About from "../(aboutAndPrivacy)/about";
|
||||
import Privacy from "../(aboutAndPrivacy)/privacy";
|
||||
import UserInfo from "../(auth)/userInfo";
|
||||
import AuthWrapper from "./AuthWrapper";
|
||||
import { RECORD_A_MEETING_URL } from "../lib/constants";
|
||||
|
||||
export default async function AppLayout({
|
||||
@@ -90,7 +91,7 @@ export default async function AppLayout({
|
||||
</div>
|
||||
</Flex>
|
||||
|
||||
{children}
|
||||
<AuthWrapper>{children}</AuthWrapper>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ export default function TranscriptDetails(details: TranscriptDetails) {
|
||||
useActiveTopic={useActiveTopic}
|
||||
waveform={waveform.waveform}
|
||||
media={mp3.media}
|
||||
mediaDuration={transcript.response.duration}
|
||||
mediaDuration={transcript.response?.duration}
|
||||
/>
|
||||
) : !mp3.loading && (waveform.error || mp3.error) ? (
|
||||
<Box p={4} bg="red.100" borderRadius="md">
|
||||
@@ -116,7 +116,7 @@ export default function TranscriptDetails(details: TranscriptDetails) {
|
||||
<Flex direction="column" gap={0}>
|
||||
<Flex alignItems="center" gap={2}>
|
||||
<TranscriptTitle
|
||||
title={transcript.response.title || "Unnamed Transcript"}
|
||||
title={transcript.response?.title || "Unnamed Transcript"}
|
||||
transcriptId={transcriptId}
|
||||
onUpdate={(newTitle) => {
|
||||
transcript.reload();
|
||||
|
||||
@@ -46,6 +46,16 @@ const useTranscript = (
|
||||
};
|
||||
}
|
||||
|
||||
// Check if data is undefined or null
|
||||
if (!data) {
|
||||
return {
|
||||
response: null,
|
||||
loading: true,
|
||||
error: false,
|
||||
reload: refetch,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
response: data as GetTranscript,
|
||||
loading: false,
|
||||
|
||||
Reference in New Issue
Block a user