Function bodies 28 total
AboutPage function · typescript · L11-L131 (121 LOC)src/app/about/page.tsx
export default function AboutPage() {
return (
<div className="pt-24 pb-16">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Header */}
<div className="flex flex-col md:flex-row items-center gap-10 mb-16">
<div className="relative w-48 h-48 md:w-56 md:h-56 rounded-2xl overflow-hidden shadow-lg flex-shrink-0">
<Image
src="/images/headshot.jpg"
alt="Pranav Bhasin"
fill
className="object-cover"
priority
/>
</div>
<div>
<p className="text-gold font-semibold text-sm uppercase tracking-widest mb-2">
About
</p>
<h1 className="text-3xl md:text-4xl font-bold text-navy mb-4">
Pranav Bhasin
</h1>
<p className="text-lg text-body leading-relaxed">
AI Leadership & Career Strategist helping mid-to-senior
professionals anAcademyPage function · typescript · L46-L146 (101 LOC)src/app/academy/page.tsx
export default function AcademyPage() {
return (
<div className="pt-24 pb-16">
<div className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Header */}
<div className="text-center mb-16">
<p className="text-gold font-semibold text-sm uppercase tracking-widest mb-3">
Future Proof Academy
</p>
<h1 className="text-3xl md:text-5xl font-bold text-navy mb-6">
Executive courses for the AI era
</h1>
<p className="text-lg text-body max-w-2xl mx-auto leading-relaxed">
Structured programs designed for mid-to-senior professionals ready to
take control of their career trajectory in an AI-driven world.
</p>
</div>
{/* Courses */}
<div className="space-y-12">
{courses.map((course, i) => (
<div
key={i}
className="border border-gray-200 rounded-2xl p-8 md:p-10 hover:shadow-lg transition-shadow"
POST function · typescript · L3-L58 (56 LOC)src/app/api/quiz-lead/route.ts
export async function POST(req: NextRequest) {
try {
const body = await req.json();
const { name, email, role, yearsOfExperience, quizId, quizName, score, tier, timestamp } = body;
// Validate required fields
if (!name || !email || !role || !yearsOfExperience) {
return NextResponse.json(
{ error: "All fields are required" },
{ status: 400 }
);
}
const webhookUrl = process.env.GOOGLE_SHEETS_WEBHOOK_URL;
if (webhookUrl) {
// Post to Google Apps Script webhook
await fetch(webhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name,
email,
role,
yearsOfExperience,
quizId: quizId || "unknown",
quizName: quizName || "Unknown Quiz",
score,
tier,
timestamp: timestamp || new Date().toISOString(),
}),
});
} else {
// Fallback: log to server cBookPage function · typescript · L9-L39 (31 LOC)src/app/book/page.tsx
export default function BookPage() {
return (
<div className="pt-24 pb-16">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-10">
<p className="text-gold font-semibold text-sm uppercase tracking-widest mb-3">
1:1 Advisory
</p>
<h1 className="text-3xl md:text-4xl font-bold text-navy mb-4">
Personal Advisory Session
</h1>
<p className="text-lg text-body max-w-2xl mx-auto">
A focused 60-minute session to discuss your career strategy, AI
leadership trajectory, or any specific challenges you're facing.
</p>
</div>
{/* Calendly embed */}
<div className="rounded-2xl overflow-hidden border border-gray-200 shadow-sm">
<iframe
src="https://calendly.com/pranavbhasin/personal-advisory-session-with-pranav-60-mins-1-1"
width="100%"
height="700"
clasRootLayout function · typescript · L32-L52 (21 LOC)src/app/layout.tsx
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<head>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap"
rel="stylesheet"
/>
</head>
<body className="bg-white antialiased">
<Navbar />
<main>{children}</main>
<Footer />
</body>
</html>
);
}NewsletterPage function · typescript · L12-L107 (96 LOC)src/app/newsletter/page.tsx
export default async function NewsletterPage() {
const articles = await getLatestArticles(20);
return (
<div className="pt-24 pb-16">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Header */}
<div className="text-center mb-12">
<p className="text-gold font-semibold text-sm uppercase tracking-widest mb-3">
Newsletter
</p>
<h1 className="text-3xl md:text-4xl font-bold text-navy mb-4">
Future Proof with Pranav
</h1>
<p className="text-lg text-body max-w-2xl mx-auto mb-8">
Weekly insights on AI leadership, career strategy, and navigating
professional disruption in an AI-driven world.
</p>
{/* Subscribe embed */}
<div className="max-w-md mx-auto mb-12">
<SubscribeForm variant="light" />
</div>
</div>
{/* Articles */}
{articles.length > 0 ? (
<div className="space-Home function · typescript · L9-L24 (16 LOC)src/app/page.tsx
export default async function Home() {
const [{ longForm }, articles] = await Promise.all([
getLatestVideos(50),
getLatestArticles(3),
]);
return (
<>
<Hero />
<AboutSection />
<AcademySection />
<ContentHub articles={articles} videos={longForm.slice(0, 3)} />
<QuizCTA />
</>
);
}Source: Repobility analyzer · https://repobility.com
getResult function · typescript · L101-L161 (61 LOC)src/app/tools/career-assessment/CareerQuiz.tsx
function getResult(score: number): Result {
const percentage = (score / (questions.length * 4)) * 100;
if (percentage >= 80) {
return {
tier: "Future-Proof Leader",
title: "You're ahead of the curve",
description:
"You have a strong foundation for thriving in the AI era. Your combination of technical adaptability, cross-domain expertise, and strategic positioning puts you in an excellent position to lead.",
recommendations: [
"Consider the AI Leadership course to formalize and amplify your advantage",
"Help others in your organization navigate the AI transition",
"Build thought leadership around your unique cross-domain expertise",
"Subscribe to the newsletter for cutting-edge frameworks",
],
color: "text-green-600",
};
} else if (percentage >= 60) {
return {
tier: "Strong Foundation",
title: "You're on the right track",
description:
"You have solid fundamentals but CareerQuiz function · typescript · L173-L500 (328 LOC)src/app/tools/career-assessment/CareerQuiz.tsx
export default function CareerQuiz() {
const [currentQuestion, setCurrentQuestion] = useState(0);
const [answers, setAnswers] = useState<Record<string, number>>({});
const [showLeadCapture, setShowLeadCapture] = useState(false);
const [showResults, setShowResults] = useState(false);
const [leadInfo, setLeadInfo] = useState<LeadInfo>({
name: "",
email: "",
role: "",
yearsOfExperience: "",
});
const [isSubmitting, setIsSubmitting] = useState(false);
const [leadError, setLeadError] = useState("");
const totalScore = Object.values(answers).reduce((a, b) => a + b, 0);
const result = getResult(totalScore);
const progress = ((currentQuestion) / questions.length) * 100;
function handleAnswer(questionId: string, score: number) {
const newAnswers = { ...answers, [questionId]: score };
setAnswers(newAnswers);
if (currentQuestion < questions.length - 1) {
setTimeout(() => setCurrentQuestion(currentQuestion + 1), 300);
} else {
handleAnswer function · typescript · L191-L200 (10 LOC)src/app/tools/career-assessment/CareerQuiz.tsx
function handleAnswer(questionId: string, score: number) {
const newAnswers = { ...answers, [questionId]: score };
setAnswers(newAnswers);
if (currentQuestion < questions.length - 1) {
setTimeout(() => setCurrentQuestion(currentQuestion + 1), 300);
} else {
setTimeout(() => setShowLeadCapture(true), 300);
}
}handleLeadSubmit function · typescript · L202-L229 (28 LOC)src/app/tools/career-assessment/CareerQuiz.tsx
async function handleLeadSubmit(e: React.FormEvent) {
e.preventDefault();
setLeadError("");
setIsSubmitting(true);
try {
const scorePercentage = Math.round((totalScore / (questions.length * 4)) * 100);
const res = await fetch("/api/quiz-lead", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
...leadInfo,
quizId: QUIZ_ID,
quizName: QUIZ_NAME,
score: scorePercentage,
tier: getResult(totalScore).tier,
timestamp: new Date().toISOString(),
}),
});
if (!res.ok) throw new Error("Failed to submit");
setShowResults(true);
} catch {
setLeadError("Something went wrong. Please try again.");
} finally {
setIsSubmitting(false);
}
}restart function · typescript · L231-L238 (8 LOC)src/app/tools/career-assessment/CareerQuiz.tsx
function restart() {
setCurrentQuestion(0);
setAnswers({});
setShowLeadCapture(false);
setShowResults(false);
setLeadInfo({ name: "", email: "", role: "", yearsOfExperience: "" });
setLeadError("");
}CareerAssessmentPage function · typescript · L10-L18 (9 LOC)src/app/tools/career-assessment/page.tsx
export default function CareerAssessmentPage() {
return (
<div className="pt-24 pb-16">
<div className="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8">
<CareerQuiz />
</div>
</div>
);
}VideoCard function · typescript · L12-L43 (32 LOC)src/app/videos/page.tsx
function VideoCard({ video }: { video: YouTubeVideo }) {
return (
<a
href={`https://www.youtube.com/watch?v=${video.videoId}`}
target="_blank"
rel="noopener noreferrer"
className="group rounded-xl overflow-hidden border border-gray-200 hover:border-gold/30 hover:shadow-lg transition-all"
>
<div className="relative aspect-video">
<Image
src={video.thumbnail}
alt={video.title}
fill
className="object-cover"
/>
<div className="absolute inset-0 bg-black/20 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
<div className="bg-red-600 rounded-full p-3">
<svg className="w-6 h-6 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z" />
</svg>
</div>
</div>
</div>
<div className="p-4">
<p className="text-xs text-body/60 mb-1">{video.date}</p>
VideosPage function · typescript · L45-L114 (70 LOC)src/app/videos/page.tsx
export default async function VideosPage() {
const { longForm } = await getLatestVideos(50);
return (
<div className="pt-24 pb-16">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Header */}
<div className="text-center mb-12">
<p className="text-gold font-semibold text-sm uppercase tracking-widest mb-3">
Videos
</p>
<h1 className="text-3xl md:text-4xl font-bold text-navy mb-4">
Future Proof with Pranav
</h1>
<p className="text-lg text-body max-w-2xl mx-auto mb-6">
In-depth videos breaking down AI trends, career frameworks, and
leadership strategies for the modern professional.
</p>
<a
href="https://www.youtube.com/@future-proof-by-pranav?sub_confirmation=1"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 bg-red-600 hover:bg-red-700 text-white fRepobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
AboutSection function · typescript · L3-L42 (40 LOC)src/components/AboutSection.tsx
export default function AboutSection() {
return (
<section id="about" className="py-16 md:py-24 bg-off-white">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-3xl mx-auto text-center">
<p className="text-gold font-semibold text-sm uppercase tracking-widest mb-3">
About
</p>
<h2 className="text-3xl md:text-4xl font-bold text-navy mb-6">
The intersection of AI and career strategy
</h2>
<p className="text-body text-lg leading-relaxed mb-6">
I help professionals navigate the most significant career disruption
of our generation. With deep expertise across AI, product strategy,
and executive leadership, I equip mid-to-senior professionals with
the frameworks, skills, and confidence to not just survive — but lead
— in an AI-transformed world.
</p>
<p className="text-body text-lg leading-relaAcademySection function · typescript · L24-L72 (49 LOC)src/components/AcademySection.tsx
export default function AcademySection() {
return (
<section id="academy" className="py-16 md:py-24 bg-white">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<p className="text-gold font-semibold text-sm uppercase tracking-widest mb-3">
Future Proof Academy
</p>
<h2 className="text-3xl md:text-4xl font-bold text-navy mb-4">
Executive courses for the AI era
</h2>
<p className="text-body text-lg max-w-2xl mx-auto">
Structured programs designed for mid-to-senior professionals ready
to take control of their career trajectory.
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 max-w-4xl mx-auto">
{courses.map((course, i) => (
<div
key={i}
className="border border-gray-200 rounded-xl p-8 hover:border-gold/50 hover:shadow-lg transition-all gContentHub function · typescript · L11-L128 (118 LOC)src/components/ContentHub.tsx
export default function ContentHub({ articles, videos }: ContentHubProps) {
return (
<section id="content" className="py-16 md:py-24 bg-off-white">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<p className="text-gold font-semibold text-sm uppercase tracking-widest mb-3">
Insights
</p>
<h2 className="text-3xl md:text-4xl font-bold text-navy mb-4">
Latest thinking on AI & careers
</h2>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
{/* Newsletter / Substack */}
<div>
<div className="flex items-center gap-3 mb-6">
<svg className="w-6 h-6 text-gold" fill="currentColor" viewBox="0 0 24 24">
<path d="M22.539 8.242H1.46V5.406h21.08v2.836zM1.46 10.812V24l9.56-5.26L20.54 24V10.812H1.46zM22.54 0H1.46v2.836h21.08V0z" />
</svg>
<h3 className=Footer function · typescript · L4-L128 (125 LOC)src/components/Footer.tsx
export default function Footer() {
return (
<footer className="bg-navy text-white">
{/* Newsletter signup */}
<div className="border-b border-white/10">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<div className="max-w-xl mx-auto text-center">
<h3 className="text-2xl font-bold text-white mb-2">
Future Proof Your Career
</h3>
<p className="text-white/70 mb-6">
Weekly insights on AI leadership, career strategy, and staying
ahead in an AI-driven world.
</p>
<SubscribeForm variant="dark" />
</div>
</div>
</div>
{/* Footer links */}
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-10">
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{/* Brand */}
<div>
<h4 className="font-bold text-lg text-white mb-3">Pranav Bhasin</h4>
<p classNameHero function · typescript · L4-L58 (55 LOC)src/components/Hero.tsx
export default function Hero() {
return (
<section className="pt-24 pb-16 md:pt-32 md:pb-24 bg-white">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex flex-col md:flex-row items-center gap-10 md:gap-16">
{/* Text */}
<div className="flex-1 text-center md:text-left">
<p className="text-gold font-semibold text-sm uppercase tracking-widest mb-3">
AI Leadership & Career Strategy
</p>
<h1 className="text-4xl md:text-5xl lg:text-6xl font-extrabold text-navy leading-tight mb-6">
Build a career that thrives in the age of AI
</h1>
<p className="text-lg text-body max-w-xl mb-8 leading-relaxed">
Helping mid-to-senior professionals and executives build
defensible careers and lead effectively in an AI-driven world.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center md:jusNavbar function · typescript · L15-L112 (98 LOC)src/components/Navbar.tsx
export default function Navbar() {
const [mobileOpen, setMobileOpen] = useState(false);
return (
<nav className="fixed top-0 left-0 right-0 z-50 bg-white/95 backdrop-blur-sm border-b border-gray-100">
<div className="max-w-6xl 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-3">
<Image
src="/images/logo.jpg"
alt="Pranav Bhasin"
width={36}
height={36}
className="rounded"
/>
<span className="text-navy font-bold text-lg tracking-tight">
Future Proof <span className="font-normal text-body">by Pranav Bhasin</span>
</span>
</Link>
{/* Desktop Nav */}
<div className="hidden md:flex items-center gap-8">
{navLinks.map((link) => (
<Link
key={link.label}
QuizCTA function · typescript · L4-L44 (41 LOC)src/components/QuizCTA.tsx
export default function QuizCTA() {
return (
<section className="py-16 md:py-24 bg-white">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="bg-navy rounded-2xl p-8 md:p-12 flex flex-col md:flex-row items-center justify-center gap-8 md:gap-12">
{/* Mascot */}
<div className="flex-shrink-0 flex items-center">
<div className="w-32 h-32 md:w-44 md:h-44 relative">
<Image
src="/images/mascot.jpg"
alt="Future Proof mascot"
fill
className="object-contain"
/>
</div>
</div>
{/* Content */}
<div className="flex-1 text-center md:text-left">
<h2 className="text-2xl md:text-3xl font-bold mb-3" style={{ color: '#D4A33C' }}>
How Future-Proof Is Your Career?
</h2>
<p className="text-white/70 text-lg mb-6 max-w-lg">
Take the free carSubscribeForm function · typescript · L9-L88 (80 LOC)src/components/SubscribeForm.tsx
export default function SubscribeForm({ variant = "light" }: SubscribeFormProps) {
const [email, setEmail] = useState("");
const [status, setStatus] = useState<"idle" | "loading" | "success" | "error">("idle");
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
if (!email) return;
setStatus("loading");
try {
const res = await fetch("https://neuralnugget.substack.com/api/v1/free?noRedirect=true", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
first_url: "https://neuralnugget.substack.com/embed",
first_referrer: "https://pranavbhasin.com",
current_url: "https://neuralnugget.substack.com/embed",
current_referrer: "https://pranavbhasin.com",
referral_code: "",
source: "embed",
email,
}),
});
if (res.ok) {
setStatus("success");
setEmail("");
} else {
setStaMethodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
handleSubmit function · typescript · L13-L43 (31 LOC)src/components/SubscribeForm.tsx
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
if (!email) return;
setStatus("loading");
try {
const res = await fetch("https://neuralnugget.substack.com/api/v1/free?noRedirect=true", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
first_url: "https://neuralnugget.substack.com/embed",
first_referrer: "https://pranavbhasin.com",
current_url: "https://neuralnugget.substack.com/embed",
current_referrer: "https://pranavbhasin.com",
referral_code: "",
source: "embed",
email,
}),
});
if (res.ok) {
setStatus("success");
setEmail("");
} else {
setStatus("error");
}
} catch {
setStatus("error");
}
}getLatestArticles function · typescript · L8-L34 (27 LOC)src/lib/substack.ts
export async function getLatestArticles(count = 3): Promise<SubstackArticle[]> {
try {
const res = await fetch("https://neuralnugget.substack.com/api/v1/posts?limit=" + count, {
next: { revalidate: 3600 },
});
if (!res.ok) {
// Fallback: try RSS
return getArticlesFromRSS(count);
}
const posts = await res.json();
return posts.map((post: Record<string, unknown>) => ({
title: post.title as string,
url: post.canonical_url as string || `https://neuralnugget.substack.com/p/${post.slug}`,
date: new Date(post.post_date as string).toLocaleDateString("en-US", {
year: "numeric",
month: "short",
day: "numeric",
}),
excerpt: (post.subtitle as string) || (post.description as string) || "",
}));
} catch {
return getArticlesFromRSS(count);
}
}getArticlesFromRSS function · typescript · L36-L77 (42 LOC)src/lib/substack.ts
async function getArticlesFromRSS(count: number): Promise<SubstackArticle[]> {
try {
const res = await fetch("https://neuralnugget.substack.com/feed", {
next: { revalidate: 3600 },
});
const xml = await res.text();
const articles: SubstackArticle[] = [];
const itemRegex = /<item>([\s\S]*?)<\/item>/g;
let match;
while ((match = itemRegex.exec(xml)) !== null && articles.length < count) {
const item = match[1];
const title = item.match(/<title><!\[CDATA\[(.*?)\]\]><\/title>/)?.[1] ||
item.match(/<title>(.*?)<\/title>/)?.[1] || "";
const link = item.match(/<link>(.*?)<\/link>/)?.[1] || "";
const pubDate = item.match(/<pubDate>(.*?)<\/pubDate>/)?.[1] || "";
const desc = item.match(/<description><!\[CDATA\[(.*?)\]\]><\/description>/)?.[1] ||
item.match(/<description>(.*?)<\/description>/)?.[1] || "";
// Strip HTML from description
const excerpt = desc.replace(/<[^>]*>/g, "").slice(0, 160);
parseDuration function · typescript · L16-L23 (8 LOC)src/lib/youtube.ts
function parseDuration(iso: string): number {
const match = iso.match(/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/);
if (!match) return 0;
const h = parseInt(match[1] || "0", 10);
const m = parseInt(match[2] || "0", 10);
const s = parseInt(match[3] || "0", 10);
return h * 3600 + m * 60 + s;
}getLatestVideos function · typescript · L25-L111 (87 LOC)src/lib/youtube.ts
export async function getLatestVideos(count = 50): Promise<YouTubeVideos> {
const apiKey = process.env.YOUTUBE_API_KEY;
const channelHandle = process.env.YOUTUBE_CHANNEL_HANDLE || "@future-proof-by-pranav";
if (!apiKey) return { longForm: [], shorts: [] };
try {
// Resolve channel handle to channel ID
const channelRes = await fetch(
`https://www.googleapis.com/youtube/v3/channels?part=contentDetails&forHandle=${channelHandle}&key=${apiKey}`,
{ next: { revalidate: 3600 } }
);
const channelData = await channelRes.json();
if (!channelData.items?.length) return { longForm: [], shorts: [] };
const uploadsPlaylistId =
channelData.items[0].contentDetails.relatedPlaylists.uploads;
// Fetch latest videos from uploads playlist
const videosRes = await fetch(
`https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=${uploadsPlaylistId}&maxResults=${count}&key=${apiKey}`,
{ next: { revalidate: 3600 } }