Skip to content

Commit da43f2a

Browse files
committed
separating storage of problems
1 parent 0b68447 commit da43f2a

File tree

4 files changed

+100
-60
lines changed

4 files changed

+100
-60
lines changed

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,27 @@ A modern, interactive web application to track your progress through the famous
99
## ✨ Features
1010

1111
### 📊 Progress Tracking
12+
1213
- **Complete Problem Tracking**: Mark problems as solved with automatic date tracking
1314
- **Visual Progress Stats**: See your progress across Easy, Medium, and Hard difficulties
1415
- **Category Filtering**: Filter by problem categories (Arrays & Hashing, Two Pointers, etc.)
1516
- **Difficulty Filtering**: Filter by Easy, Medium, or Hard problems
1617

1718
### 🔄 Spaced Repetition System
19+
1820
- **Scientifically-Based Intervals**: Review problems at optimal intervals (1, 3, 7, 14, 30 days)
1921
- **Smart Review Scheduling**: Automatic calculation of review due dates
2022
- **Due Today Filter**: Quickly see which problems need review today
2123
- **Visual Review Status**: Color-coded review buttons showing completion status
2224

2325
### 💾 Data Persistence
26+
2427
- **Local Storage**: All progress automatically saved to browser's local storage
2528
- **Export/Import**: Backup your progress with JSON export/import functionality
2629
- **Cross-Session Persistence**: Progress survives browser restarts and refreshes
2730

2831
### 🎨 Modern UI/UX
32+
2933
- **Responsive Design**: Works perfectly on desktop, tablet, and mobile devices
3034
- **Clean Interface**: Modern, distraction-free design using Tailwind CSS
3135
- **Interactive Elements**: Hover effects, color-coded status indicators
@@ -38,22 +42,27 @@ A modern, interactive web application to track your progress through the famous
3842
## 🛠️ Installation
3943

4044
### Prerequisites
45+
4146
- Node.js
4247
- npm or yarn
4348

4449
### Setup
50+
4551
1. **Clone the repository**
52+
4653
```bash
4754
git clone https://github.com/javydevx/leetcode-tracker.git
4855
cd leetcode-tracker
4956
```
5057

5158
2. **Install dependencies**
59+
5260
```bash
5361
npm install
5462
```
5563

5664
3. **Start development server**
65+
5766
```bash
5867
npm run dev
5968
```
@@ -72,25 +81,29 @@ The built files will be in the `dist/` directory, ready for deployment.
7281
## 🎯 How to Use
7382

7483
### Getting Started
84+
7585
1. **Mark Problems as Solved**: Click the circle icon next to any problem when you complete it
7686
2. **Review Schedule Appears**: Once solved, you'll see 5 review buttons (R1-R5) with due dates
7787
3. **Complete Reviews**: Click review buttons when you successfully review the problem
7888
4. **Track Progress**: Use filters and stats to monitor your overall progress
7989

8090
### Spaced Repetition Schedule
91+
8192
- **R1**: Review after 1 day
8293
- **R2**: Review after 3 days
8394
- **R3**: Review after 7 days (1 week)
8495
- **R4**: Review after 14 days (2 weeks)
8596
- **R5**: Review after 30 days (1 month)
8697

8798
### Color Coding
99+
88100
- 🟢 **Green**: Review completed
89101
- 🟡 **Yellow**: Due today
90102
- 🔴 **Red**: Overdue
91103
-**Gray**: Future review
92104

93105
### Data Management
106+
94107
- **Export**: Download your progress as a JSON file for backup
95108
- **Import**: Restore progress from a previously exported file
96109
- **Clear All**: Reset all progress (with confirmation dialog)
@@ -114,7 +127,7 @@ The built files will be in the `dist/` directory, ready for deployment.
114127

115128
## 📋 Roadmap
116129

117-
- [ ] Dark mode support
130+
- [x] Dark mode support
118131
- [ ] Custom problem sets
119132
- [ ] Study streaks tracking
120133
- [ ] Performance analytics

