From 35cde8b29194b482a96a89c7ab47605bce150dcf Mon Sep 17 00:00:00 2001 From: unkeett Date: Mon, 22 Sep 2025 02:22:29 +0530 Subject: [PATCH 1/5] Fix: Dark mode text visibility on profile page --- backend/services/emailService.js | 34 ++- backend/utils/emailVerificationHelpers.js | 66 +++-- frontend/package-lock.json | 8 +- frontend/package.json | 2 +- frontend/src/Components/profile/Profile.jsx | 281 ++++++++------------ 5 files changed, 174 insertions(+), 217 deletions(-) diff --git a/backend/services/emailService.js b/backend/services/emailService.js index 7b2b54c..f8aefa4 100644 --- a/backend/services/emailService.js +++ b/backend/services/emailService.js @@ -1,26 +1,22 @@ const nodemailer = require('nodemailer'); -const transporter = nodemailer.createTransport({ - service: 'gmail', - auth: { - user: process.env.EMAIL_USER, - pass: process.env.EMAIL_PASSWORD // Use App Password for Gmail - } -}); +// Comment out transporter since we won't use it in dev +// const transporter = nodemailer.createTransport({ +// service: 'gmail', +// auth: { +// user: process.env.EMAIL_USER, +// pass: process.env.EMAIL_PASSWORD // Use App Password for Gmail +// } +// }); const sendVerificationEmail = async (email, verificationCode) => { - const mailOptions = { - from: process.env.EMAIL_USER, - to: email, - subject: 'Email Verification - DevSync', - html: ` -

Email Verification

-

Your verification code is: ${verificationCode}

-

This code will expire in 15 minutes.

- ` - }; + // Simply log instead of sending an email + console.log(`[DEV] Skipping email. Verification code for ${email}: ${verificationCode}`); - await transporter.sendMail(mailOptions); + // If you want to keep sending emails in production: + // if (process.env.NODE_ENV !== "development") { + // await transporter.sendMail(mailOptions); + // } }; -module.exports = { sendVerificationEmail }; \ No newline at end of file +module.exports = { sendVerificationEmail }; diff --git a/backend/utils/emailVerificationHelpers.js b/backend/utils/emailVerificationHelpers.js index cec5cf4..e94623a 100644 --- a/backend/utils/emailVerificationHelpers.js +++ b/backend/utils/emailVerificationHelpers.js @@ -1,46 +1,46 @@ -const { sendVerificationEmail } = require('../services/emailService') +const { sendVerificationEmail } = require('../services/emailService'); const crypto = require("crypto"); -const jwt = require('jsonwebtoken'); // Also add this if missing +const jwt = require('jsonwebtoken'); // Use a fallback JWT secret if env variable is missing const JWT_SECRET = process.env.JWT_SECRET || 'devsync_secure_jwt_secret_key_for_authentication'; -// Helper function to generate verification code +/** + * Generate a 6-digit verification code + */ const generateVerificationCode = () => { return crypto.randomInt(100000, 999999).toString(); }; -// Helper function to generate JWT token +/** + * Generate JWT token for a user + * @param {String} userId - User ID + * @param {String} expiresIn - Token expiration + */ const generateJWT = (userId, expiresIn = "24h") => { return new Promise((resolve, reject) => { - const payload = { - user: { - id: userId, - }, - }; - + const payload = { user: { id: userId } }; jwt.sign(payload, JWT_SECRET, { expiresIn }, (err, token) => { - if (err) { - reject(err); - } else { - resolve(token); - } + if (err) reject(err); + else resolve(token); }); }); }; -// Helper function to format user response -const formatUserResponse = (user) => { - return { - id: user._id, - name: user.name, - email: user.email, - avatar: user.avatar, - isEmailVerified: user.isEmailVerified, - }; -}; +/** + * Format user object to send in response + */ +const formatUserResponse = (user) => ({ + id: user._id, + name: user.name, + email: user.email, + avatar: user.avatar, + isEmailVerified: user.isEmailVerified, +}); -// Helper function to set verification token on user +/** + * Set verification token and expiration on user + */ const setVerificationToken = async (user) => { const verificationCode = generateVerificationCode(); user.emailVerificationToken = verificationCode; @@ -49,14 +49,22 @@ const setVerificationToken = async (user) => { return verificationCode; }; -// Helper function to send verification email with error handling +/** + * Send verification email or log code in development + */ const handleVerificationEmail = async (email, verificationCode) => { + if (process.env.NODE_ENV === "development") { + // Log verification code in dev instead of sending email + console.log(`[DEV] Verification code for ${email}: ${verificationCode}`); + return; // skip sending email + } + try { await sendVerificationEmail(email, verificationCode); console.log(`Verification code for ${email}: ${verificationCode}`); } catch (emailError) { console.error("Email sending failed:", emailError); - throw emailError; + throw emailError; } }; @@ -66,4 +74,4 @@ module.exports = { formatUserResponse, setVerificationToken, handleVerificationEmail -}; \ No newline at end of file +}; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b35757e..7e674fc 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17,7 +17,7 @@ "@radix-ui/react-toast": "^1.2.14", "@tailwindcss/vite": "^4.1.11", "add": "^2.0.6", - "axios": "^1.11.0", + "axios": "^1.12.1", "button": "^1.1.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -3115,9 +3115,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", - "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.1.tgz", + "integrity": "sha512-Kn4kbSXpkFHCGE6rBFNwIv0GQs4AvDT80jlveJDKFxjbTYMUeB4QtsdPCv6H8Cm19Je7IU6VFtRl2zWZI0rudQ==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", diff --git a/frontend/package.json b/frontend/package.json index 36faab8..19625c3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,7 +19,7 @@ "@radix-ui/react-toast": "^1.2.14", "@tailwindcss/vite": "^4.1.11", "add": "^2.0.6", - "axios": "^1.11.0", + "axios": "^1.12.1", "button": "^1.1.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/frontend/src/Components/profile/Profile.jsx b/frontend/src/Components/profile/Profile.jsx index a8af372..5108248 100644 --- a/frontend/src/Components/profile/Profile.jsx +++ b/frontend/src/Components/profile/Profile.jsx @@ -3,10 +3,7 @@ import { motion } from "framer-motion"; import { useNavigate } from "react-router-dom"; import Navbar from "../Navbar/Navbar"; import { Camera, RefreshCw } from "lucide-react"; -import { FaGithub, FaGitlab, FaLinkedin, FaGlobe } from "react-icons/fa"; import { SiLeetcode, SiCodechef, SiHackerrank, SiHackerearth, SiCodeforces, SiLinkedin, SiGitlab, SiGithub } from "react-icons/si"; -import { Button } from "../ui/button"; - const Profile = () => { const [profileData, setProfileData] = useState({ @@ -244,14 +241,13 @@ const Profile = () => { // Clear auth token and redirect to login localStorage.removeItem("token"); navigate("/login"); - // window.location.href = "/login"; }; const notIsEditingButton = (icon, buttonUrl, buttonName) => { return @@ -354,18 +347,9 @@ const Profile = () => { className="px-4 py-2 bg-[#1D3557] text-white rounded-lg hover:opacity-90 transition duration-300 flex items-center gap-2 shadow-md" > {isSaving ? ( - <> - - - - - Saving... - + <>Saving... ) : ( - <> - - Save Changes - + <>Save Changes )} )} @@ -381,21 +365,17 @@ const Profile = () => {
- {/* Left Column - Avatar */}
{profileData.name} { - // Fallback to default avatar if image fails to load - e.target.src = "https://api.dicebear.com/6.x/micah/svg?seed=fallback"; - }} + onError={(e) => { e.target.src = "https://api.dicebear.com/6.x/micah/svg?seed=fallback"; }} /> {isEditing && (
@@ -419,175 +399,151 @@ const Profile = () => { )}
{!isEditing ? ( -

{profileData.name}

+

{profileData.name}

) : ( )} {!isEditing && ( -

{profileData.email}

+

{profileData.email}

)}
- {/* Right Column - Details */}
- {/* Bio Section */}
-

Bio

+

Bio

{!isEditing ? ( -

{profileData.bio}

+

{profileData.bio}

) : (