Skip to content

Commit

Permalink
21 implementing api endpoints in the frontend (#29)
Browse files Browse the repository at this point in the history
Co-authored-by: AlligatorW <[email protected]>
Co-authored-by: n30w <[email protected]>

closes #26 and #21
  • Loading branch information
reesedychiao authored Mar 18, 2024
1 parent a58a5f0 commit 8b01567
Show file tree
Hide file tree
Showing 33 changed files with 617 additions and 226 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# env
.env
.env.local

# dependencies
frontend/node_modules
frontend/.pnp.cjs
Expand Down Expand Up @@ -27,6 +31,9 @@ frontend/build
.DS_Store
*.pem

# fonts
.woff2

# debug
frontend/npm-debug.log*
frontend/yarn-debug.log*
Expand Down
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"cSpell.words": [
"cmds",
"coursepage",
"corepack",
"Darkspace",
"healthcheck",
Expand Down
14 changes: 14 additions & 0 deletions frontend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# INSTRUCTIONS:
# 1. Make a copy of this in the root of the frontend directory.
# 2. Rename that copy to .env.local
#
# Quotation marks for the key values are optional.

# Name of the API server. This would be "localhost" in a development environment.
API_HOSTNAME=

# Port of the server. The backend's default is 6789.
API_PORT=

# Small note about environment variables...
# According to this link https://nextjs.org/docs/app/building-your-application/configuring/environment-variables#loading-environment-variables: "If you are using a /src folder, please note that Next.js will load the .env files only from the parent folder and not from the /src folder."
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"format:fix": "prettier --write --list-different ./src"
},
"dependencies": {
"@sanity/icons": "^2.11.2",
"next": "14.1.0",
"react": "^18",
"react-dom": "^18"
Expand Down
Binary file added frontend/public/backgrounds/profile-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 58 additions & 0 deletions frontend/src/app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"use client";

import React, { useState } from "react";
import { useRouter } from "next/navigation";
import Image from "next/image";
import Link from "next/link";
import { userAgentFromString } from "next/server";

export default function Page() {
// const [isBlurred, setIsBlurred] = useState(false);
Expand All @@ -11,6 +13,58 @@ export default function Page() {
// setIsBlurred(true);
// };

const [userLogin, setUserLogin] = useState({
email: "",
password: "",
});
const [loginError, setLoginError] = useState<string>("");
const route = useRouter();

const fetchUserInfo = async () => {
try {
const res: Response = await fetch("/v1/user/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(userLogin),
});
if (res.ok) {
const userInfo = await res.json();
return userInfo;
} else {
console.error("Failed to fetch user info:", res.statusText);
return [];
}
} catch (error) {
console.error("Error fetching user info:", error);
return [];
}
};

const handleChange = (e: { target: { name: any; value: any } }) => {
const { name, value } = e.target;
setUserLogin({
...userLogin,
[name]: value,
});
};

const handleSubmit = async (e: { preventDefault: () => void }) => {
e.preventDefault();
const info = await fetchUserInfo();
for (let i = 0; i < info.length; i++) {
if (info[i].email === userLogin.email) {
if (info[i].password === userLogin.password) {
route.push("");
} else {
setLoginError("Wrong password entered");
}
}
}
setLoginError("Wrong email entered");
};

return (
<div className="flex h-screen">
<div className="h-screen bg-black py-8 px-32 w-1/2">
Expand All @@ -37,6 +91,7 @@ export default function Page() {
method="post"
className="flex flex-col"
// onClick={handleFormClick}
onSubmit={handleSubmit}
>
<label htmlFor="email" className="text-white font-light py-2">
Email<span className="text-red-500">*</span>
Expand All @@ -48,6 +103,7 @@ export default function Page() {
placeholder="[email protected]"
required
className="w-80 h-10 px-4 mb-8"
onChange={handleChange}
/>
<label htmlFor="password" className="text-white font-light py-2">
Password<span className="text-red-500">*</span>
Expand All @@ -59,7 +115,9 @@ export default function Page() {
placeholder="••••••••••"
required
className="w-80 h-10 px-4 mb-8"
onChange={handleChange}
/>
{loginError && <p className="text-red-500 pb-2">{loginError}</p>}
<input
type="submit"
value="LOG IN"
Expand Down
98 changes: 76 additions & 22 deletions frontend/src/app/(auth)/signup/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import React, { useState } from "react";
import Image from "next/image";
import Link from "next/link";
import validatePassword from "@/lib/passwordValidator";
import validatePassword from "@/lib/helpers/passwordValidator";

export default function Page() {
// const [isBlurred, setIsBlurred] = useState(false);
Expand All @@ -12,34 +12,61 @@ export default function Page() {
// setIsBlurred(true);
// };

const [password, setPassword] = useState<string>("");
// const [password, setPassword] = useState<string>("");
const [reenteredPassword, setReenteredPassword] = useState<string>("");
const [passwordError, setPasswordError] = useState<string>("");
const [reenteredPasswordError, setReenteredPasswordError] =
useState<string>("");
const [userData, setUserData] = useState({
email: "",
password: "",
netid: "",
});

const handlePasswordChange = (
e: React.ChangeEvent<HTMLInputElement>
): void => {
const newPassword = e.target.value;
setPassword(newPassword);
setPasswordError("");
if (passwordError) setPasswordError("");
};
// const handlePasswordChange = (
// e: React.ChangeEvent<HTMLInputElement>
// ): void => {
// const newPassword = e.target.value;
// setPassword(newPassword);
// setPasswordError("");
// if (passwordError) setPasswordError("");
// };

const handleReenteredPasswordChange = (
e: React.ChangeEvent<HTMLInputElement>
): void => {
const newReenteredPassword = e.target.value;
setReenteredPassword(newReenteredPassword);
setReenteredPasswordError("");
if (reenteredPasswordError) setReenteredPasswordError("");
// const handleReenteredPasswordChange = (
// e: React.ChangeEvent<HTMLInputElement>
// ): void => {
// const newReenteredPassword = e.target.value;
// setReenteredPassword(newReenteredPassword);
// setReenteredPasswordError("");
// if (reenteredPasswordError) setReenteredPasswordError("");
// };

const postNewUser = async (userData: any) => {
try {
const res: Response = await fetch("/v1/user/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(userData),
});
if (res.ok) {
const newUser = await res.json();
newUser.email = userData.email;
newUser.password = userData.password;
newUser.netid = userData.netid;
} else {
console.error("Failed to create user:", res.statusText);
}
} catch (error) {
console.error("Error creating user:", error);
}
};

const handleSubmit = (e: React.FormEvent<HTMLFormElement>): void => {
e.preventDefault();
const isValidPassword = validatePassword(password);
const doPasswordsMatch = password === reenteredPassword;
const isValidPassword = validatePassword(userData.password);
const doPasswordsMatch = userData.password === reenteredPassword;

if (!isValidPassword) {
setPasswordError(
Expand All @@ -52,10 +79,21 @@ export default function Page() {
setReenteredPasswordError("Passwords do not match.");
return;
}

postNewUser(userData);
console.log("Form submitted");
};

const handleChange = (e: { target: { name: any; value: any } }) => {
const { name, value } = e.target;
setUserData({
...userData,
[name]: value,
});
setPasswordError("");
setReenteredPassword(value);
setReenteredPasswordError("");
};

return (
<div className="flex h-screen">
<div className="h-screen bg-black py-8 px-32 w-1/2">
Expand Down Expand Up @@ -84,6 +122,19 @@ export default function Page() {
// onClick={handleFormClick}
onSubmit={handleSubmit}
>
<label htmlFor="email" className="text-white font-light py-2">
NetId<span className="text-red-500">*</span>
</label>
<input
type="text"
id="netid"
name="netid"
placeholder="abc123"
required
className="w-80 h-10 px-4 mb-8"
value={userData.netid}
onChange={handleChange}
/>
<label htmlFor="email" className="text-white font-light py-2">
Email<span className="text-red-500">*</span>
</label>
Expand All @@ -94,6 +145,8 @@ export default function Page() {
placeholder="[email protected]"
required
className="w-80 h-10 px-4 mb-8"
value={userData.email}
onChange={handleChange}
/>
<label htmlFor="password" className="text-white font-light py-2">
Password<span className="text-red-500">*</span>
Expand All @@ -104,8 +157,8 @@ export default function Page() {
name="password"
placeholder="••••••••••"
required
value={password}
onChange={handlePasswordChange}
value={userData.password}
onChange={handleChange}
className={`w-80 h-10 px-4 mb-8 ${
passwordError && "border-red-500"
}`}
Expand All @@ -128,6 +181,7 @@ export default function Page() {
className={`w-80 h-10 px-4 mb-8 ${
reenteredPasswordError && "border-red-500"
}`}
onChange={handleChange}
/>
{reenteredPasswordError && (
<p className="text-red-500 pb-2">{reenteredPasswordError}</p>
Expand Down
Loading

0 comments on commit 8b01567

Please sign in to comment.