diff --git a/apps/web/app/composables/useAuth.ts b/apps/web/app/composables/useAuth.ts index 7e9879b..fe02db1 100644 --- a/apps/web/app/composables/useAuth.ts +++ b/apps/web/app/composables/useAuth.ts @@ -1,4 +1,5 @@ import { jwtDecode } from 'jwt-decode' +import { getApps } from 'firebase/app' import { getAuth, signInWithPopup, GoogleAuthProvider, signOut, onAuthStateChanged } from 'firebase/auth' interface User { @@ -15,8 +16,6 @@ export const useAuth = () => { sameSite: 'lax' }) - const isInitializing = useState('auth_initializing', () => true) - const user = computed(() => { if (!token.value) return null try { @@ -30,6 +29,10 @@ export const useAuth = () => { const isAdmin = computed(() => user.value?.role === 'admin') const googleSignIn = async () => { + if (!getApps().length) { + alert('Ошибка: Firebase не настроен. Проверьте переменные окружения FIREBASE_API_KEY в Coolify.') + return + } const auth = getAuth() const provider = new GoogleAuthProvider() const result = await signInWithPopup(auth, provider) @@ -46,8 +49,10 @@ export const useAuth = () => { const logout = async () => { try { - const auth = getAuth() - await signOut(auth) + if (getApps().length) { + const auth = getAuth() + await signOut(auth) + } } catch (e) { console.warn('[Firebase] Sign out failed or not initialized', e) } finally { @@ -58,37 +63,44 @@ export const useAuth = () => { const initAuth = () => { if (process.server) return - - const auth = getAuth() - const unsubscribe = onAuthStateChanged(auth, async (firebaseUser) => { - // 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') { - await navigateTo('/') + if (!getApps().length) { + console.warn('[Firebase] Firebase App not initialized, skipping onAuthStateChanged.') + return + } + + try { + const auth = getAuth() + const unsubscribe = onAuthStateChanged(auth, async (firebaseUser) => { + // 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') { + await navigateTo('/') + } + } catch (e) { + console.error('Failed to restore backend auth from Firebase', e) } - } catch (e) { - console.error('Failed to restore backend auth from Firebase', e) } - } - isInitializing.value = false - }) - return unsubscribe + }) + + onUnmounted(() => unsubscribe()) + } catch (err) { + console.warn('[Firebase] Auth initialization skipped:', err) + } } return { - token, user, + token, isAuthenticated, isAdmin, - isInitializing, googleSignIn, logout, initAuth diff --git a/apps/web/public/favicon.ico b/apps/web/public/favicon.ico new file mode 100644 index 0000000..32e99af Binary files /dev/null and b/apps/web/public/favicon.ico differ diff --git a/apps/web/public/favicon.png b/apps/web/public/favicon.png new file mode 100644 index 0000000..c309f17 Binary files /dev/null and b/apps/web/public/favicon.png differ diff --git a/apps/web/public/favicon.svg b/apps/web/public/favicon.svg new file mode 100644 index 0000000..6dadbe0 --- /dev/null +++ b/apps/web/public/favicon.svg @@ -0,0 +1,4 @@ + + + N + diff --git a/apps/web/public/manifest.json b/apps/web/public/manifest.json new file mode 100644 index 0000000..c96845b --- /dev/null +++ b/apps/web/public/manifest.json @@ -0,0 +1,34 @@ +{ + "id": "/", + "name": "XFlow", + "short_name": "XFlow", + "description": "XFlow Intelligent Unified Platform", + "lang": "ru", + "categories": ["productivity", "business"], + "theme_color": "#090A0F", + "background_color": "#090A0F", + "display": "standalone", + "orientation": "portrait", + "start_url": "/", + "scope": "/", + "icons": [ + { + "src": "/pwa-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/pwa-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/pwa-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/apps/web/public/manifest.webmanifest b/apps/web/public/manifest.webmanifest new file mode 100644 index 0000000..c96845b --- /dev/null +++ b/apps/web/public/manifest.webmanifest @@ -0,0 +1,34 @@ +{ + "id": "/", + "name": "XFlow", + "short_name": "XFlow", + "description": "XFlow Intelligent Unified Platform", + "lang": "ru", + "categories": ["productivity", "business"], + "theme_color": "#090A0F", + "background_color": "#090A0F", + "display": "standalone", + "orientation": "portrait", + "start_url": "/", + "scope": "/", + "icons": [ + { + "src": "/pwa-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/pwa-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/pwa-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/apps/web/public/maskable-icon-512x512.svg b/apps/web/public/maskable-icon-512x512.svg new file mode 100644 index 0000000..1a70ffe --- /dev/null +++ b/apps/web/public/maskable-icon-512x512.svg @@ -0,0 +1,4 @@ + + + N + diff --git a/apps/web/public/pwa-192x192.png b/apps/web/public/pwa-192x192.png new file mode 100644 index 0000000..f012412 Binary files /dev/null and b/apps/web/public/pwa-192x192.png differ diff --git a/apps/web/public/pwa-192x192.svg b/apps/web/public/pwa-192x192.svg new file mode 100644 index 0000000..99dbdcc --- /dev/null +++ b/apps/web/public/pwa-192x192.svg @@ -0,0 +1,4 @@ + + + N + diff --git a/apps/web/public/pwa-512x512.png b/apps/web/public/pwa-512x512.png new file mode 100644 index 0000000..f1dba4e Binary files /dev/null and b/apps/web/public/pwa-512x512.png differ diff --git a/apps/web/public/pwa-512x512.svg b/apps/web/public/pwa-512x512.svg new file mode 100644 index 0000000..2b6afe2 --- /dev/null +++ b/apps/web/public/pwa-512x512.svg @@ -0,0 +1,4 @@ + + + N +