From 2e4975a901a30cd76a46bcf0741270b4a16dd9b7 Mon Sep 17 00:00:00 2001 From: lizerk Date: Thu, 16 Apr 2026 20:04:21 +0300 Subject: [PATCH] feat: add installable pwa baseline --- frontend/next-env.d.ts | 2 +- frontend/public/apple-touch-icon.png | Bin 0 -> 7500 bytes frontend/public/icon-192.png | Bin 0 -> 8464 bytes frontend/public/icon-512-maskable.png | Bin 0 -> 18218 bytes frontend/public/icon-512.png | Bin 0 -> 25631 bytes frontend/public/sw.js | 73 +++++++++++++- frontend/src/app/layout.tsx | 22 +++- frontend/src/app/manifest.ts | 32 ++++++ frontend/src/app/settings/page.tsx | 58 +++++++++++ frontend/src/components/AppShell.tsx | 18 +++- frontend/src/components/BigCalendar.tsx | 20 +++- .../components/CalendarParticipantsModal.tsx | 12 +-- .../components/CalendarSubscriptionsModal.tsx | 6 +- frontend/src/components/Providers.tsx | 7 +- .../src/components/calendar/CalendarCard.tsx | 7 +- frontend/src/contexts/PwaContext.tsx | 95 ++++++++++++++++++ frontend/src/hooks/useCalendarModals.ts | 18 ++-- frontend/src/lib/push.ts | 23 +---- frontend/src/lib/pwa.ts | 49 +++++++++ frontend/src/services/calendarService.ts | 19 ++++ 20 files changed, 411 insertions(+), 50 deletions(-) create mode 100644 frontend/public/apple-touch-icon.png create mode 100644 frontend/public/icon-192.png create mode 100644 frontend/public/icon-512-maskable.png create mode 100644 frontend/public/icon-512.png create mode 100644 frontend/src/app/manifest.ts create mode 100644 frontend/src/contexts/PwaContext.tsx create mode 100644 frontend/src/lib/pwa.ts diff --git a/frontend/next-env.d.ts b/frontend/next-env.d.ts index c4b7818f..9edff1c7 100644 --- a/frontend/next-env.d.ts +++ b/frontend/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/dev/types/routes.d.ts"; +import "./.next/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/frontend/public/apple-touch-icon.png b/frontend/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1c3c3402eadaaf36fb32f8930b9252c5b92882c9 GIT binary patch literal 7500 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 literal 0 HcmV?d00001 diff --git a/frontend/public/icon-512-maskable.png b/frontend/public/icon-512-maskable.png new file mode 100644 index 0000000000000000000000000000000000000000..e5e7cb63c16ac41aa6c6b3a0a17bb16e463c3592 GIT binary patch literal 18218 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 literal 0 HcmV?d00001 diff --git a/frontend/public/icon-512.png b/frontend/public/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..97c957000bd2b73e620b5aa895a9b3d9fb566e6f GIT binary patch literal 25631 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%0Ag~0|Xo-3& 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 JyMcQBKLGv84q^ZR literal 0 HcmV?d00001 diff --git a/frontend/public/sw.js b/frontend/public/sw.js index ec07d267..fa7cba04 100644 --- a/frontend/public/sw.js +++ b/frontend/public/sw.js @@ -7,6 +7,16 @@ */ const SW_VERSION = '2.0.0'; +const STATIC_CACHE = `eusrr-static-${SW_VERSION}`; +const PRECACHE_URLS = [ + '/manifest.webmanifest', + '/logo.png', + '/logo.webp', + '/icon-192.png', + '/icon-512.png', + '/icon-512-maskable.png', + '/apple-touch-icon.png', +]; // Настройки по умолчанию для уведомлений const DEFAULT_NOTIFICATION_OPTIONS = { @@ -22,8 +32,15 @@ const DEFAULT_NOTIFICATION_OPTIONS = { */ self.addEventListener('install', (event) => { console.log('[SW] Service Worker installing, version:', SW_VERSION); - // Немедленно активировать новую версию - self.skipWaiting(); + event.waitUntil( + caches + .open(STATIC_CACHE) + .then((cache) => cache.addAll(PRECACHE_URLS)) + .catch((error) => { + console.error('[SW] Failed to precache static assets:', error); + }) + .then(() => self.skipWaiting()) + ); }); /** @@ -31,8 +48,56 @@ self.addEventListener('install', (event) => { */ self.addEventListener('activate', (event) => { console.log('[SW] Service Worker activated, version:', SW_VERSION); - // Захватить все клиенты без перезагрузки - event.waitUntil(self.clients.claim()); + event.waitUntil( + caches.keys().then((cacheKeys) => + Promise.all( + cacheKeys.map((cacheKey) => { + if (cacheKey !== STATIC_CACHE && cacheKey.startsWith('eusrr-static-')) { + return caches.delete(cacheKey); + } + return Promise.resolve(false); + }) + ) + ).then(() => self.clients.claim()) + ); +}); + +self.addEventListener('fetch', (event) => { + const { request } = event; + + if (request.method !== 'GET') { + return; + } + + const url = new URL(request.url); + if (url.origin !== self.location.origin) { + return; + } + + const isApiRequest = url.pathname.startsWith('/api/'); + const isStaticAsset = + url.pathname.startsWith('/_next/static/') || + PRECACHE_URLS.includes(url.pathname) || + ['image', 'style', 'script', 'font', 'worker'].includes(request.destination); + + if (isApiRequest || !isStaticAsset) { + return; + } + + event.respondWith( + caches.open(STATIC_CACHE).then(async (cache) => { + const cachedResponse = await cache.match(request); + if (cachedResponse) { + return cachedResponse; + } + + const networkResponse = await fetch(request); + if (networkResponse.ok) { + cache.put(request, networkResponse.clone()).catch(() => undefined); + } + return networkResponse; + }) + ); }); /** diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index 9c831f2a..cd2f63c7 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -18,13 +18,31 @@ const geistMono = Geist_Mono({ export const metadata: Metadata = { title: "EUSRR - Корпоративная система", description: "Корпоративная система управления EUSRR", + applicationName: "EUSRR", + manifest: "/manifest.webmanifest", + appleWebApp: { + capable: true, + statusBarStyle: "default", + title: "EUSRR", + }, + icons: { + icon: [ + { url: "/icon-192.png", sizes: "192x192", type: "image/png" }, + { url: "/icon-512.png", sizes: "512x512", type: "image/png" }, + ], + apple: [{ url: "/apple-touch-icon.png", sizes: "180x180", type: "image/png" }], + }, }; export const viewport: Viewport = { - width: 'device-width', + width: "device-width", initialScale: 1, maximumScale: 1, - interactiveWidget: 'resizes-content', + interactiveWidget: "resizes-content", + themeColor: [ + { media: "(prefers-color-scheme: light)", color: "#f4f8fc" }, + { media: "(prefers-color-scheme: dark)", color: "#111923" }, + ], }; export default function RootLayout({ diff --git a/frontend/src/app/manifest.ts b/frontend/src/app/manifest.ts new file mode 100644 index 00000000..656b1569 --- /dev/null +++ b/frontend/src/app/manifest.ts @@ -0,0 +1,32 @@ +import type { MetadataRoute } from "next"; + +export default function manifest(): MetadataRoute.Manifest { + return { + name: "EUSRR", + short_name: "EUSRR", + description: "Корпоративная система управления EUSRR", + start_url: "/", + scope: "/", + display: "standalone", + background_color: "#111923", + theme_color: "#111923", + icons: [ + { + src: "/icon-192.png", + sizes: "192x192", + type: "image/png", + }, + { + src: "/icon-512.png", + sizes: "512x512", + type: "image/png", + }, + { + src: "/icon-512-maskable.png", + sizes: "512x512", + type: "image/png", + purpose: "maskable", + }, + ], + }; +} diff --git a/frontend/src/app/settings/page.tsx b/frontend/src/app/settings/page.tsx index 42b16670..e56b02e7 100644 --- a/frontend/src/app/settings/page.tsx +++ b/frontend/src/app/settings/page.tsx @@ -7,6 +7,7 @@ import { Bell, Check, Clock3, + Download, Eye, EyeOff, KeyRound, @@ -21,6 +22,7 @@ import { } from "lucide-react"; import { AppShell } from "@/components/AppShell"; +import { usePwa } from "@/contexts/PwaContext"; import { useMobileNavPlacement } from "@/contexts/MobileNavPlacementContext"; import { formatSessionDateTime, @@ -126,6 +128,7 @@ function SectionCard({ export default function SettingsPage() { const { mobileNavPlacement, setMobileNavPlacement } = useMobileNavPlacement(); + const { canInstall, install, isInstalled, isRegistrationReady } = usePwa(); const { activeVerbCount, avatarInputRef, @@ -400,6 +403,61 @@ export default function SettingsPage() { + +
+
+
+ + + +
+

Статус установки

+

+ {isInstalled + ? "Приложение уже установлено на это устройство." + : canInstall + ? "Приложение можно установить через системный prompt браузера." + : "Установка через браузер сейчас недоступна."} +

+
+
+
+ +
+
+ + + +
+

PWA-компоненты

+

+ Service Worker: {isRegistrationReady ? "зарегистрирован" : "не зарегистрирован"}. +

+
+ +
+
+
+
+
+
+ + {/* eslint-disable-next-line @next/next/no-img-element */} Логотип setUserMenuOpen((v) => !v)} > {user?.avatar ? ( + /* eslint-disable-next-line @next/next/no-img-element */ {userName} ) : ( userInitials @@ -216,6 +220,18 @@ function Header({ mobileNavPlacement, suppressMobileChrome = false, onOpenLeftNa className="app-action-ghost w-full px-4 py-2 text-left text-sm transition" onClick={() => { setUserMenuOpen(false); router.push('/settings'); }} >Настройки + {canInstall ? ( + + ) : null}