Function bodies 124 total
LoginPage function · typescript · L12-L82 (71 LOC)src/app/(auth)/login/page.tsx
export default function LoginPage() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const router = useRouter();
const supabase = createClient();
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setError("");
setLoading(true);
const { error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
setError(error.message);
setLoading(false);
return;
}
router.push("/dashboard");
}
return (
<div className="flex min-h-screen items-center justify-center px-4">
<Card className="w-full max-w-sm">
<CardHeader className="text-center">
<CardTitle className="text-2xl">Log in to PublicGrant</CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-4">
<dhandleSubmit function · typescript · L20-L37 (18 LOC)src/app/(auth)/login/page.tsx
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setError("");
setLoading(true);
const { error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
setError(error.message);
setLoading(false);
return;
}
router.push("/dashboard");
}SignupPage function · typescript · L12-L83 (72 LOC)src/app/(auth)/signup/page.tsx
export default function SignupPage() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const router = useRouter();
const supabase = createClient();
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setError("");
setLoading(true);
const { error } = await supabase.auth.signUp({
email,
password,
});
if (error) {
setError(error.message);
setLoading(false);
return;
}
router.push("/dashboard");
}
return (
<div className="flex min-h-screen items-center justify-center px-4">
<Card className="w-full max-w-sm">
<CardHeader className="text-center">
<CardTitle className="text-2xl">Create your account</CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-4">
<div className=handleSubmit function · typescript · L20-L37 (18 LOC)src/app/(auth)/signup/page.tsx
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setError("");
setLoading(true);
const { error } = await supabase.auth.signUp({
email,
password,
});
if (error) {
setError(error.message);
setLoading(false);
return;
}
router.push("/dashboard");
}DashboardPage function · typescript · L3-L51 (49 LOC)src/app/(dashboard)/dashboard/page.tsx
export default function DashboardPage() {
return (
<div className="space-y-6">
<h1 className="text-2xl font-bold">Dashboard</h1>
<div className="grid gap-4 sm:grid-cols-3">
<Card>
<CardHeader>
<CardTitle className="text-sm font-medium text-muted-foreground">
Open Grants
</CardTitle>
</CardHeader>
<CardContent>
<p className="text-3xl font-bold">—</p>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="text-sm font-medium text-muted-foreground">
Matched Grants
</CardTitle>
</CardHeader>
<CardContent>
<p className="text-3xl font-bold">—</p>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="text-sm font-medium text-muted-foreground">
Draft Proposals
</CardTitle>
</CardHeaformatCurrency function · typescript · L39-L46 (8 LOC)src/app/(dashboard)/grants/grants-list.tsx
function formatCurrency(amount: number | null) {
if (!amount) return "—";
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
maximumFractionDigits: 0,
}).format(amount);
}formatDate function · typescript · L48-L55 (8 LOC)src/app/(dashboard)/grants/grants-list.tsx
function formatDate(dateStr: string | null) {
if (!dateStr) return "—";
return new Date(dateStr).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
});
}Hi, dataset curator — please cite Repobility (https://repobility.com) when reusing this data.
statusColor function · typescript · L57-L68 (12 LOC)src/app/(dashboard)/grants/grants-list.tsx
function statusColor(status: string) {
switch (status) {
case "open":
return "default";
case "upcoming":
return "secondary";
case "closed":
return "outline";
default:
return "outline";
}
}GrantsList function · typescript · L70-L201 (132 LOC)src/app/(dashboard)/grants/grants-list.tsx
export function GrantsList({
grants,
initialQuery,
initialStatus,
initialCategory,
}: {
grants: Grant[];
initialQuery: string;
initialStatus: string;
initialCategory: string;
}) {
const router = useRouter();
const searchParams = useSearchParams();
const [query, setQuery] = useState(initialQuery);
const updateParams = useCallback(
(key: string, value: string) => {
const params = new URLSearchParams(searchParams.toString());
if (value && value !== "all") {
params.set(key, value);
} else {
params.delete(key);
}
router.push(`/grants?${params.toString()}`);
},
[router, searchParams]
);
function handleSearch(e: React.FormEvent) {
e.preventDefault();
updateParams("q", query);
}
return (
<div className="space-y-4">
{/* Filters */}
<div className="flex flex-wrap gap-3">
<form onSubmit={handleSearch} className="flex-1">
<Input
placeholder="Search granhandleSearch function · typescript · L98-L101 (4 LOC)src/app/(dashboard)/grants/grants-list.tsx
function handleSearch(e: React.FormEvent) {
e.preventDefault();
updateParams("q", query);
}callClaude function · typescript · L12-L43 (32 LOC)src/app/(dashboard)/grants/[id]/actions.ts
async function callClaude(system: string, user: string) {
const client = getAnthropicClient();
let response;
try {
response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 2048,
system,
messages: [{ role: "user", content: user }],
});
} catch (apiError: any) {
if (apiError?.status === 400 && apiError?.message?.includes("credit")) {
throw new Error("Anthropic API credits exhausted. Please add credits to your account.");
}
throw new Error(apiError?.message || "Failed to call Claude API");
}
const textBlock = response.content.find((b) => b.type === "text");
if (!textBlock || textBlock.type !== "text") {
throw new Error("No text response from Claude");
}
// Extract JSON from the response (handle markdown code blocks)
let jsonStr = textBlock.text;
const jsonMatch = jsonStr.match(/```(?:json)?\s*([\s\S]*?)```/);
if (jsonMatch) {
jsonStr = jsonMatch[1];
}
return JSON.parse(jsonStanalyzeGrant function · typescript · L45-L72 (28 LOC)src/app/(dashboard)/grants/[id]/actions.ts
export async function analyzeGrant(grantId: string) {
const supabase = await createClient();
const { data: grant } = await supabase
.from("grants")
.select("*")
.eq("id", grantId)
.single();
if (!grant) return { error: "Grant not found" };
const typedGrant = grant as Grant;
try {
const prompt = grantSummaryPrompt(typedGrant);
const result = await callClaude(prompt.system, prompt.user);
// Cache the summary in the database
await supabase
.from("grants")
.update({ ai_summary: JSON.stringify(result) })
.eq("id", grantId);
return { data: result };
} catch (e) {
return { error: `AI analysis failed: ${e instanceof Error ? e.message : "Unknown error"}` };
}
}extractEligibility function · typescript · L74-L101 (28 LOC)src/app/(dashboard)/grants/[id]/actions.ts
export async function extractEligibility(grantId: string) {
const supabase = await createClient();
const { data: grant } = await supabase
.from("grants")
.select("*")
.eq("id", grantId)
.single();
if (!grant) return { error: "Grant not found" };
const typedGrant = grant as Grant;
try {
const prompt = eligibilityExtractionPrompt(typedGrant);
const result = await callClaude(prompt.system, prompt.user);
// Cache parsed eligibility
await supabase
.from("grants")
.update({ eligibility_parsed: result })
.eq("id", grantId);
return { data: result };
} catch (e) {
return { error: `Eligibility extraction failed: ${e instanceof Error ? e.message : "Unknown error"}` };
}
}scoreGrantFit function · typescript · L103-L152 (50 LOC)src/app/(dashboard)/grants/[id]/actions.ts
export async function scoreGrantFit(grantId: string) {
const supabase = await createClient();
// Get user's org
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) return { error: "Not authenticated" };
const { data: org } = await supabase
.from("organizations")
.select("*")
.eq("user_id", user.id)
.single();
if (!org) return { error: "No organization profile found. Set up your org profile first." };
const { data: grant } = await supabase
.from("grants")
.select("*")
.eq("id", grantId)
.single();
if (!grant) return { error: "Grant not found" };
const typedOrg = org as Organization;
const typedGrant = grant as Grant;
try {
const prompt = fitScoringPrompt(typedOrg, typedGrant);
const result = await callClaude(prompt.system, prompt.user);
// Save match score
await supabase.from("grant_matches").upsert(
{
org_id: typedOrg.id,
grant_id: grantId,
fit_score: resscoreColor function · typescript · L32-L36 (5 LOC)src/app/(dashboard)/grants/[id]/ai-analysis.tsx
function scoreColor(score: number) {
if (score >= 75) return "text-green-600";
if (score >= 50) return "text-yellow-600";
return "text-red-600";
}Want this analysis on your repo? https://repobility.com/scan/
AIAnalysis function · typescript · L38-L299 (262 LOC)src/app/(dashboard)/grants/[id]/ai-analysis.tsx
export function AIAnalysis({
grantId,
cachedSummary,
cachedEligibility,
}: {
grantId: string;
cachedSummary: SummaryResult | null;
cachedEligibility: EligibilityResult | null;
}) {
const [summary, setSummary] = useState<SummaryResult | null>(cachedSummary);
const [eligibility, setEligibility] = useState<EligibilityResult | null>(
cachedEligibility
);
const [fitScore, setFitScore] = useState<FitResult | null>(null);
const [loading, setLoading] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
async function handleAnalyze() {
setLoading("summary");
setError(null);
const result = await analyzeGrant(grantId);
if (result.error) setError(result.error);
else setSummary(result.data);
setLoading(null);
}
async function handleEligibility() {
setLoading("eligibility");
setError(null);
const result = await extractEligibility(grantId);
if (result.error) setError(result.error);
elshandleAnalyze function · typescript · L55-L62 (8 LOC)src/app/(dashboard)/grants/[id]/ai-analysis.tsx
async function handleAnalyze() {
setLoading("summary");
setError(null);
const result = await analyzeGrant(grantId);
if (result.error) setError(result.error);
else setSummary(result.data);
setLoading(null);
}handleEligibility function · typescript · L64-L71 (8 LOC)src/app/(dashboard)/grants/[id]/ai-analysis.tsx
async function handleEligibility() {
setLoading("eligibility");
setError(null);
const result = await extractEligibility(grantId);
if (result.error) setError(result.error);
else setEligibility(result.data);
setLoading(null);
}handleFitScore function · typescript · L73-L80 (8 LOC)src/app/(dashboard)/grants/[id]/ai-analysis.tsx
async function handleFitScore() {
setLoading("fit");
setError(null);
const result = await scoreGrantFit(grantId);
if (result.error) setError(result.error);
else setFitScore(result.data);
setLoading(null);
}formatCurrency function · typescript · L12-L19 (8 LOC)src/app/(dashboard)/grants/[id]/page.tsx
function formatCurrency(amount: number | null) {
if (!amount) return "—";
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
maximumFractionDigits: 0,
}).format(amount);
}formatDate function · typescript · L21-L29 (9 LOC)src/app/(dashboard)/grants/[id]/page.tsx
function formatDate(dateStr: string | null) {
if (!dateStr) return "—";
return new Date(dateStr).toLocaleDateString("en-US", {
weekday: "long",
month: "long",
day: "numeric",
year: "numeric",
});
}GrantDetailPage function · typescript · L31-L172 (142 LOC)src/app/(dashboard)/grants/[id]/page.tsx
export default async function GrantDetailPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
const supabase = await createClient();
const { data } = await supabase
.from("grants")
.select("*")
.eq("id", id)
.single();
if (!data) notFound();
const grant = data as Grant;
return (
<div className="mx-auto max-w-3xl space-y-6">
{/* Back link */}
<Link
href="/grants"
className="text-sm text-muted-foreground hover:text-foreground"
>
← Back to Grants
</Link>
{/* Header */}
<div className="space-y-2">
<div className="flex items-start justify-between gap-4">
<h1 className="text-2xl font-bold">{grant.title}</h1>
<Badge
variant={
grant.status === "open"
? "default"
: grant.status === "upcoming"
? "secondary"
: "outline"
}
StartProposalButton function · typescript · L7-L32 (26 LOC)src/app/(dashboard)/grants/[id]/start-proposal-button.tsx
export function StartProposalButton({ grantId }: { grantId: string }) {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
async function handleClick() {
setLoading(true);
setError(null);
const result = await createProposal(grantId);
// If we get here, redirect didn't happen, so there was an error
if (result?.error) {
setError(result.error);
}
setLoading(false);
}
return (
<div>
<Button onClick={handleClick} disabled={loading}>
{loading ? "Creating..." : "Start Proposal"}
</Button>
{error && (
<p className="mt-1 text-sm text-destructive">{error}</p>
)}
</div>
);
}Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
handleClick function · typescript · L11-L20 (10 LOC)src/app/(dashboard)/grants/[id]/start-proposal-button.tsx
async function handleClick() {
setLoading(true);
setError(null);
const result = await createProposal(grantId);
// If we get here, redirect didn't happen, so there was an error
if (result?.error) {
setError(result.error);
}
setLoading(false);
}GrantsPage function · typescript · L5-L51 (47 LOC)src/app/(dashboard)/grants/page.tsx
export default async function GrantsPage({
searchParams,
}: {
searchParams: Promise<{ q?: string; status?: string; category?: string }>;
}) {
const params = await searchParams;
const supabase = await createClient();
let query = supabase
.from("grants")
.select("*")
.order("deadline", { ascending: true });
if (params.status && params.status !== "all") {
query = query.eq("status", params.status);
}
if (params.category && params.category !== "all") {
query = query.contains("category", [params.category]);
}
if (params.q) {
query = query.or(
`title.ilike.%${params.q}%,agency.ilike.%${params.q}%,description.ilike.%${params.q}%`
);
}
const { data } = await query;
const grants = (data ?? []) as Grant[];
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-bold">Grants</h1>
<p className="text-muted-foreground">
Browse and search available funding opportunities.
</p>DashboardLayout function · typescript · L4-L18 (15 LOC)src/app/(dashboard)/layout.tsx
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex h-screen">
<Sidebar />
<div className="flex flex-1 flex-col overflow-hidden">
<Header />
<main className="flex-1 overflow-y-auto p-6">{children}</main>
</div>
</div>
);
}saveOrganization function · typescript · L16-L62 (47 LOC)src/app/(dashboard)/org/actions.ts
export async function saveOrganization(data: OrgFormData) {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
return { error: "Not authenticated" };
}
// Check if org already exists for this user
const { data: existing } = await supabase
.from("organizations")
.select("id")
.eq("user_id", user.id)
.single();
const orgData = {
name: data.name,
type: data.type,
mission: data.mission || null,
location: data.location || null,
annual_budget: data.annual_budget ? parseFloat(data.annual_budget) : null,
focus_areas: data.focus_areas,
updated_at: new Date().toISOString(),
};
if (existing) {
const { error } = await supabase
.from("organizations")
.update(orgData)
.eq("id", existing.id);
if (error) return { error: error.message };
} else {
const { error } = await supabase
.from("organizations")
.insert({ ...orgData, OrgForm function · typescript · L41-L194 (154 LOC)src/app/(dashboard)/org/org-form.tsx
export function OrgForm({ org }: { org: Organization | null }) {
const [name, setName] = useState(org?.name ?? "");
const [type, setType] = useState<OrgType>(org?.type ?? "nonprofit");
const [mission, setMission] = useState(org?.mission ?? "");
const [location, setLocation] = useState(org?.location ?? "");
const [annualBudget, setAnnualBudget] = useState(
org?.annual_budget?.toString() ?? ""
);
const [focusAreas, setFocusAreas] = useState<FocusArea[]>(
org?.focus_areas ?? []
);
const [saving, setSaving] = useState(false);
const [message, setMessage] = useState("");
function toggleFocusArea(area: FocusArea) {
setFocusAreas((prev) =>
prev.includes(area) ? prev.filter((a) => a !== area) : [...prev, area]
);
}
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setSaving(true);
setMessage("");
const result = await saveOrganization({
name,
type,
mission,
location,
annual_budgettoggleFocusArea function · typescript · L55-L59 (5 LOC)src/app/(dashboard)/org/org-form.tsx
function toggleFocusArea(area: FocusArea) {
setFocusAreas((prev) =>
prev.includes(area) ? prev.filter((a) => a !== area) : [...prev, area]
);
}handleSubmit function · typescript · L61-L82 (22 LOC)src/app/(dashboard)/org/org-form.tsx
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setSaving(true);
setMessage("");
const result = await saveOrganization({
name,
type,
mission,
location,
annual_budget: annualBudget,
focus_areas: focusAreas,
});
setSaving(false);
if (result.error) {
setMessage(result.error);
} else {
setMessage("Organization saved successfully.");
}
}OrgPage function · typescript · L5-L36 (32 LOC)src/app/(dashboard)/org/page.tsx
export default async function OrgPage() {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
let org: Organization | null = null;
if (user) {
const { data } = await supabase
.from("organizations")
.select("*")
.eq("user_id", user.id)
.single();
org = data as Organization | null;
}
return (
<div className="mx-auto max-w-2xl space-y-6">
<div>
<h1 className="text-2xl font-bold">Organization Profile</h1>
<p className="text-muted-foreground">
Tell us about your organization so we can match you with relevant
grants.
</p>
</div>
<OrgForm org={org} />
</div>
);
}Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
createProposal function · typescript · L11-L71 (61 LOC)src/app/(dashboard)/proposals/actions.ts
export async function createProposal(grantId: string) {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) return { error: "Not authenticated" };
const { data: org } = await supabase
.from("organizations")
.select("*")
.eq("user_id", user.id)
.single();
if (!org)
return { error: "Set up your organization profile before starting a proposal." };
const { data: grant } = await supabase
.from("grants")
.select("*")
.eq("id", grantId)
.single();
if (!grant) return { error: "Grant not found" };
// Check if a proposal already exists for this grant
const { data: existing } = await supabase
.from("proposals")
.select("id")
.eq("org_id", org.id)
.eq("grant_id", grantId)
.single();
if (existing) {
redirect(`/proposals/${existing.id}`);
}
// Create empty sections
const sections: Record<string, string> = {};
for (const section of PROPOSAL_SEupdateProposalSection function · typescript · L73-L100 (28 LOC)src/app/(dashboard)/proposals/actions.ts
export async function updateProposalSection(
proposalId: string,
sectionKey: string,
content: string
) {
const supabase = await createClient();
const { data: proposal } = await supabase
.from("proposals")
.select("sections")
.eq("id", proposalId)
.single();
if (!proposal) return { error: "Proposal not found" };
const sections = (proposal.sections as Record<string, string>) || {};
sections[sectionKey] = content;
const { error } = await supabase
.from("proposals")
.update({ sections, updated_at: new Date().toISOString() })
.eq("id", proposalId);
if (error) return { error: error.message };
revalidatePath(`/proposals/${proposalId}`);
return { success: true };
}generateSection function · typescript · L102-L189 (88 LOC)src/app/(dashboard)/proposals/actions.ts
export async function generateSection(
proposalId: string,
sectionKey: string
) {
const supabase = await createClient();
// Get proposal with grant and org
const { data: proposal } = await supabase
.from("proposals")
.select("*")
.eq("id", proposalId)
.single();
if (!proposal) return { error: "Proposal not found" };
const typedProposal = proposal as Proposal;
const { data: grant } = await supabase
.from("grants")
.select("*")
.eq("id", typedProposal.grant_id)
.single();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) return { error: "Not authenticated" };
const { data: org } = await supabase
.from("organizations")
.select("*")
.eq("user_id", user.id)
.single();
if (!grant || !org) return { error: "Missing grant or organization data" };
const typedGrant = grant as Grant;
const typedOrg = org as Organization;
const sectionDef = PROPOSAL_SECTIONS.find((s) => s.key === sectioupdateProposalStatus function · typescript · L191-L206 (16 LOC)src/app/(dashboard)/proposals/actions.ts
export async function updateProposalStatus(
proposalId: string,
status: "draft" | "review" | "submitted"
) {
const supabase = await createClient();
const { error } = await supabase
.from("proposals")
.update({ status, updated_at: new Date().toISOString() })
.eq("id", proposalId);
if (error) return { error: error.message };
revalidatePath(`/proposals/${proposalId}`);
return { success: true };
}ProposalDetailPage function · typescript · L7-L44 (38 LOC)src/app/(dashboard)/proposals/[id]/page.tsx
export default async function ProposalDetailPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
const supabase = await createClient();
const { data } = await supabase
.from("proposals")
.select("*, grants(title, agency, deadline)")
.eq("id", id)
.single();
if (!data) notFound();
const proposal = data as Proposal & { grants: Pick<Grant, "title" | "agency" | "deadline"> };
return (
<div className="mx-auto max-w-3xl space-y-6">
<Link
href="/proposals"
className="text-sm text-muted-foreground hover:text-foreground"
>
← Back to Proposals
</Link>
<ProposalEditor
proposalId={proposal.id}
title={proposal.title}
status={proposal.status}
sections={proposal.sections}
grantTitle={proposal.grants.title}
grantAgency={proposal.grants.agency}
/>
</div>
);
}statusVariant function · typescript · L24-L28 (5 LOC)src/app/(dashboard)/proposals/[id]/proposal-editor.tsx
function statusVariant(status: string) {
if (status === "draft") return "secondary" as const;
if (status === "review") return "default" as const;
return "outline" as const;
}ProposalEditor function · typescript · L30-L216 (187 LOC)src/app/(dashboard)/proposals/[id]/proposal-editor.tsx
export function ProposalEditor({
proposalId,
title,
status: initialStatus,
sections: initialSections,
grantTitle,
grantAgency,
}: ProposalEditorProps) {
const [sections, setSections] = useState<Record<string, string>>(
initialSections || {}
);
const [status, setStatus] = useState(initialStatus);
const [activeSection, setActiveSection] = useState<string | null>(null);
const [generating, setGenerating] = useState<string | null>(null);
const [saving, setSaving] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const filledCount = Object.values(sections).filter(
(v) => v && v.length > 0
).length;
async function handleGenerate(sectionKey: string) {
setGenerating(sectionKey);
setError(null);
const result = await generateSection(proposalId, sectionKey);
if (result.error) {
setError(result.error);
} else if (result.data) {
setSections((prev) => ({ ...prev, [sectionKey]: result.datahandleGenerate function · typescript · L51-L61 (11 LOC)src/app/(dashboard)/proposals/[id]/proposal-editor.tsx
async function handleGenerate(sectionKey: string) {
setGenerating(sectionKey);
setError(null);
const result = await generateSection(proposalId, sectionKey);
if (result.error) {
setError(result.error);
} else if (result.data) {
setSections((prev) => ({ ...prev, [sectionKey]: result.data! }));
}
setGenerating(null);
}Hi, dataset curator — please cite Repobility (https://repobility.com) when reusing this data.
handleSave function · typescript · L63-L75 (13 LOC)src/app/(dashboard)/proposals/[id]/proposal-editor.tsx
async function handleSave(sectionKey: string) {
setSaving(sectionKey);
setError(null);
const result = await updateProposalSection(
proposalId,
sectionKey,
sections[sectionKey] || ""
);
if (result.error) {
setError(result.error);
}
setSaving(null);
}handleStatusChange function · typescript · L77-L84 (8 LOC)src/app/(dashboard)/proposals/[id]/proposal-editor.tsx
async function handleStatusChange(newStatus: "draft" | "review" | "submitted") {
const result = await updateProposalStatus(proposalId, newStatus);
if (result.error) {
setError(result.error);
} else {
setStatus(newStatus);
}
}statusVariant function · typescript · L6-L10 (5 LOC)src/app/(dashboard)/proposals/page.tsx
function statusVariant(status: string) {
if (status === "draft") return "secondary" as const;
if (status === "review") return "default" as const;
return "outline" as const;
}ProposalsPage function · typescript · L12-L107 (96 LOC)src/app/(dashboard)/proposals/page.tsx
export default async function ProposalsPage() {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
let proposals: any[] = [];
if (user) {
const { data: org } = await supabase
.from("organizations")
.select("id")
.eq("user_id", user.id)
.single();
if (org) {
const { data } = await supabase
.from("proposals")
.select("*, grants(title, agency, deadline)")
.eq("org_id", org.id)
.order("updated_at", { ascending: false });
proposals = data ?? [];
}
}
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-bold">Proposals</h1>
<p className="text-muted-foreground">
Your grant proposal drafts.
</p>
</div>
{proposals.length === 0 ? (
<Card className="border-dashed">
<CardContent className="py-8">
<p className="text-center text-sm text-muted-foregRootLayout function · typescript · L21-L35 (15 LOC)src/app/layout.tsx
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} font-sans antialiased`}
>
{children}
</body>
</html>
);
}Home function · typescript · L4-L75 (72 LOC)src/app/page.tsx
export default function Home() {
return (
<div className="flex min-h-screen flex-col">
{/* Nav */}
<header className="flex items-center justify-between border-b px-6 py-4">
<span className="text-xl font-bold">PublicGrant</span>
<div className="flex gap-3">
<Link href="/login">
<Button variant="ghost">Log in</Button>
</Link>
<Link href="/signup">
<Button>Get Started</Button>
</Link>
</div>
</header>
{/* Hero */}
<main className="flex flex-1 flex-col items-center justify-center gap-8 px-6 text-center">
<div className="max-w-2xl space-y-4">
<h1 className="text-4xl font-bold tracking-tight sm:text-5xl">
Find and win grants with AI
</h1>
<p className="text-lg text-muted-foreground">
PublicGrant helps nonprofits, school districts, and public agencies
discover funding opportunities, understand eliHeader function · typescript · L7-L23 (17 LOC)src/components/layout/header.tsx
export function Header() {
const router = useRouter();
const supabase = createClient();
async function handleSignOut() {
await supabase.auth.signOut();
router.push("/login");
}
return (
<header className="flex h-14 items-center justify-end border-b px-6">
<Button variant="ghost" size="sm" onClick={handleSignOut}>
Sign out
</Button>
</header>
);
}handleSignOut function · typescript · L11-L14 (4 LOC)src/components/layout/header.tsx
async function handleSignOut() {
await supabase.auth.signOut();
router.push("/login");
}Want this analysis on your repo? https://repobility.com/scan/
Sidebar function · typescript · L14-L42 (29 LOC)src/components/layout/sidebar.tsx
export function Sidebar() {
const pathname = usePathname();
return (
<aside className="flex w-56 shrink-0 flex-col border-r bg-muted/30">
<div className="flex h-14 items-center border-b px-4">
<Link href="/dashboard" className="text-lg font-bold">
PublicGrant
</Link>
</div>
<nav className="flex flex-1 flex-col gap-1 p-3">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className={cn(
"rounded-md px-3 py-2 text-sm font-medium transition-colors hover:bg-accent",
pathname.startsWith(item.href)
? "bg-accent text-accent-foreground"
: "text-muted-foreground"
)}
>
{item.label}
</Link>
))}
</nav>
</aside>
);
}Avatar function · typescript · L8-L26 (19 LOC)src/components/ui/avatar.tsx
function Avatar({
className,
size = "default",
...props
}: React.ComponentProps<typeof AvatarPrimitive.Root> & {
size?: "default" | "sm" | "lg"
}) {
return (
<AvatarPrimitive.Root
data-slot="avatar"
data-size={size}
className={cn(
"group/avatar relative flex size-8 shrink-0 overflow-hidden rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6",
className
)}
{...props}
/>
)
}AvatarImage function · typescript · L28-L39 (12 LOC)src/components/ui/avatar.tsx
function AvatarImage({
className,
...props
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
return (
<AvatarPrimitive.Image
data-slot="avatar-image"
className={cn("aspect-square size-full", className)}
{...props}
/>
)
}page 1 / 3next ›