Aplikasi billing & manajemen ISP (fiber optic) — PWA pelanggan, portal teknisi & kolektor, admin panel lengkap, multi-vendor OLT, RADIUS, WhatsApp/Telegram, pembayaran QRIS. Kredit & lisensi (ISC): - Base kode & repo: alijayanet/billing-rtrw oleh Alijaya Net — terima kasih banyak atas base kode dan repo yang bermanfaat. - Add-on: GoWA, LibreSpeed/OpenSpeedTest, Uptime Kuma, notification-forwarder. - Dikembangkan menjadi OPEN-ISP oleh oxpoe — https://github.com/oxpoe/open-isp
124 lines
3.5 KiB
JavaScript
124 lines
3.5 KiB
JavaScript
/* Service Worker — Portal Pelanggan OPEN-ISP
|
|
Strategi: HTML & CSS/JS = network-first (selalu ambil terbaru saat online),
|
|
gambar & manifest & font = cache-first (jarang berubah).
|
|
Naikkan CACHE_NAME bila perlu purge (v4 → v5 → ...). */
|
|
const CACHE_NAME = 'customer-pwa-v7';
|
|
const PRECACHE_URLS = [
|
|
// Aset inti (network-first tapi disimpan untuk offline)
|
|
'/css/auth.css',
|
|
'/css/landing.css',
|
|
'/css/dashboard.css',
|
|
'/css/pages.css',
|
|
'/css/theme-toggle.css',
|
|
'/js/theme-toggle.js',
|
|
// Ikon & manifest PWA
|
|
'/img/icons/icon-192.png',
|
|
'/img/icons/icon-512.png',
|
|
'/img/icons/icon-maskable-192.png',
|
|
'/img/icons/icon-maskable-512.png',
|
|
'/img/icons/apple-touch-icon.png',
|
|
'/manifest.webmanifest',
|
|
'/manifest-landing.webmanifest',
|
|
// Halaman shell untuk fallback offline
|
|
'/offline.html',
|
|
'/customer/login',
|
|
'/customer/register'
|
|
];
|
|
|
|
self.addEventListener('install', (event) => {
|
|
self.skipWaiting();
|
|
event.waitUntil(
|
|
caches.open(CACHE_NAME).then((cache) =>
|
|
// Tambah satu-per-satu agar satu URL gagal tidak membatalkan semuanya
|
|
Promise.all(
|
|
PRECACHE_URLS.map((url) =>
|
|
cache.add(url).catch(() => null)
|
|
)
|
|
)
|
|
).catch(() => {})
|
|
);
|
|
});
|
|
|
|
self.addEventListener('activate', (event) => {
|
|
event.waitUntil(
|
|
Promise.all([
|
|
caches.keys().then((keys) =>
|
|
Promise.all(keys.map((k) => (k === CACHE_NAME ? null : caches.delete(k))))
|
|
),
|
|
self.clients.claim()
|
|
])
|
|
);
|
|
});
|
|
|
|
async function cacheFirst(request) {
|
|
const cached = await caches.match(request);
|
|
if (cached) return cached;
|
|
const res = await fetch(request);
|
|
const cache = await caches.open(CACHE_NAME);
|
|
if (res && res.ok) cache.put(request, res.clone()).catch(() => {});
|
|
return res;
|
|
}
|
|
|
|
async function networkFirst(request, fallbackUrl) {
|
|
try {
|
|
const res = await fetch(request, { cache: 'no-cache' });
|
|
const cache = await caches.open(CACHE_NAME);
|
|
if (res && res.ok) cache.put(request, res.clone()).catch(() => {});
|
|
return res;
|
|
} catch (e) {
|
|
const cached = await caches.match(request);
|
|
if (cached) return cached;
|
|
if (fallbackUrl) {
|
|
const fallback = await caches.match(fallbackUrl);
|
|
if (fallback) return fallback;
|
|
}
|
|
return new Response('Offline', {
|
|
status: 200,
|
|
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
|
|
});
|
|
}
|
|
}
|
|
|
|
self.addEventListener('fetch', (event) => {
|
|
const req = event.request;
|
|
if (req.method !== 'GET') return;
|
|
|
|
const url = new URL(req.url);
|
|
if (url.origin !== self.location.origin) return;
|
|
|
|
const path = url.pathname;
|
|
|
|
// version.txt → selalu network (mekanisme deteksi update)
|
|
if (path === '/version.txt') return;
|
|
|
|
// Navigasi halaman pelanggan → network-first
|
|
if (req.mode === 'navigate') {
|
|
if (path.startsWith('/customer/')) event.respondWith(networkFirst(req, '/customer/login'));
|
|
else event.respondWith(networkFirst(req));
|
|
return;
|
|
}
|
|
|
|
// CSS & JS → network-first agar perubahan desain langsung terlihat
|
|
if (path.startsWith('/css/') || path.startsWith('/js/')) {
|
|
event.respondWith(networkFirst(req));
|
|
return;
|
|
}
|
|
|
|
// Gambar, ikon, manifest, font → cache-first
|
|
if (
|
|
path.startsWith('/img/') ||
|
|
path.startsWith('/fonts/') ||
|
|
path === '/manifest.webmanifest' ||
|
|
path === '/manifest-landing.webmanifest'
|
|
) {
|
|
event.respondWith(cacheFirst(req));
|
|
return;
|
|
}
|
|
|
|
event.respondWith(networkFirst(req));
|
|
});
|
|
|
|
self.addEventListener('message', (event) => {
|
|
if (event.data === 'SKIP_WAITING') self.skipWaiting();
|
|
});
|