Skip to content

Commit

Permalink
Merge pull request #31 from asusoda/headshots
Browse files Browse the repository at this point in the history
Headshots
  • Loading branch information
code-wolf-byte authored Nov 7, 2024
2 parents 338c672 + 0bdb976 commit 47d798f
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 10 deletions.
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Home from "./pages/Home";
import Mentorship from "./pages/Mentorship";
import PointsSystem from "./pages/PointsSystem";
import Footer from "./components/Footer/Footer";
import Leaderboard from "./pages/LeaderBoard";

function App() {
return (
Expand All @@ -13,6 +14,7 @@ function App() {
<Route path="/" element={<Home />} />
<Route path="/mentorship" element={<Mentorship />} />
<Route path="/distinguishedMembers" element={<PointsSystem />} />
<Route path="/leaderboard" element={<Leaderboard />} />
</Routes>
<Footer />
</Router>
Expand Down
21 changes: 17 additions & 4 deletions src/components/Navigation/DesktopNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,39 @@ const navLinks = [
id_href: "https://asu.campuslabs.com/engage/organization/soda/events",
cssClass: "nav-text-animation",
},
{
{
name: "HackSoDA24",
id_href: "https://hack.thesoda.io",
cssClass: "nav-text-animation",
}
];

export default function DesktopNav() {

const handleNavigation = (href) => {
if (href.startsWith("#")) {
// Redirect to root and append the hash section
window.location.href = `/${href}`;
} else {
// For external links, open them in a new tab
window.open(href, "_blank");
}
};

return (
<section className="nav-container">
<a href="/" className="flex gap-4 items-center">
<img src="logo/Soda_Logo_Dark_Mode.svg" className="w-28 aspect-square" />
</a>
<ul className="flex gap-14 items-center text-soda-white font-bold">
{navLinks.map((el) => (
<li>
<li key={el.name}>
<a
href={el.id_href}
onClick={(e) => {
e.preventDefault();
handleNavigation(el.id_href);
}}
className={`${el.cssClass}`}
target={el.id_href.startsWith("https://") ? "_blank" : "_self"}
>
{el.name}
</a>
Expand Down
56 changes: 50 additions & 6 deletions src/components/Navigation/Mobile/OpenedMobileNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ type setIsOpenTypes = {
};

export default function OpenedMobileNav({ setIsOpen }: setIsOpenTypes) {

const handleNavigation = (href) => {
if (href.startsWith("#")) {
window.location.href = `/${href}`;
} else {
window.open(href, "_blank");
}
setIsOpen(false);
};

return (
<section
className="fixed inset-0 bg-opacity-50"
Expand All @@ -21,22 +31,56 @@ export default function OpenedMobileNav({ setIsOpen }: setIsOpenTypes) {
</div>
<hr className="w-full mx-auto bg-soda-gray"></hr>
<div className="flex flex-col gap-5 p-5">
<a href="#hero" onClick={() => setIsOpen(false)}>
<a
href="#hero"
onClick={(e) => {
e.preventDefault();
handleNavigation("#hero");
}}
>
<h1 className="text-[20px]">Home</h1>
</a>
<a href="#info" onClick={() => setIsOpen(false)}>
<a
href="#info"
onClick={(e) => {
e.preventDefault();
handleNavigation("#info");
}}
>
<h1 className="text-[20px]">Info</h1>
</a>
<a href="#sponsors" onClick={() => setIsOpen(false)}>
<a
href="#sponsors"
onClick={(e) => {
e.preventDefault();
handleNavigation("#sponsors");
}}
>
<h1 className="text-[20px]">Sponsors</h1>
</a>
<a href="#team" onClick={() => setIsOpen(false)}>
<a
href="#team"
onClick={(e) => {
e.preventDefault();
handleNavigation("#team");
}}
>
<h1 className="text-[20px]">Team</h1>
</a>
<a href="https://asu.campuslabs.com/engage/organization/soda/events" target="_blank" onClick={() => setIsOpen(false)}>
<a
href="https://asu.campuslabs.com/engage/organization/soda/events"
target="_blank"
onClick={() => setIsOpen(false)}
>
<h1 className="text-[20px]">Events</h1>
</a>
<a href="https://hack.thesoda.io" onClick={() => setIsOpen(false)}>
<a
href="https://hack.thesoda.io"
onClick={(e) => {
e.preventDefault();
handleNavigation("https://hack.thesoda.io");
}}
>
<h1 className="text-[20px]">HackSoDA24</h1>
</a>
</div>
Expand Down
138 changes: 138 additions & 0 deletions src/pages/LeaderBoard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import React, { useEffect, useState } from 'react';

interface PointsDetails {
awarded_by: string;
event: string;
points: number;
timestamp: string;
}

interface LeaderboardEntry {
name: string;
points_details: PointsDetails[];
total_points: number;
}

const Leaderboard: React.FC = () => {
const [leaderboardData, setLeaderboardData] = useState<LeaderboardEntry[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(10);
const [searchTerm, setSearchTerm] = useState('');

useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('https://api.thesoda.io/leaderboard');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data: LeaderboardEntry[] = await response.json();
setLeaderboardData(data);
} catch (error) {
setError(error.message);
} finally {
setLoading(false);
}
};

fetchData();
}, []);

const filteredData = leaderboardData.filter((entry) =>
entry.name.toLowerCase().includes(searchTerm.toLowerCase())
);

const totalPages = Math.ceil(filteredData.length / itemsPerPage);
const startIndex = (currentPage - 1) * itemsPerPage;
const currentItems = filteredData.slice(startIndex, startIndex + itemsPerPage);

const handlePrevious = () => setCurrentPage((prev) => Math.max(prev - 1, 1));
const handleNext = () => setCurrentPage((prev) => Math.min(prev + 1, totalPages));
const handleItemsPerPageChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setItemsPerPage(Number(e.target.value));
setCurrentPage(1); // Reset to first page on items per page change
};

const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchTerm(e.target.value);
setCurrentPage(1); // Reset to first page on new search
};

if (loading) return <div className="flex justify-center items-center h-screen text-lg">Loading...</div>;
if (error) return <div className="flex justify-center items-center h-screen text-lg text-red-500">Error: {error}</div>;

return (
<div className="flex flex-col items-center mt-10">
<h1 className="text-3xl font-bold mb-6">Leaderboard</h1>

{/* Search and Items Per Page Selector */}
<div className="flex items-center space-x-4 mb-4">
<input
type="text"
placeholder="Search by name..."
value={searchTerm}
onChange={handleSearchChange}
className="border border-gray-300 p-2 rounded w-64"
/>
<div className="flex items-center">
<label htmlFor="itemsPerPage" className="mr-2 font-medium">Show:</label>
<select
id="itemsPerPage"
value={itemsPerPage}
onChange={handleItemsPerPageChange}
className="border border-gray-300 p-2 rounded"
>
<option value={10}>10</option>
<option value={15}>15</option>
<option value={20}>20</option>
<option value={filteredData.length}>All</option>
</select>
<span className="ml-2">entries per page</span>
</div>
</div>

{/* Leaderboard Table */}
<table className="table-auto border-collapse border border-gray-300 w-2/4 text-center">
<thead>
<tr className="bg-gray-200 ">
<th className="border border-gray-300 py-2 px-4 text-lg font-semibold text-center">Name</th>
<th className="border border-gray-300 py-2 px-4 text-lg font-semibold text-center">Points Earned</th>
</tr>
</thead>
<tbody>
{currentItems.map((entry, index) => (
<tr key={index} className="hover:bg-gray-100 hover:text-black">
<td className="border border-gray-300 py-2 px-4 text-center">{entry.name}</td>
<td className="border border-gray-300 py-2 px-4 text-center">{entry.total_points}</td>
</tr>
))}
</tbody>
</table>

{/* Pagination Controls */}
<div className="flex justify-between items-center w-3/4 mt-4">
<button
onClick={handlePrevious}
disabled={currentPage === 1}
className="px-4 py-2 rounded disabled:opacity-50 bg-[rgb(202_35_82_/_var(--tw-bg-opacity))] text-white"
>
Previous
</button>
<span className="text-lg">
Page {currentPage} of {totalPages}
</span>
<button
onClick={handleNext}
disabled={currentPage === totalPages}
className="px-4 py-2 rounded disabled:opacity-50 bg-[rgb(202_35_82_/_var(--tw-bg-opacity))] text-white"
>
Next
</button>
</div>
</div>
);
};

export default Leaderboard;

0 comments on commit 47d798f

Please sign in to comment.