diff --git a/backend/controller/user.controller.js b/backend/controller/user.controller.js index 141e174..ff23c3c 100644 --- a/backend/controller/user.controller.js +++ b/backend/controller/user.controller.js @@ -44,30 +44,49 @@ const updatelanguage = expressAsyncHandler(async (req, res) => { const registeruser = expressAsyncHandler (async (req,res) => { const {name,email,password,pic} = req.body + // Validate required fields if (!name || !email || !password) { return res.status(400).json({ success: false, message: "Please provide all fields" }); } - if (name.length < 2 || name.length > 50) { + // Validate name length + const trimmedName = name.trim(); + if (trimmedName.length < 2 || trimmedName.length > 50) { return res.status(400).json({ success: false, message: "Name must be between 2 and 50 characters" }); } + // Validate email format const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - if (!emailRegex.test(email)) { + const trimmedEmail = email.trim().toLowerCase(); + if (!emailRegex.test(trimmedEmail)) { return res.status(400).json({ success: false, message: "Please provide a valid email address" }); } + // Validate password strength if (password.length < 6) { return res.status(400).json({ success: false, message: "Password must be at least 6 characters long" }); } + + // Additional password validation: check for at least one letter and one number + if (!/(?=.*[a-zA-Z])(?=.*\d)/.test(password)) { + return res.status(400).json({ success: false, message: "Password must contain at least one letter and one number" }); + } - const userExists = await User.findOne({email}) + // Check if user already exists + const userExists = await User.findOne({ email: trimmedEmail }) if(userExists) { return res.status(409).json({ success: false, message: "User already exists" }); } - const user = await User.create({name, email, password,pic}) + + // Create new user with trimmed and normalized data + const user = await User.create({ + name: trimmedName, + email: trimmedEmail, + password, + pic: pic || undefined + }) if(user){ res.status(201).json({ diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index 02c408d..c6893cf 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -5,14 +5,72 @@ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } +/** + * Get user profile pictures from a chat + * @param chat - The chat object containing users + * @param currentUserId - The ID of the current user to exclude + * @returns Array of user profile picture URLs + */ export function getUserPics(chat, currentUserId) { - if (!chat?.users) return []; + if (!chat?.users || !Array.isArray(chat.users)) return []; - const otherUsers = chat.users.filter(user => user?._id?.toString() !== currentUserId?.toString()); + const otherUsers = chat.users.filter(user => { + if (!user?._id) return false; + return user._id.toString() !== currentUserId?.toString(); + }); if (chat.isGroupChat) { - return otherUsers.slice(0, 3).map(user => user?.pic).filter(Boolean); + // For group chats, return up to 3 user pics + return otherUsers + .slice(0, 3) + .map(user => user?.pic) + .filter(Boolean); } else { - return otherUsers.length > 0 && otherUsers[0]?.pic ? [otherUsers[0].pic] : []; + // For one-on-one chats, return the other user's pic + return otherUsers.length > 0 && otherUsers[0]?.pic + ? [otherUsers[0].pic] + : []; } } + +/** + * Validate email format + * @param email - Email string to validate + * @returns Boolean indicating if email is valid + */ +export function isValidEmail(email) { + if (!email || typeof email !== 'string') return false; + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email.trim()); +} + +/** + * Format file size to human-readable format + * @param bytes - File size in bytes + * @returns Formatted string (e.g., "1.5 MB") + */ +export function formatFileSize(bytes) { + if (!bytes || bytes === 0) return '0 Bytes'; + const k = 1024; + const sizes = ['Bytes', 'KB', 'MB', 'GB']; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i]; +} + +/** + * Debounce function to limit function calls + * @param func - Function to debounce + * @param wait - Wait time in milliseconds + * @returns Debounced function + */ +export function debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; +}