← back to inzamulhaque1__my-blog

Function bodies 345 total

All specs Real LLM only Function bodies
getTenantFromCustomDomain function · typescript · L13-L24 (12 LOC)
src/app/cd/privacy/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 · L26-L38 (13 LOC)
src/app/cd/privacy/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;

  return {
    title: `Privacy Policy | ${siteName}`,
    description: `Privacy Policy for ${siteName}`,
  };
}
PrivacyPage function · typescript · L40-L156 (117 LOC)
src/app/cd/privacy/page.tsx
export default async function PrivacyPage() {
  const tenant = await getTenantFromCustomDomain();
  if (!tenant) {
    notFound();
  }

  await connectDB();
  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';
  const privacyPolicy = settings?.privacyPolicy || '';

  // Footer settings
  const copyrightText = (settings?.copyrightText || '© {year} All rights reserved.')
    .replace('{year}', new Date().getFullYear().toString());
  const socialLinks = (settings?.socialLinks || {}) as any;
  const contactEmail = settings?.contactEmail || '';
  const contactPhone = settings?.contactPhone || '';
  const contactAddress = settings?.contactAddress || '';
  const footerLinks = (settings?.footerLinks || []) as Array<{
    id: str
getTenantFromCustomDomain function · typescript · L13-L24 (12 LOC)
src/app/cd/terms/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 · L26-L38 (13 LOC)
src/app/cd/terms/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;

  return {
    title: `Terms of Service | ${siteName}`,
    description: `Terms of Service for ${siteName}`,
  };
}
TermsPage function · typescript · L40-L156 (117 LOC)
src/app/cd/terms/page.tsx
export default async function TermsPage() {
  const tenant = await getTenantFromCustomDomain();
  if (!tenant) {
    notFound();
  }

  await connectDB();
  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';
  const termsOfService = settings?.termsOfService || '';

  // Footer settings
  const copyrightText = (settings?.copyrightText || '© {year} All rights reserved.')
    .replace('{year}', new Date().getFullYear().toString());
  const socialLinks = (settings?.socialLinks || {}) as any;
  const contactEmail = settings?.contactEmail || '';
  const contactPhone = settings?.contactPhone || '';
  const contactAddress = settings?.contactAddress || '';
  const footerLinks = (settings?.footerLinks || []) as Array<{
    id: str
ContactPage function · typescript · L5-L171 (167 LOC)
src/app/contact/page.tsx
export default function ContactPage() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    subject: '',
    message: '',
  });
  const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
  const [errorMessage, setErrorMessage] = useState('');

  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault();
    setStatus('loading');
    setErrorMessage('');

    try {
      const response = await fetch('/api/contact', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(formData),
      });

      const data = await response.json();

      if (!response.ok) {
        throw new Error(data.error || 'Failed to send message');
      }

      setStatus('success');
      setFormData({ name: '', email: '', subject: '', message: '' });
    } catch (error: any) {
      setStatus('error');
      setErrorMessage(error.message || 'Something went wrong');
    }
  };

  return 
