Skip to content

Commit cf61db5

Browse files
committed
PWA and Service worker includes Caching, Push Notitication
1 parent b1178cb commit cf61db5

10 files changed

+260
-0
lines changed

public/icons/icon-128x128.png

10.6 KB
Loading

public/icons/icon-192x192.png

18.8 KB
Loading

public/icons/icon-512x512.png

28.8 KB
Loading

public/icons/icon-72x72.png

6.79 KB
Loading

public/icons/icon-96x96.png

8.98 KB
Loading

public/manifest.json

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"name": "Symfony Authentication",
3+
"description": "Symfony Authentication.",
4+
"short_name": "SymfonyAuth",
5+
"theme_color": "#065b9f",
6+
"background_color": "#000000",
7+
"display": "standalone",
8+
"scope": "/",
9+
"start_url": "/",
10+
"icons": [
11+
{
12+
"src": "icons/icon-72x72.png",
13+
"sizes": "72x72",
14+
"type": "image/png"
15+
},
16+
{
17+
"src": "icons/icon-96x96.png",
18+
"sizes": "96x96",
19+
"type": "image/png"
20+
},
21+
{
22+
"src": "icons/icon-128x128.png",
23+
"sizes": "128x128",
24+
"type": "image/png"
25+
},
26+
{
27+
"src": "icons/icon-192x192.png",
28+
"sizes": "192x192",
29+
"type": "image/png"
30+
},
31+
{
32+
"src": "icons/icon-512x512.png",
33+
"sizes": "512x512",
34+
"type": "image/png"
35+
}
36+
],
37+
"shortcuts": [
38+
{
39+
"name": "List of Feature",
40+
"short_name": "Feature",
41+
"description": "List of Feature....",
42+
"url": "/feature.html",
43+
"icons": [{ "src": "/images/icons/icon-96x96.png", "sizes": "96x96" }]
44+
},
45+
{
46+
"name": "List of Pricing",
47+
"short_name": "Price",
48+
"description": "List of pricing....",
49+
"url": "/pricing.html",
50+
"icons": [{ "src": "/images/icons/icon-96x96.png", "sizes": "96x96" }]
51+
}
52+
],
53+
"splash_pages": "/splash.html"
54+
}

public/offline.html

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Offline</title>
6+
<link rel="stylesheet" href="css/app.css">
7+
<link rel="manifest" href="manifest.json">
8+
9+
</head>
10+
<body>
11+
<div class="container">
12+
<nav class="navbar navbar-expand-lg navbar-light bg-light">
13+
<div class="container-fluid">
14+
<a class="navbar-brand" href="#">Navbar</a>
15+
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup"
16+
aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
17+
<span class="navbar-toggler-icon"></span>
18+
</button>
19+
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
20+
<div class="navbar-nav">
21+
<a class="nav-link active" aria-current="page" href="/">Home</a>
22+
<a class="nav-link" href="/">Your Link</a>
23+
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
24+
</div>
25+
</div>
26+
</div>
27+
</nav>
28+
<div class="card-group" id="image-container">
29+
<h1>Sorry we you are offline</h1>
30+
</div>
31+
</div>
32+
<script type="text/javascript">
33+
34+
window.addEventListener('load', async e => {
35+
if ('serviceWorker' in navigator) {
36+
try {
37+
navigator.serviceWorker.register('/serviceWorker.js');
38+
} catch (e) {
39+
console.log(e.message);
40+
}
41+
}
42+
});
43+
</script>
44+
</body>
45+
</html>

