feat: Improve PWA standalone experience and redirect to dashboard (#90)
## Summary - Add service worker registration and `viewport-fit=cover` for proper iOS standalone mode (no Safari chrome) - Change manifest `start_url` to `/dashboard` so PWA users skip the landing page - Add tests for PWA configuration ## Test plan - [x] Deploy and re-add PWA to iOS home screen — should open as standalone (no address bar) - [x] PWA launch should go to `/dashboard` instead of the landing page - [x] Non-authenticated PWA users should be redirected to login Closes #71
This commit is contained in:
parent
dfd8bf8092
commit
b4897ef425
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "Whisper Money",
|
"name": "Whisper Money",
|
||||||
"short_name": "Whisper Money",
|
"short_name": "Whisper Money",
|
||||||
"description": "Track your finances privately and securely",
|
"description": "Track your finances privately and securely",
|
||||||
"start_url": "/",
|
"start_url": "/dashboard",
|
||||||
"scope": "/",
|
"scope": "/",
|
||||||
"id": "/",
|
"id": "/",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
const CACHE_NAME = 'whisper-money-v1';
|
||||||
|
|
||||||
|
self.addEventListener('install', (event) => {
|
||||||
|
self.skipWaiting();
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('activate', (event) => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches.keys().then((cacheNames) =>
|
||||||
|
Promise.all(
|
||||||
|
cacheNames
|
||||||
|
.filter((name) => name !== CACHE_NAME)
|
||||||
|
.map((name) => caches.delete(name)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
self.clients.claim();
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('fetch', (event) => {
|
||||||
|
// Let all requests pass through to the network.
|
||||||
|
// The app handles offline state via IndexedDB (Dexie).
|
||||||
|
});
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" @class(['dark' => ($appearance ?? 'system') == 'dark'])>
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" @class(['dark' => ($appearance ?? 'system') == 'dark'])>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||||
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
|
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
|
||||||
<meta name="theme-color" content="#383838" media="(prefers-color-scheme: dark)">
|
<meta name="theme-color" content="#383838" media="(prefers-color-scheme: dark)">
|
||||||
|
|
||||||
|
|
@ -62,5 +62,11 @@
|
||||||
event-uuid="696e6c66-33e0-482c-aa4a-a21410ec38c8"
|
event-uuid="696e6c66-33e0-482c-aa4a-a21410ec38c8"
|
||||||
src="https://tracker.metricswave.com/js/visits.js"
|
src="https://tracker.metricswave.com/js/visits.js"
|
||||||
></script>
|
></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.register('/sw.js', { scope: '/' });
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
test('service worker exists', function () {
|
||||||
|
expect(file_exists(public_path('sw.js')))->toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('web manifest starts at dashboard with standalone display', function () {
|
||||||
|
$manifest = json_decode(file_get_contents(public_path('favicon/site.webmanifest')), true);
|
||||||
|
|
||||||
|
expect($manifest['start_url'])->toBe('/dashboard')
|
||||||
|
->and($manifest['display'])->toBe('standalone');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('app template includes pwa meta tags and service worker registration', function () {
|
||||||
|
$response = $this->get('/');
|
||||||
|
|
||||||
|
$response->assertStatus(200)
|
||||||
|
->assertSee('apple-mobile-web-app-capable', false)
|
||||||
|
->assertSee('serviceWorker', false)
|
||||||
|
->assertSee('viewport-fit=cover', false);
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue