Skip to content

Commit 8063f23

Browse files
committed
🐛 fix: reset scroll position to top on route change and fix lint issues
1 parent 6c6bc3e commit 8063f23

7 files changed

Lines changed: 1772 additions & 33 deletions

File tree

bun.lock

Lines changed: 1656 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Footer from "./components/Footer";
44
import ScrollProgressBar from "./components/ScrollProgressBar";
55
import { Toaster } from "react-hot-toast";
66
import Router from "./Routes/Router";
7+
import ScrollToTop from "./components/ScrollToTop";
78

89
const FULLSCREEN_ROUTES = ["/signup", "/login"];
910

@@ -13,6 +14,8 @@ function App() {
1314

1415
return (
1516
<div className="relative flex flex-col min-h-screen">
17+
<ScrollToTop />
18+
1619
{!isFullscreen && <ScrollProgressBar />}
1720

1821
{!isFullscreen && <Navbar />}

src/components/Navbar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { NavLink, Link } from "react-router-dom";
22
import { useState, useContext } from "react";
33
import { ThemeContext } from "../context/ThemeContext";
4-
import { Moon, Sun, Menu, X, Github } from "lucide-react";
4+
import { Moon, Sun, Menu, X} from "lucide-react";
55

66
const Navbar: React.FC = () => {
77
const [isOpen, setIsOpen] = useState(false);

src/components/ScrollToTop.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { useEffect } from "react";
2+
import { useLocation } from "react-router-dom";
3+
4+
const ScrollToTop = () => {
5+
const location = useLocation();
6+
7+
useEffect(() => {
8+
window.scrollTo(0, 0);
9+
}, [location]);
10+
11+
return null;
12+
};
13+
14+
export default ScrollToTop;

src/components/__test__/Navbar.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// src/components/__tests__/Navbar.test.tsx
22
import { render, screen, fireEvent } from '@testing-library/react'
3-
import { describe, it, expect, vi, beforeEach } from 'vitest'
3+
import { describe, it, expect, vi} from 'vitest'
44
import { MemoryRouter } from 'react-router-dom'
55
import { ThemeContext } from "../../context/ThemeContext";
66
import Navbar from '../Navbar.tsx'

src/hooks/useGitHubData.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export const useGitHubData = (
112112
const shouldFetchPrs =
113113
activeTab === 'pr' || activeTab === 'both';
114114

115-
const requests: Promise<any>[] = [];
115+
const requests: Promise<unknown>[] = [];
116116

117117
if (shouldFetchIssues) {
118118
requests.push(

src/pages/Signup/Signup.tsx

Lines changed: 96 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,11 @@ const SignUp: React.FC = () => {
5353
if (name === "password") {
5454
if (!value.trim()) {
5555
errorMessage = "Password is required";
56-
} else if (!/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*#?&]{8,}$/.test(value)) {
57-
errorMessage = "Password must be 8+ characters with letters and numbers";
56+
} else if (
57+
!/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*#?&]{8,}$/.test(value)
58+
) {
59+
errorMessage =
60+
"Password must be 8+ characters with letters and numbers";
5861
}
5962
}
6063
setErrors((prev) => ({ ...prev, [name]: errorMessage }));
@@ -65,35 +68,49 @@ const SignUp: React.FC = () => {
6568
const usernameError = !formData.username.trim()
6669
? "Username is required"
6770
: !/^[A-Za-z\s]+$/.test(formData.username)
68-
? "Only letters are allowed"
69-
: "";
71+
? "Only letters are allowed"
72+
: "";
7073
const emailError = !formData.email.trim()
7174
? "Email is required"
7275
: !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email.trim())
73-
? "Enter a valid email"
74-
: "";
76+
? "Enter a valid email"
77+
: "";
7578
const passwordError = !formData.password.trim()
7679
? "Password is required"
77-
: !/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*#?&]{8,}$/.test(formData.password)
78-
? "Password must be 8+ characters with letters and numbers"
79-
: "";
80+
: !/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*#?&]{8,}$/.test(
81+
formData.password,
82+
)
83+
? "Password must be 8+ characters with letters and numbers"
84+
: "";
8085
if (usernameError || emailError || passwordError) {
81-
setErrors({ username: usernameError, email: emailError, password: passwordError });
86+
setErrors({
87+
username: usernameError,
88+
email: emailError,
89+
password: passwordError,
90+
});
8291
return;
8392
}
8493
setIsLoading(true);
8594
try {
86-
const response = await axios.post(`${backendUrl}/api/auth/signup`,
87-
formData // Include cookies for session
95+
const response = await axios.post(
96+
`${backendUrl}/api/auth/signup`,
97+
formData, // Include cookies for session
8898
);
8999
setMessage(response.data.message); // Show success message from backend
90100

91101
// Navigate to login page after successful signup
92-
if (response.data.message === 'User created successfully') {
102+
if (response.data.message === "User created successfully") {
93103
navigate("/login");
94104
}
95-
} catch (error: any) {
96-
setMessage(error.response?.data?.message || "Something went wrong. Please try again.");
105+
} catch (error: unknown) {
106+
if (axios.isAxiosError(error)) {
107+
setMessage(
108+
error.response?.data?.message ||
109+
"Something went wrong. Please try again.",
110+
);
111+
} else {
112+
setMessage("Something went wrong. Please try again.");
113+
}
97114
} finally {
98115
setIsLoading(false);
99116
}
@@ -138,10 +155,22 @@ const SignUp: React.FC = () => {
138155
className="text-center mb-10"
139156
>
140157
<div className="inline-flex items-center justify-center w-20 h-20 bg-white rounded-3xl mb-6 shadow-2xl transform hover:scale-105 transition-transform duration-300 overflow-hidden">
141-
<img src="/crl-icon.png" alt="Logo" className="w-14 h-14 object-contain" />
158+
<img
159+
src="/crl-icon.png"
160+
alt="Logo"
161+
className="w-14 h-14 object-contain"
162+
/>
142163
</div>
143-
<h1 className={`text-4xl font-bold mb-2 ${mode === "dark" ? "text-white" : "text-black"}`}>GitHubTracker</h1>
144-
<p className={`text-lg font-medium ${mode === "dark" ? "text-slate-300" : "text-gray-700"}`}>Join your GitHub journey</p>
164+
<h1
165+
className={`text-4xl font-bold mb-2 ${mode === "dark" ? "text-white" : "text-black"}`}
166+
>
167+
GitHubTracker
168+
</h1>
169+
<p
170+
className={`text-lg font-medium ${mode === "dark" ? "text-slate-300" : "text-gray-700"}`}
171+
>
172+
Join your GitHub journey
173+
</p>
145174
</motion.div>
146175

147176
<motion.div
@@ -154,7 +183,6 @@ const SignUp: React.FC = () => {
154183
: "bg-white border-gray-200 text-black"
155184
}`}
156185
>
157-
158186
<h2
159187
className={`text-2xl font-bold text-center mb-8 ${
160188
mode === "dark" ? "text-white" : "text-gray-800"
@@ -169,39 +197,72 @@ const SignUp: React.FC = () => {
169197
<div className="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
170198
<User className="h-5 w-5 text-gray-400" />
171199
</div>
172-
<input type="text" name="username" placeholder="Enter your username" value={formData.username} onChange={handleChange} required
200+
<input
201+
type="text"
202+
name="username"
203+
placeholder="Enter your username"
204+
value={formData.username}
205+
onChange={handleChange}
206+
required
173207
className={`w-full pl-12 pr-4 py-4 rounded-2xl border focus:outline-none focus:ring-2 focus:ring-gray-400 focus:border-transparent transition-all duration-300 ${mode === "dark" ? "bg-white/10 border-white/20 text-white placeholder-gray-400" : "bg-gray-100 border-gray-300 text-black placeholder-gray-400"}`}
174208
/>
175209
</div>
176-
{errors.username && <p className="text-red-500 text-sm mt-2">{errors.username}</p>}
210+
{errors.username && (
211+
<p className="text-red-500 text-sm mt-2">{errors.username}</p>
212+
)}
177213
</div>
178214

179215
<div>
180216
<div className="relative">
181217
<div className="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
182218
<Mail className="h-5 w-5 text-gray-400" />
183219
</div>
184-
<input type="email" name="email" placeholder="Enter your email" value={formData.email} onChange={handleChange} required
220+
<input
221+
type="email"
222+
name="email"
223+
placeholder="Enter your email"
224+
value={formData.email}
225+
onChange={handleChange}
226+
required
185227
className={`w-full pl-12 pr-4 py-4 rounded-2xl border focus:outline-none focus:ring-2 focus:ring-gray-400 focus:border-transparent transition-all duration-300 ${mode === "dark" ? "bg-white/10 border-white/20 text-white placeholder-gray-400" : "bg-gray-100 border-gray-300 text-black placeholder-gray-400"}`}
186228
/>
187229
</div>
188-
{errors.email && <p className="text-red-500 text-sm mt-2">{errors.email}</p>}
230+
{errors.email && (
231+
<p className="text-red-500 text-sm mt-2">{errors.email}</p>
232+
)}
189233
</div>
190234

191235
<div>
192236
<div className="relative">
193237
<div className="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
194238
<Lock className="h-5 w-5 text-gray-400" />
195239
</div>
196-
<input type={showPassword ? "text" : "password"} name="password" placeholder="Enter your password" value={formData.password} onChange={handleChange} required
240+
<input
241+
type={showPassword ? "text" : "password"}
242+
name="password"
243+
placeholder="Enter your password"
244+
value={formData.password}
245+
onChange={handleChange}
246+
required
197247
className={`w-full pl-12 pr-12 py-4 rounded-2xl border focus:outline-none focus:ring-2 focus:ring-gray-400 focus:border-transparent transition-all duration-300 ${mode === "dark" ? "bg-white/10 border-white/20 text-white placeholder-gray-400" : "bg-gray-100 border-gray-300 text-black placeholder-gray-400"}`}
198248
/>
199-
<button type="button" onClick={() => setShowPassword(!showPassword)} aria-label={showPassword ? "Hide password" : "Show password"} aria-pressed={showPassword}
200-
className={`absolute inset-y-0 right-0 pr-4 flex items-center transition-colors duration-200 ${mode === "dark" ? "text-slate-400 hover:text-white" : "text-gray-500 hover:text-gray-800"}`}>
201-
{showPassword ? <EyeOff className="h-5 w-5" /> : <Eye className="h-5 w-5" />}
249+
<button
250+
type="button"
251+
onClick={() => setShowPassword(!showPassword)}
252+
aria-label={showPassword ? "Hide password" : "Show password"}
253+
aria-pressed={showPassword}
254+
className={`absolute inset-y-0 right-0 pr-4 flex items-center transition-colors duration-200 ${mode === "dark" ? "text-slate-400 hover:text-white" : "text-gray-500 hover:text-gray-800"}`}
255+
>
256+
{showPassword ? (
257+
<EyeOff className="h-5 w-5" />
258+
) : (
259+
<Eye className="h-5 w-5" />
260+
)}
202261
</button>
203262
</div>
204-
{errors.password && <p className="text-red-500 text-sm mt-2">{errors.password}</p>}
263+
{errors.password && (
264+
<p className="text-red-500 text-sm mt-2">{errors.password}</p>
265+
)}
205266
</div>
206267

207268
<button
@@ -214,15 +275,20 @@ const SignUp: React.FC = () => {
214275
</form>
215276

216277
{message && (
217-
<div className={`text-center mt-6 p-3 rounded-xl ${message.includes("successfully") ? "text-green-600 bg-green-100" : "text-red-600 bg-red-100"}`}>
278+
<div
279+
className={`text-center mt-6 p-3 rounded-xl ${message.includes("successfully") ? "text-green-600 bg-green-100" : "text-red-600 bg-red-100"}`}
280+
>
218281
{message}
219282
</div>
220283
)}
221284

222285
<div className="text-center mt-8">
223286
<p className={mode === "dark" ? "text-gray-300" : "text-gray-600"}>
224287
Already have an account?{" "}
225-
<Link to="/login" className={`font-medium hover:underline transition-colors duration-300 ${mode === "dark" ? "text-white" : "text-black"}`}>
288+
<Link
289+
to="/login"
290+
className={`font-medium hover:underline transition-colors duration-300 ${mode === "dark" ? "text-white" : "text-black"}`}
291+
>
226292
Sign in here
227293
</Link>
228294
</p>

0 commit comments

Comments
 (0)