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
116 changes: 0 additions & 116 deletions src/client/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,119 +36,3 @@
transform: rotate(360deg);
}
}

/* LeetCode-like styling for ProblemPage */
.lcw-problem-page {
max-width: 800px;
margin: 32px auto;
background: #fff;
border-radius: 12px;
box-shadow: 0 2px 16px rgba(0,0,0,0.08);
padding: 32px;
font-family: 'Segoe UI', 'Roboto', 'Arial', sans-serif;
}

.lcw-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 18px;
}

.lcw-link {
color: #ffa116;
text-decoration: none;
font-weight: 500;
border-bottom: 1px dashed #ffa116;
transition: border-bottom 0.2s;
}
.lcw-link:hover {
border-bottom: 2px solid #ffa116;
}

.lcw-meta {
display: flex;
gap: 18px;
margin-bottom: 24px;
font-size: 16px;
}

.lcw-meta-item {
color: #555;
}

.lcw-difficulty {
padding: 4px 12px;
border-radius: 8px;
font-weight: bold;
color: #fff;
}
.lcw-difficulty-easy {
background: #43a047;
}
.lcw-difficulty-medium {
background: #ffa116;
}
.lcw-difficulty-hard {
background: #d32f2f;
}
.lcw-difficulty-unknown {
background: #888;
}

.lcw-section-title {
margin-top: 32px;
margin-bottom: 12px;
font-size: 20px;
color: #222;
font-weight: 600;
}

.lcw-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 24px;
background: #fafbfc;
border-radius: 8px;
overflow: hidden;
}

.lcw-table th, .lcw-table td {
padding: 12px 10px;
border-bottom: 1px solid #eee;
text-align: left;
}

.lcw-table th {
background: #f6f8fa;
font-weight: 600;
color: #333;
}

.lcw-tag {
display: inline-block;
background: #e3e6ea;
color: #444;
padding: 4px 10px;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
}

.lcw-company {
display: inline-block;
background: #f5f5f5;
color: #222;
margin: 2px 6px 2px 0;
padding: 4px 10px;
border-radius: 6px;
font-size: 14px;
border: 1px solid #eee;
}

.lcw-loading, .lcw-error {
text-align: center;
margin-top: 40px;
font-size: 18px;
color: #d32f2f;
}
4 changes: 4 additions & 0 deletions src/client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ import "./App.css";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Main from "./components/layout/Main";
import ProblemPage from "./components/problems/ProblemPage";
import Header from "./components/layout/Header";
import Footer from "./components/layout/Footer";