All rows scored by the Repobility analyzer (https://repobility.com)
RootLayout function · typescript · L55-L72 (18 LOC)
src/app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en" suppressHydrationWarning>
      <head>
        <link rel="icon" href="/favicon.ico" sizes="any" />
      </head>
      <body className={inter.className}>
        <SessionProvider>
          <LayoutWrapper>{children}</LayoutWrapper>
        </SessionProvider>
      </body>
    </html>
  );
}
LoginPage function · typescript · L9-L359 (351 LOC)
src/app/login/page.tsx
export default function LoginPage() {
  const router = useRouter();
  const { data: session, status } = useSession();
  const [isFormLoading, setIsFormLoading] = useState(false);
  const [isGoogleLoading, setIsGoogleLoading] = useState(false);
  const [error, setError] = useState('');
  const [loginMode, setLoginMode] = useState<'owner' | 'author'>('owner');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  // If user is logged in, redirect to their blog or dashboard
  useEffect(() => {
    if (status === 'authenticated' && session?.user) {
      // Check if user has a tenant
      checkUserTenant();
    }
  }, [status, session]);

  const checkUserTenant = async () => {
    try {
      const res = await fetch('/api/user/tenant');
      const data = await res.json();

      if (data.success && data.data) {
        // Redirect to their tenant admin
        router.push(`/t/${data.data.slug}/admin`);
      } else {
        // No tenant, redirect 
MarketingLayout function · typescript · L5-L109 (105 LOC)
src/app/(marketing)/layout.tsx
export default async function MarketingLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  // Check if this is a tenant subdomain - if so, redirect to tenant site
  const headersList = await headers();
  const tenantType = headersList.get('x-tenant-type');

  if (tenantType === 'tenant') {
    // This is a tenant subdomain, shouldn't show marketing pages
    redirect('/');
  }

  return (
    <div className="min-h-screen bg-white dark:bg-gray-950">
      {/* Navigation */}
      <nav className="fixed top-0 left-0 right-0 z-50 bg-white/80 dark:bg-gray-950/80 backdrop-blur-xl border-b border-gray-200 dark:border-gray-800">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
          <div className="flex items-center justify-between h-16">
            {/* Logo */}
            <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">
        
HomePage function · typescript · L4-L270 (267 LOC)
src/app/(marketing)/page.tsx
export default function HomePage() {
  return (
    <>
      {/* Hero Section */}
      <section className="relative overflow-hidden">
        {/* Background gradient */}
        <div className="absolute inset-0 bg-gradient-to-br from-indigo-50 via-white to-purple-50 dark:from-gray-950 dark:via-gray-900 dark:to-gray-950" />
        <div className="absolute inset-0 bg-[linear-gradient(to_right,#8080800a_1px,transparent_1px),linear-gradient(to_bottom,#8080800a_1px,transparent_1px)] bg-[size:24px_24px]" />

        {/* Floating shapes */}
        <div className="absolute top-20 left-10 w-72 h-72 bg-indigo-500/10 rounded-full blur-3xl" />
        <div className="absolute bottom-20 right-10 w-96 h-96 bg-purple-500/10 rounded-full blur-3xl" />

        <div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-24 md:py-32">
          <div className="text-center max-w-4xl mx-auto">
            <div className="inline-flex items-center gap-2 px-4 py-2 bg-indigo-50 dark:bg-indigo-500/10 
PricingPage function · typescript · L81-L276 (196 LOC)
src/app/(marketing)/pricing/page.tsx
export default function PricingPage() {
  return (
    <div className="py-16">
      {/* Header */}
      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center mb-16">
        <h1 className="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-4">
          Simple, transparent pricing
        </h1>
        <p className="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
          Choose the perfect plan for your blogging needs. Start free and upgrade anytime.
        </p>
      </div>

      {/* Pricing Cards */}
      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
          {plans.map((plan) => (
            <div
              key={plan.slug}
              className={`relative rounded-2xl p-6 ${
                plan.popular
                  ? 'bg-indigo-600 text-white ring-4 ring-indigo-600 ring-offset-2 dark:ring-offset-gray-950'
                  : 'bg-white dark:bg-gray-8
CompleteRegistrationPage function · typescript · L22-L209 (188 LOC)
src/app/(marketing)/register/complete/page.tsx
export default function CompleteRegistrationPage() {
  const router = useRouter();
  const { data: session, status } = useSession();
  const [state, setState] = useState<'loading' | 'creating' | 'success' | 'error' | 'no-data'>('loading');
  const [error, setError] = useState('');
  const [subdomain, setSubdomain] = useState('');

  useEffect(() => {
    // Wait for session to load
    if (status === 'loading') return;

    // If not authenticated, redirect to register
    if (status === 'unauthenticated') {
      router.push('/register');
      return;
    }

    // Get pending registration data from localStorage
    const pendingData = localStorage.getItem('pendingRegistration');

    if (!pendingData) {
      setState('no-data');
      return;
    }

    const registrationData: PendingRegistration = JSON.parse(pendingData);

    // Validate data
    if (!registrationData.plan || !registrationData.blogName || !registrationData.slug) {
      setState('no-data');
      return;
    }

 
fetchPlans function · typescript · L365-L383 (19 LOC)
src/app/(marketing)/register/page.tsx
    async function fetchPlans() {
      try {
        const res = await fetch('/api/plans');
        const data = await res.json();
        if (data.success) {
          setPlans(data.data);
          if (!preselectedPlan && data.data.length > 0) {
            const freePlan = data.data.find((p: Plan) => p.slug === 'free');
            if (freePlan) {
              setSelectedPlan('free');
            }
          }
        }
      } catch (err) {
        console.error('Error fetching plans:', err);
      } finally {
        setLoadingPlans(false);
      }
    }
LoadingFallback function · typescript · L1040-L1049 (10 LOC)
src/app/(marketing)/register/page.tsx
function LoadingFallback() {
  return (
    <div className="min-h-[calc(100vh-4rem)] flex items-center justify-center py-12 px-4">
      <div className="text-center">
        <Loader2 className="w-8 h-8 animate-spin text-indigo-600 mx-auto mb-4" />
        <p className="text-gray-600 dark:text-gray-400">Loading...</p>
      </div>
    </div>
  );
}
Repobility · open methodology · https://repobility.com/research/
RegisterPage function · typescript · L1051-L1057 (7 LOC)
src/app/(marketing)/register/page.tsx
export default function RegisterPage() {
  return (
    <Suspense fallback={<LoadingFallback />}>
      <RegisterPageContent />
    </Suspense>
  );
}
RegisterSuccessContent function · typescript · L8-L128 (121 LOC)
src/app/(marketing)/register/success/page.tsx
function RegisterSuccessContent() {
  const searchParams = useSearchParams();
  const subdomain = searchParams.get('subdomain') || 'yourblog.launchory.org';
  const planRequest = searchParams.get('planRequest');
  const requestedPlan = searchParams.get('requestedPlan');

  // Extract slug from subdomain (e.g., "myblog.launchory.org" -> "myblog")
  const slug = subdomain.split('.')[0];

  // Use internal URL format for development compatibility
  const blogUrl = `/t/${slug}`;
  const adminUrl = `/t/${slug}/admin`;

  return (
    <div className="min-h-[calc(100vh-4rem)] flex items-center justify-center py-12 px-4">
      <div className="w-full max-w-md text-center">
        {/* Success Icon */}
        <div className="w-20 h-20 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-8">
          <CheckCircle className="w-10 h-10 text-green-600 dark:text-green-400" />
        </div>

        <h1 className="text-3xl font-bold text-gray-900 dark:text-whi
LoadingFallback function · typescript · L130-L139 (10 LOC)
src/app/(marketing)/register/success/page.tsx
function LoadingFallback() {
  return (
    <div className="min-h-[calc(100vh-4rem)] flex items-center justify-center py-12 px-4">
      <div className="text-center">
        <div className="h-8 w-8 animate-spin rounded-full border-4 border-indigo-600 border-t-transparent mx-auto mb-4" />
        <p className="text-gray-600 dark:text-gray-400">Loading...</p>
      </div>
    </div>
  );
}
RegisterSuccessPage function · typescript · L141-L147 (7 LOC)
src/app/(marketing)/register/success/page.tsx
export default function RegisterSuccessPage() {
  return (
    <Suspense fallback={<LoadingFallback />}>
      <RegisterSuccessContent />
    </Suspense>
  );
}
NotFound function · typescript · L3-L29 (27 LOC)
src/app/not-found.tsx
export default function NotFound() {
  return (
    <div className="container mx-auto flex min-h-[60vh] flex-col items-center justify-center px-4 py-12 text-center">
      <h1 className="mb-4 text-6xl font-bold text-gray-900 dark:text-white">404</h1>
      <h2 className="mb-4 text-2xl font-semibold text-gray-700 dark:text-gray-300">
        Page Not Found
      </h2>
      <p className="mb-8 max-w-md text-gray-600 dark:text-gray-400">
        Sorry, the page you are looking for doesn&apos;t exist or has been moved.
      </p>
      <div className="flex gap-4">
        <Link
          href="/"
          className="rounded-lg bg-primary-600 px-6 py-3 font-medium text-white transition-colors hover:bg-primary-700"
        >
          Go Home
        </Link>
        <Link
          href="/blog"
          className="rounded-lg border border-gray-300 px-6 py-3 font-medium text-gray-700 transition-colors hover:bg-gray-100 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-gray-800"
        
getStats function · typescript · L9-L20 (12 LOC)
src/app/page.tsx
async function getStats() {
  try {
    await connectDB();
    const [tenantsCount, plansData] = await Promise.all([
      Tenant.countDocuments({ status: 'active' }),
      Plan.find({ isActive: true }).sort({ sortOrder: 1 }).lean(),
    ]);
    return { tenantsCount, plans: plansData };
  } catch (error) {
    return { tenantsCount: 0, plans: [] };
  }
}
MarketingHomePage function · typescript · L22-L395 (374 LOC)
src/app/page.tsx
export default async function MarketingHomePage() {
  const { tenantsCount, plans } = await getStats();

  return (
    <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">
                <svg className="w-5 h-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
                </svg>
              </div>
              <span className="text-xl font-bold text-gray-90
robots function · typescript · L4-L13 (10 LOC)
src/app/robots.ts
export default function robots(): MetadataRoute.Robots {
  return {
    rules: {
      userAgent: '*',
      allow: '/',
      disallow: ['/api/', '/admin/'],
    },
    sitemap: `${siteConfig.url}/sitemap.xml`,
  };
}
Repobility · code-quality intelligence · https://repobility.com
SearchPage function · typescript · L15-L49 (35 LOC)
src/app/search/page.tsx
export default async function SearchPage({ searchParams }: SearchPageProps) {
  const { q: query } = await searchParams;
  const posts = query ? await searchPosts(query) : [];

  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">
          Search
        </h1>
        <p className="mb-6 text-lg text-gray-600 dark:text-gray-400">
          Find articles by title, description, or tags
        </p>
        <div className="mx-auto max-w-md">
          <SearchBar />
        </div>
      </div>

      {/* Results */}
      {query ? (
        <div>
          <p className="mb-8 text-center text-gray-600 dark:text-gray-400">
            {posts.length} {posts.length === 1 ? 'result' : 'results'} for &quot;{query}&quot;
          </p>
          <PostList posts={posts} />
        </div>
      ) : (
        <p className="text-center text-gray-500 dar
SignupContent function · typescript · L6-L25 (20 LOC)
src/app/signup/page.tsx
function SignupContent() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const plan = searchParams.get('plan');

  useEffect(() => {
    // Redirect to register page with plan param if provided
    const redirectUrl = plan ? `/register?plan=${plan}` : '/register';
    router.replace(redirectUrl);
  }, [router, plan]);

  return (
    <div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex items-center justify-center">
      <div className="text-center">
        <div className="h-8 w-8 animate-spin rounded-full border-4 border-indigo-600 border-t-transparent mx-auto mb-4" />
        <p className="text-gray-600 dark:text-gray-400">Redirecting...</p>
      </div>
    </div>
  );
}
LoadingFallback function · typescript · L27-L36 (10 LOC)
src/app/signup/page.tsx
function LoadingFallback() {
  return (
    <div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex items-center justify-center">
      <div className="text-center">
        <div className="h-8 w-8 animate-spin rounded-full border-4 border-indigo-600 border-t-transparent mx-auto mb-4" />
        <p className="text-gray-600 dark:text-gray-400">Loading...</p>
      </div>
    </div>
  );
}
SignupPage function · typescript · L39-L45 (7 LOC)
src/app/signup/page.tsx
export default function SignupPage() {
  return (
    <Suspense fallback={<LoadingFallback />}>
      <SignupContent />
    </Suspense>
  );
}
sitemap function · typescript · L6-L42 (37 LOC)
src/app/sitemap.ts
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const baseUrl = siteConfig.url;

  // Static pages
  const staticPages = [
    '',
    '/blog',
    '/authors',
    '/about',
    '/contact',
  ].map((route) => ({
    url: `${baseUrl}${route}`,
    lastModified: new Date(),
    changeFrequency: 'weekly' as const,
    priority: route === '' ? 1 : 0.8,
  }));

  // Blog posts
  const posts = await getAllPosts();
  const postPages = posts.map((post) => ({
    url: `${baseUrl}/blog/${post.slug}`,
    lastModified: new Date(post.date),
    changeFrequency: 'monthly' as const,
    priority: 0.6,
  }));

  // Author pages
  const authors = await getAllAuthors();
  const authorPages = authors.map((author) => ({
    url: `${baseUrl}/authors/${author.slug}`,
    lastModified: new Date(),
    changeFrequency: 'monthly' as const,
    priority: 0.5,
  }));

  return [...staticPages, ...postPages, ...authorPages];
}
SuperAdminAuthorsPage function · typescript · L54-L405 (352 LOC)
src/app/(super-admin)/super-admin/authors/page.tsx
export default function SuperAdminAuthorsPage() {
  const [authors, setAuthors] = useState<Author[]>([]);
  const [pagination, setPagination] = useState<Pagination>({
    page: 1,
    limit: 20,
    total: 0,
    totalPages: 0,
  });
  const [loading, setLoading] = useState(true);
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState({
    canLogin: '',
    canPost: '',
  });
  const [showFilters, setShowFilters] = useState(false);

  useEffect(() => {
    fetchAuthors();
  }, [pagination.page, filters]);

  const fetchAuthors = async () => {
    setLoading(true);
    try {
      const params = new URLSearchParams({
        page: pagination.page.toString(),
        limit: pagination.limit.toString(),
      });

      if (search) params.set('search', search);
      if (filters.canLogin) params.set('canLogin', filters.canLogin);
      if (filters.canPost) params.set('canPost', filters.canPost);

      const res = await fetch(`/api/super-admin/authors?${para
ImpersonatePage function · typescript · L29-L221 (193 LOC)
src/app/(super-admin)/super-admin/impersonate/[id]/page.tsx
export default function ImpersonatePage() {
  const params = useParams();
  const id = params.id as string;
  const [data, setData] = useState<ImpersonationData | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');
  const [countdown, setCountdown] = useState(5);
  const [autoRedirect, setAutoRedirect] = useState(false);

  const initiateImpersonation = async () => {
    try {
      setLoading(true);
      setError('');

      const res = await fetch(`/api/super-admin/impersonate/${id}`, {
        method: 'POST',
      });

      const responseData = await res.json();

      if (!res.ok) {
        throw new Error(responseData.error || 'Failed to create impersonation session');
      }

      setData(responseData.data);
    } catch (err: any) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    if (autoRedirect && data && countdown > 0) {
      const timer = setTimeout(() => {
    
SuperAdminLayout function · typescript · L54-L312 (259 LOC)
src/app/(super-admin)/super-admin/layout.tsx
export default function SuperAdminLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const router = useRouter();
  const pathname = usePathname();
  const [session, setSession] = useState<SuperAdminSession | null>(null);
  const [loading, setLoading] = useState(true);
  const [sidebarOpen, setSidebarOpen] = useState(false);
  const [badges, setBadges] = useState<Record<string, number>>({});

  // Use refs to cache session check timestamp
  const lastSessionCheck = useRef<number>(0);
  const sessionChecked = useRef<boolean>(false);

  // Skip auth check for login page
  const isLoginPage = pathname === '/super-admin/login';

  // Fetch badge counts (pending plan requests)
  const fetchBadgeCounts = useCallback(async () => {
    try {
      const res = await fetch('/api/super-admin/plan-requests?status=pending&limit=1');
      const data = await res.json();
      if (data.success) {
        setBadges({
          pendingRequests: data.data.stats?.pending || 0,
        });
     
Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
SuperAdminLoginPage function · typescript · L7-L131 (125 LOC)
src/app/(super-admin)/super-admin/login/page.tsx
export default function SuperAdminLoginPage() {
  const router = useRouter();
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [showPassword, setShowPassword] = useState(false);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    setError('');

    try {
      const res = await fetch('/api/super-admin/auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, password }),
      });

      const data = await res.json();

      if (!res.ok) {
        throw new Error(data.error || 'Login failed');
      }

      // Redirect to dashboard
      router.push('/super-admin');
      router.refresh();
    } catch (err: any) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div class
StatCard function · typescript · L73-L122 (50 LOC)
src/app/(super-admin)/super-admin/page.tsx
function StatCard({
  title,
  value,
  icon: Icon,
  change,
  changeLabel,
  gradient,
  link,
}: {
  title: string;
  value: number | string;
  icon: any;
  change?: number;
  changeLabel?: string;
  gradient: string;
  link?: string;
}) {
  const content = (
    <div className={`relative overflow-hidden rounded-2xl p-6 ${gradient}`}>
      <div className="relative z-10">
        <div className="flex items-center justify-between">
          <p className="text-sm font-medium text-white/80">{title}</p>
          <div className="rounded-xl bg-white/20 p-2">
            <Icon className="h-5 w-5 text-white" />
          </div>
        </div>
        <p className="mt-3 text-3xl font-bold text-white">{value.toLocaleString()}</p>
        {(change !== undefined || changeLabel) && (
          <div className="mt-3 flex items-center gap-2">
            {change !== undefined && (
              <span className={`flex items-center text-sm font-medium ${change >= 0 ? 'text-emerald-200' : 'text-red-
GrowthIndicator function · typescript · L124-L143 (20 LOC)
src/app/(super-admin)/super-admin/page.tsx
function GrowthIndicator({ value, label }: { value: number; label: string }) {
  const isPositive = value >= 0;
  return (
    <div className="flex items-center gap-3 rounded-xl bg-gray-50 dark:bg-gray-800/50 p-4">
      <div className={`rounded-full p-2 ${isPositive ? 'bg-emerald-100 dark:bg-emerald-900/30' : 'bg-red-100 dark:bg-red-900/30'}`}>
        {isPositive ? (
          <TrendingUp className={`h-4 w-4 ${isPositive ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400'}`} />
        ) : (
          <TrendingDown className="h-4 w-4 text-red-600 dark:text-red-400" />
        )}
      </div>
      <div>
        <p className={`text-lg font-bold ${isPositive ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400'}`}>
          {isPositive ? '+' : ''}{value}%
        </p>
        <p className="text-xs text-gray-500 dark:text-gray-400">{label}</p>
      </div>
    </div>
  );
}
SuperAdminPlansPage function · typescript · L27-L138 (112 LOC)
src/app/(super-admin)/super-admin/plans/page.tsx
export default function SuperAdminPlansPage() {
  const [plans, setPlans] = useState<Plan[]>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetchPlans();
  }, []);

  const fetchPlans = async () => {
    try {
      const res = await fetch('/api/super-admin/plans');
      const data = await res.json();
      if (data.success) {
        setPlans(data.data);
      }
    } catch (error) {
      console.error('Error fetching plans:', error);
    } finally {
      setLoading(false);
    }
  };

  if (loading) {
    return (
      <div className="flex items-center justify-center py-12">
        <div className="h-8 w-8 animate-spin rounded-full border-4 border-indigo-600 border-t-transparent" />
      </div>
    );
  }

  return (
    <div>
      <div className="mb-8">
        <h1 className="text-2xl font-bold text-gray-900 dark:text-white">Plans</h1>
        <p className="mt-1 text-gray-500 dark:text-gray-400">
          Manage subscription plans
        </p>
 
SuperAdminUsersPage function · typescript · L19-L125 (107 LOC)
src/app/(super-admin)/super-admin/users/page.tsx
export default function SuperAdminUsersPage() {
  const [users, setUsers] = useState<User[]>([]);
  const [loading, setLoading] = useState(true);
  const [search, setSearch] = useState('');

  useEffect(() => {
    fetchUsers();
  }, []);

  const fetchUsers = async () => {
    try {
      const res = await fetch('/api/super-admin/users');
      const data = await res.json();
      if (data.success) {
        setUsers(data.data);
      }
    } catch (error) {
      console.error('Error fetching users:', error);
    } finally {
      setLoading(false);
    }
  };

  const filteredUsers = users.filter(user =>
    user.name?.toLowerCase().includes(search.toLowerCase()) ||
    user.email?.toLowerCase().includes(search.toLowerCase())
  );

  if (loading) {
    return (
      <div className="flex items-center justify-center py-12">
        <div className="h-8 w-8 animate-spin rounded-full border-4 border-indigo-600 border-t-transparent" />
      </div>
    );
  }

  return (
    <div>
      
generateMetadata function · typescript · L11-L17 (7 LOC)
src/app/tags/[slug]/page.tsx
export async function generateMetadata({ params }: TagPageProps): Promise<Metadata> {
  const { slug } = await params;
  return {
    title: `#${slug}`,
    description: `Posts tagged with #${slug}`,
  };
}
TagPage function · typescript · L19-L42 (24 LOC)
src/app/tags/[slug]/page.tsx
export default async function TagPage({ params }: TagPageProps) {
  const { slug } = await params;
  const posts = await getPostsByTag(slug);

  return (
    <div className="container mx-auto px-4 py-12">
      {/* Header */}
      <div className="mb-12 text-center">
        <span className="mb-4 inline-flex rounded-full bg-gray-100 px-4 py-2 text-lg font-medium text-gray-700 dark:bg-gray-800 dark:text-gray-300">
          #{slug}
        </span>
        <h1 className="mb-4 text-4xl font-bold text-gray-900 dark:text-white">
          Posts tagged with #{slug}
        </h1>
        <p className="text-lg text-gray-600 dark:text-gray-400">
          {posts.length} {posts.length === 1 ? 'post' : 'posts'} found
        </p>
      </div>

      {/* Posts Grid */}
      <PostList posts={posts} />
    </div>
  );
}
AnalyticsPage function · typescript · L53-L374 (322 LOC)
src/app/t/[tenant]/admin/analytics/page.tsx
export default function AnalyticsPage() {
  const [loading, setLoading] = useState(true);
  const [locked, setLocked] = useState(false);
  const [data, setData] = useState<AnalyticsData | null>(null);
  const [error, setError] = useState('');

  useEffect(() => {
    fetchAnalytics();
  }, []);

  const fetchAnalytics = async () => {
    try {
      const res = await fetch('/api/admin/analytics');
      const result = await res.json();

      if (result.locked) {
        setLocked(true);
      } else if (result.success) {
        setData(result.data);
      } else {
        setError(result.error || 'Failed to load analytics');
      }
    } catch (err) {
      setError('Failed to load analytics');
    } finally {
      setLoading(false);
    }
  };

  if (loading) {
    return (
      <div className="flex items-center justify-center py-12">
        <div className="h-8 w-8 animate-spin rounded-full border-4 border-indigo-600 border-t-transparent" />
      </div>
    );
  }

  // Locked 
All rows scored by the Repobility analyzer (https://repobility.com)
TenantAdminCategoriesPage function · typescript · L32-L400 (369 LOC)
src/app/t/[tenant]/admin/categories/page.tsx
export default function TenantAdminCategoriesPage() {
  const { status } = useSession();

  const [categories, setCategories] = useState<Category[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');
  const [success, setSuccess] = useState('');


  // Modal state
  const [showModal, setShowModal] = useState(false);
  const [editingCategory, setEditingCategory] = useState<Category | null>(null);
  const [formData, setFormData] = useState({ name: '', description: '', color: 'bg-blue-500' });
  const [saving, setSaving] = useState(false);

  // Delete confirmation
  const [deleteConfirm, setDeleteConfirm] = useState<string | null>(null);
  const [deleting, setDeleting] = useState(false);

  useEffect(() => {
    if (status === 'authenticated') {
      fetchCategories();
    }
  }, [status]);

  const fetchCategories = async () => {
    try {
      const res = await fetch('/api/admin/categories');
      if (!res.ok) throw new Error('Failed to fe
getCookie function · typescript · L28-L34 (7 LOC)
src/app/t/[tenant]/admin/layout.tsx
function getCookie(name: string): string | null {
  if (typeof document === 'undefined') return null;
  const value = `; ${document.cookie}`;
  const parts = value.split(`; ${name}=`);
  if (parts.length === 2) return parts.pop()?.split(';').shift() || null;
  return null;
}
TenantAdminLayout function · typescript · L63-L381 (319 LOC)
src/app/t/[tenant]/admin/layout.tsx
export default function TenantAdminLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const router = useRouter();
  const pathname = usePathname();
  const params = useParams();
  const { data: session, status } = useSession();
  const [sidebarOpen, setSidebarOpen] = useState(false);
  const [tenant, setTenant] = useState<TenantInfo | null>(null);
  const [accessDenied, setAccessDenied] = useState(false);
  const [loading, setLoading] = useState(true);
  const [isImpersonating, setIsImpersonating] = useState(false);
  const [impersonationUser, setImpersonationUser] = useState<{ name: string; email: string } | null>(null);
  const [userRole, setUserRole] = useState<string | undefined>(undefined);

  // Cache tenant fetch to avoid repeated API calls on navigation
  const tenantFetchedRef = useRef<boolean>(false);
  const tenantCacheRef = useRef<TenantInfo | null>(null);

  const tenantSlug = params.tenant as string;
  const basePath = `/t/${tenantSlug}/admin`;
  const isLoginP
TenantAdminLoginPage function · typescript · L9-L301 (293 LOC)
src/app/t/[tenant]/admin/login/page.tsx
export default function TenantAdminLoginPage() {
  const params = useParams();
  const router = useRouter();
  const tenantSlug = params.tenant as string;

  const [isFormLoading, setIsFormLoading] = useState(false);
  const [isGoogleLoading, setIsGoogleLoading] = useState(false);
  const [error, setError] = useState('');
  const [loginMode, setLoginMode] = useState<'owner' | 'author'>('owner');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleGoogleSignIn = async () => {
    setIsGoogleLoading(true);
    setError('');

    try {
      const result = await signIn('google', {
        callbackUrl: `/t/${tenantSlug}/admin`,
        redirect: true,
      });
    } catch (err) {
      setError('An error occurred. Please try again.');
      setIsGoogleLoading(false);
    }
  };

  const handleOwnerLogin = async (e: React.FormEvent) => {
    e.preventDefault();
    setIsFormLoading(true);
    setError('');

    try {
      const result =
AdminPagesPage function · typescript · L149-L487 (339 LOC)
src/app/t/[tenant]/admin/pages/page.tsx
export default function AdminPagesPage() {
  const params = useParams();
  const { data: session, status } = useSession();
  const tenantSlug = params.tenant as string;
  const basePath = `/t/${tenantSlug}/admin`;

  const [pages, setPages] = useState<Page[]>([]);
  const [loading, setLoading] = useState(true);
  const [showTemplates, setShowTemplates] = useState(false);
  const [creating, setCreating] = useState(false);
  const [error, setError] = useState('');
  const [accessDenied, setAccessDenied] = useState(false);

  const userRole = (session?.user as any)?.role;

  useEffect(() => {
    if (status === 'authenticated' && userRole === 'author') {
      setAccessDenied(true);
      setLoading(false);
      return;
    }

    if (status === 'authenticated') {
      fetchPages();
    }
  }, [status, userRole]);

  const fetchPages = async () => {
    try {
      const response = await fetch('/api/admin/pages');
      const data = await response.json();
      if (data.success) {
     
TenantAdminDashboard function · typescript · L55-L411 (357 LOC)
src/app/t/[tenant]/admin/page.tsx
export default function TenantAdminDashboard() {
  const params = useParams();
  const tenantSlug = params.tenant as string;
  const basePath = `/t/${tenantSlug}/admin`;

  const [stats, setStats] = useState<DashboardStats | null>(null);
  const [loading, setLoading] = useState(true);
  const [pendingRequest, setPendingRequest] = useState<PendingRequest | null>(null);
  const [platformContact, setPlatformContact] = useState<PlatformContact | null>(null);
  const [profileComplete, setProfileComplete] = useState(true);
  const [showProfileAlert, setShowProfileAlert] = useState(true);

  useEffect(() => {
    fetchStats();
    fetchPlanRequest();
    fetchProfileStatus();
  }, []);

  const fetchStats = async () => {
    try {
      const res = await fetch('/api/admin/dashboard');
      const data = await res.json();
      if (data.success) {
        setStats(data.data);
      }
    } catch (error) {
      console.error('Error fetching stats:', error);
    } finally {
      setLoading(fal
TenantAdminEditPostPage function · typescript · L26-L145 (120 LOC)
src/app/t/[tenant]/admin/posts/[id]/edit/page.tsx
export default function TenantAdminEditPostPage() {
  const params = useParams();
  const router = useRouter();
  const { data: session, status } = useSession();
  const tenantSlug = params.tenant as string;
  const postId = params.id as string;
  const basePath = `/t/${tenantSlug}/admin`;

  const [authors, setAuthors] = useState<Author[]>([]);
  const [post, setPost] = useState<PostData | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');

  const userRole = (session?.user as any)?.role;
  const userAuthorId = (session?.user as any)?.authorId;
  const userName = session?.user?.name;
  const isAuthor = userRole === 'author';

  useEffect(() => {
    if (status === 'loading') return;

    const loadData = async () => {
      await fetchPost();

      // For authors, use their own info - don't fetch authors list
      if (isAuthor && userAuthorId) {
        setAuthors([{ id: userAuthorId, name: userName || 'You' }]);
      } else {
   
TenantAdminNewPostPage function · typescript · L13-L81 (69 LOC)
src/app/t/[tenant]/admin/posts/new/page.tsx
export default function TenantAdminNewPostPage() {
  const params = useParams();
  const { data: session, status } = useSession();
  const tenantSlug = params.tenant as string;

  const [authors, setAuthors] = useState<Author[]>([]);
  const [loading, setLoading] = useState(true);

  const userRole = (session?.user as any)?.role;
  const userAuthorId = (session?.user as any)?.authorId;
  const userName = session?.user?.name;
  const isAuthor = userRole === 'author';

  useEffect(() => {
    if (status === 'loading') return;

    // For authors, use their own info - don't fetch authors list
    if (isAuthor && userAuthorId) {
      setAuthors([{ id: userAuthorId, name: userName || 'You' }]);
      setLoading(false);
      return;
    }

    // For admins/owners, fetch the authors list
    fetchAuthors();
  }, [status, isAuthor, userAuthorId, userName]);

  const fetchAuthors = async () => {
    try {
      const res = await fetch('/api/admin/authors');
      const data = await res.json(
Repobility · open methodology · https://repobility.com/research/
ReviewsPage function · typescript · L26-L299 (274 LOC)
src/app/t/[tenant]/admin/reviews/page.tsx
export default function ReviewsPage() {
  const params = useParams();
  const router = useRouter();
  const tenant = params.tenant as string;

  const [reviews, setReviews] = useState<Review[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [requiresUpgrade, setRequiresUpgrade] = useState(false);

  useEffect(() => {
    fetchReviews();
  }, []);

  const fetchReviews = async () => {
    try {
      const response = await fetch('/api/admin/reviews');
      const data = await response.json();

      if (data.requiresUpgrade) {
        setRequiresUpgrade(true);
        setError(data.error);
        return;
      }

      if (data.success) {
        setReviews(data.data);
      } else {
        setError(data.error);
      }
    } catch (err: any) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  const handleDelete = async (id: string) => {
    if (!confirm('Are you sure you want to
generateMetadata function · typescript · L23-L40 (18 LOC)
src/app/t/[tenant]/blog/page.tsx
export async function generateMetadata({ params }: { params: Promise<{ tenant: string }> }): Promise<Metadata> {
  const { tenant: tenantSlug } = await params;
  const tenant = await getTenantBySlug(tenantSlug);
  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 || 'Read our latest blog posts';

  return {
    title: {
      absolute: `Blog | ${siteName}`,
    },
    description: seoDescription,
  };
}
getReviewBySlugOrId function · typescript · L22-L42 (21 LOC)
src/app/t/[tenant]/blog/[slug]/page.tsx
async function getReviewBySlugOrId(slugOrId: string, tenantId: string) {
  await connectDB();

  // First try by slug
  let review = await Review.findOne({
    tenantId,
    'generatedReview.slug': slugOrId,
    published: true,
  }).lean();

  // If not found and looks like MongoDB ObjectId, try by _id
  if (!review && /^[a-f0-9]{24}$/i.test(slugOrId)) {
    review = await Review.findOne({
      _id: slugOrId,
      tenantId,
      published: true,
    }).lean();
  }

  return review ? JSON.parse(JSON.stringify(review)) : null;
}
‹ prevpage 4 / 7next ›