feat: добавлена поддержка PWA (v3.8.0)
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:
poignatov
2026-01-10 21:46:54 +03:00
parent dde8858d7d
commit 11e0d0074c
16 changed files with 5449 additions and 8 deletions

View File

@@ -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>
)
}

View 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>
)
}