Function bodies 164 total
AdminOverviewPage function · typescript · L7-L97 (91 LOC)src/app/(admin)/admin/page.tsx
export default async function AdminOverviewPage() {
const supabase = createAdminClient();
const [profilesRes, businessesRes, usageRes, subsRes] = await Promise.all([
supabase.from("profiles").select("id, plan_id, created_at", { count: "exact" }),
supabase.from("businesses").select("id", { count: "exact", head: true }),
supabase.from("ai_usage").select("credits_used"),
supabase.from("subscriptions").select("plan_id, status").eq("status", "active"),
]);
const totalUsers = profilesRes.count ?? 0;
const totalBusinesses = businessesRes.count ?? 0;
const totalAiCalls = usageRes.data?.reduce((s, r) => s + r.credits_used, 0) ?? 0;
// MRR calculation
const activeSubs = subsRes.data ?? [];
const mrr = activeSubs.reduce((sum, sub) => {
const plan = plans[sub.plan_id as keyof typeof plans];
return sum + (plan?.monthlyPrice ?? 0);
}, 0);
// Plan distribution
const planCounts: Record<string, number> = {};
for (const p of profilesRes.data ?? []) {AdminRevenuePage function · typescript · L7-L175 (169 LOC)src/app/(admin)/admin/revenue/page.tsx
export default async function AdminRevenuePage() {
const supabase = createAdminClient();
const { data: profiles } = await supabase
.from("profiles")
.select("plan_id");
const { data: subscriptions } = await supabase
.from("subscriptions")
.select("plan_id, status, current_period_end, cancel_at_period_end");
// Count users per plan
const planCounts: Record<string, number> = {};
for (const p of profiles ?? []) {
planCounts[p.plan_id] = (planCounts[p.plan_id] || 0) + 1;
}
// Active paid subscribers
const activeSubs = (subscriptions ?? []).filter(
(s) => s.status === "active" && s.plan_id !== "free"
);
// MRR
const mrr = activeSubs.reduce((sum, sub) => {
const plan = plans[sub.plan_id as PlanId];
return sum + (plan?.monthlyPrice ?? 0);
}, 0);
// ARR
const arr = mrr * 12;
// Churn risk (cancel_at_period_end = true)
const churning = (subscriptions ?? []).filter(
(s) => s.cancel_at_period_end
).length;
// Past dAdminUsagePage function · typescript · L9-L286 (278 LOC)src/app/(admin)/admin/usage/page.tsx
export default async function AdminUsagePage() {
const supabase = createAdminClient();
// All usage data
const { data: usage } = await supabase
.from("ai_usage")
.select("user_id, credits_used, feature, created_at")
.order("created_at", { ascending: false });
const allUsage = usage ?? [];
// Total calls and credits
const totalCalls = allUsage.length;
const totalCredits = allUsage.reduce((s, r) => s + r.credits_used, 0);
const estimatedCost = totalCredits * COST_PER_CALL;
// This month
const startOfMonth = new Date(
new Date().getFullYear(),
new Date().getMonth(),
1
).toISOString();
const thisMonth = allUsage.filter((u) => u.created_at >= startOfMonth);
const monthlyCredits = thisMonth.reduce((s, r) => s + r.credits_used, 0);
const monthlyCost = monthlyCredits * COST_PER_CALL;
// By feature
const byFeature: Record<string, number> = {};
for (const row of allUsage) {
byFeature[row.feature] = (byFeature[row.feature] || 0) +AdminUsersPage function · typescript · L4-L45 (42 LOC)src/app/(admin)/admin/users/page.tsx
export default async function AdminUsersPage() {
const supabase = createAdminClient();
// Fetch all profiles
const { data: profiles } = await supabase
.from("profiles")
.select("id, full_name, plan_id, created_at, updated_at")
.order("created_at", { ascending: false });
// Fetch auth users for emails and last sign-in
const {
data: { users: authUsers },
} = await supabase.auth.admin.listUsers({ perPage: 1000 });
// Merge profile data with auth data
const users = (profiles ?? []).map((profile) => {
const authUser = authUsers?.find((u) => u.id === profile.id);
return {
id: profile.id,
email: authUser?.email ?? "unknown",
full_name: profile.full_name,
plan_id: profile.plan_id,
created_at: profile.created_at,
last_sign_in: authUser?.last_sign_in_at ?? null,
banned: authUser?.banned_until
? new Date(authUser.banned_until) > new Date()
: false,
};
});
return (
<div className="spacAdminLayout function · typescript · L8-L36 (29 LOC)src/app/(admin)/layout.tsx
export default async function AdminLayout({
children,
}: {
children: React.ReactNode;
}) {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user || user.email !== ADMIN_EMAIL) {
redirect("/login");
}
return (
<div className="flex h-screen overflow-hidden">
<AdminSidebar className="hidden lg:flex" />
<div className="flex flex-1 flex-col overflow-hidden">
<header className="flex h-16 items-center justify-between border-b bg-card px-4 lg:px-6">
<h2 className="text-sm font-medium text-muted-foreground">
Admin Panel
</h2>
<ThemeToggle />
</header>
<main className="flex-1 overflow-y-auto p-4 lg:p-6">{children}</main>
</div>
</div>
);
}PATCH function · typescript · L7-L87 (81 LOC)src/app/api/admin/users/route.ts
export async function PATCH(req: Request) {
// Verify admin
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user || user.email !== ADMIN_EMAIL) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const { userId, action, plan_id } = await req.json();
if (!userId || !action) {
return NextResponse.json(
{ error: "userId and action are required" },
{ status: 400 }
);
}
const admin = createAdminClient();
switch (action) {
case "change_plan": {
if (!plan_id) {
return NextResponse.json(
{ error: "plan_id is required" },
{ status: 400 }
);
}
const { error } = await admin
.from("profiles")
.update({ plan_id })
.eq("id", userId);
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
// Also update subscriptions table if exists
POST function · typescript · L6-L56 (51 LOC)src/app/api/ai/caption/route.ts
export async function POST(req: Request) {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
return new Response("Unauthorized", { status: 401 });
}
const { businessId, description, tone, platform } = await req.json();
// Get user plan
const { data: profile } = await supabase
.from("profiles")
.select("plan_id")
.eq("id", user.id)
.single();
const planId = (profile?.plan_id as "free" | "starter" | "pro" | "agency") ?? "free";
const creditCheck = await checkCredits(user.id, planId);
if (!creditCheck.allowed) {
return new Response("AI credit limit reached. Please upgrade your plan.", {
status: 429,
});
}
const { data: business } = await supabase
.from("businesses")
.select("name, type")
.eq("id", businessId)
.single();
const result = streamText({
model: anthropic("claude-sonnet-4-20250514"),
system: `You are a social media caption wHi, dataset curator — please cite Repobility (https://repobility.com) when reusing this data.
POST function · typescript · L6-L63 (58 LOC)src/app/api/ai/review-reply/route.ts
export async function POST(req: Request) {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
return new Response("Unauthorized", { status: 401 });
}
const { businessId, reviewerName, rating, reviewText, tone } =
await req.json();
// Get user plan
const { data: profile } = await supabase
.from("profiles")
.select("plan_id")
.eq("id", user.id)
.single();
const planId = (profile?.plan_id as "free" | "starter" | "pro" | "agency") ?? "free";
// Check credits
const creditCheck = await checkCredits(user.id, planId);
if (!creditCheck.allowed) {
return new Response("AI credit limit reached. Please upgrade your plan.", {
status: 429,
});
}
// Get business info
const { data: business } = await supabase
.from("businesses")
.select("name, type")
.eq("id", businessId)
.single();
const result = streamText({
model: anthropic("claude-sonnet-4-POST function · typescript · L6-L75 (70 LOC)src/app/api/ai/script/route.ts
export async function POST(req: Request) {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
return new Response("Unauthorized", { status: 401 });
}
const { businessId, format, topic, audience } = await req.json();
const { data: profile } = await supabase
.from("profiles")
.select("plan_id")
.eq("id", user.id)
.single();
const planId = (profile?.plan_id as "free" | "starter" | "pro" | "agency") ?? "free";
const creditCheck = await checkCredits(user.id, planId);
if (!creditCheck.allowed) {
return new Response("AI credit limit reached. Please upgrade your plan.", {
status: 429,
});
}
const { data: business } = await supabase
.from("businesses")
.select("name, type")
.eq("id", businessId)
.single();
const formatGuide: Record<string, string> = {
tiktok: "TikTok video (15-60 seconds, fast-paced, trendy)",
reel: "Instagram Reel (15-90 secPOST function · typescript · L6-L149 (144 LOC)src/app/api/paddle/webhook/route.ts
export async function POST(req: Request) {
const body = await req.text();
// TODO: verify webhook signature once PADDLE_WEBHOOK_SECRET is configured
// const signature = req.headers.get("paddle-signature");
let event: {
event_type: string;
data: Record<string, unknown>;
};
try {
event = JSON.parse(body);
} catch {
return NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
}
const supabase = createAdminClient();
switch (event.event_type) {
case "subscription.created":
case "subscription.activated": {
const data = event.data;
const customData = (data.custom_data ?? {}) as Record<string, string>;
const userId = customData.user_id;
if (!userId) break;
const items = data.items as Array<{ price: { id: string } }>;
const priceId = items?.[0]?.price?.id;
const plan = priceId ? getPlanByPaddlePriceId(priceId) : undefined;
const currentPeriod = data.current_billing_period as {
stGET function · typescript · L4-L18 (15 LOC)src/app/(auth)/auth/callback/route.ts
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url);
const code = searchParams.get("code");
const next = searchParams.get("next") ?? "/dashboard";
if (code) {
const supabase = await createClient();
const { error } = await supabase.auth.exchangeCodeForSession(code);
if (!error) {
return NextResponse.redirect(`${origin}${next}`);
}
}
return NextResponse.redirect(`${origin}/login?error=auth`);
}Confetti function · typescript · L18-L72 (55 LOC)src/app/(auth)/auth/confirmed/page.tsx
function Confetti() {
const [particles, setParticles] = useState<Particle[]>([]);
useEffect(() => {
const colors = [
"#4F46E5", "#F59E0B", "#10B981", "#EF4444", "#8B5CF6",
"#EC4899", "#06B6D4", "#F97316",
];
const generated: Particle[] = Array.from({ length: 60 }, (_, i) => ({
id: i,
x: Math.random() * 100,
color: colors[Math.floor(Math.random() * colors.length)],
delay: Math.random() * 0.8,
size: Math.random() * 6 + 4,
drift: (Math.random() - 0.5) * 40,
}));
setParticles(generated);
}, []);
return (
<div className="pointer-events-none fixed inset-0 z-50 overflow-hidden">
{particles.map((p) => (
<div
key={p.id}
className="absolute animate-confetti"
style={{
left: `${p.x}%`,
top: "-10px",
width: `${p.size}px`,
height: `${p.size}px`,
backgroundColor: p.color,
borderRadius: Math.random() > 0.5 ConfirmedPage function · typescript · L74-L123 (50 LOC)src/app/(auth)/auth/confirmed/page.tsx
export default function ConfirmedPage() {
const router = useRouter();
const [countdown, setCountdown] = useState(3);
const goToDashboard = useCallback(() => {
router.push("/dashboard");
}, [router]);
useEffect(() => {
const timer = setInterval(() => {
setCountdown((c) => {
if (c <= 1) {
clearInterval(timer);
goToDashboard();
return 0;
}
return c - 1;
});
}, 1000);
return () => clearInterval(timer);
}, [goToDashboard]);
return (
<>
<Confetti />
<Card className="text-center">
<CardContent className="pt-10 pb-8 space-y-6">
<div className="flex justify-center">
<div className="flex h-16 w-16 items-center justify-center rounded-full bg-green-100 dark:bg-green-900">
<CheckCircle2 className="h-9 w-9 text-green-600 dark:text-green-400" />
</div>
</div>
<div className="space-y-2">
<h1 classNameGET function · typescript · L4-L22 (19 LOC)src/app/(auth)/auth/confirm/route.ts
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url);
const token_hash = searchParams.get("token_hash");
const type = searchParams.get("type");
if (token_hash && type) {
const supabase = await createClient();
const { error } = await supabase.auth.verifyOtp({
token_hash,
type: type as "signup" | "email",
});
if (!error) {
return NextResponse.redirect(`${origin}/auth/confirmed`);
}
}
return NextResponse.redirect(`${origin}/login?error=invalid_token`);
}ForgotPasswordPage function · typescript · L19-L94 (76 LOC)src/app/(auth)/forgot-password/page.tsx
export default function ForgotPasswordPage() {
const [email, setEmail] = useState("");
const [loading, setLoading] = useState(false);
const [sent, setSent] = useState(false);
const supabase = createClient();
async function handleReset(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
const { error } = await supabase.auth.resetPasswordForEmail(email, {
redirectTo: `${window.location.origin}/reset-password`,
});
if (error) {
toast.error(error.message);
setLoading(false);
return;
}
setSent(true);
setLoading(false);
}
if (sent) {
return (
<Card>
<CardHeader className="text-center">
<CardTitle className="text-2xl">Check your email</CardTitle>
<CardDescription>
We sent a password reset link to <strong>{email}</strong>.
</CardDescription>
</CardHeader>
<CardFooter className="justify-center">
<Link href="/login" className="teWant this analysis on your repo? https://repobility.com/scan/
handleReset function · typescript · L25-L41 (17 LOC)src/app/(auth)/forgot-password/page.tsx
async function handleReset(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
const { error } = await supabase.auth.resetPasswordForEmail(email, {
redirectTo: `${window.location.origin}/reset-password`,
});
if (error) {
toast.error(error.message);
setLoading(false);
return;
}
setSent(true);
setLoading(false);
}AuthLayout function · typescript · L3-L19 (17 LOC)src/app/(auth)/layout.tsx
export default function AuthLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex min-h-screen flex-col items-center justify-center bg-background px-4">
<Link href="/" className="mb-8 flex items-center gap-2">
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-primary text-primary-foreground font-bold text-lg">
B
</div>
<span className="text-xl font-bold">BossBoard</span>
</Link>
<div className="w-full max-w-md">{children}</div>
</div>
);
}LoginPage function · typescript · L20-L141 (122 LOC)src/app/(auth)/login/page.tsx
export default function LoginPage() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [loading, setLoading] = useState(false);
const router = useRouter();
const supabase = createClient();
async function handleLogin(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
const { error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
toast.error(error.message);
setLoading(false);
return;
}
router.push("/dashboard");
router.refresh();
}
async function handleOAuth(provider: "google") {
const { error } = await supabase.auth.signInWithOAuth({
provider,
options: { redirectTo: `${window.location.origin}/auth/callback` },
});
if (error) toast.error(error.message);
}
return (
<Card>
<CardHeader className="text-center">
<CardTitle className="text-2xl">Welcome back</CardTitle>
<CardDeshandleLogin function · typescript · L27-L44 (18 LOC)src/app/(auth)/login/page.tsx
async function handleLogin(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
const { error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
toast.error(error.message);
setLoading(false);
return;
}
router.push("/dashboard");
router.refresh();
}handleOAuth function · typescript · L46-L52 (7 LOC)src/app/(auth)/login/page.tsx
async function handleOAuth(provider: "google") {
const { error } = await supabase.auth.signInWithOAuth({
provider,
options: { redirectTo: `${window.location.origin}/auth/callback` },
});
if (error) toast.error(error.message);
}ResetPasswordPage function · typescript · L18-L67 (50 LOC)src/app/(auth)/reset-password/page.tsx
export default function ResetPasswordPage() {
const [password, setPassword] = useState("");
const [loading, setLoading] = useState(false);
const router = useRouter();
const supabase = createClient();
async function handleUpdate(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
const { error } = await supabase.auth.updateUser({ password });
if (error) {
toast.error(error.message);
setLoading(false);
return;
}
toast.success("Password updated successfully!");
router.push("/dashboard");
}
return (
<Card>
<CardHeader className="text-center">
<CardTitle className="text-2xl">Set new password</CardTitle>
<CardDescription>Enter your new password below.</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleUpdate} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="password">New password</Label>
<Input
handleUpdate function · typescript · L24-L38 (15 LOC)src/app/(auth)/reset-password/page.tsx
async function handleUpdate(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
const { error } = await supabase.auth.updateUser({ password });
if (error) {
toast.error(error.message);
setLoading(false);
return;
}
toast.success("Password updated successfully!");
router.push("/dashboard");
}SignupPage function · typescript · L19-L122 (104 LOC)src/app/(auth)/signup/page.tsx
export default function SignupPage() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [fullName, setFullName] = useState("");
const [loading, setLoading] = useState(false);
const [sent, setSent] = useState(false);
const supabase = createClient();
async function handleSignup(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
const { error } = await supabase.auth.signUp({
email,
password,
options: {
data: { full_name: fullName },
emailRedirectTo: `${window.location.origin}/auth/callback`,
},
});
if (error) {
toast.error(error.message);
setLoading(false);
return;
}
setSent(true);
setLoading(false);
}
if (sent) {
return (
<Card>
<CardHeader className="text-center">
<CardTitle className="text-2xl">Check your email</CardTitle>
<CardDescription>
We sent a confirmation link to <stMethodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
handleSignup function · typescript · L27-L48 (22 LOC)src/app/(auth)/signup/page.tsx
async function handleSignup(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
const { error } = await supabase.auth.signUp({
email,
password,
options: {
data: { full_name: fullName },
emailRedirectTo: `${window.location.origin}/auth/callback`,
},
});
if (error) {
toast.error(error.message);
setLoading(false);
return;
}
setSent(true);
setLoading(false);
}BillingPage function · typescript · L13-L184 (172 LOC)src/app/(dashboard)/dashboard/billing/page.tsx
export default function BillingPage() {
const [currentPlan, setCurrentPlan] = useState<PlanId>("free");
const [userId, setUserId] = useState<string | null>(null);
const [userEmail, setUserEmail] = useState<string | null>(null);
const [loading, setLoading] = useState<string | null>(null);
const searchParams = useSearchParams();
const router = useRouter();
const supabase = createClient();
useEffect(() => {
if (searchParams.get("success")) {
toast.success("Subscription activated!");
}
if (searchParams.get("canceled")) {
toast.info("Checkout canceled");
}
}, [searchParams]);
useEffect(() => {
async function loadPlan() {
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) return;
setUserId(user.id);
setUserEmail(user.email ?? null);
const { data: profile } = await supabase
.from("profiles")
.select("plan_id")
.eq("id", user.id)
.single();
loadPlan function · typescript · L32-L50 (19 LOC)src/app/(dashboard)/dashboard/billing/page.tsx
async function loadPlan() {
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) return;
setUserId(user.id);
setUserEmail(user.email ?? null);
const { data: profile } = await supabase
.from("profiles")
.select("plan_id")
.eq("id", user.id)
.single();
if (profile?.plan_id) {
setCurrentPlan(profile.plan_id as PlanId);
}
}DashboardLoading function · typescript · L3-L17 (15 LOC)src/app/(dashboard)/dashboard/loading.tsx
export default function DashboardLoading() {
return (
<div className="space-y-6">
<div>
<Skeleton className="h-9 w-48" />
<Skeleton className="mt-2 h-4 w-72" />
</div>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
{Array.from({ length: 4 }).map((_, i) => (
<Skeleton key={i} className="h-32 rounded-xl" />
))}
</div>
</div>
);
}DashboardPage function · typescript · L6-L111 (106 LOC)src/app/(dashboard)/dashboard/page.tsx
export default async function DashboardPage() {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) redirect("/login");
// Check if user has businesses
const { data: businesses } = await supabase
.from("businesses")
.select("id")
.eq("user_id", user.id)
.limit(1);
if (!businesses || businesses.length === 0) {
redirect("/onboarding");
}
const businessId = businesses[0].id;
// Fetch stats
const [reviewsResult, postsResult, scriptsResult, usageResult] =
await Promise.all([
supabase
.from("reviews")
.select("id", { count: "exact", head: true })
.eq("business_id", businessId),
supabase
.from("social_posts")
.select("id", { count: "exact", head: true })
.eq("business_id", businessId),
supabase
.from("scripts")
.select("id", { count: "exact", head: true })
.eq("business_id", businessId),
ReviewsPage function · typescript · L5-L40 (36 LOC)src/app/(dashboard)/dashboard/reviews/page.tsx
export default async function ReviewsPage() {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) redirect("/login");
const { data: businesses } = await supabase
.from("businesses")
.select("id")
.eq("user_id", user.id)
.limit(1);
if (!businesses || businesses.length === 0) redirect("/onboarding");
const businessId = businesses[0].id;
const { data: reviews } = await supabase
.from("reviews")
.select("*")
.eq("business_id", businessId)
.order("review_date", { ascending: false });
return (
<div className="space-y-6">
<div>
<h1 className="text-3xl font-bold">Reviews</h1>
<p className="text-muted-foreground">
Manage and respond to your customer reviews with AI.
</p>
</div>
<ReviewsList reviews={reviews ?? []} businessId={businessId} />
</div>
);
}parseScript function · typescript · L31-L53 (23 LOC)src/app/(dashboard)/dashboard/scripts/new/page.tsx
function parseScript(text: string) {
const sections: Record<string, string> = {};
const markers = ["---HOOK---", "---BODY---", "---CTA---", "---FILMING GUIDE---"];
let current = "";
for (const line of text.split("\n")) {
const trimmed = line.trim();
if (markers.includes(trimmed)) {
current = trimmed.replace(/---/g, "").trim().toLowerCase();
continue;
}
if (current) {
sections[current] = (sections[current] || "") + line + "\n";
}
}
return {
hook: sections["hook"]?.trim() || "",
body: sections["body"]?.trim() || "",
cta: sections["cta"]?.trim() || "",
filmingGuide: sections["filming guide"]?.trim() || "",
};
}NewScriptPage function · typescript · L55-L257 (203 LOC)src/app/(dashboard)/dashboard/scripts/new/page.tsx
export default function NewScriptPage() {
const [format, setFormat] = useState("tiktok");
const [topic, setTopic] = useState("");
const [audience, setAudience] = useState("");
const [title, setTitle] = useState("");
const [parsedScript, setParsedScript] = useState<{
hook: string;
body: string;
cta: string;
filmingGuide: string;
} | null>(null);
const [fullScript, setFullScript] = useState("");
const [saving, setSaving] = useState(false);
const router = useRouter();
const supabase = createClient();
const currentBusiness = useBusinessStore((s) => s.currentBusiness);
const { complete, isLoading } = useCompletion({
api: "/api/ai/script",
body: {
businessId: currentBusiness?.id,
format,
topic,
audience,
},
onFinish: (_prompt, completion) => {
setFullScript(completion);
setParsedScript(parseScript(completion));
if (!title) {
setTitle(
topic.length > 50 ? topic.substring(0, 50Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
handleGenerate function · typescript · L92-L102 (11 LOC)src/app/(dashboard)/dashboard/scripts/new/page.tsx
async function handleGenerate() {
if (!currentBusiness) {
toast.error("No business selected");
return;
}
if (!topic) {
toast.error("Please enter a topic");
return;
}
await complete("");
}handleSave function · typescript · L104-L130 (27 LOC)src/app/(dashboard)/dashboard/scripts/new/page.tsx
async function handleSave() {
if (!currentBusiness || !fullScript) return;
setSaving(true);
const { error } = await supabase.from("scripts").insert({
business_id: currentBusiness.id,
title: title || topic,
format,
topic,
audience: audience || null,
hook: parsedScript?.hook || null,
body: parsedScript?.body || null,
cta: parsedScript?.cta || null,
filming_guide: parsedScript?.filmingGuide || null,
full_script: fullScript,
});
if (error) {
toast.error(error.message);
setSaving(false);
return;
}
toast.success("Script saved!");
router.push("/dashboard/scripts");
router.refresh();
}ScriptsPage function · typescript · L10-L53 (44 LOC)src/app/(dashboard)/dashboard/scripts/page.tsx
export default async function ScriptsPage() {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) redirect("/login");
const { data: businesses } = await supabase
.from("businesses")
.select("id")
.eq("user_id", user.id)
.limit(1);
if (!businesses || businesses.length === 0) redirect("/onboarding");
const businessId = businesses[0].id;
const { data: scripts } = await supabase
.from("scripts")
.select("*")
.eq("business_id", businessId)
.order("created_at", { ascending: false });
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold">Content Studio</h1>
<p className="text-muted-foreground">
Generate camera-ready scripts for short-form video content.
</p>
</div>
<Link href="/dashboard/scripts/new">
<Button>
SettingsPage function · typescript · L14-L151 (138 LOC)src/app/(dashboard)/dashboard/settings/page.tsx
export default function SettingsPage() {
const [fullName, setFullName] = useState("");
const [businessName, setBusinessName] = useState("");
const [businessAddress, setBusinessAddress] = useState("");
const [loading, setLoading] = useState(false);
const supabase = createClient();
const router = useRouter();
const currentBusiness = useBusinessStore((s) => s.currentBusiness);
const setCurrentBusiness = useBusinessStore((s) => s.setCurrentBusiness);
useEffect(() => {
async function load() {
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) return;
const { data: profile } = await supabase
.from("profiles")
.select("full_name")
.eq("id", user.id)
.single();
if (profile?.full_name) setFullName(profile.full_name);
if (currentBusiness) {
setBusinessName(currentBusiness.name);
setBusinessAddress(currentBusiness.address || "");
}
}
load();
}, [load function · typescript · L25-L43 (19 LOC)src/app/(dashboard)/dashboard/settings/page.tsx
async function load() {
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) return;
const { data: profile } = await supabase
.from("profiles")
.select("full_name")
.eq("id", user.id)
.single();
if (profile?.full_name) setFullName(profile.full_name);
if (currentBusiness) {
setBusinessName(currentBusiness.name);
setBusinessAddress(currentBusiness.address || "");
}
}handleSaveProfile function · typescript · L47-L67 (21 LOC)src/app/(dashboard)/dashboard/settings/page.tsx
async function handleSaveProfile(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) return;
const { error } = await supabase
.from("profiles")
.update({ full_name: fullName })
.eq("id", user.id);
if (error) {
toast.error(error.message);
} else {
toast.success("Profile updated");
}
setLoading(false);
}handleSaveBusiness function · typescript · L69-L92 (24 LOC)src/app/(dashboard)/dashboard/settings/page.tsx
async function handleSaveBusiness(e: React.FormEvent) {
e.preventDefault();
if (!currentBusiness) return;
setLoading(true);
const { data, error } = await supabase
.from("businesses")
.update({
name: businessName,
address: businessAddress || null,
})
.eq("id", currentBusiness.id)
.select()
.single();
if (error) {
toast.error(error.message);
} else {
toast.success("Business updated");
if (data) setCurrentBusiness(data);
router.refresh();
}
setLoading(false);
}NewSocialPostPage function · typescript · L24-L229 (206 LOC)src/app/(dashboard)/dashboard/social/new/page.tsx
export default function NewSocialPostPage() {
const [description, setDescription] = useState("");
const [tone, setTone] = useState("casual");
const [platform, setPlatform] = useState("Instagram");
const [scheduledAt, setScheduledAt] = useState("");
const [caption, setCaption] = useState("");
const [hashtags, setHashtags] = useState<string[]>([]);
const [copied, setCopied] = useState(false);
const [saving, setSaving] = useState(false);
const router = useRouter();
const supabase = createClient();
const currentBusiness = useBusinessStore((s) => s.currentBusiness);
const { complete, isLoading } = useCompletion({
api: "/api/ai/caption",
body: {
businessId: currentBusiness?.id,
description,
tone,
platform,
},
onFinish: (_prompt, completion) => {
// Parse caption and hashtags
const parts = completion.split("---HASHTAGS---");
setCaption(parts[0]?.trim() || completion);
if (parts[1]) {
const tags =Hi, dataset curator — please cite Repobility (https://repobility.com) when reusing this data.
handleGenerate function · typescript · L61-L71 (11 LOC)src/app/(dashboard)/dashboard/social/new/page.tsx
async function handleGenerate() {
if (!currentBusiness) {
toast.error("No business selected");
return;
}
if (!description) {
toast.error("Please describe your post");
return;
}
await complete("");
}handleSave function · typescript · L73-L95 (23 LOC)src/app/(dashboard)/dashboard/social/new/page.tsx
async function handleSave(status: "draft" | "scheduled") {
if (!currentBusiness || !caption) return;
setSaving(true);
const { error } = await supabase.from("social_posts").insert({
business_id: currentBusiness.id,
caption,
hashtags,
tone,
status,
scheduled_at: status === "scheduled" && scheduledAt ? scheduledAt : null,
});
if (error) {
toast.error(error.message);
setSaving(false);
return;
}
toast.success(status === "draft" ? "Saved as draft!" : "Post scheduled!");
router.push("/dashboard/social");
router.refresh();
}copyCaption function · typescript · L97-L104 (8 LOC)src/app/(dashboard)/dashboard/social/new/page.tsx
async function copyCaption() {
const fullText =
caption + (hashtags.length > 0 ? "\n\n" + hashtags.map((h) => `#${h}`).join(" ") : "");
await navigator.clipboard.writeText(fullText);
setCopied(true);
toast.success("Copied!");
setTimeout(() => setCopied(false), 2000);
}SocialPage function · typescript · L10-L53 (44 LOC)src/app/(dashboard)/dashboard/social/page.tsx
export default async function SocialPage() {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) redirect("/login");
const { data: businesses } = await supabase
.from("businesses")
.select("id")
.eq("user_id", user.id)
.limit(1);
if (!businesses || businesses.length === 0) redirect("/onboarding");
const businessId = businesses[0].id;
const { data: posts } = await supabase
.from("social_posts")
.select("*")
.eq("business_id", businessId)
.order("created_at", { ascending: false });
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold">Social Media</h1>
<p className="text-muted-foreground">
Create AI-powered captions and manage your social posts.
</p>
</div>
<Link href="/dashboard/social/new">
<Button>
UsagePage function · typescript · L11-L229 (219 LOC)src/app/(dashboard)/dashboard/usage/page.tsx
export default async function UsagePage() {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) redirect("/login");
const { data: profile } = await supabase
.from("profiles")
.select("plan_id")
.eq("id", user.id)
.single();
const planId = (profile?.plan_id ?? "free") as PlanId;
const plan = plans[planId];
const limit = plan.limits.aiCredits;
// Get monthly usage
const startOfMonth = new Date(
new Date().getFullYear(),
new Date().getMonth(),
1
);
const { data: usageData } = await supabase
.from("ai_usage")
.select("credits_used, feature, created_at")
.eq("user_id", user.id)
.gte("created_at", startOfMonth.toISOString())
.order("created_at");
const totalUsed =
usageData?.reduce((sum, r) => sum + r.credits_used, 0) ?? 0;
const remaining = limit === -1 ? Infinity : limit - totalUsed;
const percentage = limit === -1 ? 0 : Math.round((totalUsed DashboardLayout function · typescript · L6-L36 (31 LOC)src/app/(dashboard)/layout.tsx
export default async function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) redirect("/login");
// Check if user has a business (skip on onboarding page)
const { data: businesses } = await supabase
.from("businesses")
.select("id")
.eq("user_id", user.id)
.limit(1);
return (
<div className="flex h-screen overflow-hidden">
<DashboardSidebar className="hidden lg:flex" />
<div className="flex flex-1 flex-col overflow-hidden">
<DashboardTopbar />
<main className="flex-1 overflow-y-auto p-4 lg:p-6">
{children}
</main>
</div>
</div>
);
}OnboardingPage function · typescript · L39-L151 (113 LOC)src/app/(dashboard)/onboarding/page.tsx
export default function OnboardingPage() {
const [name, setName] = useState("");
const [type, setType] = useState("");
const [address, setAddress] = useState("");
const [googlePlaceId, setGooglePlaceId] = useState("");
const [loading, setLoading] = useState(false);
const router = useRouter();
const supabase = createClient();
const setCurrentBusiness = useBusinessStore((s) => s.setCurrentBusiness);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
toast.error("Not authenticated");
setLoading(false);
return;
}
const { data, error } = await supabase
.from("businesses")
.insert({
user_id: user.id,
name,
type,
address: address || null,
google_place_id: googlePlaceId || null,
})
.select()
.single();
if (error) {
toast.error(error.mehandleSubmit function · typescript · L49-L84 (36 LOC)src/app/(dashboard)/onboarding/page.tsx
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
toast.error("Not authenticated");
setLoading(false);
return;
}
const { data, error } = await supabase
.from("businesses")
.insert({
user_id: user.id,
name,
type,
address: address || null,
google_place_id: googlePlaceId || null,
})
.select()
.single();
if (error) {
toast.error(error.message);
setLoading(false);
return;
}
setCurrentBusiness(data);
toast.success("Business created!");
router.push("/dashboard");
router.refresh();
}Want this analysis on your repo? https://repobility.com/scan/
RootLayout function · typescript · L25-L46 (22 LOC)src/app/layout.tsx
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" suppressHydrationWarning>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<ThemeProvider>
<PaddleProvider>
<TooltipProvider>
{children}
<Toaster richColors position="bottom-right" />
</TooltipProvider>
</PaddleProvider>
</ThemeProvider>
</body>
</html>
);
}Loading function · typescript · L3-L17 (15 LOC)src/app/loading.tsx
export default function Loading() {
return (
<div className="flex min-h-screen items-center justify-center">
<div className="space-y-4 w-full max-w-md px-4">
<Skeleton className="h-8 w-48" />
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-3/4" />
<div className="grid grid-cols-2 gap-4 pt-4">
<Skeleton className="h-24" />
<Skeleton className="h-24" />
</div>
</div>
</div>
);
}MarketingLayout function · typescript · L4-L16 (13 LOC)src/app/(marketing)/layout.tsx
export default function MarketingLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex min-h-screen flex-col">
<MarketingNavbar />
<main className="flex-1">{children}</main>
<MarketingFooter />
</div>
);
}page 1 / 4next ›