src/components/ProblemTable.jsx

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -118,31 +118,38 @@ const ProblemTable = ({
118118
>
119119
{problem.difficulty}
120120
</td>
121-
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100 flex gap-2 flex-wrap">
122-
{problem.companies?.map((company, idx) => (
123-
<div
124-
key={idx}
125-
className="flex items-center gap-1 relative group"
126-
>
127-
{company.logo ? (
128-
<img
129-
src={company.logo}
130-
alt={company.name}
131-
className="h-5 w-5 object-contain cursor-pointer"
132-
title={company.name}
133-
/>
134-
) : (
135-
<div className="h-5 w-5 bg-gray-300 dark:bg-gray-700 rounded flex items-center justify-center text-xs font-semibold text-gray-800 dark:text-gray-100 cursor-pointer group-hover:block relative">
136-
{company.name[0]}
137-
<span className="absolute bottom-full mb-1 hidden group-hover:block bg-gray-700 text-white text-xs px-2 py-1 rounded whitespace-nowrap">
138-
{company.name}
139-
</span>
121+
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
122+
<div className="flex items-center gap-2 flex-wrap h-full">
123+
{problem.companies && problem.companies.length > 0 ? (
124+
problem.companies.map((company, idx) => (
125+
<div
126+
key={idx}
127+
className="flex items-center gap-1 relative group"
128+
>
129+
{company.logo ? (
130+
<img
131+
src={company.logo}
132+
alt={company.name}
133+
className="h-5 w-5 object-contain cursor-pointer"
134+
title={company.name}
135+
/>
136+
) : (
137+
<div className="h-5 w-5 bg-gray-300 dark:bg-gray-700 rounded flex items-center justify-center text-xs font-semibold text-gray-800 dark:text-gray-100 cursor-pointer group-hover:block relative">
138+
{company.name[0]}
139+
<span className="absolute bottom-full mb-1 hidden group-hover:block bg-gray-700 text-white text-xs px-2 py-1 rounded whitespace-nowrap">
140+
{company.name}
141+
</span>
142+
</div>
143+
)}
140144
</div>
141-
)}
142-
</div>
143-
))}
145+
))
146+
) : (
147+
<span className="text-sm text-red-500 dark:text-red-400">
148+
No companies data yet
149+
</span>
150+
)}
151+
</div>
144152
</td>
145-
146153
<td className="px-6 py-4 whitespace-nowrap">
147154
<button
148155
onClick={() => toggleComplete(problem.id)}

src/data/blind75.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
[
22
{
33
"id": 1,
4-
"name": "Contains Duplicate",
4+
"name": "Longest Consecutive Sequence",
55
"category": "Arrays & Hashing",
66
"difficulty": "Easy",
77
"day": 1,
8-
"url": "https://neetcode.io/problems/duplicate-integer"
8+
"url": "https://leetcode.com/problems/longest-consecutive-sequence/description/?envType=problem-list-v2&envId=oizxjoit"
99
}
1010
]

src/pages/NeetCodeTracker.jsx

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,25 @@ const intervals = [1, 3, 7, 14, 30];
2727

2828
const NeetCodeTracker = () => {
2929
// --- Local state with localStorage ---
30-
const [progress, setProgress] = useState(() => {
31-
try {
32-
const savedProgress = localStorage.getItem("leetcode-progress");
33-
return savedProgress ? JSON.parse(savedProgress) : {};
34-
} catch (error) {
35-
console.error("Error loading progress from localStorage:", error);
36-
return {};
37-
}
38-
});
30+
const [progress, setProgress] = useState(() => {
31+
try {
32+
const savedProgress = localStorage.getItem("leetcode-progress-v2");
33+
return savedProgress
34+
? JSON.parse(savedProgress)
35+
: {
36+
"Blind 75": {},
37+
"LeetCode 75": {},
38+
"NeetCode 150": {},
39+
};
40+
} catch (error) {
41+
console.error("Error loading progress from localStorage:", error);
42+
return {
43+
"Blind 75": {},
44+
"LeetCode 75": {},
45+
"NeetCode 150": {},
46+
};
47+
}
48+
});
3949

4050
const [filterCategory, setFilterCategory] = useState("All");
4151
const [filterDifficulty, setFilterDifficulty] = useState("All");
@@ -44,15 +54,16 @@ const NeetCodeTracker = () => {
4454
const [selectedList, setSelectedList] = useState("NeetCode 150");
4555

4656

47-
// Save progress to localStorage whenever it changes
57+
// Save progress to localStorage whenever it changes
4858
useEffect(() => {
4959
try {
50-
localStorage.setItem("leetcode-progress", JSON.stringify(progress));
60+
localStorage.setItem("leetcode-progress-v2", JSON.stringify(progress));
5161
} catch (error) {
5262
console.error("Error saving progress to localStorage:", error);
5363
}
5464
}, [progress]);
5565

66+
5667
// --- Helpers ---
5768
const today = new Date().toISOString().split("T")[0];
5869

@@ -70,7 +81,8 @@ const NeetCodeTracker = () => {
7081
const toggleComplete = (problemId, reviewIndex = null) => {
7182
const todayStr = new Date().toISOString().split("T")[0];
7283
setProgress((prev) => {
73-
const current = prev[problemId] || {
84+
const listProgress = prev[selectedList] || {};
85+
const current = listProgress[problemId] || {
7486
solved: false,
7587
reviews: Array(5).fill(false),
7688
dates: {},
@@ -80,12 +92,15 @@ const NeetCodeTracker = () => {
8092
const newSolved = !current.solved;
8193
return {
8294
...prev,
83-
[problemId]: {
84-
...current,
85-
solved: newSolved,
86-
solvedDate: newSolved ? todayStr : null,
87-
reviews: newSolved ? current.reviews : Array(5).fill(false),
88-
dates: newSolved ? { ...current.dates, initial: todayStr } : {},
95+
[selectedList]: {
96+
...listProgress,
97+
[problemId]: {
98+
...current,
99+
solved: newSolved,
100+
solvedDate: newSolved ? todayStr : null,
101+
reviews: newSolved ? current.reviews : Array(5).fill(false),
102+
dates: newSolved ? { ...current.dates, initial: todayStr } : {},
103+
},
89104
},
90105
};
91106
} else {
@@ -99,36 +114,41 @@ const NeetCodeTracker = () => {
99114
}
100115
return {
101116
...prev,
102-
[problemId]: { ...current, reviews: newReviews, dates: newDates },
117+
[selectedList]: {
118+
...listProgress,
119+
[problemId]: { ...current, reviews: newReviews, dates: newDates },
120+
},
103121
};
104122
}
105123
});
106124
};
107125

108126
const problems = problemLists[selectedList];
127+
const currentProgress = progress[selectedList] || {};
128+
109129
const categories = [
110130
"All",
111131
...Array.from(new Set(problems.map((p) => p.category))),
112132
];
113133
const difficulties = ["All", "Easy", "Medium", "Hard"];
114134

115-
const stats = {
116-
total: problems.length,
117-
solved: Object.values(progress).filter((p) => p.solved).length,
118-
easy: problems.filter(
119-
(p) => p.difficulty === "Easy" && progress[p.id]?.solved
120-
).length,
121-
medium: problems.filter(
122-
(p) => p.difficulty === "Medium" && progress[p.id]?.solved
123-
).length,
124-
hard: problems.filter(
125-
(p) => p.difficulty === "Hard" && progress[p.id]?.solved
126-
).length,
127-
};
135+
const stats = {
136+
total: problems.length,
137+
solved: problems.filter((p) => currentProgress[p.id]?.solved).length,
138+
easy: problems.filter(
139+
(p) => p.difficulty === "Easy" && currentProgress[p.id]?.solved
140+
).length,
141+
medium: problems.filter(
142+
(p) => p.difficulty === "Medium" && currentProgress[p.id]?.solved
143+
).length,
144+
hard: problems.filter(
145+
(p) => p.difficulty === "Hard" && currentProgress[p.id]?.solved
146+
).length,
147+
};
128148

129149
const getDueProblems = () => {
130150
return problems.filter((problem) => {
131-
const prob = progress[problem.id];
151+
const prob = currentProgress[problem.id];
132152
if (!prob || !prob.solved) return false;
133153
const nextReviews = calculateNextReviews(prob.solvedDate);
134154
return nextReviews.some(
@@ -282,7 +302,7 @@ const NeetCodeTracker = () => {
282302
{/* Problems Table */}
283303
<ProblemTable
284304
problems={problems}
285-
progress={progress}
305+
progress={currentProgress}
286306
toggleComplete={toggleComplete}
287307
calculateNextReviews={calculateNextReviews}
288308
filterCategory={filterCategory}

0 commit comments

Comments
 (0)