From fad9cacd3e943ed54c9d00b9ea97980e5c0f7c3a Mon Sep 17 00:00:00 2001 From: AlexIves16 Date: Tue, 28 Apr 2026 14:50:13 +0500 Subject: [PATCH] fix: pwa, firebase and auth initial load issues --- app/composables/useAchievements.ts | 5 ++++- app/composables/useAuth.ts | 19 +++++++++++++++---- app/pages/canvas/index.vue | 4 ++-- app/pages/canvases.vue | 27 ++++++++++++++++++++++----- app/pages/profile.vue | 27 ++++++++++++++++++++++----- nuxt.config.ts | 1 - server/docker-compose.yml | 10 +++++----- session-2026-04-23.canvas | 2 ++ 8 files changed, 72 insertions(+), 23 deletions(-) diff --git a/app/composables/useAchievements.ts b/app/composables/useAchievements.ts index 233f551..d62dbdb 100644 --- a/app/composables/useAchievements.ts +++ b/app/composables/useAchievements.ts @@ -14,7 +14,10 @@ export const useAchievements = () => { const loadAchievements = async () => { pending.value = true try { - const data = await $fetch<{ achievements: Achievement[], stats: { total: number, completedTasks: number } }>('/api/achievements') + const auth = useAuth() + const data = await $fetch<{ achievements: Achievement[], stats: { total: number, completedTasks: number } }>('/api/achievements', { + headers: { Authorization: `Bearer ${auth.token.value}` } + }) achievements.value = data.achievements || [] stats.value = data.stats || { total: 0, completedTasks: 0 } } catch (e) { diff --git a/app/composables/useAuth.ts b/app/composables/useAuth.ts index 2deecda..abfaa47 100644 --- a/app/composables/useAuth.ts +++ b/app/composables/useAuth.ts @@ -51,10 +51,21 @@ export const useAuth = () => { const initAuth = () => { const auth = getAuth() onAuthStateChanged(auth, async (firebaseUser) => { - if (firebaseUser) { - const idToken = await firebaseUser.getIdToken() - if (idToken !== token.value) { - token.value = idToken + // If user is authenticated in Firebase but we lost our backend token, try to restore + if (firebaseUser && !token.value) { + try { + const idToken = await firebaseUser.getIdToken() + const res = await $fetch<{ token: string; user: User }>('/api/auth/google', { + method: 'POST', + body: { idToken } + }) + token.value = res.token + + if (useRoute().path === '/login') { + navigateTo('/') + } + } catch (e) { + console.error('Failed to restore backend auth from Firebase', e) } } }) diff --git a/app/pages/canvas/index.vue b/app/pages/canvas/index.vue index cab424c..e88ab30 100644 --- a/app/pages/canvas/index.vue +++ b/app/pages/canvas/index.vue @@ -87,9 +87,9 @@ const createNewCanvas = () => { // Redirect to specific canvas if ID is provided onMounted(() => { - if (auth.user) { + if (auth.isAuthenticated.value) { // Load user's canvases - console.log('Loading canvases for user:', auth.user.email) + console.log('Loading canvases for user:', auth.user.value?.email) } }) diff --git a/app/pages/canvases.vue b/app/pages/canvases.vue index 478929d..852d901 100644 --- a/app/pages/canvases.vue +++ b/app/pages/canvases.vue @@ -119,10 +119,19 @@ definePageMeta({ const auth = useAuth() const user = computed(() => auth.user) -const authFetch = (url, opts = {}) => $fetch(url, { - ...opts, - headers: { Authorization: `Bearer ${auth.token.value}`, ...opts.headers } -}) +const authFetch = async (url, opts = {}) => { + try { + return await $fetch(url, { + ...opts, + headers: { Authorization: `Bearer ${auth.token.value}`, ...opts.headers } + }) + } catch (error) { + if (error.response?.status === 401) { + auth.logout() + } + throw error + } +} const canvases = ref([]) const userGroups = ref([]) @@ -287,5 +296,13 @@ const getGroupName = (groupId) => { return group?.name || 'Unknown Group' } -onMounted(loadData) +onMounted(() => { + if (auth.isAuthenticated.value) { + loadData() + } +}) + +watch(() => auth.isAuthenticated.value, (isAuth) => { + if (isAuth) loadData() +}) diff --git a/app/pages/profile.vue b/app/pages/profile.vue index 3fb26df..2d2c230 100644 --- a/app/pages/profile.vue +++ b/app/pages/profile.vue @@ -170,10 +170,19 @@ definePageMeta({ const auth = useAuth() const route = useRoute() -const authFetch = (url, opts = {}) => $fetch(url, { - ...opts, - headers: { Authorization: `Bearer ${auth.token.value}`, ...opts.headers } -}) +const authFetch = async (url, opts = {}) => { + try { + return await $fetch(url, { + ...opts, + headers: { Authorization: `Bearer ${auth.token.value}`, ...opts.headers } + }) + } catch (error) { + if (error.response?.status === 401) { + auth.logout() + } + throw error + } +} const profileId = computed(() => route.params.id || auth.user.value?.id) const currentUserId = computed(() => auth.user.value?.id || '') @@ -329,6 +338,14 @@ const followButtonClass = computed(() => { : 'bg-blue-600 hover:bg-blue-500 text-white' }) -onMounted(loadProfile) +onMounted(() => { + if (auth.isAuthenticated.value) { + loadProfile() + } +}) + +watch(() => auth.isAuthenticated.value, (isAuth) => { + if (isAuth) loadProfile() +}) watch(profileId, loadProfile) diff --git a/nuxt.config.ts b/nuxt.config.ts index 8d52876..962ecf5 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -17,7 +17,6 @@ export default defineNuxtConfig({ pwa: { registerType: 'autoUpdate', workbox: { - navigateFallback: '/', globPatterns: ['**/*.{js,css,html,png,svg,ico}'], }, client: { diff --git a/server/docker-compose.yml b/server/docker-compose.yml index 46d343f..eb7b7ed 100644 --- a/server/docker-compose.yml +++ b/server/docker-compose.yml @@ -77,11 +77,11 @@ services: GITEA_MINDMAP_REPO: ${GITEA_MINDMAP_REPO:-MMAVTEX} GITEA_PROJECT_REPO: ${GITEA_PROJECT_REPO:-XFlow} DATABASE_URL: postgresql://xflow:${XFLOW_DB_PASSWORD:-xflow_pass}@postgres:5432/xflow - NUXT_PUBLIC_FIREBASE_API_KEY: ${NUXT_PUBLIC_FIREBASE_API_KEY} - NUXT_PUBLIC_FIREBASE_AUTH_DOMAIN: ${NUXT_PUBLIC_FIREBASE_AUTH_DOMAIN} - NUXT_PUBLIC_FIREBASE_PROJECT_ID: ${NUXT_PUBLIC_FIREBASE_PROJECT_ID} - NUXT_PUBLIC_FIREBASE_APP_ID: ${NUXT_PUBLIC_FIREBASE_APP_ID} - NUXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID: ${NUXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID} + NUXT_PUBLIC_FIREBASE_API_KEY: ${NUXT_PUBLIC_FIREBASE_API_KEY:-${FIREBASE_API_KEY}} + NUXT_PUBLIC_FIREBASE_AUTH_DOMAIN: ${NUXT_PUBLIC_FIREBASE_AUTH_DOMAIN:-${FIREBASE_AUTH_DOMAIN}} + NUXT_PUBLIC_FIREBASE_PROJECT_ID: ${NUXT_PUBLIC_FIREBASE_PROJECT_ID:-${FIREBASE_PROJECT_ID}} + NUXT_PUBLIC_FIREBASE_APP_ID: ${NUXT_PUBLIC_FIREBASE_APP_ID:-${FIREBASE_APP_ID}} + NUXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID: ${NUXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID:-${FIREBASE_MESSAGING_SENDER_ID}} volumes: - /opt/xflow/.output:/app/.output - /opt/xflow/prisma:/app/prisma:ro diff --git a/session-2026-04-23.canvas b/session-2026-04-23.canvas index a676148..2d6a9f5 100644 --- a/session-2026-04-23.canvas +++ b/session-2026-04-23.canvas @@ -156,3 +156,5 @@ { "id": "e16", "fromNode": "solution", "fromSide": "right", "toNode": "arch", "toSide": "left" } ] } + +