diff --git a/frontend/src/pages/AccountSettings/AccountSettings.tsx b/frontend/src/pages/AccountSettings/AccountSettings.tsx index e8ef288b75..76cd1ef6c2 100644 --- a/frontend/src/pages/AccountSettings/AccountSettings.tsx +++ b/frontend/src/pages/AccountSettings/AccountSettings.tsx @@ -1,5 +1,15 @@ import { ReactElement, useState } from "react"; -import { Autocomplete, Box, Button, TextField, IconButton, InputAdornment, Typography } from "@mui/material"; +import { + Autocomplete, + Box, + Button, + TextField, + IconButton, + InputAdornment, + Typography, + Alert, + CircularProgress, +} from "@mui/material"; import Navbar from "../../components/Navbar/Navbar"; import Footer from "../../components/Footer/Footer"; import Visibility from "@mui/icons-material/Visibility"; @@ -9,9 +19,18 @@ import "./AccountSettings.scss"; const AccountSettings = (): ReactElement => { const [showPassword, setShowPassword] = useState(false); const [showEmail, setShowEmail] = useState(false); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [confirmationMessage, setConfirmationMessage] = useState(null); + const [displayedName, setDisplayedName] = useState("Echomo"); + const [profilePhotoUrl, setProfilePhotoUrl] = useState(""); + const [preferredLanguage, setPreferredLanguage] = useState(""); + const [email, setEmail] = useState("echomo@gmail.com"); + const [password, setPassword] = useState("password"); const handleClickShowPassword = () => setShowPassword(!showPassword); const handleClickShowEmail = () => setShowEmail(!showEmail); + const programmingLanguages = [ "JavaScript", "Python2", @@ -36,18 +55,52 @@ const AccountSettings = (): ReactElement => { "MATLAB", ]; + const handleSaveChanges = async () => { + setLoading(true); + setError(null); + setConfirmationMessage(null); + + try { + if (!displayedName || !email || !password) { + throw new Error("Displayed name, email, and password are required."); + } + // Simulate API call + await new Promise((resolve, reject) => { + setTimeout(() => { + if (email === "error@example.com") { + reject(new Error("Email already in use.")); + } else { + resolve("Account details updated successfully!"); + } + }, 3000); + }); + + setConfirmationMessage("Account details saved successfully!"); + } catch (err: any) { + setError(err.message); + } finally { + setLoading(false); + } + }; + return ( - Login + Account Settings - Customize your information and experience here!{" "} + Customize your information and experience here! -
+ { + e.preventDefault(); + handleSaveChanges(); + }} + > Displayed Name (to others) { placeholder="Enter your name" className="AccountSettings-input" fullWidth - defaultValue="Echomo" + value={displayedName} + onChange={(e) => setDisplayedName(e.target.value)} /> @@ -63,7 +117,7 @@ const AccountSettings = (): ReactElement => { Profile Photo Profile @@ -72,6 +126,8 @@ const AccountSettings = (): ReactElement => { placeholder="Enter new URL to change" className="AccountSettings-url-input" fullWidth + value={profilePhotoUrl} + onChange={(e) => setProfilePhotoUrl(e.target.value)} /> @@ -88,6 +144,8 @@ const AccountSettings = (): ReactElement => { placeholder="Enter your preferred programming language" className="AccountSettings-input" fullWidth + value={preferredLanguage} + onChange={(e) => setPreferredLanguage(e.target.value)} /> )} filterOptions={(options, { inputValue }) => @@ -103,7 +161,8 @@ const AccountSettings = (): ReactElement => { variant="outlined" className="AccountSettings-input" fullWidth - defaultValue="echomo@gmail.com" + value={email} + onChange={(e) => setEmail(e.target.value)} type={showEmail ? "text" : "email"} /> @@ -114,8 +173,9 @@ const AccountSettings = (): ReactElement => { variant="outlined" className="AccountSettings-input" fullWidth + value={password} + onChange={(e) => setPassword(e.target.value)} type={showPassword ? "text" : "password"} - defaultValue="password" InputProps={{ endAdornment: ( @@ -128,8 +188,26 @@ const AccountSettings = (): ReactElement => { /> -
diff --git a/frontend/src/pages/Login/Login.tsx b/frontend/src/pages/Login/Login.tsx index 7c56b52697..d4c1196ed0 100644 --- a/frontend/src/pages/Login/Login.tsx +++ b/frontend/src/pages/Login/Login.tsx @@ -1,5 +1,6 @@ import { ReactElement, useState } from "react"; -import { Box, Button, Typography, TextField, IconButton, InputAdornment } from "@mui/material"; +import { useNavigate } from "react-router-dom"; +import { Box, Button, Typography, TextField, IconButton, InputAdornment, Alert, CircularProgress } from "@mui/material"; import Navbar from "../../components/Navbar/Navbar"; import Footer from "../../components/Footer/Footer"; import Visibility from "@mui/icons-material/Visibility"; @@ -8,11 +9,62 @@ import "./Login.scss"; const Login = (): ReactElement => { const [showPassword, setShowPassword] = useState(false); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [errors, setErrors] = useState<{ email?: string; password?: string }>({}); + const [loginError, setLoginError] = useState(null); + const [loading, setLoading] = useState(false); + const navigate = useNavigate(); const togglePasswordVisibility = () => { setShowPassword((prev) => !prev); }; + const validateEmail = (email: string) => { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email); + }; + + const handleLogin = () => { + setErrors({}); + setLoginError(null); + + let formValid = true; + const newErrors: { email?: string; password?: string } = {}; + + if (!email) { + formValid = false; + newErrors.email = "Email is required."; + } else if (!validateEmail(email)) { + formValid = false; + newErrors.email = "Please enter a valid email."; + } + + if (!password) { + formValid = false; + newErrors.password = "Password is required."; + } + + if (!formValid) { + setErrors(newErrors); + return; + } + + // Simulate login process + try { + if (email === "test@example.com" && password === "password") { + setLoading(true); + setTimeout(() => { + navigate("/"); + }, 3000); + } else { + setLoginError("Invalid email or password."); + } + } catch (error) { + setLoginError("An unexpected error occurred. Please try again."); + } + }; + return ( @@ -26,42 +78,66 @@ const Login = (): ReactElement => { - - - - - {showPassword ? : } - - - ), - }} - /> - - - Forgot password? - - - - - - Not registered yet? Sign Up - - - {/* Or Continue with */} + {loading ? ( + + ) : ( + <> + + setEmail(e.target.value)} + error={!!errors.email} + helperText={errors.email} + /> + setPassword(e.target.value)} + error={!!errors.password} + helperText={errors.password} + InputProps={{ + endAdornment: ( + + + {showPassword ? : } + + + ), + }} + /> + + + + Forgot password? + + + {loginError && ( + + {loginError} + + )} + + + + + Not registered yet? Sign Up + + + )} diff --git a/frontend/src/pages/SignUp/SignUp.tsx b/frontend/src/pages/SignUp/SignUp.tsx index 9b40aaf02e..c8ca1dca80 100644 --- a/frontend/src/pages/SignUp/SignUp.tsx +++ b/frontend/src/pages/SignUp/SignUp.tsx @@ -1,5 +1,6 @@ import { ReactElement, useState } from "react"; -import { Box, Button, Typography, TextField, IconButton, InputAdornment } from "@mui/material"; +import { useNavigate } from "react-router-dom"; +import { Box, Button, Typography, TextField, IconButton, InputAdornment, Alert, CircularProgress } from "@mui/material"; import Navbar from "../../components/Navbar/Navbar"; import Footer from "../../components/Footer/Footer"; import Visibility from "@mui/icons-material/Visibility"; @@ -8,11 +9,88 @@ import "./SignUp.scss"; const SignUp = (): ReactElement => { const [showPassword, setShowPassword] = useState(false); + const [firstName, setFirstName] = useState(""); + const [lastName, setLastName] = useState(""); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [errors, setErrors] = useState<{ firstName?: string; lastName?: string; email?: string; password?: string }>( + {}, + ); + const [loading, setLoading] = useState(false); + const [signUpError, setSignUpError] = useState(null); + const navigate = useNavigate(); const togglePasswordVisibility = () => { setShowPassword((prev) => !prev); }; + const validateEmail = (email: string) => { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email); + }; + + const validatePassword = (password: string) => { + const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/; + return passwordRegex.test(password); + }; + + const handleSignUp = () => { + setErrors({}); + setSignUpError(null); + + let formValid = true; + const newErrors: { firstName?: string; lastName?: string; email?: string; password?: string } = {}; + + // First Name validation + if (!firstName) { + formValid = false; + newErrors.firstName = "First name is required."; + } + + // Last Name validation + if (!lastName) { + formValid = false; + newErrors.lastName = "Last name is required."; + } + + // Email validation + if (!email) { + formValid = false; + newErrors.email = "Email is required."; + } else if (!validateEmail(email)) { + formValid = false; + newErrors.email = "Please enter a valid email."; + } + + // Password validation + if (!password) { + formValid = false; + newErrors.password = "Password is required."; + } else if (!validatePassword(password)) { + formValid = false; + newErrors.password = "Password must be at least 8 characters long and contain letters and numbers."; + } + + if (!formValid) { + setErrors(newErrors); + return; + } + + // Simulate sign-up process + try { + if (email === "existing@example.com") { + setSignUpError("An account with this email already exists."); + } else { + setLoading(true); + setTimeout(() => { + navigate("/"); + }, 3000); + } + } catch (error) { + setSignUpError("An unexpected error occurred. Please try again."); + } + }; + return ( @@ -26,36 +104,78 @@ const SignUp = (): ReactElement => { experiences. - - - - - - - {showPassword ? : } - - - ), - }} - /> - - - - - Already have an account? Login - - - {/* Or Continue with */} + + {loading ? ( + + ) : ( + <> + + setFirstName(e.target.value)} + error={!!errors.firstName} + helperText={errors.firstName} + /> + setLastName(e.target.value)} + error={!!errors.lastName} + helperText={errors.lastName} + /> + + + + setEmail(e.target.value)} + error={!!errors.email} + helperText={errors.email} + /> + setPassword(e.target.value)} + error={!!errors.password} + helperText={errors.password} + InputProps={{ + endAdornment: ( + + + {showPassword ? : } + + + ), + }} + /> + + + {signUpError && ( + + {signUpError} + + )} + + + + + Already have an account? Login + + + )}