From 3917203626d7498f1e85083ba6511f47607ace5c Mon Sep 17 00:00:00 2001 From: MarkusW Date: Fri, 1 Nov 2024 11:42:39 -0400 Subject: [PATCH] Login Profile Signup Pages added more comments --- client/src/pages/Login.tsx | 224 +++++++++++++++------------- client/src/pages/Profile.tsx | 240 ++++++++++++++++++------------ client/src/pages/SignUp.tsx | 275 ++++++++++++++++++++--------------- 3 files changed, 430 insertions(+), 309 deletions(-) diff --git a/client/src/pages/Login.tsx b/client/src/pages/Login.tsx index c784faa..0abed05 100644 --- a/client/src/pages/Login.tsx +++ b/client/src/pages/Login.tsx @@ -2,113 +2,139 @@ import React, { useState } from 'react'; import { useNavigate, Link } from 'react-router-dom'; import { UserDetails } from '../types'; -const Login: React.FC<{ - setUser: React.Dispatch>; +/** + * Login component renders a login form that allows users to login via username or email and password. + * + * @param {{ setUser: React.Dispatch>; }} param0 - Object containing a function to update the user state. + * @param {React.Dispatch>} param0.setUser - Function to update the current user's state in the application. + * @returns {React.FC} - A functional component that renders the login form UI and handles login functionality. + */ +const Login: React.FC<{ + setUser: React.Dispatch> }> = ({ setUser }) => { - const [localUsername, setLocalUsername] = useState(''); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [error, setError] = useState(null); - const navigate = useNavigate(); + // Local state variables for form data + const [localUsername, setLocalUsername] = useState(''); // Stores the username entered by the user + const [email, setEmail] = useState(''); // Stores the email entered by the user + const [password, setPassword] = useState(''); // Stores the password entered by the user + const [error, setError] = useState(null); // Stores any error message to be displayed + const navigate = useNavigate(); // Hook to navigate programmatically - const handleLogin = async (event: React.FormEvent) => { - event.preventDefault(); - setError(null); + /** + * Handles the login form submission, validating input and making a request to the backend API. + * + * @param {React.FormEvent} event - The form submission event. + * @returns {Promise} - A promise that resolves after handling the login request. + */ + const handleLogin = async (event: React.FormEvent) => { + event.preventDefault(); // Prevents default form submission behavior + setError(null); // Resets any previous error messages - // Basic form validation - if ((!localUsername && !email) || (localUsername && email)) { - setError('Please provide either a username or an email, but not both'); - return; - } + // Basic form validation + if ((!localUsername && !email) || (localUsername && email)) { + setError('Please provide either a username or an email, but not both.'); + return; + } - // Email format validation if email is provided - if (email) { - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - if (!emailRegex.test(email)) { - setError('Please enter a valid email address'); - return; - } - } + // Email format validation if email is provided + if (email) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + setError('Please enter a valid email address'); + return; + } + } - try { - //Send resgiter request to the backend - const response = await fetch('/api/login', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - username: localUsername || null, - work_email: email || null, - password, - }), - }); - const user = (await response.json()) as UserDetails; + try { + // Send login request to the backend + const response = await fetch('/api/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + username: localUsername || null, // Sends username if provided, else null + work_email: email || null, // Sends email if provided, else null + password, // Sends password + }), + }); + const user = (await response.json()) as UserDetails; // Parses response as UserDetails type - if (response.ok) { - setUser(user); - window.localStorage.setItem('user', JSON.stringify(user)); - navigate('/profile'); - } else { - setError('Could Not Log In. Please Try again'); - } - } catch (err) { - setError('Error logging in. Please try again.'); - console.error(err, 'Error in login at Login.tsx;'); - } - }; + // Handle successful login + if (response.ok) { + setUser(user); // Sets the logged-in user in the app state + window.localStorage.setItem('user', JSON.stringify(user)); // Stores user data in localStorage + navigate('/profile'); // Navigates to the profile page + } else { + setError('Could Not Log In. Please Try again.'); // Displays error message for failed login + } + } catch (err) { + setError('Error logging in. Please try again.'); // Displays error for request failure + console.error(err, 'Error in login at Login.tsx'); // Logs the error to console for debugging + } + }; - return ( -
-

Login

- {error && ( -
- {error} -
- )} -
void handleLogin(event)}> -
- - setLocalUsername(e.target.value)} - autoComplete="username" - /> -
-
- - setEmail(e.target.value)} - autoComplete="email" - /> -
-
- - setPassword(e.target.value)} - required - autoComplete="current-password" - /> + return ( +
+

Login

+ {/* Display error message if there is one */} + {error && ( +
+ {error} +
+ )} + {/* Login form */} + void handleLogin(event)}> + {/* Username input field */} +
+ + setLocalUsername(e.target.value)} + autoComplete="username" + /> +
+ + {/* Email input field */} +
+ + setEmail(e.target.value)} + autoComplete="email" + /> +
+ + {/* Password input field */} +
+ + setPassword(e.target.value)} + required // Field is required + autoComplete="current-password" + /> +
+ + {/* Submit button */} + + + + {/* Link to sign-up page */} +
+

