Skip to content
Merged
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
2 changes: 1 addition & 1 deletion next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const nextConfig: NextConfig = {
/* config options here */
reactStrictMode: true,
images: {
domains: ['images.unsplash.com', 'assets.aceternity.com', 'pbs.twimg.com', 'drive.google.com', 'userpic.codeforces.org', 'cdn.jsdelivr.net', 'api.microlink.io'],
domains: ['images.unsplash.com', 'assets.aceternity.com', 'pbs.twimg.com', 'drive.google.com', 'userpic.codeforces.org', 'cdn.jsdelivr.net', 'api.microlink.io', 'api.github.com', 'avatars.githubusercontent.com'],
},
};

Expand Down
2 changes: 2 additions & 0 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import MainNavbar from '@/components/shared/main-navbar';
import { CursorWrapper } from "@/components/home/ui/cursor-wrapper";
import Footer from "../components/shared/footer";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import Contributors from "@/components/home/sections/contributors";

const navLinks = [
{ key: "home", label: "Home", href: "#home" },
Expand All @@ -26,6 +27,7 @@ export default function HomePage() {
<Hero />
<AboutUs />
<Members />
<Contributors />
<Footer />
</CursorWrapper>
</QueryClientProvider>
Expand Down
48 changes: 48 additions & 0 deletions src/components/home/sections/contributors.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use client";

import { useEffect, useState } from "react";
import { Contributor } from "@/models/contributor.model";
import { getContributors } from "@/controllers/contributor.controller";
import Image from "next/image";

export default function Contributors() {
const [contributors, setContributors] = useState<Contributor[]>([]);

useEffect(() => {
const fetchContributors = async () => {
const data = await getContributors();
setContributors(data);
};

fetchContributors();
}, []);

return (
<div
id="contributors"
className="space-y-8 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12"
>
<div className="text-center space-x-4 mb-10">
<h3 className="inline dark:text-white">
Contribuyen con este proyecto
</h3>
<span className="dark:text-white font-sans text-semibold bg-gray-400 rounded px-3 py-1">
{contributors.length}
</span>
</div>
<div className="flex justify-center items-center flex-wrap gap-8">
{contributors?.map((contributor) => (
<a key={contributor._id} href={contributor.github}>
<Image
src={contributor.image}
alt={`Avatar de ${contributor.name}`}
width={58}
height={58}
className="rounded-full border-1 border-black/20 dark:border-white/20"
/>
</a>
))}
</div>
</div>
);
}
52 changes: 52 additions & 0 deletions src/controllers/contributor.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Contributor, GitHubContributor } from "@/models/contributor.model";

const repositories = [
{ owner: "CapituloJaverianoACM", repo: "ACM-Web-Page-UI" },
{ owner: "CapituloJaverianoACM", repo: "ACM-cli" },
{ owner: "CapituloJaverianoACM", repo: "ACM-api" },
];

function mapRepositoriesToUrls(
repos: { owner: string; repo: string }[],
): string[] {
return repos.map(
(repo) =>
`https://api.github.com/repos/${repo.owner}/${repo.repo}/contributors`,
);
}

async function fetchAndTransformContributors(
apiUrl: string,
): Promise<Contributor[]> {
const res = await fetch(apiUrl);

if (!res.ok) {
console.error(`Error al obtener contribuyentes de ${apiUrl}`);
return [];
}

const githubContributors: GitHubContributor[] = await res.json();
return githubContributors.map((contributor) => ({
_id: contributor.id,
name: contributor.login,
image: contributor.avatar_url,
github: contributor.html_url,
}));
}

export async function getContributors(): Promise<Contributor[]> {
const reposUrls = mapRepositoriesToUrls(repositories);

const promises = reposUrls.map((url) => fetchAndTransformContributors(url));
const allContributorsArrays = await Promise.all(promises);

const uniqueContributorsMap = new Map<number, Contributor>();

allContributorsArrays.flat().forEach((contributor) => {
if (!uniqueContributorsMap.has(contributor._id)) {
uniqueContributorsMap.set(contributor._id, contributor);
}
});

return Array.from(uniqueContributorsMap.values());
}
4 changes: 2 additions & 2 deletions src/lib/supabase.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createClient } from '@supabase/supabase-js';

const supabaseUrl = process.env.SUPABASE_URL!;
const supabaseKey = process.env.SUPABASE_ANON_KEY!;
const supabaseUrl = process.env.SUPABASE_URL || "";
const supabaseKey = process.env.SUPABASE_ANON_KEY || "";

export const supabase = createClient(supabaseUrl, supabaseKey);
13 changes: 13 additions & 0 deletions src/models/contributor.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export interface GitHubContributor {
id: number;
login: string;
avatar_url: string;
html_url: string;
}

export interface Contributor {
_id: number;
name: string;
image: string;
github: string;
}
Loading