-
-
- Create Account
-
-
- Join us and get started
-
+
Create Account
+
Join us and get started
-
- {/* Signup Form */}
diff --git a/savebook/app/api/auth/register/route.js b/savebook/app/api/auth/register/route.js
index 1dc57da..4719791 100644
--- a/savebook/app/api/auth/register/route.js
+++ b/savebook/app/api/auth/register/route.js
@@ -6,36 +6,63 @@ export async function POST(request) {
try {
await dbConnect();
- const { username, password } = await request.json();
+ const { username, password, email, education, course, phoneNumber, subjectsOfInterest, name } = await request.json();
// ✅ Input validation
if (
!username ||
!password ||
+ !email ||
typeof username !== "string" ||
typeof password !== "string" ||
+ typeof email !== "string" ||
password.length < 6
) {
return NextResponse.json(
- { success: false, message: "Invalid input" },
+ { success: false, message: "Invalid input. Username, password (min 6 chars), and email are required." },
{ status: 400 }
);
}
- // ✅ Prevent username enumeration
- const existingUser = await User.findOne({ username });
+ // Basic email validation regex
+ const emailRegex = /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/;
+ if (!emailRegex.test(email)) {
+ return NextResponse.json(
+ { success: false, message: "Invalid email format." },
+ { status: 400 }
+ );
+ }
+
+ // ✅ Prevent username/email enumeration
+ const existingUser = await User.findOne({ $or: [{ username }, { email }] });
if (existingUser) {
return NextResponse.json(
- { success: false, message: "Unable to create account" },
+ { success: false, message: "Username or Email already exists" },
{ status: 400 }
);
}
+ // Split name into firstName and lastName if provided
+ let firstName = '';
+ let lastName = '';
+ if (name) {
+ const parts = name.trim().split(' ');
+ firstName = parts[0];
+ lastName = parts.slice(1).join(' ');
+ }
+
// ✅ Create user
await User.create({
username,
- password
+ password,
+ email,
+ education,
+ course,
+ phoneNumber,
+ subjectsOfInterest: Array.isArray(subjectsOfInterest) ? subjectsOfInterest : [],
+ firstName,
+ lastName
});
return NextResponse.json(
diff --git a/savebook/app/api/auth/update-profile/route.js b/savebook/app/api/auth/update-profile/route.js
index c584cf5..f19749e 100644
--- a/savebook/app/api/auth/update-profile/route.js
+++ b/savebook/app/api/auth/update-profile/route.js
@@ -11,33 +11,46 @@ export async function PUT(request) {
// Get token from cookies
const authtoken = request.cookies.get("authToken");
-
+
if (!authtoken) {
return NextResponse.json({ success: false, message: "Unauthorized - No token provided" }, { status: 401 });
}
// Verify token
- const decoded = verifyJwtToken(authtoken.value);
-
+ const decoded = await verifyJwtToken(authtoken.value);
+
if (!decoded || !decoded.success) {
return NextResponse.json({ success: false, message: "Unauthorized - Invalid token" }, { status: 401 });
}
-
+
// Get user ID from token
const userId = new mongoose.Types.ObjectId(decoded.userId);
// Get updated user data from request
- const { profileImage, firstName, lastName, bio, location } = await request.json();
+ const { profileImage, firstName, lastName, bio, location, email, education, course, phoneNumber, subjectsOfInterest } = await request.json();
+
+ // Check if email is being updated and if it's already taken
+ if (email) {
+ const emailExists = await User.findOne({ email, _id: { $ne: userId } });
+ if (emailExists) {
+ return NextResponse.json({ success: false, message: "Email already in use" }, { status: 400 });
+ }
+ }
// Update user
const updatedUser = await User.findByIdAndUpdate(
userId,
- {
+ {
...(profileImage !== undefined && { profileImage }),
...(firstName !== undefined && { firstName }),
...(lastName !== undefined && { lastName }),
...(bio !== undefined && { bio }),
- ...(location !== undefined && { location })
+ ...(location !== undefined && { location }),
+ ...(email !== undefined && { email }),
+ ...(education !== undefined && { education }),
+ ...(course !== undefined && { course }),
+ ...(phoneNumber !== undefined && { phoneNumber }),
+ ...(subjectsOfInterest !== undefined && { subjectsOfInterest })
},
{ new: true, select: "-password" } // Return updated user without password
);
@@ -47,16 +60,21 @@ export async function PUT(request) {
}
// Return success response with updated user data
- return NextResponse.json({
- success: true,
+ return NextResponse.json({
+ success: true,
message: "Profile updated successfully",
user: {
username: updatedUser.username,
+ email: updatedUser.email,
profileImage: updatedUser.profileImage,
firstName: updatedUser.firstName,
lastName: updatedUser.lastName,
bio: updatedUser.bio,
- location: updatedUser.location
+ location: updatedUser.location,
+ education: updatedUser.education,
+ course: updatedUser.course,
+ phoneNumber: updatedUser.phoneNumber,
+ subjectsOfInterest: updatedUser.subjectsOfInterest
}
}, { status: 200 });
diff --git a/savebook/app/api/auth/user/route.js b/savebook/app/api/auth/user/route.js
index 97eca38..3326551 100644
--- a/savebook/app/api/auth/user/route.js
+++ b/savebook/app/api/auth/user/route.js
@@ -48,7 +48,12 @@ export async function GET(request) {
firstName: user.firstName,
lastName: user.lastName,
bio: user.bio,
- location: user.location
+ location: user.location,
+ email: user.email,
+ education: user.education,
+ course: user.course,
+ phoneNumber: user.phoneNumber,
+ subjectsOfInterest: user.subjectsOfInterest
}
}, { status: 200 });
diff --git a/savebook/app/profile/page.js b/savebook/app/profile/page.js
index d1f4beb..ac88114 100644
--- a/savebook/app/profile/page.js
+++ b/savebook/app/profile/page.js
@@ -11,7 +11,12 @@ export default function ProfilePage() {
firstName: '',
lastName: '',
bio: '',
- location: ''
+ location: '',
+ email: '',
+ education: '',
+ course: '',
+ phoneNumber: '',
+ subjectsOfInterest: ''
});
const [imagePreview, setImagePreview] = useState('');
const [message, setMessage] = useState('');
@@ -26,7 +31,12 @@ export default function ProfilePage() {
firstName: user.firstName || '',
lastName: user.lastName || '',
bio: user.bio || '',
- location: user.location || ''
+ location: user.location || '',
+ email: user.email || '',
+ education: user.education || '',
+ course: user.course || '',
+ phoneNumber: user.phoneNumber || '',
+ subjectsOfInterest: user.subjectsOfInterest ? (Array.isArray(user.subjectsOfInterest) ? user.subjectsOfInterest.join(', ') : user.subjectsOfInterest) : ''
});
setImagePreview(user.profileImage || '');
setIsDataLoaded(true);
@@ -43,35 +53,35 @@ export default function ProfilePage() {
const handleImageChange = async (e) => {
const file = e.target.files[0];
-
+
if (file) {
// Validate file type
if (!file.type.match('image.*')) {
setError('Please select an image file');
return;
}
-
+
// Validate file size (max 5MB)
if (file.size > 5 * 1024 * 1024) {
setError('File size exceeds 5MB limit');
return;
}
-
+
// Show loading state
setMessage('Uploading image...');
-
+
const formData = new FormData();
formData.append('image', file);
-
+
try {
const response = await fetch('/api/upload', {
method: 'POST',
body: formData,
credentials: 'include'
});
-
+
const result = await response.json();
-
+
if (result.success) {
setImagePreview(result.imageUrl);
setFormData(prev => ({
@@ -80,7 +90,7 @@ export default function ProfilePage() {
}));
setMessage('Image uploaded successfully!');
setError(''); // Clear any previous error
-
+
// Clear message after 2 seconds
setTimeout(() => setMessage(''), 2000);
} else {
@@ -109,7 +119,12 @@ export default function ProfilePage() {
firstName: formData.firstName,
lastName: formData.lastName,
bio: formData.bio,
- location: formData.location
+ location: formData.location,
+ email: formData.email,
+ education: formData.education,
+ course: formData.course,
+ phoneNumber: formData.phoneNumber,
+ subjectsOfInterest: formData.subjectsOfInterest.split(',').map(s => s.trim()).filter(s => s)
}),
credentials: 'include'
});
@@ -118,28 +133,33 @@ export default function ProfilePage() {
if (data.success) {
setMessage('Profile updated successfully!');
-
+
// Update form data to reflect the changes immediately
setFormData({
profileImage: data.user.profileImage,
firstName: data.user.firstName,
lastName: data.user.lastName,
bio: data.user.bio,
- location: data.user.location
+ location: data.user.location,
+ email: data.user.email,
+ education: data.user.education,
+ course: data.user.course,
+ phoneNumber: data.user.phoneNumber,
+ subjectsOfInterest: Array.isArray(data.user.subjectsOfInterest) ? data.user.subjectsOfInterest.join(', ') : data.user.subjectsOfInterest
});
-
+
// Update image preview
setImagePreview(data.user.profileImage);
-
+
// Refresh user data from the server to ensure we have the latest data in context
if (checkUserAuthentication) {
await checkUserAuthentication();
}
-
+
setTimeout(() => {
setIsEditing(false);
}, 500);
-
+
setTimeout(() => {
setMessage(''); // Clear message
// Optionally redirect after update
@@ -174,11 +194,11 @@ export default function ProfilePage() {
);
}
-
+
const handleEditClick = () => {
setIsEditing(true);
};
-
+
const handleCancelEdit = () => {
setIsEditing(false);
// Reset form to current user data
@@ -188,39 +208,44 @@ export default function ProfilePage() {
firstName: user.firstName || '',
lastName: user.lastName || '',
bio: user.bio || '',
- location: user.location || ''
+ location: user.location || '',
+ email: user.email || '',
+ education: user.education || '',
+ course: user.course || '',
+ phoneNumber: user.phoneNumber || '',
+ subjectsOfInterest: user.subjectsOfInterest ? (Array.isArray(user.subjectsOfInterest) ? user.subjectsOfInterest.join(', ') : user.subjectsOfInterest) : ''
});
setImagePreview(user.profileImage || '');
}
};
-
+
return (