+ Don't have an account? Sign up here +

+
- - -
-

- Don't have an account? Sign up here -

-
-
- ); + ); }; export default Login; diff --git a/client/src/pages/Profile.tsx b/client/src/pages/Profile.tsx index 45388e4..71138b0 100644 --- a/client/src/pages/Profile.tsx +++ b/client/src/pages/Profile.tsx @@ -1,99 +1,161 @@ import React from 'react'; import { AWSCredentials, ProfileProps, UserDetails } from '../types'; +/** + * Profile component renders the user's profile information, AWS credentials form, and handles updates. + * + * @param {ProfileProps} props - Props passed to the Profile component. + * @returns {React.FC} - A functional component that displays user profile information and manages AWS credentials. + */ const Profile: React.FC = ({ - isDarkMode, - user, - updateCredentials, + isDarkMode, // Boolean indicating if dark mode is active + user, // User details object containing user information + updateCredentials, // Function to update AWS credentials }) => { - function handleCredentialSubmit() { - const locallyStoredUser: UserDetails = JSON.parse( - window.localStorage.getItem('user')! - ) as UserDetails; - const domCollectedCreds: AWSCredentials = { - aws_access_key: - (document.getElementById('accessKey') as HTMLInputElement | null) - ?.value ?? 'Could not find accessKey element', - aws_secret_access_key: - (document.getElementById('secretAccessKey') as HTMLInputElement | null) - ?.value ?? 'Could not find secretAccessKey element', - aws_region: - (document.getElementById('region') as HTMLInputElement | null)?.value ?? - 'Could not find region element', - }; - console.log(locallyStoredUser); - console.log(domCollectedCreds); - updateCredentials({ - aws_access_key: - domCollectedCreds.aws_access_key !== '' - ? domCollectedCreds.aws_access_key - : locallyStoredUser.aws_access_key ?? 'No locally stored access key', - aws_secret_access_key: - domCollectedCreds.aws_secret_access_key !== '' - ? domCollectedCreds.aws_secret_access_key - : locallyStoredUser.aws_secret_access_key ?? - 'No locally stored secret access key', - aws_region: - domCollectedCreds.aws_region !== '' - ? domCollectedCreds.aws_region - : locallyStoredUser.aws_region ?? 'No locally stored region', - }); - } - - return ( -
-
-
-
- Profile -
-
-
-

Username: {user?.username ?? 'Not Logged In'}

-
-
-

Display Name: {user?.display_name ?? 'Not Logged In'}

-
-
-

Work Email: {user?.work_email ?? 'Not Logged In'}

+ + /** + * Handles the submission of AWS credentials by extracting values from form fields, + * validating them, and updating the credentials in the application state. + * + * @returns {void} + */ + function handleCredentialSubmit() { + const locallyStoredUser: UserDetails = JSON.parse( + window.localStorage.getItem('user')! + ) as UserDetails; + + // Retrieve values from input fields by their IDs + const domCollectedCreds: AWSCredentials = { + aws_access_key: + (document.getElementById('accesskey') as HTMLInputElement | null)?.value ?? + 'Could not find accessKey element', // Fallback message if element is not found + aws_secret_access_key: + (document.getElementById('secretAccessKey') as HTMLInputElement | null)?.value ?? + 'Could not find secretAccessKey element', // Fallback message if element is not found + aws_region: + (document.getElementById('region') as HTMLInputElement | null)?.value ?? + 'Could not find region element', // Fallback message if element is not found + }; + + // Log retrieved user details and AWS credentials to the console for debugging purposes + console.log(locallyStoredUser); // Logs the locally stored user details + console.log(domCollectedCreds); // Logs the collected AWS credentials + + // Update credentials, preferring non-empty values from input fields, otherwise use locally stored values + updateCredentials({ + aws_access_key: + domCollectedCreds.aws_access_key !== '' + ? domCollectedCreds.aws_access_key + : locallyStoredUser.aws_access_key ?? 'No locally stored access key', + aws_secret_access_key: + domCollectedCreds.aws_secret_access_key !== '' + ? domCollectedCreds.aws_secret_access_key + : locallyStoredUser.aws_secret_access_key ?? 'No locally stored secret access key', + aws_region: + domCollectedCreds.aws_region !== '' + ? domCollectedCreds.aws_region + : locallyStoredUser.aws_region ?? 'No locally stored region', + }); + } + + return ( +
+ {/* Left container for displaying user profile settings and AWS logo */} +
+
+
+ {/* Profile picture section with a placeholder image URL */} + Profile +
+
+ + {/* Section to display user information with default messages if not logged in */} +
+ {/* Display username or "Not Logged In" if no user data is available */} +
+

Username: {user?.username ?? 'Not Logged In'}

+
+ {/* Display display name or "Not Logged In" if not provided */} +
+

Display Name: {user?.display_name ?? 'Not Logged In'}

+
+ {/* Display work email or "Not Logged In" if not provided */} +
+

Work Email: {user?.work_email ?? 'Not Logged In'}

+
+ {/* Display work phone or "Not Logged In" if not provided */} +
+

Work Phone: {user?.work_phone ?? 'Not Logged In'}

+
+
+ + {/* AWS Logo - Positioned in the left container for branding */} +
+ AWS Logo +
-
-

Work Phone: {user?.work_phone ?? 'Not Logged In'}

+ + {/* Right container where users can input AWS credentials */} +
+ {/* Input field for AWS Access Key */} +
+ + +
+ + {/* Input field for AWS Secret Access Key - hidden input for security */} +
+ + +
+ + {/* Input field for AWS Region - allows users to specify AWS region */} +
+ + +
+ + {/* Button to submit AWS credentials; triggers handleCredentialSubmit function */} + + + {/* Link to AWS login information page - opens in a new tab */} +
- AWS Logo -
-
-
- - -
-
- - -
-
- - -
- - - AWS Log-in Information - -
{/*}
diff --git a/client/src/pages/SignUp.tsx b/client/src/pages/SignUp.tsx index ff3cd9a..694473e 100644 --- a/client/src/pages/SignUp.tsx +++ b/client/src/pages/SignUp.tsx @@ -1,136 +1,169 @@ -// import { deepStrictEqual } from 'assert'; import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; +/** + * SignUp component renders a sign-up form that allows users to create an account with various details. + * + * @returns {React.FC} - A functional component that renders the sign-up form UI and handles sign-up functionality. + */ const SignUp: React.FC = () => { - const [username, setUsername] = useState(''); - const [displayName, setDisplayName] = useState(''); - const [work_email, setWorkEmail] = useState(''); - const [workPhone, setWorkPhone] = useState(''); - const [password, setPassword] = useState(''); - const [confirmPassword, setConfirmPassword] = useState(''); - const [error, setError] = useState(null); - const navigate = useNavigate(); + // Local state variables for form data + const [username, setUsername] = useState(''); // Stores the username entered by the user + const [displayName, setDisplayName] = useState(''); // Stores the display name entered by the user + const [work_email, setWorkEmail] = useState(''); // Stores the work email entered by the user + const [workPhone, setWorkPhone] = useState(''); // Stores the work phone number entered by the user + const [password, setPassword] = useState(''); // Stores the password entered by the user + const [confirmPassword, setConfirmPassword] = useState(''); // Stores the confirmed password for validation + const [error, setError] = useState(null); // Stores any error message to be displayed + const navigate = useNavigate(); // Hook to navigate programmatically - const handleSignUp = async (event: React.FormEvent) => { - event.preventDefault(); - setError(null); + /** + * Handles the sign-up form submission, validating input and making a request to the backend API. + * + * @param {React.FormEvent} event - The form submission event. + * @returns {Promise} - A promise that resolves after handling the sign-up request. + */ + const handleSignUp = async (event: React.FormEvent) => { + event.preventDefault(); // Prevents default form submission behavior + setError(null); // Resets any previous error messages - // Basic form validation - if (!username || !work_email || !password || !confirmPassword) { - setError('Please fill in fields that is mandatory'); - return; - } + // Basic form validation + if (!username || !work_email || !password || !confirmPassword) { + setError('Please fill in fields that is mandatory'); + return; + } - // Email format validation - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - if (!emailRegex.test(work_email)) { - setError('Please enter a valid email address'); - return; - } + // Email format validation + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(work_email)) { + setError('Please enter a valid email address'); + return; + } - // Password match validation - if (password !== confirmPassword) { - setError('Passwords do not match'); - return; - } + // Password match validation + if (password !== confirmPassword) { + setError('Passwords do not match'); + return; + } - try { - //Send resgiter request to the backend - const response = await fetch('/api/signup', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - username, - password, - displayName, - work_email, - workPhone, - }), - }); + try { + // Send register request to the backend + const response = await fetch('/api/signup', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + username, + password, + displayName, + work_email, + workPhone, + }), + }); - if (response.ok) { - navigate('/login'); - } - } catch (err) { - setError('Error signing up. Please try again.'); - console.error(err, 'Error in signup at SignUp.tsx;'); - } - }; + // Handle successful sign-up + if (response.ok) { + navigate('/login'); // Navigate to the login page after successful registration + } else { + setError('Error signing up. Please try again.'); // Display error message if sign-up fails + } + } catch (err) { + setError('Error signing up. Please try again.'); // Displays error for request failure + console.error(err, 'Error in signup at SignUp.tsx'); // Logs the error to console for debugging + } + }; - return ( -
-

Sign Up

- {error &&
{error}
} -
void handleSignUp(event)}> -
- - setUsername(e.target.value)} - required - /> -
-
- - setDisplayName(e.target.value)} - required - /> -
-
- - setWorkEmail(e.target.value)} - required - /> -
-
- - setWorkPhone(e.target.value)} - required - /> -
-
- - setPassword(e.target.value)} - required - /> -
-
- - setConfirmPassword(e.target.value)} - required - /> + return ( +
+ {/* Title of the sign-up form */} +

Sign Up

+ + {/* Error message area that displays any errors that occurred during sign-up */} + {error &&
{error}
} + + {/* Sign-up form that contains input fields for user details */} + void handleSignUp(event)}> + + {/* Username input field: used for entering the desired username */} +
+ + setUsername(e.target.value)} + required // Required field for the sign-up form + /> +
+ + {/* Display name input field: used for entering the name that will be shown publicly */} +
+ + setDisplayName(e.target.value)} + required // Required field for the display name + /> +
+ + {/* Work email input field: used for entering a valid work email address */} +
+ + setWorkEmail(e.target.value)} + required // Required field for a valid work email + /> +
+ + {/* Work phone input field: used for entering a phone number associated with work */} +
+ + setWorkPhone(e.target.value)} + required // Required field for the work phone number + /> +
+ + {/* Password input field: used for entering a password for the account */} +
+ + setPassword(e.target.value)} + required // Required field for the password + /> +
+ + {/* Confirm password input field: used for re-entering the password to ensure accuracy */} +
+ + setConfirmPassword(e.target.value)} + required // Required field for password confirmation + /> +
+ + {/* Submit button to initiate the sign-up process */} + +
- - -
- ); + ); }; export default SignUp;