function App() {
return (
<div className="App">
<Router>
<Header />
<Routes>
<Route path="/" element={<Main />} />
<Route path="/problems/:id" element={<ProblemPage />} />
</Routes>
<Footer />
</Router>
</div>
);
Expand Down
18 changes: 16 additions & 2 deletions src/client/src/components/layout/Body.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import React from "react";
import ProblemGrid from "../problems/ProblemGrid";
import Pagination from "./Pagination"; // Add this import
import "../../styles/layout/Body.css";

const Body = ({ problems, loading, error, filters }) => {
const Body = ({
problems,
loading,
error,
filters,
currentPage,
totalPages,
onPageChange
}) => {
if (loading) {
return (
<div className="body loading">
Expand All @@ -26,9 +35,14 @@ const Body = ({ problems, loading, error, filters }) => {
<main className="body">
<div className="body-content">
<ProblemGrid problems={problems} filters={filters} />
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={onPageChange}
/>
</div>
</main>
);
};

export default Body;
export default Body;
5 changes: 4 additions & 1 deletion src/client/src/components/layout/Header.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import React from "react";
import "../../styles/layout/Header.css";
import { Link } from "react-router-dom";

const Header = () => {
return (
<header className="header">
<div className="header-content">
<h1>LeetCode Problem Tracker</h1>
<Link to="/" className="header-link">
<h1>LeetCode Problem Tracker</h1>
</Link>
</div>
</header>
);
Expand Down
31 changes: 24 additions & 7 deletions src/client/src/components/layout/Main.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import React, { useState, useEffect, useMemo } from "react";
import { fetchProblems } from "../../services/api";
import Header from "./Header";
import Nav from "./Nav";
import Body from "./Body";
import Footer from "./Footer";
import "../../styles/layout/Main.css";

const Main = () => {
Expand All @@ -15,14 +13,25 @@ const Main = () => {
timePeriod: "",
difficulty: "",
});
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);

const PROBLEMS_PER_PAGE = 50;

useEffect(() => {
const loadProblems = async () => {
setLoading(true);
try {
const data = await fetchProblems();
const data = await fetchProblems(currentPage, PROBLEMS_PER_PAGE, filters);
setProblems(data);
setError(null);

// Estimate total pages based on response
if (data.length < PROBLEMS_PER_PAGE) {
setTotalPages(currentPage);
} else {
setTotalPages(currentPage + 1);
}
} catch (err) {
setError("Failed to fetch problems. Please try again later.");
setProblems([]);
Expand All @@ -32,7 +41,7 @@ const Main = () => {
};

loadProblems();
}, []);
}, [currentPage, filters]);

// Extract unique company names from problems
const companies = useMemo(() => {
Expand All @@ -49,11 +58,17 @@ const Main = () => {

const handleFilterChange = (newFilters) => {
setFilters(newFilters);
setCurrentPage(1); // Reset to first page when filters change
};

const handlePageChange = (page) => {
setCurrentPage(page);
// Scroll to top when page changes
window.scrollTo({ top: 0, behavior: 'smooth' });
};

return (
<div className="main-container">
<Header />
<Nav
filters={filters}
onFilterChange={handleFilterChange}
Expand All @@ -64,10 +79,12 @@ const Main = () => {
loading={loading}
error={error}
filters={filters}
currentPage={currentPage}
totalPages={totalPages}
onPageChange={handlePageChange}
/>
<Footer />
</div>
);
};

export default Main;
export default Main;
75 changes: 75 additions & 0 deletions src/client/src/components/layout/Pagination.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// components/Pagination.js
import React from "react";
import "../../styles/layout/Pagination.css";

const Pagination = ({ currentPage, totalPages, onPageChange }) => {
const getPageNumbers = () => {
const pages = [];
const maxVisiblePages = 5;

let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2));
let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);

// Adjust start page if we're near the end
if (endPage - startPage + 1 < maxVisiblePages) {
startPage = Math.max(1, endPage - maxVisiblePages + 1);
}

for (let i = startPage; i <= endPage; i++) {
pages.push(i);
}

return pages;
};

if (totalPages <= 1) return null;

return (
<div className="pagination">
{/* First Page Button */}
<button
className="pagination-btn pagination-first"
disabled={currentPage === 1}
onClick={() => onPageChange(1)}
title="First Page"
>
&laquo;
</button>

{/* Previous Page Button */}
<button
className="pagination-btn pagination-prev"
disabled={currentPage === 1}
onClick={() => onPageChange(currentPage - 1)}
title="Previous Page"
>
&lsaquo;
</button>

{/* Page Numbers */}
<div className="pagination-pages">
{getPageNumbers().map(page => (
<button
key={page}
className={`pagination-btn ${currentPage === page ? 'active' : ''}`}
onClick={() => onPageChange(page)}
>
{page}
</button>
))}
</div>

{/* Next Page Button */}
<button
className="pagination-btn pagination-next"
disabled={currentPage === totalPages}
onClick={() => onPageChange(currentPage + 1)}
title="Next Page"
>
&rsaquo;
</button>
</div>
);
};

export default Pagination;
5 changes: 2 additions & 3 deletions src/client/src/components/problems/ProblemCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
getDifficultyClass,
} from "../../constants/difficulty";
import "../../styles/components/ProblemCard.css";
import { Link } from "react-router-dom";

const TIME_PERIOD_LABELS = {
"thirty-days": "Last 30 Days",
Expand Down Expand Up @@ -43,9 +44,7 @@ const ProblemCard = ({ problem }) => {
<div className="problem-card">
<div className="problem-header">
<h3>
<a href={problem.url} target="_blank" rel="noopener noreferrer">
{problem.title}
</a>
<Link to={`/problems/${problem.id}`}>{problem.title}</Link>
</h3>
<span className={`difficulty ${difficultyClass}`}>
{difficultyText}
Expand Down
1 change: 1 addition & 0 deletions src/client/src/components/problems/ProblemPage.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { getProblemById } from "../../services/api";
import "../../styles/components/ProblemPage.css";

const tagOrder = ["thirty-days", "three-months", "six-months", "one-year", "all"];

Expand Down
Loading