public/serviceWorker.js

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
const staticAssets = [
2+
'offline.html',
3+
'manifest.json',
4+
'/css/app.css',
5+
'/js/app.js',
6+
'/js/vendor.js',
7+
'/js/manifest.js',
8+
];
9+
//Will cache any url from this domain while fetch
10+
const dynamicAssetDomain = [
11+
'tfhub.dev',
12+
'storage.googleapis.com'
13+
];
14+
15+
const CACHE_VERSION = 1;
16+
const CURRENT_CACHES = {
17+
static: 'static-assets-v' + CACHE_VERSION,
18+
dynamic: 'dynamic-assets-v' + CACHE_VERSION
19+
};
20+
21+
self.addEventListener('install', async event => {
22+
const cache = await caches.open(CURRENT_CACHES.static);
23+
24+
await cache.addAll(staticAssets);
25+
self.skipWaiting();
26+
});
27+
28+
self.addEventListener('activate', function (event) {
29+
// Delete all caches that aren't named in CURRENT_CACHES.
30+
var expectedCacheNamesSet = new Set(Object.values(CURRENT_CACHES));
31+
if (self.registration.navigationPreload) {
32+
// Enable navigation preloads!
33+
self.registration.navigationPreload.enable();
34+
}
35+
event.waitUntil(
36+
caches.keys().then(function (cacheNames) {
37+
return Promise.all(
38+
cacheNames.map(function (cacheName) {
39+
if (!expectedCacheNamesSet.has(cacheName)) {
40+
// If this cache name isn't present in the set of "expected" cache names, then delete it.
41+
return caches.delete(cacheName);
42+
}
43+
})
44+
);
45+
})
46+
);
47+
});
48+
49+
50+
self.addEventListener('fetch', event => {
51+
const req = event.request;
52+
event.respondWith(cacheFirst(req, event));
53+
});
54+
55+
async function cacheFirst(req, event) {
56+
try {
57+
const cachedResponse = await caches.match(req);
58+
if (cachedResponse) {
59+
return cachedResponse
60+
}
61+
62+
const response = await event.preloadResponse;
63+
if (response) {
64+
return response
65+
}
66+
67+
return networkFirst(req);
68+
} catch (e) {
69+
if (req.mode === 'navigate') {
70+
return caches.match('/offline.html');
71+
}
72+
}
73+
74+
}
75+
76+
async function networkFirst(req) {
77+
78+
const urlObj = new URL(req.url);
79+
80+
const res = await fetch(req).catch(() => {
81+
if (req.mode === 'navigate') {
82+
return caches.match('/offline.html');
83+
}
84+
});
85+
if (dynamicAssetDomain.indexOf(urlObj.hostname) !== -1) {
86+
const cache = await caches.open(CURRENT_CACHES.dynamic);
87+
88+
cache.put(req, res.clone());
89+
}
90+
91+
return res;
92+
}
93+
94+
self.addEventListener('push', event => {
95+
var data = event.data.json();
96+
var promise = self.registration.showNotification(data.title, data);
97+
event.waitUntil(promise);
98+
});
99+
100+
self.addEventListener('notificationclick', function (event) {
101+
const clickedNotification = event.notification;
102+
let url = '';
103+
if (typeof clickedNotification.data !== 'undefined' && typeof clickedNotification.data.url !== 'undefined') {
104+
url = clickedNotification.data.url;
105+
}
106+
clickedNotification.close();
107+
event.waitUntil(
108+
clients.matchAll({type: 'window'}).then(windowClients => {
109+
// Check if there is already a window/tab open with the target URL
110+
for (var i = 0; i < windowClients.length; i++) {
111+
var client = windowClients[i];
112+
// If so, just focus it.
113+
if (client.url === url && 'focus' in client) {
114+
return client.focus().reload();
115+
}
116+
}
117+
// If not, then open the target URL in a new window/tab.
118+
if (clients.openWindow) {
119+
return clients.openWindow(url);
120+
}
121+
})
122+
);
123+
});

public/splash.html

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Waiting</title>
6+
</head>
7+
<body>
8+
<h1>Awesome Content is loading.....</h1>
9+
</body>
10+
</html>

templates/app.html.twig

+28
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
<title>{% block title %}Welcome!{% endblock %}</title>
66
{{ encore_entry_link_tags('app') }}
77
{% block stylesheets %}{% endblock %}
8+
<link rel="manifest" href="/manifest.json">
9+
810
</head>
911
<body class="">
1012
<div class="bg-blue-800">
@@ -14,6 +16,11 @@
1416
<li class="flex-1">
1517
<a href="">Home</a>
1618
</li>
19+
<li class="flex-1">
20+
<a id="installAppBtn" href="javascript:void(0)" class="" style="display: none">
21+
Install App
22+
</a>
23+
</li>
1724
</ul>
1825
<div class="">
1926
<button class="block overflow-hidden rounded-full" id="dropdown-initiator">
@@ -79,5 +86,26 @@
7986
document.querySelector("#dropdown-container").classList.toggle("hidden")
8087
});
8188
</script>
89+
<script type="text/javascript">
90+
91+
window.addEventListener('load', async e => {
92+
if ('serviceWorker' in navigator) {
93+
try {
94+
navigator.serviceWorker.register('/serviceWorker.js');
95+
} catch (e) {
96+
console.log(e.message);
97+
}
98+
}
99+
});
100+
window.addEventListener('beforeinstallprompt', (e) => {
101+
// Prevent the mini-infobar from appearing on mobile
102+
e.preventDefault();
103+
// Stash the event so it can be triggered later.
104+
deferredPrompt = e;
105+
// Update UI notify the user they can install the PWA
106+
var buttonInstall = document.getElementById('installAppBtn');
107+
buttonInstall.style.display = "block";
108+
});
109+
</script>
82110
</body>
83111
</html>

0 commit comments

Comments
 (0)