Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions app/PwaRegister.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"use client";

import { useEffect } from "react";

export default function PwaRegister() {
useEffect(() => {
// Force registration on local dev server
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker
.register("/sw.js")
.then((registration) => {
console.log("Service Worker registered: ", registration.scope);
})
.catch((error) => {
console.error("Service Worker registration failed: ", error);
});
});
}
}, []);

return null;
}

16 changes: 12 additions & 4 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import Providers from "./providers";
import PwaRegister from "./PwaRegister";

const inter = Inter({
subsets: ["latin"],
Expand All @@ -11,6 +12,11 @@ const inter = Inter({
export const metadata: Metadata = {
title: "LinkID",
description: "Your professional identity, simplified.",
appleWebApp: {
capable: true,
statusBarStyle: "default",
title: "LinkID",
},
};

export default function RootLayout({
Expand All @@ -20,10 +26,12 @@ export default function RootLayout({
}>) {
return (
<html lang="en" suppressHydrationWarning>
<body
className={`${inter.variable} antialiased`}
>
<Providers>{children}</Providers>
<body className={`${inter.variable} antialiased`}>
<Providers>
{children}
</Providers>
{/* Safely registers the service worker on the client side */}
<PwaRegister />
</body>
</html>
);
Expand Down
8 changes: 7 additions & 1 deletion app/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
{
"name": "LinkID",
"short_name": "LinkID",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#6366f1",
"orientation": "portrait-primary",
"icons": [
{
"src": "/web-app-manifest-192x192.png",
Expand Down Expand Up @@ -30,4 +35,5 @@
"theme_color": "#6366f1",
"background_color": "#ffffff",
"display": "standalone"
}
}

47 changes: 47 additions & 0 deletions app/sw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const CACHE_NAME = 'linkid-cache-v1';
const ASSETS_TO_CACHE = [
'/',
'/offline.html', // Create a simple offline page if you want a fallback
];

// Install Service Worker
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(ASSETS_TO_CACHE);
})
);
self.skipWaiting();
});

// Activate Service Worker
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cache) => {
if (cache !== CACHE_NAME) {
return caches.delete(cache);
}
})
);
})
);
self.clients.claim();
});

// Fetch Assets
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
if (cachedResponse) {
return cachedResponse;
}
return fetch(event.request).catch(() => {
// Fallback when network fails
return caches.match('/offline.html');
});
})
);
});