Skip to content

Commit fffd548

Browse files
committed
fix: wait for auth to be ready to run queries
1 parent 00d41a9 commit fffd548

File tree

14 files changed

+94
-26
lines changed

14 files changed

+94
-26
lines changed

frontend/app/composables/useAuth.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@ export function useAuth() {
3939
const token = useCookie('token')
4040
const isLoading = useState('isLoading', () => true)
4141
const me = useState<GetMeQuery['me'] | null | undefined>('me', () => null)
42-
const { data } = useGetMeQuery()
42+
43+
// Only fetch user data if we have a token AND we're not on the callback page
44+
const { isAuthReady } = useAuthReady()
45+
46+
const { data } = useGetMeQuery({
47+
pause: computed(() => !isAuthReady.value),
48+
})
4349

4450
watch(
4551
() => data.value?.me,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Composable that provides a reactive flag indicating whether auth is ready for GraphQL queries.
3+
* Use this to pause queries until we have a valid token and are not on the callback page.
4+
*/
5+
export function useAuthReady() {
6+
const token = useCookie('token')
7+
const route = useRoute()
8+
9+
const isAuthReady = computed(() => {
10+
return !!token.value && route.path !== '/callback'
11+
})
12+
13+
return { isAuthReady }
14+
}

frontend/app/layouts/admin.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ gql(`
2121
}
2222
`)
2323
24-
const { data } = useAdminSidebarQuery()
24+
const { isAuthReady } = useAuthReady()
25+
const { data } = useAdminSidebarQuery({
26+
pause: computed(() => !isAuthReady.value),
27+
})
28+
2529
const projectsLinks = computed(() => {
2630
return data.value?.projects.edges.map(({ node: project }) => ({
2731
label: project.name,

frontend/app/layouts/default.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ onBeforeMount(() => {
4949
document.documentElement.classList.add('light')
5050
})
5151
52-
const { data } = useCurrentProjectQuery()
52+
const { isAuthReady } = useAuthReady()
53+
const { data } = useCurrentProjectQuery({
54+
pause: computed(() => !isAuthReady.value),
55+
})
5356
5457
watch(data, (newData) => {
5558
if (!newData) return

frontend/app/pages/admin/index.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ gql(`
3333
}
3434
`)
3535
36-
const { data, fetching, error } = useAdminHomePageQuery()
36+
const { isAuthReady } = useAuthReady()
37+
const { data, fetching, error } = useAdminHomePageQuery({
38+
pause: computed(() => !isAuthReady.value),
39+
})
3740
const { currentProjects } = useGroupedProjects(() =>
3841
data.value?.projects.edges.map((edge) => edge.node),
3942
)

frontend/app/pages/admin/projects/[projectId].vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ gql(`
5757
}
5858
`)
5959
60+
const { isAuthReady } = useAuthReady()
6061
const { data, error, fetching } = useAdminProjectPageQuery({
6162
variables: {
6263
projectId: route.params.projectId,
6364
},
65+
pause: computed(() => !isAuthReady.value),
6466
})
6567
6668
const state = reactive({

frontend/app/pages/admin/projects/index.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ gql(`
2626
}
2727
`)
2828
29-
const { data, error, fetching } = useAdminProjectsPageQuery()
29+
const { isAuthReady } = useAuthReady()
30+
const { data, error, fetching } = useAdminProjectsPageQuery({
31+
pause: computed(() => !isAuthReady.value),
32+
})
3033
3134
const { currentProjects, futureProjects, pastProjects } = useGroupedProjects(
3235
() => data.value?.projects.edges.map((edge) => edge.node),

frontend/app/pages/admin/users/[userId].vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ gql(`
3333
3434
const route = useRoute('admin-users-userId')
3535
36+
const { isAuthReady } = useAuthReady()
3637
const { data, fetching, error } = useAdminUserPageQuery({
3738
variables: {
3839
id: route.params.userId,
3940
},
41+
pause: computed(() => !isAuthReady.value),
4042
})
4143
</script>
4244

frontend/app/pages/admin/users/index.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ gql(`
4646
const pagination = usePagination({
4747
defaultPageSize: 15,
4848
})
49+
const { isAuthReady } = useAuthReady()
4950
const { data, fetching, error } = useAdminUsersPageQuery({
5051
variables: pagination.variables,
52+
pause: computed(() => !isAuthReady.value),
5153
})
5254
5355
// Update pagination state when data changes

frontend/app/pages/callback.vue

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,43 @@ definePageMeta({
99
const config = useRuntimeConfig()
1010
const { setAccessToken } = useAuth()
1111
12-
onBeforeMount(async () => {
12+
// Use a global state to prevent multiple concurrent callbacks across component re-mounts
13+
const processing = useState('callback-processing', () => false)
14+
15+
onMounted(async () => {
16+
// Only process once globally
17+
if (processing.value) {
18+
return
19+
}
20+
21+
processing.value = true
22+
1323
const { token, redirect } = route.query
14-
if (token) {
15-
try {
16-
const response = await $fetch<{ token: string }>(
17-
`${config.public.callbackUrl}?token=${token}`,
18-
{ method: 'GET' },
19-
)
20-
if (response && response.token) {
21-
setAccessToken(response.token)
22-
23-
if (redirect && typeof redirect === 'string') {
24-
navigateTo(redirect)
25-
} else {
26-
navigateTo('/')
27-
}
28-
}
29-
} catch (e) {
30-
console.error(e)
24+
if (!token || typeof token !== 'string') {
25+
processing.value = false
26+
return
27+
}
28+
29+
try {
30+
const response = await $fetch<{ token: string }>(
31+
`${config.public.callbackUrl}?token=${token}`,
32+
{ method: 'GET' },
33+
)
34+
35+
if (response && response.token) {
36+
setAccessToken(response.token)
37+
38+
const redirectPath =
39+
redirect && typeof redirect === 'string' ? redirect : '/'
40+
41+
// Use replace to prevent back button issues
42+
await navigateTo(redirectPath, { replace: true })
43+
processing.value = false
44+
} else {
45+
processing.value = false
3146
}
47+
} catch {
48+
processing.value = false
3249
}
3350
})
3451
</script>

0 commit comments

Comments
 (0)