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
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
// 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 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user