Skip to content

Commit c52b33a

Browse files
authored
Merge pull request #53 from Vaibhav0527/feature/Responsive
feat: responsive
2 parents c0ce2d2 + df6cbd4 commit c52b33a

File tree

2 files changed

+143
-86
lines changed

2 files changed

+143
-86
lines changed

frontend/src/components/Header.tsx

Lines changed: 108 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,173 @@
11
import { useState, useEffect } from "react";
22
import { Button } from "../components/ui/button.js";
33
import { useNavigate } from "react-router-dom";
4-
import { Menu, X, PlusSquare, LogIn, LogOut } from "lucide-react";
4+
import { Menu, X } from "lucide-react";
55
import axios from "axios";
66

77
function Header() {
88
const [isScrolled, setIsScrolled] = useState(false);
99
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
1010
const [user, setUser] = useState<{ _id: string; name: string } | null>(null);
11-
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
1211
const navigate = useNavigate();
1312

14-
// Scroll effect
13+
// Scroll shadow effect
1514
useEffect(() => {
16-
const handleScroll = () => setIsScrolled(window.scrollY > 20);
15+
const handleScroll = () => setIsScrolled(window.scrollY > 10);
1716
window.addEventListener("scroll", handleScroll);
1817
return () => window.removeEventListener("scroll", handleScroll);
1918
}, []);
2019

21-
// Fetch authenticated user
20+
// Fetch logged-in user
2221
useEffect(() => {
2322
const token = localStorage.getItem("token");
2423
if (!token) return;
25-
2624
const fetchUser = async () => {
2725
try {
2826
const res = await axios.get("http://localhost:3000/api/auth/me", {
2927
headers: { Authorization: `Bearer ${token}` },
3028
});
3129
setUser(res.data.user);
3230
} catch {
31+
localStorage.removeItem("token");
3332
setUser(null);
34-
localStorage.removeItem("token"); // remove invalid token
3533
}
3634
};
37-
3835
fetchUser();
3936
}, []);
4037

38+
// Scroll to section smoothly
4139
const scrollToSection = (id: string) => {
42-
const element = document.getElementById(id);
43-
if (element) {
44-
element.scrollIntoView({ behavior: "smooth" });
40+
const el = document.getElementById(id);
41+
if (el) {
42+
el.scrollIntoView({ behavior: "smooth" });
4543
setIsMobileMenuOpen(false);
4644
}
4745
};
4846

49-
// Navigate to a separate page which provides actions (join/create/logout)
5047
const handleJoinNow = () => {
51-
if (!user) {
52-
navigate("/signin");
53-
} else {
54-
navigate("/room-actions");
55-
}
48+
if (!user) navigate("/signin");
49+
else navigate("/room-actions");
5650
};
5751

5852
const handleLogout = () => {
5953
localStorage.removeItem("token");
6054
setUser(null);
61-
setIsDropdownOpen(false);
6255
navigate("/");
6356
};
6457

6558
return (
6659
<header
6760
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
68-
isScrolled ? "bg-white/80 backdrop-blur-lg shadow-lg" : "bg-transparent"
61+
isScrolled
62+
? "bg-white/70 backdrop-blur-md shadow-md"
63+
: "bg-transparent"
6964
}`}
7065
>
71-
<nav className="container mx-auto px-6 py-4">
72-
<div className="flex items-center justify-between">
73-
<a href="/" className="text-2xl font-bold text-green-600 bg-clip-text">
74-
PeerCall
75-
</a>
66+
<nav
67+
className={`flex items-center justify-between w-full px-4 sm:px-6 py-3 md:py-4 max-w-[100vw] mx-auto`}
68+
>
69+
{/* Logo aligned to extreme left */}
70+
<a
71+
href="/"
72+
className="text-2xl md:text-3xl font-extrabold text-green-600 tracking-tight"
73+
>
74+
PeerCall
75+
</a>
7676

77-
{/* Desktop Navigation */}
78-
<div className="hidden md:flex items-center gap-8 relative">
79-
<button
80-
onClick={() => scrollToSection("features")}
81-
className="text-gray-900 hover:text-green-600 transition-colors font-medium"
82-
>
83-
Features
84-
</button>
85-
<button
86-
onClick={() => scrollToSection("tech-stack")}
87-
className="text-gray-900 hover:text-green-600 transition-colors font-medium"
88-
>
89-
Tech Stack
90-
</button>
91-
<div className="relative">
92-
<Button
93-
size="default"
94-
className="bg-green-600 text-white hover:bg-green-700 flex items-center gap-2"
95-
onClick={handleJoinNow}
96-
>
97-
Join Now
98-
</Button>
99-
</div>
100-
</div>
77+
{/* Desktop Navigation */}
78+
<div className="hidden md:flex items-center gap-8">
79+
<button
80+
onClick={() => scrollToSection("features")}
81+
className="text-gray-800 hover:text-green-600 transition-colors font-medium"
82+
>
83+
Features
84+
</button>
85+
<button
86+
onClick={() => scrollToSection("tech-stack")}
87+
className="text-gray-800 hover:text-green-600 transition-colors font-medium"
88+
>
89+
Tech Stack
90+
</button>
91+
92+
{user ? (
93+
<div className="flex items-center gap-4">
94+
<span className="text-gray-700 font-medium">
95+
Hi, {user.name.split(" ")[0]}
96+
</span>
97+
<Button
98+
onClick={handleLogout}
99+
variant="outline"
100+
className="border-green-600 text-green-600 hover:bg-green-50"
101+
>
102+
Logout
103+
</Button>
104+
</div>
105+
) : (
106+
<Button
107+
onClick={handleJoinNow}
108+
className="bg-green-600 text-white hover:bg-green-700"
109+
>
110+
Join Now
111+
</Button>
112+
)}
113+
</div>
114+
115+
{/* Mobile Menu Button */}
116+
<button
117+
className="md:hidden text-gray-800 focus:outline-none"
118+
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
119+
aria-label="Toggle menu"
120+
>
121+
{isMobileMenuOpen ? <X size={26} /> : <Menu size={26} />}
122+
</button>
123+
</nav>
101124

102-
{/* Mobile Menu Button */}
125+
126+
{/* Mobile Menu */}
127+
<div
128+
className={`md:hidden absolute top-full left-0 right-0 bg-white/95 backdrop-blur-md shadow-lg transform transition-all duration-300 origin-top ${
129+
isMobileMenuOpen
130+
? "opacity-100 scale-y-100 visible"
131+
: "opacity-0 scale-y-0 invisible"
132+
}`}
133+
>
134+
<div className="flex flex-col px-6 py-4 space-y-4">
103135
<button
104-
className="md:hidden text-gray-900"
105-
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
106-
aria-label="Toggle menu"
136+
onClick={() => scrollToSection("features")}
137+
className="text-gray-800 hover:text-green-600 text-lg text-left font-medium"
107138
>
108-
{isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
139+
Features
140+
</button>
141+
<button
142+
onClick={() => scrollToSection("tech-stack")}
143+
className="text-gray-800 hover:text-green-600 text-lg text-left font-medium"
144+
>
145+
Tech Stack
109146
</button>
110-
</div>
111147

112-
{/* Mobile Navigation */}
113-
{isMobileMenuOpen && (
114-
<div className="md:hidden mt-4 pb-4 space-y-4 animate-fade-in">
115-
<button
116-
onClick={() => scrollToSection("features")}
117-
className="block w-full text-left text-gray-900 hover:text-green-600 transition-colors font-medium py-2"
118-
>
119-
Features
120-
</button>
121-
<button
122-
onClick={() => scrollToSection("tech-stack")}
123-
className="block w-full text-left text-gray-900 hover:text-green-600 transition-colors font-medium py-2"
124-
>
125-
Tech Stack
126-
</button>
148+
{user ? (
149+
<>
150+
<span className="text-gray-700 font-medium">
151+
Hello, {user.name.split(" ")[0]}
152+
</span>
153+
<Button
154+
onClick={handleLogout}
155+
variant="outline"
156+
className="border-green-600 text-green-600 hover:bg-green-50"
157+
>
158+
Logout
159+
</Button>
160+
</>
161+
) : (
127162
<Button
128-
size="default"
129-
className="w-full bg-green-600 text-white hover:bg-green-700 flex items-center justify-center gap-2"
130163
onClick={handleJoinNow}
164+
className="bg-green-600 text-white hover:bg-green-700 w-full"
131165
>
132166
Join Now
133167
</Button>
134-
{/* mobile: action buttons moved to /room-actions page */}
135-
</div>
136-
)}
137-
</nav>
168+
)}
169+
</div>
170+
</div>
138171
</header>
139172
);
140173
}

frontend/src/pages/Signup.tsx

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ interface SignUpFormData {
2323

2424
const SignUp = () => {
2525
const [isLoading, setIsLoading] = useState(false);
26+
const [serverMessage, setServerMessage] = useState<string | null>(null);
27+
const [isError, setIsError] = useState(false);
2628
const navigate = useNavigate();
2729

2830
const {
@@ -42,13 +44,16 @@ const SignUp = () => {
4244
description: "Passwords do not match",
4345
variant: "destructive",
4446
});
47+
// Removed duplicated inline error message for password mismatch
48+
// setServerMessage("Passwords do not match");
49+
// setIsError(true);
4550
return;
4651
}
4752

4853
setIsLoading(true);
54+
setServerMessage(null);
4955
try {
5056
const name = data.email.split("@")[0];
51-
5257
const response = await axios.post(
5358
"http://localhost:3000/api/auth/signup",
5459
{
@@ -67,29 +72,35 @@ const SignUp = () => {
6772
response.data.message || "Account created successfully. Welcome!",
6873
});
6974

75+
setServerMessage("Account created successfully! Redirecting...");
76+
setIsError(false);
77+
7078
if (response.data.token) {
7179
localStorage.setItem("token", response.data.token);
7280
}
7381

7482
reset();
75-
navigate("/signin");
83+
setTimeout(() => navigate("/signin"), 1500);
7684
} catch (error: any) {
85+
const msg =
86+
error.response?.data?.message ||
87+
"Registration failed. Please try again.";
7788
toast({
7889
title: "Error",
79-
description:
80-
error.response?.data?.message ||
81-
"Registration failed. Please try again.",
90+
description: msg,
8291
variant: "destructive",
8392
});
93+
setServerMessage(msg);
94+
setIsError(true);
8495
} finally {
8596
setIsLoading(false);
8697
}
8798
};
8899

89100
return (
90-
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-green-50 via-white to-green-100 px-4 py-8">
91-
<Card className="w-full max-w-md bg-white/80 backdrop-blur-md shadow-xl border border-green-100 rounded-2xl p-6 animate-fadeIn">
92-
<CardHeader className="space-y-1 text-center">
101+
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-green-50 via-white to-green-100 px-4 py-10 sm:px-6">
102+
<Card className="w-full max-w-md bg-white/90 backdrop-blur-xl shadow-2xl border border-green-100 rounded-2xl p-6 sm:p-8 animate-fadeIn">
103+
<CardHeader className="space-y-2 text-center">
93104
<CardTitle className="text-4xl font-extrabold text-green-600 tracking-tight">
94105
PeerCall
95106
</CardTitle>
@@ -98,7 +109,20 @@ const SignUp = () => {
98109
</CardDescription>
99110
</CardHeader>
100111

101-
<CardContent>
112+
<CardContent className="mt-2">
113+
{/* Message Area (prevents layout shift) */}
114+
{serverMessage && (
115+
<div
116+
className={`text-center text-sm mb-4 px-3 py-2 rounded-lg transition-all duration-300 ${
117+
isError
118+
? "bg-red-50 text-red-600 border border-red-200"
119+
: "bg-green-50 text-green-700 border border-green-200"
120+
}`}
121+
>
122+
{serverMessage}
123+
</div>
124+
)}
125+
102126
<form onSubmit={handleSubmit(onSubmit)} className="space-y-5">
103127
<InputField
104128
label="Email"
@@ -143,7 +167,7 @@ const SignUp = () => {
143167

144168
<Button
145169
type="submit"
146-
className="w-full bg-green-600 text-white hover:bg-green-700 transition-all duration-300 rounded-lg py-3 font-medium shadow-md hover:shadow-lg"
170+
className="w-full bg-green-600 text-white hover:bg-green-700 transition-all duration-300 rounded-lg py-3 font-medium shadow-md hover:shadow-lg flex items-center justify-center"
147171
size="lg"
148172
disabled={isLoading}
149173
>
@@ -159,7 +183,7 @@ const SignUp = () => {
159183
</form>
160184
</CardContent>
161185

162-
<CardFooter className="flex flex-col space-y-2 mt-4">
186+
<CardFooter className="flex flex-col space-y-3 mt-5">
163187
<div className="text-sm text-gray-600 text-center">
164188
Already have an account?{" "}
165189
<Link

0 commit comments

Comments
 (0)