← back to jessperate__campaign-quiz

Function bodies 101 total

All specs Real LLM only Function bodies
MetricCard function · typescript · L32-L50 (19 LOC)
app/admin/dashboard/page.tsx
function MetricCard({ title, value, change, icon }: {
  title: string;
  value: string | number;
  change?: string;
  icon: string;
}) {
  return (
    <div className="bg-white rounded-lg shadow p-6 border border-gray-200">
      <div className="flex items-center justify-between mb-2">
        <span className="text-gray-600 text-sm font-medium">{title}</span>
        <span className="text-2xl">{icon}</span>
      </div>
      <div className="text-3xl font-bold text-gray-900 mb-1">{value}</div>
      {change && (
        <div className="text-sm text-green-600">{change}</div>
      )}
    </div>
  );
}
ErrorModal function · typescript · L52-L153 (102 LOC)
app/admin/dashboard/page.tsx
function ErrorModal({ error, onClose }: { error: ErrorDetail; onClose: () => void }) {
  return (
    <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
      <div className="bg-white rounded-lg shadow-xl max-w-3xl w-full max-h-[90vh] overflow-auto">
        {/* Header */}
        <div className="sticky top-0 bg-white border-b border-gray-200 px-6 py-4 flex items-center justify-between">
          <div>
            <h3 className="text-xl font-bold text-gray-900">Error Details</h3>
            <p className="text-sm text-gray-500 mt-1">{error.timestamp}</p>
          </div>
          <button
            onClick={onClose}
            className="text-gray-400 hover:text-gray-600 text-2xl leading-none"
          >
            ×
          </button>
        </div>

        {/* Content */}
        <div className="p-6 space-y-4">
          {/* Error Type */}
          <div>
            <label className="text-sm font-semibold text-gray-700 block mb-1
DashboardPage function · typescript · L201-L494 (294 LOC)
app/admin/dashboard/page.tsx
export default function DashboardPage() {
  const [metrics, setMetrics] = useState<MetricData | null>(null);
  const [healthChecks, setHealthChecks] = useState<HealthCheck[]>([]);
  const [loading, setLoading] = useState(true);
  const [selectedError, setSelectedError] = useState<ErrorDetail | null>(null);
  const [lastUpdate, setLastUpdate] = useState<Date>(new Date());

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

  async function loadDashboardData() {
    setLoading(true);
    try {
      // Simulate API calls - replace with actual API
      await new Promise(resolve => setTimeout(resolve, 500));

      // Mock metrics
      setMetrics({
        users: 1234,
        sessions: 2456,
        pageviews: 5678,
        conversions: 89,
        avgSessionDuration: 145,
      });

      // Mock health checks with detailed errors
      const checks: HealthCheck[] = [
        {
          name: 'Submit Quiz API',
          status: 'healthy',
          message: 'Responding normally'
loadDashboardData function · typescript · L212-L325 (114 LOC)
app/admin/dashboard/page.tsx
  async function loadDashboardData() {
    setLoading(true);
    try {
      // Simulate API calls - replace with actual API
      await new Promise(resolve => setTimeout(resolve, 500));

      // Mock metrics
      setMetrics({
        users: 1234,
        sessions: 2456,
        pageviews: 5678,
        conversions: 89,
        avgSessionDuration: 145,
      });

      // Mock health checks with detailed errors
      const checks: HealthCheck[] = [
        {
          name: 'Submit Quiz API',
          status: 'healthy',
          message: 'Responding normally',
          lastChecked: new Date().toISOString(),
        },
        {
          name: 'Get Results API',
          status: 'healthy',
          message: 'Responding normally',
          lastChecked: new Date().toISOString(),
        },
        {
          name: 'Generate Image API',
          status: 'error',
          message: 'Timeout after 30s',
          lastChecked: new Date().toISOString(),
          details: {
        
Bar function · typescript · L67-L76 (10 LOC)
app/admin/insights/page.tsx
function Bar({ pct, color }: { pct: number; color: string }) {
  return (
    <div className="w-full bg-gray-100 rounded-full h-2.5 overflow-hidden">
      <div
        className="h-2.5 rounded-full transition-all duration-500"
        style={{ width: `${Math.max(pct, pct > 0 ? 1 : 0)}%`, backgroundColor: color }}
      />
    </div>
  );
}
Card function · typescript · L78-L84 (7 LOC)
app/admin/insights/page.tsx
function Card({ children, className = "" }: { children: React.ReactNode; className?: string }) {
  return (
    <div className={`bg-white rounded-xl border border-gray-200 shadow-sm p-6 ${className}`}>
      {children}
    </div>
  );
}
SectionHeader function · typescript · L86-L93 (8 LOC)
app/admin/insights/page.tsx
function SectionHeader({ title, subtitle }: { title: string; subtitle?: string }) {
  return (
    <div className="mb-5">
      <h2 className="text-xl font-bold text-gray-900">{title}</h2>
      {subtitle && <p className="text-sm text-gray-500 mt-1">{subtitle}</p>}
    </div>
  );
}
Repobility · code-quality intelligence · https://repobility.com
generateInsightsSynthesis function · typescript · L95-L152 (58 LOC)
app/admin/insights/page.tsx
function generateInsightsSynthesis(data: InsightsData): string[] {
  const top = data.archetypeRanked[0];
  const second = data.archetypeRanked[1];
  const topRole = Object.entries(data.roleCounts).sort((a, b) => b[1] - a[1])[0][0];
  const insights: string[] = [];

  if (top) {
    if (top.id === "craft" || top.id === "vision") {
      insights.push(
        `${top.pct}% of respondents identify as ${top.label}s — the largest segment. This signals a market grappling with quality and strategy in an AI-saturated landscape. These marketers aren't looking for shortcuts; they want tools that help them do their best work at scale.`
      );
    } else if (top.id === "maverick") {
      insights.push(
        `${top.pct}% of respondents are Mavericks — a strong signal that this audience is AI-forward and willing to experiment. They're likely already using AEO tools and are primed for advanced workflows rather than introductory content.`
      );
    } else if (top.id === "spark") {
      insi
QuestionSection function · typescript · L154-L229 (76 LOC)
app/admin/insights/page.tsx
function QuestionSection({
  questions,
  roleKey,
  distributions,
  answeredSubmissions,
  isEstimated,
}: {
  questions: QuestionInterpretation[];
  roleKey: string;
  distributions: Record<string, { answer: string; count: number; pct: number }[]>;
  answeredSubmissions: number;
  isEstimated: boolean;
}) {
  const hasData = answeredSubmissions > 0 || isEstimated;

  return (
    <div className="space-y-6">
      {questions.map((q) => {
        const dist = distributions[q.id] || [];
        const distMap: Record<string, { count: number; pct: number }> = {};
        for (const d of dist) distMap[d.answer] = { count: d.count, pct: d.pct };

        return (
          <Card key={q.id}>
            <div className="mb-4">
              <span className="text-xs font-semibold uppercase tracking-wide text-gray-400">
                {q.id.toUpperCase()}
              </span>
              <h3 className="text-base font-semibold text-gray-900 mt-1">{q.text}</h3>
            </div>
           
InsightsPage function · typescript · L231-L521 (291 LOC)
app/admin/insights/page.tsx
export default function InsightsPage() {
  const [data, setData] = useState<InsightsData | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [activeRole, setActiveRole] = useState<string>("all");
  const [activeQuestionRole, setActiveQuestionRole] = useState<"ic" | "manager" | "executive">("ic");

  useEffect(() => {
    fetch("/api/insights")
      .then((r) => r.json())
      .then((d) => {
        if (d.error) throw new Error(d.error);
        setData(d);
      })
      .catch((e) => setError(e.message))
      .finally(() => setLoading(false));
  }, []);

  if (loading) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-gray-500 text-sm">Loading insights...</div>
      </div>
    );
  }

  if (error || !data) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-r
DELETE function · typescript · L4-L22 (19 LOC)
app/api/admin/remove-user/route.ts
export async function DELETE(request: NextRequest) {
  const secret = request.headers.get("x-admin-secret");
  if (!secret || secret !== process.env.ADMIN_SECRET) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const userId = request.nextUrl.searchParams.get("userId");
  if (!userId) {
    return NextResponse.json({ error: "Missing userId" }, { status: 400 });
  }

  const deleted = await redis.del(`quiz:${userId}`);

  return NextResponse.json({
    success: true,
    deleted: deleted > 0,
    message: deleted > 0 ? `Removed quiz:${userId}` : `No record found for ${userId}`,
  });
}
verifySlackSignature function · typescript · L5-L20 (16 LOC)
app/api/admin/slack-action/route.ts
function verifySlackSignature(request: NextRequest, body: string): boolean {
  const signingSecret = process.env.SLACK_SIGNING_SECRET;
  if (!signingSecret) return false;

  const timestamp = request.headers.get("x-slack-request-timestamp") || "";
  const slackSig = request.headers.get("x-slack-signature") || "";

  // Reject requests older than 5 minutes
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const baseString = `v0:${timestamp}:${body}`;
  const hmac = crypto.createHmac("sha256", signingSecret).update(baseString).digest("hex");
  const computedSig = `v0=${hmac}`;

  return crypto.timingSafeEqual(Buffer.from(computedSig), Buffer.from(slackSig));
}
POST function · typescript · L22-L100 (79 LOC)
app/api/admin/slack-action/route.ts
export async function POST(request: NextRequest) {
  const body = await request.text();

  if (!verifySlackSignature(request, body)) {
    return NextResponse.json({ error: "Invalid signature" }, { status: 401 });
  }

  const params = new URLSearchParams(body);
  const payload = JSON.parse(params.get("payload") || "{}");

  const action = payload.actions?.[0];
  if (!action) {
    return NextResponse.json({ error: "No action" }, { status: 400 });
  }

  const userId = action.value;
  const actionId = action.action_id;
  const responseUrl = payload.response_url;
  const userName = payload.user?.name || "Someone";

  if (actionId === "remove_user") {
    // Delete from Redis
    const deleted = await redis.del(`quiz:${userId}`);

    // Update the Slack message to show it was removed
    if (responseUrl) {
      const originalBlocks = payload.message?.blocks || [];
      // Keep the info and image blocks, replace the actions block
      const updatedBlocks = originalBlocks
        .filt
normalizeArchetypeId function · typescript · L12-L14 (3 LOC)
app/api/all-cards/route.ts
function normalizeArchetypeId(id: string): string {
  return ARCHETYPE_ID_MAP[id] || id;
}
OPTIONS function · typescript · L28-L30 (3 LOC)
app/api/all-cards/route.ts
export async function OPTIONS() {
  return new NextResponse(null, { status: 204, headers: CORS_HEADERS });
}
Repobility analyzer · published findings · https://repobility.com
GET function · typescript · L32-L123 (92 LOC)
app/api/all-cards/route.ts
export async function GET() {
  try {
    // Return cached response if fresh
    if (cachedResponse && Date.now() - cachedResponse.timestamp < CACHE_TTL_MS) {
      return NextResponse.json({ cards: cachedResponse.cards }, { headers: CORS_HEADERS });
    }

    const baseUrl = process.env.VERCEL_PROJECT_PRODUCTION_URL
      ? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`
      : "https://campaign-quiz.vercel.app";

    const cards: Array<Record<string, unknown>> = [];

    let cursor = "0";
    do {
      const [nextCursor, keys] = await redis.scan(cursor, "MATCH", "quiz:*", "COUNT", 100);
      cursor = nextCursor;

      if (keys.length > 0) {
        const pipeline = redis.pipeline();
        for (const key of keys) {
          pipeline.get(key);
        }
        const results = await pipeline.exec();

        if (results) {
          for (const [err, val] of results) {
            if (err || !val) continue;
            try {
              const data = JSON.parse(val as st
OPTIONS function · typescript · L17-L19 (3 LOC)
app/api/enrich-linkedin/route.ts
export async function OPTIONS() {
  return new NextResponse(null, { status: 204, headers: CORS_HEADERS });
}
POST function · typescript · L21-L168 (148 LOC)
app/api/enrich-linkedin/route.ts
export async function POST(request: NextRequest) {
  try {
    const { userId, linkedinUrl } = await request.json();

    if (!userId || !linkedinUrl) {
      return NextResponse.json(
        { success: false, error: "userId and linkedinUrl are required." },
        { status: 400, headers: CORS_HEADERS }
      );
    }

    // Fetch existing data from Redis
    const existing = await redis.get(`quiz:${userId}`);
    if (!existing) {
      return NextResponse.json(
        { success: false, error: "User not found." },
        { status: 404, headers: CORS_HEADERS }
      );
    }

    const data = JSON.parse(existing);

    // If already enriched, verify the headshot blob is still accessible
    if (data.firstName && data.headshotUrl && data.enriched) {
      let headshotValid = false;
      try {
        const headCheck = await fetch(data.headshotUrl, { method: 'HEAD' });
        headshotValid = headCheck.ok;
      } catch {
        // Network error - treat as invalid
      }

      if
OPTIONS function · typescript · L13-L15 (3 LOC)
app/api/generate-image/route.ts
export async function OPTIONS() {
  return new NextResponse(null, { status: 204, headers: CORS_HEADERS });
}
POST function · typescript · L19-L194 (176 LOC)
app/api/generate-image/route.ts
export async function POST(request: NextRequest) {
  try {
    const { userName, archetype, tagline, photoBase64, photoUrl } = await request.json();

    const apiKey = process.env.GOOGLE_API_KEY;
    if (!apiKey) {
      return NextResponse.json(
        { error: "Google API key not configured. Please add GOOGLE_API_KEY to your environment variables." },
        { status: 500, headers: CORS_HEADERS }
      );
    }

    const ai = new GoogleGenAI({ apiKey });

    // Resolve photo data: use base64 directly, or download from URL
    let resolvedPhotoBase64 = photoBase64;
    if (!resolvedPhotoBase64 && photoUrl) {
      console.log(`Downloading photo from URL: ${photoUrl.substring(0, 100)}...`);
      try {
        const imageResponse = await fetch(photoUrl);
        if (imageResponse.ok) {
          const arrayBuffer = await imageResponse.arrayBuffer();
          const buffer = Buffer.from(arrayBuffer);
          const contentType = (imageResponse.headers.get('content-type') || 'image
normalizeArchetypeId function · typescript · L13-L15 (3 LOC)
app/api/get-results/route.ts
function normalizeArchetypeId(id: string): string {
  return ARCHETYPE_ID_MAP[id] || id;
}
OPTIONS function · typescript · L23-L25 (3 LOC)
app/api/get-results/route.ts
export async function OPTIONS() {
  return new NextResponse(null, { status: 204, headers: CORS_HEADERS });
}
GET function · typescript · L27-L112 (86 LOC)
app/api/get-results/route.ts
export async function GET(request: NextRequest) {
  try {
    const userId = request.nextUrl.searchParams.get("userId");

    if (!userId) {
      return NextResponse.json(
        { success: false, error: "userId query parameter is required." },
        { status: 400, headers: CORS_HEADERS }
      );
    }

    const data = await redis.get(`quiz:${userId}`);

    if (!data) {
      return NextResponse.json(
        { success: false, error: "Results not found for the given userId." },
        { status: 404, headers: CORS_HEADERS }
      );
    }

    const parsed = JSON.parse(data);

    // Normalize old archetype IDs (trendsetter→maverick, etc.) for existing records
    if (parsed.archetype?.id) {
      parsed.archetype.id = normalizeArchetypeId(parsed.archetype.id);
    }

    // Resolve base URL for absolute image paths
    const baseUrl = process.env.VERCEL_PROJECT_PRODUCTION_URL
      ? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`
      : "https://campaign-quiz.vercel.ap
Want this analysis on your repo? https://repobility.com/scan/
estimateAnswerDistributions function · typescript · L25-L28 (4 LOC)
app/api/insights/route.ts
function estimateAnswerDistributions(
  archetypeByRole: Record<string, Record<string, number>>,
  roleCounts: Record<string, number>
): Record<string, Record<string, { answer: string; count: number; pct: number }[]>> {
GET function · typescript · L59-L206 (148 LOC)
app/api/insights/route.ts
export async function GET() {
  try {
    let cursor = "0";
    const archetypeCounts: Record<string, number> = {};
    const roleCounts: Record<string, number> = { ic: 0, manager: 0, executive: 0 };
    const archetypeByRole: Record<string, Record<string, number>> = {
      ic: {},
      manager: {},
      executive: {},
    };
    const dailyCounts: Record<string, number> = {};
    const companyCounts: Record<string, number> = {};
    const answerCounts: AnswerCounts = { ic: {}, manager: {}, executive: {} };
    let answeredSubmissions = 0;
    let wantsDemoCount = 0;
    let total = 0;

    do {
      const [nextCursor, keys] = await redis.scan(cursor, "MATCH", "quiz:*", "COUNT", 200);
      cursor = nextCursor;

      if (keys.length === 0) continue;

      const values = await redis.mget(...keys);
      for (const val of values) {
        if (!val) continue;
        let data: Record<string, any>;
        try {
          data = JSON.parse(val);
        } catch {
          continue;
OPTIONS function · typescript · L12-L14 (3 LOC)
app/api/og-image/route.tsx
export async function OPTIONS() {
  return new Response(null, { status: 204, headers: CORS_HEADERS });
}
loadFonts function · typescript · L19-L32 (14 LOC)
app/api/og-image/route.tsx
async function loadFonts(baseUrl: string) {
  if (fontCache) return fontCache;
  const cdnBase = process.env.VERCEL_PROJECT_PRODUCTION_URL
    ? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`
    : baseUrl;
  const [serrif, serrifItalic, saans, saansMono] = await Promise.all([
    fetch(`${cdnBase}/fonts/Serrif-400.ttf`).then((r) => r.arrayBuffer()),
    fetch(`${cdnBase}/fonts/Serrif-400-Italic.ttf`).then((r) => r.arrayBuffer()),
    fetch(`${cdnBase}/fonts/Saans-Regular.woff`).then((r) => r.arrayBuffer()),
    fetch(`${cdnBase}/fonts/SaansMono-Medium.otf`).then((r) => r.arrayBuffer()),
  ]);
  fontCache = { serrif, serrifItalic, saans, saansMono };
  return fontCache;
}
POST function · typescript · L4-L36 (33 LOC)
app/api/save-card-url/route.ts
export async function POST(request: NextRequest) {
  try {
    const { userId, cardUrl, field } = await request.json();

    if (!userId || !cardUrl) {
      return NextResponse.json({ error: "Missing userId or cardUrl" }, { status: 400 });
    }

    // Read existing data, add cardUrl, write back with same TTL
    const existing = await redis.get(`quiz:${userId}`);
    if (!existing) {
      return NextResponse.json({ error: "User not found" }, { status: 404 });
    }

    const parsed = typeof existing === "string" ? JSON.parse(existing) : existing;
    // Use custom field name if provided, otherwise default to cardUrl
    const fieldName = field || "cardUrl";
    parsed[fieldName] = cardUrl;

    // Get remaining TTL and preserve it
    const ttl = await redis.ttl(`quiz:${userId}`);
    if (ttl > 0) {
      await redis.set(`quiz:${userId}`, JSON.stringify(parsed), "EX", ttl);
    } else {
      await redis.set(`quiz:${userId}`, JSON.stringify(parsed));
    }

    return NextResponse
normalizeArchetypeId function · typescript · L12-L14 (3 LOC)
app/api/share-copy/route.ts
function normalizeArchetypeId(id: string): string {
  return ARCHETYPE_ID_MAP[id] || id;
}
OPTIONS function · typescript · L32-L34 (3 LOC)
app/api/share-copy/route.ts
export async function OPTIONS() {
  return new NextResponse(null, { status: 204, headers: CORS_HEADERS });
}
GET function · typescript · L36-L118 (83 LOC)
app/api/share-copy/route.ts
export async function GET(request: NextRequest) {
  try {
    const userId = request.nextUrl.searchParams.get("userId");

    if (!userId) {
      return NextResponse.json(
        { success: false, error: "userId query parameter is required." },
        { status: 400, headers: CORS_HEADERS }
      );
    }

    const data = await redis.get(`quiz:${userId}`);

    if (!data) {
      return NextResponse.json(
        { success: false, error: "Results not found for the given userId." },
        { status: 404, headers: CORS_HEADERS }
      );
    }

    const parsed = JSON.parse(data);

    const archetypeId = normalizeArchetypeId(parsed.archetype?.id || "maverick");
    const archetypeName = parsed.archetype?.name || "Champion";
    const tagline = parsed.archetype?.tagline || "";
    const mostLikelyTo = parsed.bullets?.mostLikelyTo || "";
    const typicallySpending = parsed.bullets?.typicallySpending || "";
    const favoritePhrase = parsed.bullets?.favoritePhrase || "";

    const ba
Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
OPTIONS function · typescript · L19-L21 (3 LOC)
app/api/submit-quiz/route.ts
export async function OPTIONS() {
  return new NextResponse(null, { status: 204, headers: CORS_HEADERS });
}
POST function · typescript · L23-L278 (256 LOC)
app/api/submit-quiz/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    let { firstName, lastName, company, title } = body;
    const { role, answers, email, headshotUrl, stippleImageUrl, linkedinUrl, wantsDemo } = body;

    // Validate role
    if (!role || !VALID_ROLES.has(role)) {
      return NextResponse.json(
        { success: false, error: `Invalid role. Must be one of: ${[...VALID_ROLES].join(", ")}` },
        { status: 400, headers: CORS_HEADERS }
      );
    }

    // Validate answers
    if (!Array.isArray(answers) || answers.length !== REQUIRED_ANSWER_COUNT) {
      return NextResponse.json(
        { success: false, error: `Exactly ${REQUIRED_ANSWER_COUNT} answers are required.` },
        { status: 400, headers: CORS_HEADERS }
      );
    }

    for (const ans of answers) {
      if (!ans.question || typeof ans.question !== "number" || ans.question < 1 || ans.question > 6) {
        return NextResponse.json(
          { success: false, e
OPTIONS function · typescript · L10-L12 (3 LOC)
app/api/upload-card/route.ts
export async function OPTIONS() {
  return new NextResponse(null, { status: 204, headers: CORS_HEADERS });
}
POST function · typescript · L14-L51 (38 LOC)
app/api/upload-card/route.ts
export async function POST(request: NextRequest) {
  try {
    const { imageBase64, uniqueId } = await request.json();

    if (!imageBase64) {
      return NextResponse.json(
        { error: 'No image data provided' },
        { status: 400, headers: CORS_HEADERS }
      );
    }

    // Remove data URL prefix if present (handle all formats)
    const base64Data = imageBase64.replace(/^data:[^;]+;base64,/, '');

    // Convert base64 to buffer
    const buffer = Buffer.from(base64Data, 'base64');

    // Generate a unique filename
    const filename = `cards/${uniqueId || Date.now()}.png`;

    // Upload to Vercel Blob
    const blob = await put(filename, buffer, {
      access: 'public',
      contentType: 'image/png',
    });

    return NextResponse.json({
      success: true,
      url: blob.url,
    }, { headers: CORS_HEADERS });
  } catch (error) {
    console.error('Upload error:', error);
    return NextResponse.json(
      { error: 'Failed to upload image', details: String(e
RootLayout function · typescript · L39-L65 (27 LOC)
app/layout.tsx
export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en" prefix="og: http://ogp.me/ns#">
      <head>
        <Script
          src="https://www.googletagmanager.com/gtag/js?id=G-41PB5YFX2D"
          strategy="afterInteractive"
        />
        <Script id="gtag-init" strategy="afterInteractive">
          {`window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config','G-41PB5YFX2D');`}
        </Script>
      </head>
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased bg-background text-foreground`}
      >
        <LogRocketProvider />
        <ErrorBoundary>
          {children}
        </ErrorBoundary>
      </body>
    </html>
  );
}
Home function · typescript · L4-L63 (60 LOC)
app/page.tsx
export default function Home() {
  return (
    <div className="min-h-screen relative" style={{ background: 'linear-gradient(180deg, #00CE50 0%, #00250E 31.25%)' }}>

      {/* Hero background illustration — pinned to top, centered */}
      <img
        src="/images/hero-illustration.avif"
        alt=""
        style={{
          position: 'absolute',
          top: '-100px',
          left: '50%',
          transform: 'translateX(-50%)',
          width: '1135px',
          height: '1135px',
          pointerEvents: 'none',
          opacity: 0.4,
        }}
      />

      <div className="relative">
        {/* Hero Section */}
        <section className="relative pt-24 md:pt-36 pb-16 px-6 overflow-hidden">

          <div className="relative max-w-4xl mx-auto text-center">
            <p className="text-white/80 text-[24px] md:text-[36px] lg:text-[42px] mb-2 leading-tight" style={{ fontFamily: 'Serrif, serif' }}>
              Get your player card
            </p>
            <h1 
PreviewContent function · typescript · L20-L152 (133 LOC)
app/preview/page.tsx
function PreviewContent() {
  const searchParams = useSearchParams();
  const userId = searchParams.get("userId") || "";
  const [data, setData] = useState<ResultData | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    if (!userId) {
      setError("No userId provided");
      setLoading(false);
      return;
    }
    fetch(`/api/get-results?userId=${userId}`)
      .then((res) => res.json())
      .then((d) => {
        if (d.success) setData(d);
        else setError(d.error || "Not found");
      })
      .catch((err) => setError(String(err)))
      .finally(() => setLoading(false));
  }, [userId]);

  if (loading) {
    return <p style={{ color: "rgba(255,255,255,0.4)", padding: 48, textAlign: "center" }}>Loading...</p>;
  }
  if (error || !data) {
    return <p style={{ color: "#ff6b6b", padding: 48, textAlign: "center" }}>Error: {error}</p>;
  }

  const ogImageUrl = `/api/og-image?use
PreviewPage function · typescript · L154-L162 (9 LOC)
app/preview/page.tsx
export default function PreviewPage() {
  return (
    <div style={{ minHeight: "100vh", background: "#0a0a0a", color: "white", fontFamily: "system-ui, sans-serif" }}>
      <Suspense fallback={<p style={{ color: "rgba(255,255,255,0.4)", padding: 48, textAlign: "center" }}>Loading...</p>}>
        <PreviewContent />
      </Suspense>
    </div>
  );
}
Repobility · code-quality intelligence · https://repobility.com
generateMetadata function · typescript · L10-L82 (73 LOC)
app/results/page.tsx
export async function generateMetadata({ searchParams }: Props): Promise<Metadata> {
  const params = await searchParams;
  const userId = params.userId;

  if (!userId) {
    return {
      title: "Your Results | Content Engineer Quiz",
      description: "Discover your Content Engineer archetype.",
    };
  }

  try {
    const data = await redis.get(`quiz:${userId}`);
    if (!data) {
      return {
        title: "Your Results | Content Engineer Quiz",
      };
    }

    const parsed = typeof data === "string" ? JSON.parse(data) : data;
    const { firstName, lastName, archetype } = parsed;
    const role = parsed.role || "ic";
    const archetypeId = archetype?.id || "vision";
    const archetypeName = archetype?.name || "Champion";
    const tagline = ARCHETYPE_TAGLINES[archetypeId] || "Find your archetype.";
    const copy = getShareCopy(archetypeId, role);

    const title = firstName
      ? `${firstName} ${lastName} is The ${archetypeName} — "${tagline}"`
      : `I'm The ${
ResultsPage function · typescript · L84-L86 (3 LOC)
app/results/page.tsx
export default function ResultsPage() {
  return <ResultsClient />;
}
normalizeArchetypeId function · typescript · L14-L16 (3 LOC)
app/share/route.ts
function normalizeArchetypeId(id: string): string {
  return ARCHETYPE_ID_MAP[id] || id;
}
getBaseUrl function · typescript · L18-L22 (5 LOC)
app/share/route.ts
function getBaseUrl() {
  return process.env.VERCEL_PROJECT_PRODUCTION_URL
    ? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`
    : 'https://campaign-quiz.vercel.app';
}
getShareBaseUrl function · typescript · L24-L26 (3 LOC)
app/share/route.ts
function getShareBaseUrl() {
  return process.env.NEXT_PUBLIC_SHARE_BASE_URL || 'https://www.airops.com';
}
esc function · typescript · L28-L34 (7 LOC)
app/share/route.ts
function esc(s: string): string {
  return s
    .replace(/&/g, '&amp;')
    .replace(/"/g, '&quot;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;');
}
GET function · typescript · L36-L129 (94 LOC)
app/share/route.ts
export async function GET(request: NextRequest) {
  const { searchParams } = request.nextUrl;
  const userId = searchParams.get('userId') || '';
  const baseUrl = getBaseUrl();
  const shareBaseUrl = getShareBaseUrl();

  let archetypeId: ArchetypeId = 'vision';
  let role = 'ic';
  let ogImageUrl: string | null = null;
  let firstName = '';
  let lastName = '';

  if (userId) {
    try {
      const data = await redis.get(`quiz:${userId}`);
      if (data) {
        const parsed = JSON.parse(data);
        archetypeId = normalizeArchetypeId(parsed.archetype?.id || 'vision') as ArchetypeId;
        role = parsed.role || 'ic';
        ogImageUrl = parsed.ogImageUrl || parsed.cardUrl || null;
        firstName = parsed.firstName || '';
        lastName = parsed.lastName || '';
      }
    } catch {
      // fall through to defaults
    }
  }

  if (!ogImageUrl) {
    const paramArchetype = searchParams.get('archetype');
    const paramCardUrl = searchParams.get('cardUrl');
    if (paramA
CardGrid function · typescript · L298-L414 (117 LOC)
components/CardGrid.tsx
export default function CardGrid() {
  const [cards, setCards] = useState<CardEntry[]>([]);
  const [loading, setLoading] = useState(true);
  const [revealed, setRevealed] = useState<Set<string>>(new Set());
  const observerRef = useRef<IntersectionObserver | null>(null);

  useEffect(() => {
    fetch("/api/all-cards")
      .then((res) => res.json())
      .then((data) => {
        setCards(data.cards || []);
        setLoading(false);
      })
      .catch(() => setLoading(false));
  }, []);

  const cardRef = useCallback(
    (node: HTMLAnchorElement | null) => {
      if (!node) return;
      if (!observerRef.current) {
        observerRef.current = new IntersectionObserver(
          (entries) => {
            entries.forEach((entry) => {
              if (entry.isIntersecting) {
                const id = (entry.target as HTMLElement).dataset.cardId;
                if (id) {
                  setRevealed((prev) => new Set(prev).add(id));
                  observerRef.current?.u
Repobility analyzer · published findings · https://repobility.com
ChampionCardFan function · typescript · L13-L56 (44 LOC)
components/ChampionCardFan.tsx
export default function ChampionCardFan() {
  return (
    <section className="relative overflow-hidden py-8 md:py-16 px-4">
      <div
        className="flex gap-3 md:gap-4 justify-center items-start max-w-[1200px] mx-auto"
      >
        {cards.map((card, i) => (
          <div
            key={i}
            className="cursor-pointer"
            style={{
              flex: "1 1 0",
              maxWidth: "160px",
              minWidth: "0",
              transition: "transform 260ms cubic-bezier(0.22, 0.61, 0.36, 1)",
            }}
            onMouseEnter={(e) => {
              e.currentTarget.style.transform = "translateY(-8px)";
              e.currentTarget.style.zIndex = "10";
            }}
            onMouseLeave={(e) => {
              e.currentTarget.style.transform = "";
              e.currentTarget.style.zIndex = "";
            }}
          >
            <img
              src={card.src}
              alt={card.alt}
              draggable={false}
             
ErrorBoundary class · typescript · L25-L105 (81 LOC)
components/ErrorBoundary.tsx
export class ErrorBoundary extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error: Error): State {
    return { hasError: true, error };
  }

  componentDidCatch(error: Error, errorInfo: any) {
    console.error('Error caught by boundary:', error, errorInfo);

    // Capture to LogRocket if available
    if (captureException) {
      captureException(error, {
        componentStack: errorInfo.componentStack,
        errorBoundary: true,
      });
    }

    this.setState({
      errorInfo: errorInfo.componentStack,
    });
  }

  handleReset = () => {
    this.setState({ hasError: false, error: undefined, errorInfo: undefined });
  };

  render() {
    if (this.state.hasError) {
      if (this.props.fallback) {
        return this.props.fallback;
      }

      return (
        <div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
          <div classNa
constructor method · typescript · L26-L29 (4 LOC)
components/ErrorBoundary.tsx
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false };
  }
page 1 / 3next ›