Function bodies 345 total
POST function · typescript · L12-L86 (75 LOC)src/app/api/super-admin/impersonate/[id]/route.ts
export async function POST(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const cookieStore = await cookies();
const token = cookieStore.get('super-admin-token')?.value;
if (!token) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const session = await verifySuperAdminToken(token);
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
await connectDB();
const { id } = await params;
// Get tenant
const tenant = await Tenant.findById(id);
if (!tenant) {
return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
}
if (tenant.status !== 'active') {
return NextResponse.json({ error: 'Tenant is not active' }, { status: 400 });
}
// Get owner user
const owner = await User.findById(tenant.ownerId);
if (!owner) {
return NextResponse.json({ error: 'Tenant owner not found' }, { verifySuperAdmin function · typescript · L13-L30 (18 LOC)src/app/api/super-admin/plan-requests/[id]/route.ts
async function verifySuperAdmin() {
const cookieStore = await cookies();
const token = cookieStore.get('super-admin-token')?.value;
if (!token) {
return null;
}
try {
const decoded = jwt.verify(token, JWT_SECRET) as any;
if (decoded.type !== 'super-admin') {
return null;
}
return decoded;
} catch {
return null;
}
}GET function · typescript · L32-L71 (40 LOC)src/app/api/super-admin/plan-requests/[id]/route.ts
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const admin = await verifySuperAdmin();
if (!admin) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const { id } = await params;
if (!mongoose.Types.ObjectId.isValid(id)) {
return NextResponse.json({ error: 'Invalid request ID' }, { status: 400 });
}
await connectDB();
const planRequest = await PlanRequest.findById(id)
.populate('tenantId', 'name slug plan')
.populate('requestedBy', 'name email')
.populate('processedBy', 'name email')
.lean();
if (!planRequest) {
return NextResponse.json({ error: 'Plan request not found' }, { status: 404 });
}
return NextResponse.json({
success: true,
data: planRequest,
});
} catch (error) {
console.error('Error fetching plan request:', error);
return NextResponse.json(
{ error: 'Failed to fetcPATCH function · typescript · L73-L207 (135 LOC)src/app/api/super-admin/plan-requests/[id]/route.ts
export async function PATCH(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const admin = await verifySuperAdmin();
if (!admin) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const { id } = await params;
if (!mongoose.Types.ObjectId.isValid(id)) {
return NextResponse.json({ error: 'Invalid request ID' }, { status: 400 });
}
await connectDB();
const planRequest = await PlanRequest.findById(id);
if (!planRequest) {
return NextResponse.json({ error: 'Plan request not found' }, { status: 404 });
}
if (planRequest.status !== 'pending') {
return NextResponse.json(
{ error: 'This request has already been processed' },
{ status: 400 }
);
}
const body = await request.json();
const { action, adminNotes, rejectionReason } = body;
if (!action || !['approve', 'reject'].includes(action)) {
return NextResponse.json(
verifySuperAdmin function · typescript · L10-L27 (18 LOC)src/app/api/super-admin/plan-requests/route.ts
async function verifySuperAdmin() {
const cookieStore = await cookies();
const token = cookieStore.get('super-admin-token')?.value;
if (!token) {
return null;
}
try {
const decoded = jwt.verify(token, JWT_SECRET) as any;
if (decoded.type !== 'super-admin') {
return null;
}
return decoded;
} catch {
return null;
}
}GET function · typescript · L29-L206 (178 LOC)src/app/api/super-admin/plan-requests/route.ts
export async function GET(request: NextRequest) {
try {
const admin = await verifySuperAdmin();
if (!admin) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
await connectDB();
const { searchParams } = new URL(request.url);
const page = Math.max(1, parseInt(searchParams.get('page') || '1'));
const limit = Math.min(100, Math.max(1, parseInt(searchParams.get('limit') || '10')));
const status = searchParams.get('status') || '';
const search = searchParams.get('search')?.trim() || '';
const skip = (page - 1) * limit;
// Build filter
const filter: any = {};
if (status && ['pending', 'approved', 'rejected', 'cancelled'].includes(status)) {
filter.status = status;
}
// Get stats
const now = new Date();
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
const [
pendingCount,
approvedCount,
rejectedCount,
thisMonthCount,
total,
verifySuperAdmin function · typescript · L9-L26 (18 LOC)src/app/api/super-admin/plans/route.ts
async function verifySuperAdmin(request: NextRequest) {
const cookieStore = await cookies();
const token = cookieStore.get('super-admin-token')?.value;
if (!token) {
return null;
}
try {
const decoded = jwt.verify(token, JWT_SECRET) as any;
if (decoded.type !== 'super-admin') {
return null;
}
return decoded;
} catch {
return null;
}
}Powered by Repobility — scan your code at https://repobility.com
GET function · typescript · L28-L52 (25 LOC)src/app/api/super-admin/plans/route.ts
export async function GET(request: NextRequest) {
try {
const admin = await verifySuperAdmin(request);
if (!admin) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
await connectDB();
const plans = await Plan.find()
.sort({ sortOrder: 1 })
.lean();
return NextResponse.json({
success: true,
data: plans,
});
} catch (error) {
console.error('Error fetching plans:', error);
return NextResponse.json(
{ error: 'Failed to fetch plans' },
{ status: 500 }
);
}
}verifySuperAdmin function · typescript · L9-L26 (18 LOC)src/app/api/super-admin/platform-settings/route.ts
async function verifySuperAdmin() {
const cookieStore = await cookies();
const token = cookieStore.get('super-admin-token')?.value;
if (!token) {
return null;
}
try {
const decoded = jwt.verify(token, JWT_SECRET) as any;
if (decoded.type !== 'super-admin') {
return null;
}
return decoded;
} catch {
return null;
}
}GET function · typescript · L28-L56 (29 LOC)src/app/api/super-admin/platform-settings/route.ts
export async function GET() {
try {
const admin = await verifySuperAdmin();
if (!admin) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
await connectDB();
// Get or create settings (singleton pattern)
let settings = await PlatformSettings.findOne();
if (!settings) {
settings = await PlatformSettings.create({
contactEmail: '[email protected]',
});
}
return NextResponse.json({
success: true,
data: settings,
});
} catch (error) {
console.error('Error fetching platform settings:', error);
return NextResponse.json(
{ error: 'Failed to fetch platform settings' },
{ status: 500 }
);
}
}PUT function · typescript · L58-L169 (112 LOC)src/app/api/super-admin/platform-settings/route.ts
export async function PUT(request: NextRequest) {
try {
const admin = await verifySuperAdmin();
if (!admin) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
await connectDB();
const body = await request.json();
const {
contactEmail,
contactPhone,
contactWhatsapp,
socialLinks,
bankDetails,
paymentInstructions,
aiSettings,
} = body;
// Get or create settings
let settings = await PlatformSettings.findOne();
if (!settings) {
settings = new PlatformSettings({ contactEmail: contactEmail || '[email protected]' });
}
// Update contact settings if provided
if (contactEmail !== undefined) {
// Validate email format
const emailRegex = /^\S+@\S+\.\S+$/;
if (!emailRegex.test(contactEmail)) {
return NextResponse.json(
{ error: 'Please enter a valid email address' },
{ status: 400 }
);
}
settings.GET function · typescript · L44-L254 (211 LOC)src/app/api/super-admin/stats/route.ts
export async function GET() {
try {
// Verify super admin
const cookieStore = await cookies();
const token = cookieStore.get('super-admin-token')?.value;
if (!token) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const session = await verifySuperAdminToken(token);
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
await connectDB();
// Get date ranges
const now = new Date();
const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const startOfWeek = new Date(now);
startOfWeek.setDate(now.getDate() - 7);
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
const startOfLastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
// Optimized: Use $facet to combine multiple counts in single query per collection
const [tenantStats, userStats, postStats, recentTenants, recentPosts, topTenantsByPOST function · typescript · L8-L141 (134 LOC)src/app/api/super-admin/tenants/create/route.ts
export async function POST(request: NextRequest) {
try {
// Verify super admin
const cookieStore = await cookies();
const token = cookieStore.get('super-admin-token')?.value;
if (!token) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const session = await verifySuperAdminToken(token);
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
await connectDB();
const body = await request.json();
const { name, slug, plan, ownerEmail } = body;
// Validate required fields
if (!name || !slug || !ownerEmail) {
return NextResponse.json(
{ error: 'Name, slug, and owner email are required' },
{ status: 400 }
);
}
// Validate slug format
const slugRegex = /^[a-z0-9-]+$/;
if (!slugRegex.test(slug)) {
return NextResponse.json(
{ error: 'Slug can only contain lowercase letters, numbers, and hyphens' },
{ stGET function · typescript · L9-L188 (180 LOC)src/app/api/super-admin/tenants/[id]/route.ts
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const cookieStore = await cookies();
const token = cookieStore.get('super-admin-token')?.value;
if (!token) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const session = await verifySuperAdminToken(token);
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
await connectDB();
const { id } = await params;
// Validate ObjectId
if (!mongoose.Types.ObjectId.isValid(id)) {
return NextResponse.json({ error: 'Invalid tenant ID' }, { status: 400 });
}
// Single aggregation to get all data at once
const [result] = await Tenant.aggregate([
{ $match: { _id: new mongoose.Types.ObjectId(id) } },
{
$lookup: {
from: 'users',
let: { tenantId: '$_id', ownerId: '$ownerId' },
pipeline: [
{
PATCH function · typescript · L191-L279 (89 LOC)src/app/api/super-admin/tenants/[id]/route.ts
export async function PATCH(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const cookieStore = await cookies();
const token = cookieStore.get('super-admin-token')?.value;
if (!token) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const session = await verifySuperAdminToken(token);
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
await connectDB();
const { id } = await params;
// Validate ObjectId
if (!mongoose.Types.ObjectId.isValid(id)) {
return NextResponse.json({ error: 'Invalid tenant ID' }, { status: 400 });
}
const body = await request.json();
const tenant = await Tenant.findById(id);
if (!tenant) {
return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
}
// Update allowed fields using set() method for type safety
if (body.name !== undefined) tenant.name Repobility · code-quality intelligence platform · https://repobility.com
DELETE function · typescript · L282-L329 (48 LOC)src/app/api/super-admin/tenants/[id]/route.ts
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const cookieStore = await cookies();
const token = cookieStore.get('super-admin-token')?.value;
if (!token) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const session = await verifySuperAdminToken(token);
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
await connectDB();
const { id } = await params;
// Validate ObjectId
if (!mongoose.Types.ObjectId.isValid(id)) {
return NextResponse.json({ error: 'Invalid tenant ID' }, { status: 400 });
}
const tenant = await Tenant.findById(id);
if (!tenant) {
return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
}
// Soft delete - change status to deleted
tenant.status = 'deleted';
await tenant.save();
return NextResponse.json({
success:GET function · typescript · L38-L215 (178 LOC)src/app/api/super-admin/tenants/route.ts
export async function GET(request: NextRequest) {
try {
// Verify super admin
const cookieStore = await cookies();
const token = cookieStore.get('super-admin-token')?.value;
if (!token) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const session = await verifySuperAdminToken(token);
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
await connectDB();
// Parse query params
const searchParams = request.nextUrl.searchParams;
const page = Math.max(1, parseInt(searchParams.get('page') || '1'));
const limit = Math.min(100, Math.max(1, parseInt(searchParams.get('limit') || '10')));
const search = searchParams.get('search')?.trim() || '';
const status = searchParams.get('status') || '';
const plan = searchParams.get('plan') || '';
const sortBy = searchParams.get('sortBy') || 'createdAt';
const sortOrder = searchParams.get('sortOrder') === 'verifySuperAdmin function · typescript · L9-L26 (18 LOC)src/app/api/super-admin/users/route.ts
async function verifySuperAdmin(request: NextRequest) {
const cookieStore = await cookies();
const token = cookieStore.get('super-admin-token')?.value;
if (!token) {
return null;
}
try {
const decoded = jwt.verify(token, JWT_SECRET) as any;
if (decoded.type !== 'super-admin') {
return null;
}
return decoded;
} catch {
return null;
}
}GET function · typescript · L28-L53 (26 LOC)src/app/api/super-admin/users/route.ts
export async function GET(request: NextRequest) {
try {
const admin = await verifySuperAdmin(request);
if (!admin) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
await connectDB();
const users = await User.find()
.populate('tenantId', 'name slug')
.sort({ createdAt: -1 })
.lean();
return NextResponse.json({
success: true,
data: users,
});
} catch (error) {
console.error('Error fetching users:', error);
return NextResponse.json(
{ error: 'Failed to fetch users' },
{ status: 500 }
);
}
}GET function · typescript · L4-L54 (51 LOC)src/app/api/tenants/check-slug/route.ts
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const slug = searchParams.get('slug');
if (!slug) {
return NextResponse.json(
{ error: 'Slug parameter is required' },
{ status: 400 }
);
}
// Validate slug format
const slugRegex = /^[a-z0-9-]+$/;
if (!slugRegex.test(slug.toLowerCase())) {
return NextResponse.json({
available: false,
message: 'Slug can only contain lowercase letters, numbers, and hyphens',
});
}
// Check minimum length
if (slug.length < 3) {
return NextResponse.json({
available: false,
message: 'Slug must be at least 3 characters',
});
}
// Check maximum length
if (slug.length > 30) {
return NextResponse.json({
available: false,
message: 'Slug cannot exceed 30 characters',
});
}
const available = await isSlugAvailable(slug);
return NextPOST function · typescript · L13-L194 (182 LOC)src/app/api/tenants/create/route.ts
export async function POST(request: NextRequest) {
try {
// Check authentication
const session = await getServerSession(authOptions);
if (!session?.user?.email) {
return NextResponse.json(
{ error: 'You must be logged in to create a blog' },
{ status: 401 }
);
}
const body = await request.json();
const { name, slug, plan: planSlug = 'free' } = body;
// Validate required fields
if (!name || !slug) {
return NextResponse.json(
{ error: 'Blog name and URL are required' },
{ status: 400 }
);
}
// Validate slug format
const slugRegex = /^[a-z0-9-]+$/;
if (!slugRegex.test(slug.toLowerCase())) {
return NextResponse.json(
{ error: 'URL can only contain lowercase letters, numbers, and hyphens' },
{ status: 400 }
);
}
// Check slug length
if (slug.length < 3 || slug.length > 30) {
return NextResponse.json(
{ error: 'URL must be betweePOST function · typescript · L12-L301 (290 LOC)src/app/api/tenants/register/route.ts
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const {
name,
slug,
email,
ownerName,
password,
phone,
countryCode,
address,
city,
country,
plan: selectedPlanSlug,
couponId,
couponCode,
discountAmount,
finalPrice,
} = body;
// Validate required fields
if (!name || !slug || !email || !ownerName) {
return NextResponse.json(
{ error: 'Name, slug, email, and owner name are required' },
{ status: 400 }
);
}
// Password is always required for registration
if (!password) {
return NextResponse.json(
{ error: 'Password is required' },
{ status: 400 }
);
}
// Validate password length
if (password && password.length < 6) {
return NextResponse.json(
{ error: 'Password must be at least 6 characters' },
{ status: 400 }
);
}
// VprocessImage function · typescript · L13-L162 (150 LOC)src/app/api/upload/route.ts
async function processImage(
imageBuffer: Buffer,
branding: {
enabled: boolean;
type: 'text' | 'image';
text?: string;
imageUrl?: string;
position: string;
opacity: number;
backgroundColor?: string;
textColor?: string;
}
): Promise<Buffer> {
if (!branding.enabled) {
return imageBuffer;
}
// Dynamic import for sharp to avoid build issues
let sharp: any;
try {
sharp = (await import('sharp')).default;
} catch (err) {
console.error('Failed to load sharp library:', err);
return imageBuffer; // Return original image if sharp fails to load
}
try {
const image = sharp(imageBuffer);
const metadata = await image.metadata();
const width = metadata.width || 800;
const height = metadata.height || 600;
// Calculate watermark position
let gravity: 'southeast' | 'southwest' | 'northeast' | 'northwest' = 'southeast';
switch (branding.position) {
case 'bottom-right':
gravity = 'southeast';Repobility · open methodology · https://repobility.com/research/
POST function · typescript · L164-L302 (139 LOC)src/app/api/upload/route.ts
export async function POST(request: NextRequest) {
try {
// Check authentication
const session = await getServerSession(authOptions);
const isAdmin = session?.user?.role === 'admin';
const isEditor = session?.user?.role === 'editor';
const isAuthor = session?.user?.role === 'author' && session?.user?.canPost;
if (!session || (!isAdmin && !isEditor && !isAuthor)) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// Check if API key is configured
if (!IMGBB_API_KEY) {
return NextResponse.json(
{ error: 'ImgBB API key not configured' },
{ status: 500 }
);
}
// Get the form data
const formData = await request.formData();
const file = formData.get('image') as File | null;
const skipWatermark = formData.get('skipWatermark') === 'true'; // For avatar uploads
if (!file) {
return NextResponse.json({ error: 'No image provided' }, { status: 400 });
}
// ValidaGET function · typescript · L10-L152 (143 LOC)src/app/api/user/tenant/route.ts
export async function GET(request: NextRequest) {
try {
const session = await getServerSession(authOptions);
if (!session?.user?.email) {
return NextResponse.json({ success: false, data: null });
}
await connectDB();
const email = session.user.email.toLowerCase();
// Check if user is an author (logged in via credentials)
// The session will have tenantId set directly from auth
if (session.user.role === 'author' && session.user.tenantId) {
const tenant = await Tenant.findById(session.user.tenantId).lean();
if (tenant && (tenant as any).status === 'active') {
return NextResponse.json({
success: true,
data: {
id: (tenant as any)._id.toString(),
name: (tenant as any).name,
slug: (tenant as any).slug,
},
});
}
}
// Also check Author model for authors who might not have tenantId in session
const author = await Author.findOne({ email });
GET function · typescript · L7-L40 (34 LOC)src/app/api/verify-domain/route.ts
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const domain = searchParams.get('domain');
if (!domain) {
return new NextResponse('Missing domain', { status: 400 });
}
// Allow main platform domains
const platformDomain = process.env.NEXT_PUBLIC_PLATFORM_DOMAIN || 'launchory.org';
if (domain === platformDomain || domain === `www.${platformDomain}`) {
return new NextResponse('OK', { status: 200 });
}
// Check if this is a verified custom domain
await connectDB();
const tenant = await Tenant.findOne({
customDomain: domain.toLowerCase(),
customDomainStatus: 'verified',
status: 'active',
}).lean();
if (tenant) {
return new NextResponse('OK', { status: 200 });
}
// Domain not found or not verified
return new NextResponse('Domain not allowed', { status: 404 });
} catch (error) {
console.error('Error verifying domain:', error);AuthorsPage function · typescript · L12-L41 (30 LOC)src/app/authors/page.tsx
export default async function AuthorsPage() {
const authors = await getAllAuthors();
return (
<div className="container mx-auto px-4 py-12">
{/* Header */}
<div className="mb-12 text-center">
<h1 className="mb-4 text-4xl font-bold text-gray-900 dark:text-white">
Our Authors
</h1>
<p className="text-lg text-gray-600 dark:text-gray-400">
Meet the talented writers behind our content
</p>
</div>
{/* Authors Grid */}
{authors.length > 0 ? (
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{authors.map((author) => (
<AuthorCard key={author._id} author={author} />
))}
</div>
) : (
<div className="py-12 text-center">
<p className="text-gray-500 dark:text-gray-400">No authors yet.</p>
</div>
)}
</div>
);
}generateMetadata function · typescript · L14-L33 (20 LOC)src/app/authors/[slug]/page.tsx
export async function generateMetadata({ params }: AuthorPageProps): Promise<Metadata> {
const { slug } = await params;
const author = await getAuthorBySlug(slug);
if (!author) {
return {
title: 'Author Not Found',
};
}
return {
title: author.name,
description: author.bio,
openGraph: {
title: author.name,
description: author.bio,
images: [{ url: author.avatar }],
},
};
}AuthorPage function · typescript · L35-L61 (27 LOC)src/app/authors/[slug]/page.tsx
export default async function AuthorPage({ params }: AuthorPageProps) {
const { slug } = await params;
const author = await getAuthorBySlug(slug);
if (!author) {
notFound();
}
const posts = await getPostsByAuthor(author.slug);
return (
<div className="container mx-auto px-4 py-12">
<div className="mx-auto max-w-5xl">
{/* Author Bio */}
<AuthorBio author={author} postCount={posts.length} />
{/* Author's Posts */}
<section>
<h2 className="mb-8 text-2xl font-bold text-gray-900 dark:text-white">
Posts by {author.name}
</h2>
<PostList posts={posts} columns={2} />
</section>
</div>
</div>
);
}BlogLoading function · typescript · L1-L27 (27 LOC)src/app/blog/loading.tsx
export default function BlogLoading() {
return (
<div className="container mx-auto px-4 py-12">
<div className="mb-8 animate-pulse">
<div className="h-10 w-48 bg-gray-200 dark:bg-gray-700 rounded mb-4" />
<div className="h-4 w-96 bg-gray-200 dark:bg-gray-700 rounded" />
</div>
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
{[...Array(6)].map((_, i) => (
<div key={i} className="animate-pulse rounded-xl bg-white dark:bg-gray-800 overflow-hidden shadow-sm">
<div className="h-48 bg-gray-200 dark:bg-gray-700" />
<div className="p-6">
<div className="h-4 w-20 bg-gray-200 dark:bg-gray-700 rounded mb-3" />
<div className="h-6 w-full bg-gray-200 dark:bg-gray-700 rounded mb-2" />
<div className="h-4 w-3/4 bg-gray-200 dark:bg-gray-700 rounded mb-4" />
<div className="flex gap-2">
<div className="h-6 w-6 bg-gray-200 dark:bg-gray-700 generateBlogListingSchema function · typescript · L160-L188 (29 LOC)src/app/blog/page.tsx
function generateBlogListingSchema() {
return {
'@context': 'https://schema.org',
'@type': 'Blog',
name: 'Launchory Blog',
description: 'Expert tips on blogging, SEO, content marketing, and monetization strategies.',
url: `${siteUrl}/blog`,
publisher: {
'@type': 'Organization',
name: 'Launchory',
logo: {
'@type': 'ImageObject',
url: `${siteUrl}/logo.png`,
},
},
blogPost: blogPosts.map((post) => ({
'@type': 'BlogPosting',
headline: post.title,
description: post.excerpt,
url: `${siteUrl}/blog/${post.slug}`,
datePublished: post.publishedAt,
author: {
'@type': 'Person',
name: post.author.name,
},
image: post.image,
})),
};
}Hi, dataset curator — please cite Repobility (https://repobility.com) when reusing this data.
BlogPage function · typescript · L190-L461 (272 LOC)src/app/blog/page.tsx
export default function BlogPage() {
const featuredPost = blogPosts.find(post => post.featured);
const regularPosts = blogPosts.filter(post => !post.featured);
const blogListingSchema = generateBlogListingSchema();
return (
<>
{/* JSON-LD Structured Data */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(blogListingSchema) }}
/>
<main className="min-h-screen bg-white dark:bg-gray-950">
{/* Navigation */}
<nav className="fixed top-0 left-0 right-0 z-50 border-b border-gray-200/50 dark:border-white/10 bg-white/80 dark:bg-gray-950/80 backdrop-blur-xl">
<div className="container mx-auto px-4">
<div className="flex items-center justify-between h-16">
<Link href="/" className="flex items-center gap-2">
<div className="w-8 h-8 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-lg flex items-center justify-center">
CopyLinkButton function · typescript · L7-L23 (17 LOC)src/app/blog/[slug]/CopyLinkButton.tsx
export default function CopyLinkButton({ url }: CopyLinkButtonProps) {
const handleCopy = () => {
navigator.clipboard?.writeText(url);
};
return (
<button
onClick={handleCopy}
className="flex items-center gap-2 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
>
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
Copy Link
</button>
);
}Loading function · typescript · L1-L26 (26 LOC)src/app/blog/[slug]/loading.tsx
export default function Loading() {
return (
<div className="container mx-auto px-4 py-12">
<div className="mx-auto max-w-3xl">
{/* Header skeleton */}
<div className="mb-8 animate-pulse">
<div className="mb-4 h-4 w-24 rounded bg-gray-200 dark:bg-gray-700" />
<div className="mb-4 h-10 w-3/4 rounded bg-gray-200 dark:bg-gray-700" />
<div className="h-6 w-full rounded bg-gray-200 dark:bg-gray-700" />
</div>
{/* Image skeleton */}
<div className="mb-8 aspect-video w-full animate-pulse rounded-xl bg-gray-200 dark:bg-gray-700" />
{/* Content skeleton */}
<div className="space-y-4 animate-pulse">
<div className="h-4 w-full rounded bg-gray-200 dark:bg-gray-700" />
<div className="h-4 w-5/6 rounded bg-gray-200 dark:bg-gray-700" />
<div className="h-4 w-4/6 rounded bg-gray-200 dark:bg-gray-700" />
<div className="h-4 w-full rounded bg-gray-200 dark:bg-gray-7NotFound function · typescript · L3-L22 (20 LOC)src/app/blog/[slug]/not-found.tsx
export default function NotFound() {
return (
<div className="container mx-auto px-4 py-12">
<div className="mx-auto max-w-2xl text-center">
<h1 className="mb-4 text-4xl font-bold text-gray-900 dark:text-white">
Post Not Found
</h1>
<p className="mb-8 text-gray-600 dark:text-gray-400">
The blog post you're looking for doesn't exist or has been removed.
</p>
<Link
href="/blog"
className="inline-block rounded-lg bg-primary-600 px-6 py-3 font-medium text-white hover:bg-primary-700"
>
Browse All Posts
</Link>
</div>
</div>
);
}generateMetadata function · typescript · L432-L475 (44 LOC)src/app/blog/[slug]/page.tsx
export async function generateMetadata({ params }: BlogPostPageProps): Promise<Metadata> {
const { slug } = await params;
const post = blogPosts.find(p => p.slug === slug);
if (!post) {
return {
title: 'Post Not Found - Launchory Blog',
};
}
return {
title: `${post.title} | Launchory Blog`,
description: post.excerpt,
keywords: post.keywords,
authors: [{ name: post.author.name }],
openGraph: {
title: post.title,
description: post.excerpt,
url: `${siteUrl}/blog/${post.slug}`,
siteName: 'Launchory',
type: 'article',
publishedTime: post.publishedAt,
modifiedTime: post.modifiedAt,
authors: [post.author.name],
images: [
{
url: post.image,
width: 1200,
height: 630,
alt: post.imageAlt,
},
],
},
twitter: {
card: 'summary_large_image',
title: post.title,
description: post.excerpt,
images: [post.image],
generateArticleSchema function · typescript · L478-L509 (32 LOC)src/app/blog/[slug]/page.tsx
function generateArticleSchema(post: typeof blogPosts[0]) {
return {
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: post.title,
description: post.excerpt,
image: post.image,
datePublished: post.publishedAt,
dateModified: post.modifiedAt,
author: {
'@type': 'Person',
name: post.author.name,
jobTitle: post.author.role,
description: post.author.bio,
},
publisher: {
'@type': 'Organization',
name: 'Launchory',
logo: {
'@type': 'ImageObject',
url: `${siteUrl}/logo.png`,
},
},
mainEntityOfPage: {
'@type': 'WebPage',
'@id': `${siteUrl}/blog/${post.slug}`,
},
keywords: post.keywords.join(', '),
articleSection: post.category,
wordCount: post.content.split(/\s+/).length,
};
}generateBreadcrumbSchema function · typescript · L512-L537 (26 LOC)src/app/blog/[slug]/page.tsx
function generateBreadcrumbSchema(post: typeof blogPosts[0]) {
return {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{
'@type': 'ListItem',
position: 1,
name: 'Home',
item: siteUrl,
},
{
'@type': 'ListItem',
position: 2,
name: 'Blog',
item: `${siteUrl}/blog`,
},
{
'@type': 'ListItem',
position: 3,
name: post.title,
item: `${siteUrl}/blog/${post.slug}`,
},
],
};
}BlogPostPage function · typescript · L539-L880 (342 LOC)src/app/blog/[slug]/page.tsx
export default async function BlogPostPage({ params }: BlogPostPageProps) {
const { slug } = await params;
const post = blogPosts.find(p => p.slug === slug);
if (!post) {
notFound();
}
// Get related posts (same category, excluding current)
const relatedPosts = blogPosts
.filter(p => p.category === post.category && p.slug !== post.slug)
.slice(0, 3);
// If not enough related posts in same category, fill with other posts
if (relatedPosts.length < 3) {
const otherPosts = blogPosts
.filter(p => p.slug !== post.slug && !relatedPosts.includes(p))
.slice(0, 3 - relatedPosts.length);
relatedPosts.push(...otherPosts);
}
const articleSchema = generateArticleSchema(post);
const breadcrumbSchema = generateBreadcrumbSchema(post);
return (
<>
{/* JSON-LD Structured Data */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(articleSchema) }}
/>
<script
tPowered by Repobility — scan your code at https://repobility.com
getTenantFromCustomDomain function · typescript · L15-L26 (12 LOC)src/app/cd/blog/page.tsx
async function getTenantFromCustomDomain() {
const headersList = await headers();
const customDomain = headersList.get('x-custom-domain');
if (!customDomain) return null;
await connectDB();
return await Tenant.findOne({
customDomain: customDomain.toLowerCase(),
customDomainStatus: 'verified',
status: 'active',
}).lean();
}CustomDomainBlogPage function · typescript · L32-L170 (139 LOC)src/app/cd/blog/page.tsx
export default async function CustomDomainBlogPage({ searchParams }: BlogPageProps) {
const tenant = await getTenantFromCustomDomain();
const { category, page } = await searchParams;
if (!tenant) {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-950">
<p className="text-gray-600 dark:text-gray-400">Domain not configured</p>
</div>
);
}
const tenantId = tenant._id.toString();
await connectDB();
const settings = await Settings.findOne({ tenantId }).lean();
const postsPerPage = settings?.postsPerPage || 10;
const currentPage = Math.max(1, parseInt(page || '1', 10));
const [paginatedResult, categoriesData] = await Promise.all([
getPaginatedPosts(tenantId, { page: currentPage, limit: postsPerPage, category }),
Category.find({ tenantId }).sort({ name: 1 }).lean(),
]);
const posts = paginatedResult.posts;
const totalPages = paginatedResult.totalPages;
const categories = categorigetTenantFromCustomDomain function · typescript · L16-L27 (12 LOC)src/app/cd/blog/[slug]/page.tsx
async function getTenantFromCustomDomain() {
const headersList = await headers();
const customDomain = headersList.get('x-custom-domain');
if (!customDomain) return null;
await connectDB();
return await Tenant.findOne({
customDomain: customDomain.toLowerCase(),
customDomainStatus: 'verified',
status: 'active',
}).lean();
}generateMetadata function · typescript · L33-L46 (14 LOC)src/app/cd/blog/[slug]/page.tsx
export async function generateMetadata({ params }: PostPageProps): Promise<Metadata> {
const { slug } = await params;
const tenant = await getTenantFromCustomDomain();
if (!tenant) return {};
await connectDB();
const post = await Post.findOne({ tenantId: tenant._id, slug, published: true }).lean();
if (!post) return {};
return {
title: post.title,
description: post.description,
};
}CustomDomainPostPage function · typescript · L48-L230 (183 LOC)src/app/cd/blog/[slug]/page.tsx
export default async function CustomDomainPostPage({ params }: PostPageProps) {
const { slug } = await params;
const tenant = await getTenantFromCustomDomain();
if (!tenant) {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-950">
<p className="text-gray-600 dark:text-gray-400">Domain not configured</p>
</div>
);
}
await connectDB();
const post = await Post.findOne({
tenantId: tenant._id,
slug,
published: true,
}).populate('author', 'name image').lean();
if (!post) {
notFound();
}
// Increment view count
await Post.findByIdAndUpdate(post._id, { $inc: { views: 1 } });
const settings = await Settings.findOne({ tenantId: tenant._id }).lean();
const siteName = settings?.siteName || tenant.settings?.siteName || tenant.name;
const siteLogo = settings?.siteLogo || '';
const primaryColor = settings?.primaryColor || '#6366f1';
const accentColor = settings?.accentColor getTenantFromCustomDomain function · typescript · L18-L29 (12 LOC)src/app/cd/[pageSlug]/page.tsx
async function getTenantFromCustomDomain() {
const headersList = await headers();
const customDomain = headersList.get('x-custom-domain');
if (!customDomain) return null;
await connectDB();
return await Tenant.findOne({
customDomain: customDomain.toLowerCase(),
customDomainStatus: 'verified',
status: 'active',
}).lean();
}generateMetadata function · typescript · L35-L56 (22 LOC)src/app/cd/[pageSlug]/page.tsx
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const { pageSlug } = await params;
if (RESERVED_SLUGS.includes(pageSlug.toLowerCase())) {
return {};
}
const tenant = await getTenantFromCustomDomain();
if (!tenant) return {};
await connectDB();
const page = await Page.findOne({ tenantId: tenant._id, slug: pageSlug, published: true }).lean() as any;
if (!page) return {};
const settings = await Settings.findOne({ tenantId: tenant._id }).lean();
const siteName = settings?.siteName || tenant.name;
return {
title: page.seoTitle || `${page.title} | ${siteName}`,
description: page.seoDescription || page.heroSubtitle || `${page.title} - ${siteName}`,
};
}CustomDomainPage function · typescript · L58-L354 (297 LOC)src/app/cd/[pageSlug]/page.tsx
export default async function CustomDomainPage({ params }: PageProps) {
const { pageSlug } = await params;
if (RESERVED_SLUGS.includes(pageSlug.toLowerCase())) {
notFound();
}
const tenant = await getTenantFromCustomDomain();
if (!tenant) {
notFound();
}
await connectDB();
const page = await Page.findOne({
tenantId: tenant._id,
slug: pageSlug,
published: true,
}).lean() as any;
if (!page) {
notFound();
}
const settings = await Settings.findOne({ tenantId: tenant._id }).lean();
const siteName = settings?.siteName || tenant.settings?.siteName || tenant.name;
const siteLogo = settings?.siteLogo || '';
const primaryColor = settings?.primaryColor || '#6366f1';
const accentColor = settings?.accentColor || '#8b5cf6';
// Get pages for navbar
const navPages = await Page.find({
tenantId: tenant._id,
published: true,
showInNavbar: true,
}).sort({ navbarOrder: 1 }).lean();
// Get categories for navbar
const categRepobility · code-quality intelligence platform · https://repobility.com
getTenantFromCustomDomain function · typescript · L20-L36 (17 LOC)src/app/cd/page.tsx
async function getTenantFromCustomDomain() {
const headersList = await headers();
const customDomain = headersList.get('x-custom-domain');
if (!customDomain) {
return null;
}
await connectDB();
const tenant = await Tenant.findOne({
customDomain: customDomain.toLowerCase(),
customDomainStatus: 'verified',
status: 'active',
}).lean();
return tenant;
}generateMetadata function · typescript · L38-L61 (24 LOC)src/app/cd/page.tsx
export async function generateMetadata(): Promise<Metadata> {
const tenant = await getTenantFromCustomDomain();
if (!tenant) return {};
await connectDB();
const settings = await Settings.findOne({ tenantId: tenant._id }).lean();
const siteName = settings?.siteName || tenant.settings?.siteName || tenant.name;
const seoDescription = settings?.seoDescription || settings?.siteDescription || 'Welcome to our blog';
const seoKeywords = settings?.seoKeywords || [];
const ogImage = settings?.ogImage || '';
return {
title: siteName,
description: seoDescription,
keywords: seoKeywords.join(', '),
openGraph: {
title: siteName,
description: seoDescription,
images: ogImage ? [ogImage] : [],
siteName: siteName,
},
};
}CustomDomainHomePage function · typescript · L67-L409 (343 LOC)src/app/cd/page.tsx
export default async function CustomDomainHomePage({ searchParams }: CustomDomainPageProps) {
const tenant = await getTenantFromCustomDomain();
const { page } = await searchParams;
if (!tenant) {
const headersList = await headers();
const customDomain = headersList.get('x-custom-domain') || 'Unknown domain';
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-950">
<div className="text-center p-8 max-w-md">
<div className="w-16 h-16 rounded-full bg-red-100 dark:bg-red-900/30 flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-red-600 dark:text-red-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
</div>