Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/app/u/[username]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export default async function PublicProfilePage({

const avatarUrl = `https://avatars.githubusercontent.com/${profile.username}`;
const topRepo = profile.repos[0]?.name ?? "";
const gistsUrl = `https://gist.github.com/${profile.username}`;
const showCompareButton =
loggedInUsername !== null &&
loggedInUsername.toLowerCase() !== profile.username.toLowerCase();
Expand All @@ -148,6 +149,18 @@ export default async function PublicProfilePage({
<p className="mt-2 text-[var(--muted-foreground)]">
GitHub activity and coding stats
</p>
{profile.publicGists > 0 && (
<div className="mt-3 flex flex-wrap items-center gap-2">
<a
href={gistsUrl}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center rounded-full border border-[var(--border)] bg-[var(--control)] px-3 py-1.5 text-sm font-medium text-[var(--card-foreground)] transition-colors hover:bg-[var(--control)]/80 hover:text-[var(--accent)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)]/50"
>
{profile.publicGists} Gists
</a>
</div>
)}
{compareHref && (
<a
href={compareHref}
Expand Down
16 changes: 16 additions & 0 deletions src/lib/public-profile-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface PublicProfileData {
username: string;
bio: string | null;
isSponsor: boolean;
publicGists: number;
repos: TopRepo[];
contributions: ContributionData;
streak: StreakData;
Expand All @@ -53,6 +54,18 @@ async function ghFetch(url: string, token?: string): Promise<Response> {
return fetch(url, { headers, cache: "no-store" });
}

export async function fetchPublicGists(
username: string,
token?: string
): Promise<number> {
const res = await ghFetch(`${GITHUB_API}/users/${username}`, token);

if (!res.ok) return 0;

const data = (await res.json()) as { public_gists?: number };
return data.public_gists ?? 0;
}

export async function fetchPublicTopRepos(
username: string,
token?: string,
Expand Down Expand Up @@ -250,6 +263,7 @@ export async function fetchPublicProfile(

const githubToken = process.env.GITHUB_TOKEN;
const [
publicGists,
repos,
contributions,
streak,
Expand All @@ -258,6 +272,7 @@ export async function fetchPublicProfile(
achievementsCache,
spotlight,
] = await Promise.all([
fetchPublicGists(user.github_login, githubToken),
fetchPublicTopRepos(user.github_login, githubToken, 30),
fetchPublicContributions(user.github_login, githubToken, 30),
fetchPublicStreak(user.github_login, githubToken),
Expand All @@ -281,6 +296,7 @@ export async function fetchPublicProfile(
username: user.github_login,
bio: user.bio ?? null,
isSponsor: user.is_sponsor ?? false,
publicGists,
repos,
contributions,
streak,
Expand Down
22 changes: 22 additions & 0 deletions test/public-profile-data.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
fetchPublicContributions,
fetchPublicStreak,
fetchTopLanguage,
fetchPublicGists,
} from "../src/lib/public-profile-data";

describe("public-profile-data", () => {
Expand Down Expand Up @@ -46,6 +47,27 @@ describe("public-profile-data", () => {
});
});

describe("fetchPublicGists", () => {
it("should return the public gist count on successful API response", async () => {
const mockFetch = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({ public_gists: 7 }),
});
vi.stubGlobal("fetch", mockFetch);

const gists = await fetchPublicGists("user123");
expect(gists).toBe(7);
});

it("should return zero on failed API response", async () => {
const mockFetch = vi.fn().mockResolvedValue({ ok: false });
vi.stubGlobal("fetch", mockFetch);

const gists = await fetchPublicGists("user123");
expect(gists).toBe(0);
});
});

describe("fetchPublicContributions", () => {
it("should aggregate commits by day on successful response", async () => {
const mockFetch = vi.fn().mockResolvedValue({
Expand Down
Loading