Merge version_2 into main #2
10
public/manifest.json
Normal file
10
public/manifest.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "Rosslyn Inn & Suites", "short_name": "Rosslyn Inn", "description": "Experience timeless comfort and hospitality at Rosslyn Inn and Suites", "start_url": "/", "display": "standalone", "background_color": "#ffffff", "theme_color": "#000000", "orientation": "portrait-primary", "icons": [
|
||||
{
|
||||
"src": "/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any"
|
||||
}
|
||||
]
|
||||
}
|
||||
96
public/sw.js
Normal file
96
public/sw.js
Normal file
@@ -0,0 +1,96 @@
|
||||
const CACHE_NAME = 'rosslyn-inn-v1';
|
||||
const urlsToCache = [
|
||||
'/',
|
||||
'/index.html',
|
||||
'/manifest.json'
|
||||
];
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_NAME)
|
||||
.then((cache) => {
|
||||
console.log('Opened cache');
|
||||
return cache.addAll(urlsToCache);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Cache opening failed:', error);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
const { request } = event;
|
||||
const url = new URL(request.url);
|
||||
|
||||
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.method !== 'GET') {
|
||||
return;
|
||||
}
|
||||
|
||||
event.respondWith(
|
||||
caches.match(request)
|
||||
.then((response) => {
|
||||
if (response) {
|
||||
return response;
|
||||
}
|
||||
|
||||
return fetch(request)
|
||||
.then((response) => {
|
||||
if (!response || response.status !== 200 || response.type === 'error') {
|
||||
return response;
|
||||
}
|
||||
|
||||
const responseToCache = response.clone();
|
||||
const isImage = request.headers.get('accept')?.includes('image');
|
||||
const isFont = request.headers.get('accept')?.includes('font') || request.url.includes('.woff') || request.url.includes('.woff2');
|
||||
const isScript = request.headers.get('accept')?.includes('javascript');
|
||||
const isStylesheet = request.headers.get('accept')?.includes('text/css');
|
||||
|
||||
if (isImage || isFont || isScript || isStylesheet) {
|
||||
caches.open(CACHE_NAME)
|
||||
.then((cache) => {
|
||||
cache.put(request, responseToCache);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Cache update failed:', error);
|
||||
});
|
||||
}
|
||||
|
||||
return response;
|
||||
})
|
||||
.catch(() => {
|
||||
if (request.destination === 'image') {
|
||||
return new Response(
|
||||
'<svg role="img" aria-label="Placeholder" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect fill="#ddd" width="100" height="100"/></svg>',
|
||||
{ headers: { 'Content-Type': 'image/svg+xml', 'Cache-Control': 'no-store' } }
|
||||
);
|
||||
}
|
||||
return new Response('Network request failed and no cache available', {
|
||||
status: 503,
|
||||
statusText: 'Service Unavailable',
|
||||
headers: new Headers({
|
||||
'Content-Type': 'text/plain'
|
||||
})
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(
|
||||
caches.keys().then((cacheNames) => {
|
||||
return Promise.all(
|
||||
cacheNames.map((cacheName) => {
|
||||
if (cacheName !== CACHE_NAME) {
|
||||
console.log('Deleting old cache:', cacheName);
|
||||
return caches.delete(cacheName);
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -47,6 +47,64 @@ export default function RootLayout({
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head>
|
||||
<script async src="https://cdn.jsdelivr.net/npm/workbox-window@7/build/workbox-window.umd.js"></script>
|
||||
<script>
|
||||
{
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', async () => {
|
||||
try {
|
||||
const registration = await navigator.serviceWorker.register('/sw.js');
|
||||
console.log('Service Worker registered:', registration);
|
||||
} catch (error) {
|
||||
console.error('Service Worker registration failed:', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
{
|
||||
if (typeof window !== 'undefined' && 'performance' in window) {
|
||||
window.addEventListener('load', () => {
|
||||
const perfData = window.performance.timing;
|
||||
const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart;
|
||||
const resourcesPerf = window.performance.getEntriesByType('resource');
|
||||
|
||||
const metrics = {
|
||||
pageLoadTime: pageLoadTime,
|
||||
domInteractive: perfData.domInteractive - perfData.navigationStart,
|
||||
domComplete: perfData.domComplete - perfData.navigationStart,
|
||||
resourceCount: resourcesPerf.length,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
if ('sendBeacon' in navigator) {
|
||||
navigator.sendBeacon('/api/metrics', JSON.stringify(metrics));
|
||||
}
|
||||
|
||||
console.log('Performance Metrics:', metrics);
|
||||
});
|
||||
|
||||
if ('PerformanceObserver' in window) {
|
||||
const observer = new PerformanceObserver((list) => {
|
||||
for (const entry of list.getEntries()) {
|
||||
console.log('Web Vital:', {
|
||||
name: entry.name,
|
||||
value: entry.value,
|
||||
rating: entry.rating
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe({
|
||||
entryTypes: ['largest-contentful-paint', 'first-input', 'layout-shift']
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<ServiceWrapper>
|
||||
<body
|
||||
className={`${halant.variable} ${inter.variable} ${sourceSans3.variable} antialiased`}
|
||||
@@ -1424,4 +1482,4 @@ export default function RootLayout({
|
||||
</ServiceWrapper>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -206,4 +206,4 @@ export default function LandingPage() {
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user