Function bodies 34 total
GET function · typescript · L4-L19 (16 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') ?? '/'
if (code) {
const supabase = await createClient()
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (!error) {
return NextResponse.redirect(`${origin}${next}`)
}
}
// Auth code exchange failed — redirect to login with error
return NextResponse.redirect(`${origin}/login`)
}AuthLayout function · typescript · L1-L11 (11 LOC)src/app/(auth)/layout.tsx
export default function AuthLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<div className="flex min-h-screen items-center justify-center bg-gray-50 px-4">
<div className="w-full max-w-sm">{children}</div>
</div>
)
}LoginPage function · typescript · L6-L111 (106 LOC)src/app/(auth)/login/page.tsx
export default function LoginPage() {
const [email, setEmail] = useState('')
const [loading, setLoading] = useState(false)
const [sent, setSent] = useState(false)
const [error, setError] = useState<string | null>(null)
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault()
setLoading(true)
setError(null)
const supabase = createClient()
const { error } = await supabase.auth.signInWithOtp({
email,
options: {
emailRedirectTo: `${window.location.origin}/auth/callback`,
},
})
if (error) {
setError('Could not send magic link. Check your email and try again.')
setLoading(false)
return
}
setSent(true)
setLoading(false)
}
return (
<div className="flex flex-col items-center">
<div className="mb-8 text-center">
<h1 className="text-2xl font-bold text-gray-900">Sitegeit</h1>
<p className="mt-1 text-sm text-gray-500">
Lead pipeline & website gClientDetailPage function · typescript · L3-L13 (11 LOC)src/app/(dashboard)/clients/[id]/page.tsx
export default function ClientDetailPage() {
return (
<div className="space-y-6">
<EmptyState
icon="person"
title="Client details"
description="Client detail view with tier management, site analytics, billing history, and reports will be available in Phase 6."
/>
</div>
)
}ClientsPage function · typescript · L5-L31 (27 LOC)src/app/(dashboard)/clients/page.tsx
export default function ClientsPage() {
return (
<div className="space-y-6">
<div>
<p className="text-sm text-gray-500">
Manage active clients, track revenue, and monitor their sites.
</p>
</div>
<EmptyState
icon="group"
title="No clients yet"
description="Convert prospects to clients to start managing them here. Clients appear once a deal closes."
action={
<Button variant="outline" asChild>
<Link href="/pipeline">
<span className="material-symbols-outlined text-[18px]">
conversion_path
</span>
View pipeline
</Link>
</Button>
}
/>
</div>
)
}DiscoverPage function · typescript · L4-L28 (25 LOC)src/app/(dashboard)/discover/page.tsx
export default function DiscoverPage() {
return (
<div className="space-y-6">
<div>
<p className="text-sm text-gray-500">
Find local businesses without websites and add them to your pipeline.
</p>
</div>
<EmptyState
icon="travel_explore"
title="No search results yet"
description="Search for businesses by region and category to discover leads without websites."
action={
<Button disabled>
<span className="material-symbols-outlined text-[18px]">
search
</span>
Start your first search
</Button>
}
/>
</div>
)
}EmailReviewPage function · typescript · L3-L19 (17 LOC)src/app/(dashboard)/email-review/page.tsx
export default function EmailReviewPage() {
return (
<div className="space-y-6">
<div>
<p className="text-sm text-gray-500">
Review, edit, and approve outreach emails before they send.
</p>
</div>
<EmptyState
icon="rate_review"
title="No emails to review"
description="When the pipeline generates outreach emails, they'll appear here for your review before sending."
/>
</div>
)
}Same scanner, your repo: https://repobility.com — Repobility
DashboardLayout function · typescript · L6-L20 (15 LOC)src/app/(dashboard)/layout.tsx
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<SidebarProvider>
<div className="min-h-screen bg-gray-50">
<Sidebar />
<Header />
<MainContent>{children}</MainContent>
</div>
</SidebarProvider>
)
}groupByDate function · typescript · L64-L85 (22 LOC)src/app/(dashboard)/notifications/page.tsx
function groupByDate(items: NotificationItem[]) {
const now = new Date()
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())
const yesterday = new Date(today.getTime() - 86400000)
const weekAgo = new Date(today.getTime() - 7 * 86400000)
const groups: { label: string; items: NotificationItem[] }[] = [
{ label: 'Today', items: [] },
{ label: 'Yesterday', items: [] },
{ label: 'This week', items: [] },
{ label: 'Earlier', items: [] },
]
items.forEach((item) => {
if (item.createdAt >= today) groups[0].items.push(item)
else if (item.createdAt >= yesterday) groups[1].items.push(item)
else if (item.createdAt >= weekAgo) groups[2].items.push(item)
else groups[3].items.push(item)
})
return groups.filter((g) => g.items.length > 0)
}NotificationsPage function · typescript · L87-L198 (112 LOC)src/app/(dashboard)/notifications/page.tsx
export default function NotificationsPage() {
const [activeTab, setActiveTab] = useState<FilterTab>('all')
const filtered =
activeTab === 'all'
? MOCK_NOTIFICATIONS
: MOCK_NOTIFICATIONS.filter(
(n) => NOTIFICATION_CATEGORY_MAP[n.type] === activeTab
)
const groups = groupByDate(filtered)
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<p className="text-sm text-gray-500">
Stay on top of pipeline events, email engagement, and system alerts.
</p>
<Button variant="ghost" size="sm">
Mark all read
</Button>
</div>
{/* Filter tabs */}
<div className="flex gap-1 rounded-lg bg-gray-100 p-1">
{TABS.map((tab) => (
<button
key={tab.key}
onClick={() => setActiveTab(tab.key)}
className={cn(
'rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
aDashboardPage function · typescript · L6-L26 (21 LOC)src/app/(dashboard)/page.tsx
export default function DashboardPage() {
return (
<div className="space-y-6">
{/* Pipeline overview cards */}
<PipelineSummary />
{/* Quick action buttons */}
<QuickActions />
{/* Two-column layout: activity + metrics */}
<div className="grid gap-6 lg:grid-cols-3">
<div className="lg:col-span-2">
<RecentActivity />
</div>
<div>
<MRRSnapshot />
</div>
</div>
</div>
)
}ProspectDetailPage function · typescript · L3-L13 (11 LOC)src/app/(dashboard)/pipeline/[id]/page.tsx
export default function ProspectDetailPage() {
return (
<div className="space-y-6">
<EmptyState
icon="business"
title="Prospect details"
description="Full prospect detail view with CRM record, generated site preview, email drafts, and activity timeline will be available in Phase 4."
/>
</div>
)
}PipelinePage function · typescript · L5-L32 (28 LOC)src/app/(dashboard)/pipeline/page.tsx
export default function PipelinePage() {
return (
<div className="space-y-6">
<div>
<p className="text-sm text-gray-500">
Track prospects as they move through discovery, enrichment, site
generation, and outreach.
</p>
</div>
<EmptyState
icon="conversion_path"
title="No prospects in pipeline"
description="Discover leads to fill your pipeline. Prospects will appear here as they move through each stage."
action={
<Button asChild>
<Link href="/discover">
<span className="material-symbols-outlined text-[18px]">
travel_explore
</span>
Discover leads
</Link>
</Button>
}
/>
</div>
)
}SettingsPage function · typescript · L31-L64 (34 LOC)src/app/(dashboard)/settings/page.tsx
export default function SettingsPage() {
return (
<div className="space-y-6">
<div>
<p className="text-sm text-gray-500">
Configure your pipeline, integrations, and preferences.
</p>
</div>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{SECTIONS.map((section) => (
<Card
key={section.title}
className="cursor-pointer transition-shadow hover:shadow-md"
>
<CardHeader>
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-gray-50">
<span className="material-symbols-outlined text-[20px] text-gray-400">
{section.icon}
</span>
</div>
<CardTitle>{section.title}</CardTitle>
</div>
</CardHeader>
<CardContent>
<p className="text-sm text-gray-500RootLayout function · typescript · L17-L36 (20 LOC)src/app/layout.tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className={manrope.variable}>
<head>
<link
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,300,0,0"
rel="stylesheet"
/>
</head>
<body className="font-sans antialiased">
{children}
<Toaster position="bottom-right" richColors />
</body>
</html>
)
}Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
MRRSnapshot function · typescript · L37-L78 (42 LOC)src/components/dashboard/MRRSnapshot.tsx
export function MRRSnapshot() {
return (
<Card>
<CardHeader>
<CardTitle>Revenue snapshot</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-4">
{METRICS.map((metric) => (
<div key={metric.label} className="flex items-start gap-3">
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-gray-50">
<span className="material-symbols-outlined text-[18px] text-gray-400">
{metric.icon}
</span>
</div>
<div>
<p className="text-lg font-bold text-gray-900">
{metric.value}
</p>
<p className="text-xs text-gray-500">{metric.label}</p>
{metric.change && (
<p
className={cn(
'mt-0.5 text-xs font-medium',
metric.changeType === 'positive'
PipelineSummary function · typescript · L14-L50 (37 LOC)src/components/dashboard/PipelineSummary.tsx
export function PipelineSummary() {
return (
<div>
<h2 className="mb-3 text-sm font-semibold text-gray-900">Pipeline overview</h2>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-7">
{STAGES.map((stage) => (
<Card
key={stage.label}
className="flex cursor-pointer flex-col items-center px-3 py-4 transition-shadow hover:shadow-md"
>
<div
className={cn(
'flex h-10 w-10 items-center justify-center rounded-lg',
stage.bg
)}
>
<span
className={cn(
'material-symbols-outlined text-[20px]',
stage.color
)}
>
{stage.icon}
</span>
</div>
<span className="mt-2 text-2xl font-bold text-gray-900">
{stage.count}
</span>
<span classNameQuickActions function · typescript · L27-L52 (26 LOC)src/components/dashboard/QuickActions.tsx
export function QuickActions() {
return (
<div>
<h2 className="mb-3 text-sm font-semibold text-gray-900">
Quick actions
</h2>
<div className="flex flex-wrap gap-2">
{ACTIONS.map((action) => (
<Button key={action.label} variant={action.variant} asChild>
<Link href={action.href} className="relative">
<span className="material-symbols-outlined text-[18px]">
{action.icon}
</span>
{action.label}
{action.badge && (
<span className="flex h-5 min-w-[20px] items-center justify-center rounded-full bg-primary px-1.5 text-[10px] font-semibold text-white">
{action.badge}
</span>
)}
</Link>
</Button>
))}
</div>
</div>
)
}RecentActivity function · typescript · L74-L113 (40 LOC)src/components/dashboard/RecentActivity.tsx
export function RecentActivity() {
return (
<Card className="flex flex-col">
<CardHeader>
<CardTitle>Recent activity</CardTitle>
</CardHeader>
<CardContent className="flex-1">
<div className="space-y-1">
{MOCK_ACTIVITY.map((item) => {
const iconConfig = ACTIVITY_ICON_MAP[item.type] ?? {
icon: 'info',
color: 'text-gray-400',
}
return (
<button
key={item.id}
className="flex w-full items-start gap-3 rounded-md px-2 py-2 text-left transition-colors hover:bg-gray-50"
>
<span
className={cn(
'material-symbols-outlined mt-0.5 text-[18px]',
iconConfig.color
)}
>
{iconConfig.icon}
</span>
<div className="min-w-0 flex-1">
<p className="text-sm text-grayHeader function · typescript · L18-L68 (51 LOC)src/components/layout/Header.tsx
export function Header() {
const pathname = usePathname()
const { toggle, toggleMobile, collapsed } = useSidebar()
const title =
PAGE_TITLES[pathname] ??
(pathname.startsWith('/pipeline/') ? 'Prospect Detail' :
pathname.startsWith('/clients/') ? 'Client Detail' : 'Sitegeit')
return (
<header
className={cn(
'sticky top-0 z-30 flex h-14 items-center justify-between border-b border-gray-200 bg-white px-4 transition-all duration-200',
collapsed ? 'lg:pl-20' : 'lg:pl-64'
)}
>
<div className="flex items-center gap-3">
{/* Mobile hamburger */}
<button
onClick={toggleMobile}
className="flex h-9 w-9 items-center justify-center rounded-md text-gray-500 hover:bg-gray-100 lg:hidden"
aria-label="Open navigation"
>
<span className="material-symbols-outlined text-[20px]">menu</span>
</button>
{/* Desktop collapse toggle */}
<button
onClickMainContent function · typescript · L6-L21 (16 LOC)src/components/layout/MainContent.tsx
export function MainContent({ children }: { children: React.ReactNode }) {
const { collapsed } = useSidebar()
return (
<main
className={cn(
'min-h-[calc(100vh-3.5rem)] transition-all duration-200',
collapsed ? 'lg:ml-16' : 'lg:ml-60'
)}
>
<div className="mx-auto max-w-7xl px-4 py-6 sm:px-6 lg:px-8">
{children}
</div>
</main>
)
}NotificationBell function · typescript · L69-L188 (120 LOC)src/components/layout/NotificationBell.tsx
export function NotificationBell() {
const [open, setOpen] = useState(false)
const panelRef = useRef<HTMLDivElement>(null)
const buttonRef = useRef<HTMLButtonElement>(null)
const unreadCount = MOCK_NOTIFICATIONS.filter((n) => !n.read).length
useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (
panelRef.current &&
!panelRef.current.contains(event.target as Node) &&
buttonRef.current &&
!buttonRef.current.contains(event.target as Node)
) {
setOpen(false)
}
}
document.addEventListener('mousedown', handleClickOutside)
return () => document.removeEventListener('mousedown', handleClickOutside)
}, [])
return (
<div className="relative">
<button
ref={buttonRef}
onClick={() => setOpen(!open)}
className="relative flex h-9 w-9 items-center justify-center rounded-md text-gray-500 hover:bg-gray-100"
aria-label={`Notifications${unreadCount > 0 ? ` ($handleClickOutside function · typescript · L77-L86 (10 LOC)src/components/layout/NotificationBell.tsx
function handleClickOutside(event: MouseEvent) {
if (
panelRef.current &&
!panelRef.current.contains(event.target as Node) &&
buttonRef.current &&
!buttonRef.current.contains(event.target as Node)
) {
setOpen(false)
}
}Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
SidebarProvider function · typescript · L15-L49 (35 LOC)src/components/layout/SidebarContext.tsx
export function SidebarProvider({ children }: { children: React.ReactNode }) {
const [collapsed, setCollapsed] = useState(false)
const [mobileOpen, setMobileOpen] = useState(false)
useEffect(() => {
const stored = localStorage.getItem('sidebar-collapsed')
if (stored !== null) {
setCollapsed(stored === 'true')
}
}, [])
const toggle = useCallback(() => {
setCollapsed((prev) => {
const next = !prev
localStorage.setItem('sidebar-collapsed', String(next))
return next
})
}, [])
const toggleMobile = useCallback(() => {
setMobileOpen((prev) => !prev)
}, [])
const closeMobile = useCallback(() => {
setMobileOpen(false)
}, [])
return (
<SidebarContext.Provider
value={{ collapsed, mobileOpen, toggle, toggleMobile, closeMobile }}
>
{children}
</SidebarContext.Provider>
)
}useSidebar function · typescript · L51-L57 (7 LOC)src/components/layout/SidebarContext.tsx
export function useSidebar() {
const context = useContext(SidebarContext)
if (!context) {
throw new Error('useSidebar must be used within a SidebarProvider')
}
return context
}Sidebar function · typescript · L9-L140 (132 LOC)src/components/layout/Sidebar.tsx
export function Sidebar() {
const pathname = usePathname()
const { collapsed, mobileOpen, closeMobile } = useSidebar()
const isActive = (href: string) => {
if (href === '/') return pathname === '/'
return pathname.startsWith(href)
}
return (
<>
{/* Mobile overlay */}
{mobileOpen && (
<div
className="fixed inset-0 z-40 bg-black/50 lg:hidden"
onClick={closeMobile}
/>
)}
{/* Sidebar */}
<aside
className={cn(
'fixed left-0 top-0 z-50 flex h-full flex-col border-r border-gray-200 bg-white transition-all duration-200',
// Desktop
collapsed ? 'lg:w-16' : 'lg:w-60',
// Mobile: slide from left
mobileOpen ? 'w-60 translate-x-0' : '-translate-x-full',
'lg:translate-x-0'
)}
>
{/* Logo */}
<div
className={cn(
'flex h-14 items-center border-b border-gray-200 px-4',
collapsed && 'lEmptyState function · typescript · L11-L33 (23 LOC)src/components/shared/EmptyState.tsx
export function EmptyState({
icon,
title,
description,
action,
className,
}: EmptyStateProps) {
return (
<div
className={cn(
'flex flex-col items-center justify-center rounded-lg border border-dashed border-gray-300 bg-white px-6 py-12 text-center',
className
)}
>
<span className="material-symbols-outlined mb-3 text-4xl text-gray-300">
{icon}
</span>
<h3 className="text-sm font-semibold text-gray-900">{title}</h3>
<p className="mt-1 max-w-sm text-sm text-gray-500">{description}</p>
{action && <div className="mt-4">{action}</div>}
</div>
)
}StatusBadge function · typescript · L23-L29 (7 LOC)src/components/shared/StatusBadge.tsx
export function StatusBadge({ status }: { status: string }) {
const stage = PIPELINE_STAGES.find((s) => s.key === status)
const label = stage?.label ?? status
const variant = STAGE_VARIANT_MAP[status] ?? 'secondary'
return <Badge variant={variant}>{label}</Badge>
}Badge function · typescript · L28-L32 (5 LOC)src/components/ui/badge.tsx
function Badge({ className, variant, ...props }: BadgeProps) {
return (
<span className={cn(badgeVariants({ variant }), className)} {...props} />
)
}createClient function · typescript · L3-L8 (6 LOC)src/lib/supabase/client.ts
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}updateSession function · typescript · L4-L55 (52 LOC)src/lib/supabase/middleware.ts
export async function updateSession(request: NextRequest) {
let supabaseResponse = NextResponse.next({
request,
})
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet: { name: string; value: string; options: CookieOptions }[]) {
cookiesToSet.forEach(({ name, value }) =>
request.cookies.set(name, value)
)
supabaseResponse = NextResponse.next({
request,
})
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
},
},
}
)
const {
data: { user },
} = await supabase.auth.getUser()
// If user is not logged in and trying to access dashboard routes, redirect to login
if (
!user &&
!request.nextUrl.pathnamRepobility analyzer · published findings · https://repobility.com
createClient function · typescript · L4-L29 (26 LOC)src/lib/supabase/server.ts
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet: { name: string; value: string; options: CookieOptions }[]) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch {
// setAll is called from Server Components where cookies
// cannot be set. This can be safely ignored when the
// middleware is refreshing the session.
}
},
},
}
)
}cn function · typescript · L4-L6 (3 LOC)src/lib/utils/cn.ts
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}middleware function · typescript · L4-L6 (3 LOC)src/middleware.ts
export async function middleware(request: NextRequest) {
return await updateSession(request)
}