Referral page, bug fixes, seed data, persona tiers
- New /refer page with share/copy/stats - Fixed modal z-index conflicts (z-50 → z-[60]) across forum, groups, souq, halal-monitor - Seed route: forum categories, marketplace listings, private groups - Mufti/Daie personas now available in Premium tier - Fixed referral share link: falahos.my/mobile/auth?ref=CODE - Fixed client-side persona access check for premium
This commit is contained in:
@@ -88,7 +88,11 @@ async function handleCallback(
|
||||
});
|
||||
|
||||
// Build the redirect URI (must match the one used in the authorization request)
|
||||
const baseUrl = `${url.protocol}//${url.host}`;
|
||||
const forwardedProto = req.headers.get("x-forwarded-proto") || "https";
|
||||
const rawHost = req.headers.get("host") || "";
|
||||
const isDockerHost = /^[a-f0-9]{12,}$/i.test(rawHost.split(":")[0]);
|
||||
const forwardedHost = req.headers.get("x-forwarded-host") || (isDockerHost ? "falahos.my" : rawHost);
|
||||
const baseUrl = `${forwardedProto}://${forwardedHost}`;
|
||||
const redirectUri = `${baseUrl}/mobile/api/auth/${provider}/callback`;
|
||||
|
||||
// Exchange code for user info
|
||||
|
||||
@@ -35,8 +35,13 @@ export async function GET(
|
||||
}
|
||||
|
||||
// Build the redirect URI — the callback URL for this provider
|
||||
const url = new URL(_req.url);
|
||||
const baseUrl = `${url.protocol}//${url.host}`;
|
||||
// Use forwarded headers (Traefik/Cloudflare) or the original Host header
|
||||
// to ensure the public domain is used, not the Docker container hostname.
|
||||
const forwardedProto = _req.headers.get("x-forwarded-proto") || "https";
|
||||
const rawHost = _req.headers.get("host") || "";
|
||||
const isDockerHost = /^[a-f0-9]{12,}$/i.test(rawHost.split(":")[0]);
|
||||
const forwardedHost = _req.headers.get("x-forwarded-host") || (isDockerHost ? "falahos.my" : rawHost);
|
||||
const baseUrl = `${forwardedProto}://${forwardedHost}`;
|
||||
const redirectUri = `${baseUrl}/mobile/api/auth/${provider}/callback`;
|
||||
|
||||
// Generate state for CSRF protection
|
||||
|
||||
@@ -2,10 +2,14 @@ import { NextRequest, NextResponse } from "next/server";
|
||||
import bcrypt from "bcryptjs";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { signJWT } from "@/lib/auth";
|
||||
import { findReferrerByCode } from "@/lib/referral";
|
||||
|
||||
const REFERRER_REWARD_FLH = 200;
|
||||
const REFERRED_BONUS_FLH = 1000;
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const { email, name, password } = await req.json();
|
||||
const { email, name, password, referralCode } = await req.json();
|
||||
|
||||
if (!email || !name || !password) {
|
||||
return NextResponse.json(
|
||||
@@ -24,17 +28,66 @@ export async function POST(req: NextRequest) {
|
||||
|
||||
const passwordHash = await bcrypt.hash(password, 12);
|
||||
|
||||
// Look up referrer if a referral code was provided
|
||||
let referrerId: string | null = null;
|
||||
if (referralCode && typeof referralCode === "string") {
|
||||
const users = await prisma.user.findMany({
|
||||
select: { id: true },
|
||||
});
|
||||
referrerId = await findReferrerByCode(users, referralCode);
|
||||
}
|
||||
|
||||
// Calculate starting balance
|
||||
let startingBalance = 5000; // default sign-up bonus
|
||||
if (referrerId) {
|
||||
startingBalance += REFERRED_BONUS_FLH; // +1,000 FLH for using a referral code
|
||||
}
|
||||
|
||||
const user = await prisma.user.create({
|
||||
data: {
|
||||
email,
|
||||
name,
|
||||
passwordHash,
|
||||
provider: "email",
|
||||
flhBalance: 5000,
|
||||
flhBalance: startingBalance,
|
||||
trialEndsAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
|
||||
},
|
||||
});
|
||||
|
||||
// If referral code was valid, create the referral record and credit the referrer
|
||||
if (referrerId) {
|
||||
await prisma.$transaction([
|
||||
// Create the referral record
|
||||
prisma.referral.create({
|
||||
data: {
|
||||
referrerId,
|
||||
referredId: user.id,
|
||||
status: "joined",
|
||||
rewardFlh: REFERRER_REWARD_FLH,
|
||||
},
|
||||
}),
|
||||
// Credit the referrer
|
||||
prisma.user.update({
|
||||
where: { id: referrerId },
|
||||
data: { flhBalance: { increment: REFERRER_REWARD_FLH } },
|
||||
}),
|
||||
// Notify the referrer
|
||||
prisma.notification.create({
|
||||
data: {
|
||||
userId: referrerId,
|
||||
type: "referral_bonus",
|
||||
title: "Referral Bonus Earned!",
|
||||
body: `${name} joined Falah using your referral code — you earned ${REFERRER_REWARD_FLH} FLH!`,
|
||||
data: JSON.stringify({
|
||||
referredUserId: user.id,
|
||||
referredName: name,
|
||||
rewardFlh: REFERRER_REWARD_FLH,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
const token = await signJWT({
|
||||
userId: user.id,
|
||||
email: user.email,
|
||||
@@ -53,6 +106,8 @@ export async function POST(req: NextRequest) {
|
||||
flhBalance: user.flhBalance,
|
||||
dailyMsgCount: user.dailyMsgCount,
|
||||
},
|
||||
referralApplied: referrerId ? true : false,
|
||||
referralReward: referrerId ? REFERRED_BONUS_FLH : 0,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Register error:", error);
|
||||
|
||||
@@ -108,8 +108,8 @@ export async function POST(request: Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// Generate AI response
|
||||
const aiContent = generateAIReply(personaId, lastUserMessage, historyContext);
|
||||
// Generate AI response (tries LLM first, falls back to keyword rules)
|
||||
const aiContent = await generateAIReply(personaId, lastUserMessage, historyContext);
|
||||
|
||||
// Save AI response to ChatHistory
|
||||
const aiMessage = await prisma.chatHistory.create({
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
// Decode a base62 referral code back to a userId prefix for lookup
|
||||
function decodeBase62Lookup(code: string): number {
|
||||
const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
let hash = 0;
|
||||
for (const ch of code) {
|
||||
const idx = chars.indexOf(ch);
|
||||
if (idx === -1) return -1;
|
||||
hash = hash * 62 + idx;
|
||||
}
|
||||
return hash >>> 0;
|
||||
}
|
||||
import { findReferrerByCode } from "@/lib/referral";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
@@ -25,42 +14,12 @@ export async function POST(req: NextRequest) {
|
||||
);
|
||||
}
|
||||
|
||||
// In a real system, you'd look up the referrer by their stored referral code.
|
||||
// For simplicity, we encode the userId in the code. We need to find the user
|
||||
// whose userId produces this code. Since encodeBase62 uses a hash, we
|
||||
// can't reverse it perfectly. Instead, we iterate active users.
|
||||
// A production approach: store referral codes in a dedicated table or column.
|
||||
// For now, we'll iterate through users and find a match.
|
||||
// Look up the referrer by matching the referral code against all users
|
||||
const users = await prisma.user.findMany({
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
// Recreate the encode logic to find the matching user
|
||||
function encodeForMatch(id: string): string {
|
||||
const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
let hash = 0;
|
||||
for (let i = 0; i < Math.min(id.length, 10); i++) {
|
||||
hash = (hash * 31 + id.charCodeAt(i)) >>> 0;
|
||||
}
|
||||
let result = "";
|
||||
let h = hash;
|
||||
while (result.length < 6) {
|
||||
result = chars[h % 62] + result;
|
||||
h = Math.floor(h / 62);
|
||||
if (h === 0 && result.length < 6) {
|
||||
h = Math.floor(Math.random() * 62 ** (6 - result.length));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
let referrerId: string | null = null;
|
||||
for (const u of users) {
|
||||
if (encodeForMatch(u.id) === code) {
|
||||
referrerId = u.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const referrerId = await findReferrerByCode(users, code);
|
||||
|
||||
if (!referrerId) {
|
||||
return NextResponse.json(
|
||||
@@ -76,12 +35,6 @@ export async function POST(req: NextRequest) {
|
||||
// Since we don't have a "referredId" yet, we store a temporary token.
|
||||
const tempToken = `pending_${referrerId}_${Date.now()}`;
|
||||
|
||||
// Check if this referrer already has a pending referral with this temp token
|
||||
const existing = await prisma.referral.findFirst({
|
||||
where: { referrerId, status: "pending" },
|
||||
orderBy: { createdAt: "desc" },
|
||||
});
|
||||
|
||||
// Store in a lightweight way — we'll use the Referral model with a placeholder referredId
|
||||
// The referredId will be updated when registration completes.
|
||||
// For production, a ReferralClaimToken model would be better.
|
||||
@@ -96,7 +49,7 @@ export async function POST(req: NextRequest) {
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: "Referral code applied! You'll get 1000 FLH when you sign up.",
|
||||
message: "Referral code applied! You'll get 1,000 FLH extra when you sign up, and your referrer earns 200 FLH.",
|
||||
referralId: referral.id,
|
||||
tempToken,
|
||||
});
|
||||
|
||||
@@ -1,25 +1,6 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { requireAuth } from "@/lib/auth";
|
||||
|
||||
// Encode a userId (UUID/CUID) into a short base62 referral code
|
||||
function encodeBase62(id: string): string {
|
||||
const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
// Convert first 10 chars of the id to a numeric hash for a short code
|
||||
let hash = 0;
|
||||
for (let i = 0; i < Math.min(id.length, 10); i++) {
|
||||
hash = (hash * 31 + id.charCodeAt(i)) >>> 0; // unsigned 32-bit
|
||||
}
|
||||
let code = "";
|
||||
while (code.length < 6) {
|
||||
code = chars[hash % 62] + code;
|
||||
hash = Math.floor(hash / 62);
|
||||
if (hash === 0 && code.length < 6) {
|
||||
// Pad with random chars
|
||||
hash = Math.floor(Math.random() * 62 ** (6 - code.length));
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
import { encodeReferralCode } from "@/lib/referral";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const jwtPayload = await requireAuth(req);
|
||||
@@ -28,11 +9,11 @@ export async function GET(req: NextRequest) {
|
||||
}
|
||||
|
||||
try {
|
||||
const referralCode = encodeBase62(jwtPayload.userId);
|
||||
const referralCode = encodeReferralCode(jwtPayload.userId);
|
||||
|
||||
return NextResponse.json({
|
||||
referralCode,
|
||||
shareLink: `${process.env.NEXT_PUBLIC_APP_URL || "https://falah.app"}/join?ref=${referralCode}`,
|
||||
shareLink: `${process.env.NEXT_PUBLIC_APP_URL || "https://falahos.my/mobile"}/auth?ref=${referralCode}`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Referral code error:", error);
|
||||
|
||||
@@ -1,24 +1,7 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { requireAuth } from "@/lib/auth";
|
||||
|
||||
// Same encodeBase62 used in the code route
|
||||
function encodeBase62(id: string): string {
|
||||
const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
let hash = 0;
|
||||
for (let i = 0; i < Math.min(id.length, 10); i++) {
|
||||
hash = (hash * 31 + id.charCodeAt(i)) >>> 0;
|
||||
}
|
||||
let code = "";
|
||||
while (code.length < 6) {
|
||||
code = chars[hash % 62] + code;
|
||||
hash = Math.floor(hash / 62);
|
||||
if (hash === 0 && code.length < 6) {
|
||||
hash = Math.floor(Math.random() * 62 ** (6 - code.length));
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
import { encodeReferralCode } from "@/lib/referral";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const jwtPayload = await requireAuth(req);
|
||||
@@ -42,14 +25,14 @@ export async function GET(req: NextRequest) {
|
||||
}),
|
||||
]);
|
||||
|
||||
const referralCode = encodeBase62(userId);
|
||||
const referralCode = encodeReferralCode(userId);
|
||||
|
||||
return NextResponse.json({
|
||||
totalReferrals,
|
||||
upgradedCount,
|
||||
totalEarned: earnings._sum.rewardFlh || 0,
|
||||
referralCode,
|
||||
shareLink: `${process.env.NEXT_PUBLIC_APP_URL || "https://falah.app"}/join?ref=${referralCode}`,
|
||||
shareLink: `${process.env.NEXT_PUBLIC_APP_URL || "https://falahos.my/mobile"}/auth?ref=${referralCode}`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Referral stats error:", error);
|
||||
|
||||
+192
-21
@@ -4,39 +4,210 @@ import { prisma } from "@/lib/prisma";
|
||||
|
||||
export async function POST() {
|
||||
try {
|
||||
const existing = await prisma.user.findUnique({
|
||||
where: { email: "demo@falah.app" },
|
||||
});
|
||||
|
||||
if (existing) {
|
||||
return NextResponse.json(
|
||||
{ message: "Demo user already exists", userId: existing.id },
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
const demoPasswordHash = await bcrypt.hash("password123", 12);
|
||||
|
||||
const demoUser = await prisma.user.create({
|
||||
data: {
|
||||
email: "demo@falah.app",
|
||||
// ── 1. Seed Demo Users ──────────────────────────────────────────
|
||||
const users = [
|
||||
{
|
||||
email: "demo@falahos.my",
|
||||
password: "password123",
|
||||
name: "Demo User",
|
||||
passwordHash: demoPasswordHash,
|
||||
flhBalance: 10000,
|
||||
isPremium: true,
|
||||
isPro: false,
|
||||
trialEndsAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
|
||||
preferredName: "Demo",
|
||||
coachingGoals: "Learn more about Islam and improve my daily prayers",
|
||||
},
|
||||
{
|
||||
email: "premium@falahos.my",
|
||||
password: "Premium123!",
|
||||
name: "Premium Demo",
|
||||
flhBalance: 50000,
|
||||
isPremium: true,
|
||||
isPro: false,
|
||||
preferredName: "Premium",
|
||||
coachingGoals: "Advanced Islamic studies and community leadership",
|
||||
},
|
||||
];
|
||||
|
||||
const userResults = [];
|
||||
|
||||
for (const user of users) {
|
||||
const { password, ...userData } = user;
|
||||
const passwordHash = await bcrypt.hash(password, 12);
|
||||
|
||||
const upserted = await prisma.user.upsert({
|
||||
where: { email: user.email },
|
||||
update: { ...userData, passwordHash },
|
||||
create: { ...userData, passwordHash },
|
||||
});
|
||||
|
||||
userResults.push({ email: upserted.email, id: upserted.id });
|
||||
}
|
||||
|
||||
// Find demo user for sample data
|
||||
const demoUser = await prisma.user.findUnique({ where: { email: "demo@falahos.my" } });
|
||||
const premiumUser = await prisma.user.findUnique({ where: { email: "premium@falahos.my" } });
|
||||
const demoId = demoUser!.id;
|
||||
const premiumId = premiumUser!.id;
|
||||
|
||||
// ── 2. Seed Forum Categories ─────────────────────────────────────
|
||||
const categoriesData = [
|
||||
{ name: "General Discussion", description: "General Islamic discussions and community topics", icon: "💬", order: 1 },
|
||||
{ name: "Quran & Tafsir", description: "Quranic studies, recitation, and interpretation", icon: "📖", order: 2 },
|
||||
{ name: "Fiqh & Hadith", description: "Islamic jurisprudence and prophetic traditions", icon: "📜", order: 3 },
|
||||
{ name: "Family & Marriage", description: "Family life, marriage, and parenting in Islam", icon: "👨👩👧👦", order: 4 },
|
||||
{ name: "Halal Lifestyle", description: "Halal food, travel, fashion, and daily living", icon: "🌿", order: 5 },
|
||||
{ name: "Community Events", description: "Local events, study circles, and gatherings", icon: "📅", order: 6 },
|
||||
];
|
||||
|
||||
const categoriesCreated: string[] = [];
|
||||
for (const cat of categoriesData) {
|
||||
const created = await prisma.forumCategory.upsert({
|
||||
where: { name: cat.name },
|
||||
update: cat,
|
||||
create: cat,
|
||||
});
|
||||
categoriesCreated.push(created.name);
|
||||
}
|
||||
|
||||
// ── 3. Seed Sample Forum Threads ─────────────────────────────────
|
||||
const generalCat = await prisma.forumCategory.findUnique({ where: { name: "General Discussion" } });
|
||||
const quranCat = await prisma.forumCategory.findUnique({ where: { name: "Quran & Tafsir" } });
|
||||
|
||||
if (generalCat) {
|
||||
await prisma.forumThread.upsert({
|
||||
where: { id: "seed-thread-welcome" },
|
||||
update: {},
|
||||
create: {
|
||||
id: "seed-thread-welcome",
|
||||
title: "Welcome to Falah Community! 👋",
|
||||
content: "Assalamu alaikum everyone! This is our community space where we can discuss all things related to Islam, seek knowledge, and support each other. Feel free to introduce yourself!",
|
||||
categoryId: generalCat.id,
|
||||
authorId: premiumId,
|
||||
pinned: true,
|
||||
shariahStatus: "approved",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (quranCat) {
|
||||
await prisma.forumThread.upsert({
|
||||
where: { id: "seed-thread-quran" },
|
||||
update: {},
|
||||
create: {
|
||||
id: "seed-thread-quran",
|
||||
title: "Daily Quran Reflection — Surah Al-Fatiha",
|
||||
content: "Let's reflect on Surah Al-Fatiha together. What does 'Guide us to the straight path' mean to you in your daily life? Share your reflections below.",
|
||||
categoryId: quranCat.id,
|
||||
authorId: demoId,
|
||||
pinned: false,
|
||||
shariahStatus: "approved",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// ── 4. Seed Sample Group (Private Forum) ─────────────────────────
|
||||
const group = await prisma.group.upsert({
|
||||
where: { id: "seed-group-study-circle" },
|
||||
update: {},
|
||||
create: {
|
||||
id: "seed-group-study-circle",
|
||||
name: "Quran Study Circle",
|
||||
description: "A private group for dedicated Quran study and memorization. Members meet weekly to review progress.",
|
||||
ownerId: premiumId,
|
||||
inviteCode: "QURAN2026",
|
||||
members: {
|
||||
create: [
|
||||
{ userId: premiumId, role: "owner" },
|
||||
{ userId: demoId, role: "member" },
|
||||
],
|
||||
},
|
||||
},
|
||||
include: { _count: { select: { members: true, threads: true } } },
|
||||
});
|
||||
|
||||
// Create a thread in the group
|
||||
const groupCat = generalCat || quranCat;
|
||||
if (groupCat) {
|
||||
await prisma.forumThread.upsert({
|
||||
where: { id: "seed-thread-group-intro" },
|
||||
update: {},
|
||||
create: {
|
||||
id: "seed-thread-group-intro",
|
||||
title: "Welcome to Quran Study Circle 📖",
|
||||
content: "Assalamu alaikum group members! This is our private space for discussing our weekly Quran study sessions. Our first session will cover Surah Al-Kahf — please review the tafsir beforehand.",
|
||||
categoryId: groupCat.id,
|
||||
authorId: premiumId,
|
||||
groupId: group.id,
|
||||
pinned: true,
|
||||
shariahStatus: "approved",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// ── 5. Seed Sample Marketplace Listings ──────────────────────────
|
||||
const listingsData = [
|
||||
{
|
||||
id: "seed-listing-tafsir",
|
||||
title: "Tafsir Ibn Kathir (Abridged) — 10 Volumes",
|
||||
description: "Complete set of Tafsir Ibn Kathir in English. Excellent condition, hardly used. Perfect for anyone looking to deepen their understanding of the Quran.",
|
||||
category: "Books",
|
||||
priceFlh: 2500,
|
||||
sellerId: premiumId,
|
||||
featured: true,
|
||||
},
|
||||
{
|
||||
id: "seed-listing-prayer-mat",
|
||||
title: "Premium Turkish Prayer Mat — Green",
|
||||
description: "High-quality woven Turkish prayer mat with mosque design. Soft texture, perfect size. Ideal gift for loved ones.",
|
||||
category: "Essentials",
|
||||
priceFlh: 800,
|
||||
sellerId: demoId,
|
||||
featured: false,
|
||||
},
|
||||
{
|
||||
id: "seed-listing-miswak",
|
||||
title: "Natural Miswak Sticks (Pack of 10)",
|
||||
description: "Fresh, high-quality miswak sticks from the Arak tree. Naturally whitens teeth, freshens breath, and follows the Sunnah. Each pack contains 10 sticks.",
|
||||
category: "Wellness",
|
||||
priceFlh: 150,
|
||||
sellerId: demoId,
|
||||
featured: false,
|
||||
},
|
||||
{
|
||||
id: "seed-listing-hijab",
|
||||
title: "Handcrafted Silk Hijabs — Assorted Colors",
|
||||
description: "Beautiful handcrafted silk hijabs in assorted colors. Lightweight, breathable fabric. Perfect for daily wear or special occasions.",
|
||||
category: "Fashion",
|
||||
priceFlh: 350,
|
||||
sellerId: premiumId,
|
||||
featured: false,
|
||||
},
|
||||
];
|
||||
|
||||
const listingsCreated: string[] = [];
|
||||
for (const listing of listingsData) {
|
||||
await prisma.listing.upsert({
|
||||
where: { id: listing.id },
|
||||
update: { ...listing },
|
||||
create: listing,
|
||||
});
|
||||
listingsCreated.push(listing.title);
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
message: "Demo user created successfully",
|
||||
userId: demoUser.id,
|
||||
credentials: { email: "demo@falah.app", password: "password123" },
|
||||
message: "Seed completed successfully",
|
||||
users: userResults,
|
||||
categories: categoriesCreated,
|
||||
group: { name: group.name, members: group._count.members },
|
||||
listings: listingsCreated,
|
||||
credentials: [
|
||||
{ email: "demo@falahos.my", password: "password123" },
|
||||
{ email: "premium@falahos.my", password: "Premium123!" },
|
||||
],
|
||||
},
|
||||
{ status: 201 }
|
||||
{ status: 200 }
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Seed error:", error);
|
||||
|
||||
Reference in New Issue
Block a user