Files
falah-mobile/public/sw.js
T
root cfff74e2db feat: Souq native integration + auth simplification + CE-wide enhancements
Souq Marketplace:
- Native souq pages: browse+filters, create listing, detail+seller profile, orders+chat
- New API: reviews (POST), sellers/[id], upload (multipart), polar-checkout webhook
- Listings API enhanced: minPrice, maxPrice, sortBy, deliveryDays filters
- Seller workflow: start order, mark delivered, upload files, confirm delivery
- Wallet: 5 Polar.sh FLH tiers, production checkout, mock fallback, success banner
- Fix: order redirect /souq/history → /souq/orders

Auth System:
- Unified auth page, removed OAuth provider routing (2 files deleted)
- Deleted oauth.ts (319 lines) — simplified auth chain
- Streamlined login/register API routes

Prisma Schema (+179 lines):
- New models: Listing, Purchase, Review, Group/GroupMember
- Gamification: DailyStreak, XpTransaction, Achievement, UserLevel
- Learning: LearnCourse/Module/Enrollment/Certificate
- Notifications, Referrals, Dhikr, PremiumBenefits

Deleted legacy code:
- src/app/api/marketplace/* (3 files) — replaced by /api/souq/*
- src/app/api/files/[listingId]/route.ts — replaced by /api/souq/upload
- src/app/api/seller/[sellerId]/route.ts — replaced by /api/souq/sellers/[id]

Infrastructure:
- Dockerfile: standalone output, Prisma runtime migration
- docker-compose.yml: Polar env vars, healthcheck fix
- docker-compose.staging.yml: staging on port 4014
- .gitea/workflows/ci.yml: CI pipeline
2026-06-24 07:02:03 +02:00

90 lines
2.2 KiB
JavaScript

// Falah PWA Service Worker
const CACHE = "falah-cache-v1";
const IMMUTABLE_CACHE = "falah-immutable-v1";
// Assets to pre-cache on install
const PRECACHE_ASSETS = [
"/mobile/manifest.json",
"/mobile/icons/icon-192x192.png",
"/mobile/icons/icon-512x512.png",
"/mobile/apple-touch-icon.png",
"/mobile/offline"
];
// Install: pre-cache core assets
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(IMMUTABLE_CACHE).then((cache) => cache.addAll(PRECACHE_ASSETS))
);
self.skipWaiting();
});
// Activate: clean old caches
self.addEventListener("activate", (event) => {
event.waitUntil(
caches.keys().then((keys) =>
Promise.all(
keys
.filter((k) => k !== CACHE && k !== IMMUTABLE_CACHE)
.map((k) => caches.delete(k))
)
)
);
self.clients.claim();
});
// Fetch: network-first for pages, cache-first for static assets
self.addEventListener("fetch", (event) => {
const { request } = event;
const url = new URL(request.url);
// Only handle same-origin /mobile requests
if (!url.pathname.startsWith("/mobile")) return;
// API calls — never cache
if (url.pathname.startsWith("/mobile/api/")) return;
// Static assets (icons, fonts, images) — cache-first
if (
url.pathname.match(/\.(png|jpg|jpeg|gif|svg|ico|webp|woff2?|css)$/)
) {
event.respondWith(cacheFirst(request));
return;
}
// Navigation & pages — network-first with fallback
if (request.mode === "navigate") {
event.respondWith(networkFirst(request));
return;
}
// Everything else — network-only
event.respondWith(fetch(request).catch(() => caches.match(request)));
});
async function networkFirst(request) {
try {
const response = await fetch(request);
if (response.ok) {
const cache = await caches.open(CACHE);
cache.put(request, response.clone());
}
return response;
} catch {
const cached = await caches.match(request);
if (cached) return cached;
// Offline fallback page
return caches.match("/mobile/offline");
}
}
async function cacheFirst(request) {
const cached = await caches.match(request);
if (cached) return cached;
try {
return await fetch(request);
} catch {
return new Response("", { status: 408 });
}
}