Skip to content

Commit

Permalink
Added Modals and made the page responsive
Browse files Browse the repository at this point in the history
  • Loading branch information
code-wolf-byte committed Nov 8, 2024
1 parent 4d0f561 commit f7553f2
Showing 1 changed file with 99 additions and 28 deletions.
127 changes: 99 additions & 28 deletions src/pages/LeaderBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,55 @@ interface LeaderboardEntry {
total_points: number;
}

const Modal: React.FC<{ isOpen: boolean; onClose: () => void; data: PointsDetails[]; name: string }> = ({ isOpen, onClose, data, name }) => {
if (!isOpen) return null;

return (
<div className="fixed inset-0 bg-black bg-opacity-75 flex justify-center items-center z-50">
<div className="bg-gray-900 p-6 rounded-lg max-w-2xl w-full max-h-[80vh] overflow-y-auto text-white">
<h2 className="text-2xl font-bold mb-4">Points Breakdown for {name}</h2>
<div className="overflow-x-auto">
<table className="w-full">
<thead>
<tr className="bg-gray-800">
<th className="p-2 text-left">Event</th>
<th className="p-2 text-left">Points</th>
<th className="p-2 text-left">Awarded By</th>
<th className="p-2 text-left">Date</th>
</tr>
</thead>
<tbody>
{data.map((detail, index) => (
<tr key={index} className="border-b border-gray-700">
<td className="p-2">{detail.event}</td>
<td className="p-2">{detail.points}</td>
<td className="p-2">{detail.awarded_by}</td>
<td className="p-2">{new Date(detail.timestamp).toLocaleDateString()}</td>
</tr>
))}
</tbody>
</table>
</div>
<button
onClick={onClose}
className="mt-4 px-4 py-2 bg-[rgb(202_35_82_/_var(--tw-bg-opacity))] text-white rounded hover:bg-opacity-80"
>
Close
</button>
</div>
</div>
);
};

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

useEffect(() => {
const fetchData = async () => {
Expand Down Expand Up @@ -52,31 +94,41 @@ const Leaderboard: React.FC = () => {
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
setCurrentPage(1);
};

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

const openModal = (entry: LeaderboardEntry) => {
setSelectedEntry(entry);
setModalOpen(true);
};

const closeModal = () => {
setModalOpen(false);
setSelectedEntry(null);
};

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 max-w-5xl mx-auto p-6 my-36 shadow-md rounded-lg">
<h1 className="text-3xl font-bold mb-6 ">Leaderboard</h1>
<div className="flex flex-col items-center w-full max-w-5xl mx-auto p-4 sm:p-6 my-8 sm:my-16 md:my-24 lg:my-36 shadow-md rounded-lg">
<h1 className="text-2xl sm:text-3xl font-bold mb-4 sm:mb-6">Leaderboard</h1>

{/* Search and Items Per Page Selector */}
<div className="flex items-center space-x-4 mb-4">
<div className="flex flex-col sm:flex-row items-center space-y-4 sm:space-y-0 sm:space-x-4 mb-4 w-full">
<input
type="text"
placeholder="Search by name..."
value={searchTerm}
onChange={handleSearchChange}
className="border border-gray-300 p-2 rounded w-64"
className="border border-gray-300 p-2 rounded w-full sm:w-64"
/>
<div className="flex items-center">
<div className="flex items-center w-full sm:w-auto">
<label htmlFor="itemsPerPage" className="mr-2 font-medium">Show:</label>
<select
id="itemsPerPage"
Expand All @@ -89,50 +141,69 @@ const Leaderboard: React.FC = () => {
<option value={20}>20</option>
<option value={filteredData.length}>All</option>
</select>
<span className="ml-2">entries per page</span>
<span className="ml-2">entries</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>
<div className="w-full overflow-x-auto">
<table className="table-auto border-collapse border border-gray-300 w-full text-center">
<thead>
<tr className="bg-gray-200">
<th className="border border-gray-300 py-2 px-4 text-base sm:text-lg font-semibold text-center">Name</th>
<th className="border border-gray-300 py-2 px-4 text-base sm:text-lg font-semibold text-center">Points Earned</th>
<th className="border border-gray-300 py-2 px-4 text-base sm:text-lg font-semibold text-center">Actions</th>
</tr>
))}
</tbody>
</table>
</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>
<td className="border border-gray-300 py-2 px-4 text-center">
<button
onClick={() => openModal(entry)}
className="px-3 py-1 bg-[rgb(202_35_82_/_var(--tw-bg-opacity))] text-white rounded hover:bg-opacity-80"
>
View Details
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>

{/* Pagination Controls */}
<div className="flex justify-between items-center w-3/4 mt-4">
<div className="flex flex-col sm:flex-row justify-between items-center w-full mt-4 space-y-4 sm:space-y-0">
<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"
className="px-4 py-2 rounded disabled:opacity-50 bg-[rgb(202_35_82_/_var(--tw-bg-opacity))] text-white w-full sm:w-auto"
>
Previous
</button>
<span className="text-lg">
<span className="text-base sm: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"
className="px-4 py-2 rounded disabled:opacity-50 bg-[rgb(202_35_82_/_var(--tw-bg-opacity))] text-white w-full sm:w-auto"
>
Next
</button>
</div>

{/* Modal */}
<Modal
isOpen={modalOpen}
onClose={closeModal}
data={selectedEntry?.points_details || []}
name={selectedEntry?.name || ''}
/>
</div>
);
};

export default Leaderboard;
export default Leaderboard;

0 comments on commit f7553f2

Please sign in to comment.