diff --git a/next.config.mjs b/next.config.mjs index 5a5a7bc..7ed8758 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -8,6 +8,58 @@ const nextConfig = { }, // Enable standalone output for Docker deployments output: 'standalone', + async headers() { + return [ + { + source: '/manifest.json', + headers: [ + { + key: 'Content-Type', + value: 'application/manifest+json; charset=utf-8', + }, + ], + }, + { + source: '/sw.js', + headers: [ + { + key: 'Content-Type', + value: 'application/javascript; charset=utf-8', + }, + { + key: 'Cache-Control', + value: 'no-cache, no-store, must-revalidate', + }, + { + key: 'Service-Worker-Allowed', + value: '/', + }, + ], + }, + { + source: '/:path*', + headers: [ + { + key: 'Link', + value: '; rel="manifest"', + }, + ], + }, + ] + }, + webpack(config, { isServer, webpack }) { + if (!isServer) { + config.plugins.push( + new webpack.BannerPlugin({ + raw: true, + entryOnly: true, + banner: + "if(typeof window!=='undefined'&&'serviceWorker'in navigator){window.addEventListener('load',function(){navigator.serviceWorker.register('/sw.js',{scope:'/',updateViaCache:'none'});});}", + }) + ) + } + return config + }, } export default nextConfig diff --git a/public/icon-192.png b/public/icon-192.png new file mode 100644 index 0000000..c650dca Binary files /dev/null and b/public/icon-192.png differ diff --git a/public/icon-512.png b/public/icon-512.png new file mode 100644 index 0000000..dbf3877 Binary files /dev/null and b/public/icon-512.png differ diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..0d38e46 --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,31 @@ +{ + "name": "Aframp - Buy Crypto, Pay Bills & Send Money in Africa", + "short_name": "Aframp", + "description": "Africa's premier cNGN stablecoin payment platform. Buy crypto from ₦2,000, pay bills instantly, and send money across 12 African countries.", + "start_url": "/", + "scope": "/", + "display": "standalone", + "orientation": "portrait-primary", + "background_color": "#0a0a0a", + "theme_color": "#10b981", + "icons": [ + { + "src": "/icon-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/public/sw.js b/public/sw.js new file mode 100644 index 0000000..07a663d --- /dev/null +++ b/public/sw.js @@ -0,0 +1,34 @@ +const CACHE_NAME = 'aframp-static-v1' + +self.addEventListener('install', (event) => { + self.skipWaiting() +}) + +self.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys().then((keys) => + Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key))) + ).then(() => self.clients.claim()) + ) +}) + +self.addEventListener('fetch', (event) => { + if (event.request.method !== 'GET') return + + const url = new URL(event.request.url) + if (url.origin !== self.location.origin) return + if (url.pathname.startsWith('/api/')) return + + event.respondWith( + caches.open(CACHE_NAME).then((cache) => + fetch(event.request) + .then((response) => { + if (response.ok) { + cache.put(event.request, response.clone()) + } + return response + }) + .catch(() => cache.match(event.request)) + ) + ) +})