feat: добавлена поддержка PWA (v3.8.0)
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 47s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 47s
- Установлен vite-plugin-pwa для поддержки Progressive Web App - Созданы иконки приложения для всех платформ (iOS, Android, Desktop) - Настроен Service Worker с кэшированием статики и API данных - Добавлен компонент PWAUpdatePrompt для уведомлений об обновлениях - Обновлены конфигурации nginx для корректной работы Service Worker - Добавлены PWA meta-теги в index.html - Создан скрипт generate-icons.cjs для генерации иконок
This commit is contained in:
@@ -14,6 +14,7 @@ import TodoistIntegration from './components/TodoistIntegration'
|
||||
import TelegramIntegration from './components/TelegramIntegration'
|
||||
import { AuthProvider, useAuth } from './components/auth/AuthContext'
|
||||
import AuthScreen from './components/auth/AuthScreen'
|
||||
import PWAUpdatePrompt from './components/PWAUpdatePrompt'
|
||||
|
||||
// API endpoints (используем относительные пути, проксирование настроено в nginx/vite)
|
||||
const CURRENT_WEEK_API_URL = '/playlife-feed'
|
||||
@@ -962,6 +963,7 @@ function App() {
|
||||
return (
|
||||
<AuthProvider>
|
||||
<AppContent />
|
||||
<PWAUpdatePrompt />
|
||||
</AuthProvider>
|
||||
)
|
||||
}
|
||||
|
||||
59
play-life-web/src/components/PWAUpdatePrompt.jsx
Normal file
59
play-life-web/src/components/PWAUpdatePrompt.jsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useRegisterSW } from 'virtual:pwa-register/react'
|
||||
|
||||
export default function PWAUpdatePrompt() {
|
||||
const [showPrompt, setShowPrompt] = useState(false)
|
||||
|
||||
const {
|
||||
needRefresh: [needRefresh, setNeedRefresh],
|
||||
updateServiceWorker
|
||||
} = useRegisterSW({
|
||||
onRegistered(r) {
|
||||
console.log('SW зарегистрирован:', r)
|
||||
},
|
||||
onRegisterError(error) {
|
||||
console.log('SW ошибка регистрации:', error)
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (needRefresh) {
|
||||
setShowPrompt(true)
|
||||
}
|
||||
}, [needRefresh])
|
||||
|
||||
const handleUpdate = () => {
|
||||
updateServiceWorker(true)
|
||||
setShowPrompt(false)
|
||||
}
|
||||
|
||||
const handleDismiss = () => {
|
||||
setNeedRefresh(false)
|
||||
setShowPrompt(false)
|
||||
}
|
||||
|
||||
if (!showPrompt) return null
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-24 left-4 right-4 md:left-auto md:right-4 md:w-80 bg-white rounded-lg shadow-lg border border-gray-200 p-4 z-50">
|
||||
<p className="text-sm text-gray-700 mb-3">
|
||||
Доступна новая версия приложения
|
||||
</p>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={handleUpdate}
|
||||
className="flex-1 px-3 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700"
|
||||
>
|
||||
Обновить
|
||||
</button>
|
||||
<button
|
||||
onClick={handleDismiss}
|
||||
className="px-3 py-2 bg-gray-100 text-gray-700 text-sm rounded-md hover:bg-gray-200"
|
||||
>
|
||||
Позже
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user