fix(pwa,auth): serve manifest and icons from apps/web/public and prevent Firebase uninitialized crash
@@ -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<User | null>(() => {
|
||||
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 {
|
||||
if (getApps().length) {
|
||||
const auth = getAuth()
|
||||
await signOut(auth)
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[Firebase] Sign out failed or not initialized', e)
|
||||
} finally {
|
||||
@@ -58,7 +63,12 @@ export const useAuth = () => {
|
||||
|
||||
const initAuth = () => {
|
||||
if (process.server) return
|
||||
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
|
||||
@@ -78,17 +88,19 @@ export const useAuth = () => {
|
||||
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
|
||||
|
||||
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<rect width="32" height="32" rx="6" fill="#0f172a"/>
|
||||
<text x="16" y="22" font-size="18" text-anchor="middle" fill="#3b82f6" font-family="system-ui">N</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 252 B |
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
|
||||
<rect width="512" height="512" fill="#0f172a"/>
|
||||
<text x="256" y="350" font-size="280" text-anchor="middle" fill="#3b82f6" font-family="system-ui" font-weight="bold">N</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 273 B |
|
After Width: | Height: | Size: 46 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 192 192">
|
||||
<rect width="192" height="192" rx="24" fill="#0f172a"/>
|
||||
<text x="96" y="128" font-size="96" text-anchor="middle" fill="#3b82f6" font-family="system-ui" font-weight="bold">N</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 279 B |
|
After Width: | Height: | Size: 292 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
|
||||
<rect width="512" height="512" rx="64" fill="#0f172a"/>
|
||||
<text x="256" y="350" font-size="280" text-anchor="middle" fill="#3b82f6" font-family="system-ui" font-weight="bold">N</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 281 B |