Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connect login page #63

Merged
merged 10 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
REACT_APP_API_ENDPOINT=
elvincheng3 marked this conversation as resolved.
Show resolved Hide resolved
18 changes: 9 additions & 9 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"editor.formatOnSave": true,
"eslint.validate": ["typescript", "typescriptreact"],
"eslint.workingDirectories": [{ "mode": "auto" }],
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.organizeImports": true,
"source.sortMembers": true
}
}
"editor.formatOnSave": true,
"eslint.validate": ["typescript", "typescriptreact"],
"eslint.workingDirectories": [{ "mode": "auto" }],
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit",
"source.sortMembers": "explicit"
}
}
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@
"@types/react-dom": "^18.0.0",
"@types/react-lottie": "^1.2.6",
"@types/react-router-dom": "^5.3.3",
"axios": "^1.7.7",
"dotenv": "^16.4.5",
"headlessui": "^0.0.0",
"heroicons": "^2.0.11",
"localforage": "^1.10.0",
"match-sorter": "^6.3.1",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.10.0",
"react-lottie": "^1.2.3",
"react-router-dom": "^6.10.0",
"react-scripts": "5.0.1",
"sort-by": "^1.2.0",
"tw-elements": "^1.0.0-beta1",
Expand Down Expand Up @@ -63,4 +65,4 @@
"tailwindcss": "^3.1.8",
"ts-jest": "^29.0.3"
}
}
}
33 changes: 23 additions & 10 deletions src/client/client.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from "axios";
import { mockAttendanceChange } from "../data/attendanceChange";
import { mockAttendanceRecord } from "../data/attendanceRecord";
import { mockEvents } from "../data/events";
import UserJSON from "../data/users.json";
import {
AttendanceChange,
AttendanceRecord,
Expand All @@ -11,6 +11,11 @@ import {
RequestType,
} from "../util/Types";

type GenericResponse<T> = {
data?: T;
error: string;
};

/**
* Gets an event with the given id
* @param id The id of the event being fetched
Expand Down Expand Up @@ -42,15 +47,23 @@ export function fetchAllEvents(): Promise<Event[]> {
* @param nuid The nuid of the member
* @returns The Member with that nuid or undefined
*/
export function fetchMember(nuid: string): Promise<Member | undefined> {
return new Promise((resolve, reject) => {
setTimeout(() => {
const member = (UserJSON as unknown as Member[]).find(
(m) => m.nuid === nuid
);
resolve(member);
});
});
export async function fetchMember(
nuid: string
): Promise<GenericResponse<Member>> {
const response = await axios.get(
`${process.env.REACT_APP_API_ENDPOINT}/api/member/getMember/?id=${nuid}`
elvincheng3 marked this conversation as resolved.
Show resolved Hide resolved
);
if (response.status === 200) {
return {
data: response.data.member,
error: "",
};
} else {
return {
data: undefined,
error: response.data,
};
}
}

//sample function to fetch all attendance change requests
Expand Down
4 changes: 2 additions & 2 deletions src/components/AttendanceButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ export const AttendanceButton = ({
setIsCreatingAttendance(true);
//using non-null assertion since it's assumed the user is logged in to make it past the home page
const member = await fetchMember(userID!);
if (member) {
await createAttendanceChange(member.id, eventid);
if (member.data) {
await createAttendanceChange(member.data.id, eventid);
setIsRegistered(false);
}
setIsCreatingAttendance(false);
Expand Down
48 changes: 28 additions & 20 deletions src/components/PopUp.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
import { ReactElement } from "react";
import { LoginError } from "../util/Types";

const PopUp = (props: {
source: string
message1: string
message2?: string
link?: string
useState: React.Dispatch<React.SetStateAction<number>>;
source: string;
message1: string;
message2?: string;
link?: string;
useState: React.Dispatch<React.SetStateAction<LoginError>>;
}): ReactElement => {

return (
<div className="fixed top-0 right-0 bottom-0 left-0 m-auto bg-[hsla(0,0%,0%,.5)] h-screen w-screen flex justify-center items-center z-50">
<div className="flex items-center flex-col h-2/4 w-2/4 my-2.5 bg-white text-white text-2xl font-semibold rounded-lg px-4 py-4">
<img src={props.source} alt="Error Icon" className="py-4" />
<div className="py-3 flex justify-center items-center flex-col justify-between h-full text-black">
<p>{props.message1}</p>
{props.link ? <a href={props.link}>{props.link}</a> : <p>{props.message2}</p>}
<button className="my-2.5 h-1/4 w-2/4 bg-black text-white text-2xl font-semibold rounded-lg hover:bg-[hsla(0, 0%, 75%)] active:bg-black" onClick={() => props.useState(0)}>Accept</button>
</div>
</div>
return (
<div className="fixed top-0 right-0 bottom-0 left-0 m-auto bg-[hsla(0,0%,0%,.5)] h-screen w-screen flex justify-center items-center z-50">
<div className="flex items-center flex-col h-2/4 w-2/4 my-2.5 bg-white text-white text-2xl font-semibold rounded-lg px-4 py-4">
<img src={props.source} alt="Error Icon" className="py-4" />
<div className="py-3 flex justify-center items-center flex-col justify-between h-full text-black">
<p>{props.message1}</p>
{props.link ? (
<a href={props.link}>{props.link}</a>
) : (
<p>{props.message2}</p>
)}
<button
className="my-2.5 h-1/4 w-2/4 bg-black text-white text-2xl font-semibold rounded-lg hover:bg-[hsla(0, 0%, 75%)] active:bg-black"
onClick={() => props.useState(LoginError.NONE)}
>
Accept
</button>
</div>
</div>
</div>
);
};

);
}

export default PopUp;
export default PopUp;
6 changes: 4 additions & 2 deletions src/pages/AttendanceRecordPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ const AttendanceRecordPage = () => {
const fetchMemberRecord = async (): Promise<Event[]> => {
// Update the member from the API
const member = await fetchMember(userID!);
elvincheng3 marked this conversation as resolved.
Show resolved Hide resolved
setMember(member);
setMember(member.data);

// Get the attendance records for the selected member
const attendanceRecords = await getAttendanceRecordForMember(member!.id);
const attendanceRecords = await getAttendanceRecordForMember(
member.data!.id
);
setAttendanceRecord(attendanceRecords);

// Fetch the event data for each event
Expand Down
6 changes: 3 additions & 3 deletions src/pages/Homepage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ const Homepage = (): ReactElement => {
useEffect(() => {
//only go on load
const loadAttendanceChanges = async () => {
const Member = await fetchMember(userID!);
if (Member) {
const member = (await fetchMember(userID!)).data;
if (member) {
const attendance = await findAttendanceChangeRequestForMember(
Member.id
member.id
);
if (attendance) setAttendanceChanges(attendance);
}
Expand Down
82 changes: 45 additions & 37 deletions src/pages/LoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import TriangleError from "../assets/TriangleError.svg";
import UnknownError from "../assets/UnknownError.svg";
import { fetchMember } from "../client/client";
import PopUp from "../components/PopUp";
import { Member } from "../util/Types";
import { LoginError, Member } from "../util/Types";

const LoginPage = (): ReactElement => {
const { setUserID } = useContext(LoginContext);
const [input, setInput] = useState(""); // value is the value that the user entered
const [lastName, setLastName] = useState(""); // value to keep track of inputted last name
const [errorType, setErrorType] = useState(0); // type of error that occured when we log in 0-3
const [errorType, setErrorType] = useState<LoginError>(LoginError.NONE); // type of error that occured when we log in 0-3
const [smallErrMsg, setSmallErrMsg] = useState<String>();

const navigate = useNavigate();
Expand All @@ -35,40 +35,46 @@ const LoginPage = (): ReactElement => {
* sign in is blocked, display the aapropriate error message
*/
async function login() {
setErrorType(0); // No error message before they get a response back
setErrorType(LoginError.NONE); // No error message before they get a response back
if (!isValidNuid(input)) {
console.log("Invalid NUID when log in pressed.");
setSmallErrMsg("Should be 9 digits.");
setErrorType(1);
setErrorType(LoginError.OTHER);
return;
}
let member = undefined;
try {
member = await fetchMember(input); // CHANGE TO API IMPL
} catch (e) {
setErrorType(4);
return;
}
if (!member) {
setErrorType(1);
setSmallErrMsg("Member does not exist.");
} else {
if (
whetherHasAccess(member) &&
member.lastName.toUpperCase() === lastName.toUpperCase()
) {
localStorage.setItem("user", input);
setUserID(input);
navigate("/events");
} else if (!member.activeMember) {
setErrorType(2);
} else if (member.signInBlocked) {
setErrorType(3);
} else {
console.log("in 4?");
setErrorType(4);
}
}
await fetchMember(input)
elvincheng3 marked this conversation as resolved.
Show resolved Hide resolved
.then((response) => {
if (response.error) {
// received error from server
if (response.error === "Member does not exist.") {
setErrorType(LoginError.DOES_NOT_EXIST);
} else if (response.error === "Database Error") {
setErrorType(LoginError.OTHER);
}
setSmallErrMsg(response.error);
} else if (!response.data) {
// no data from server
setErrorType(LoginError.OTHER);
setSmallErrMsg("Unknown error fetching member");
} else {
if (
whetherHasAccess(response.data) &&
response.data.lastName.toUpperCase() === lastName.toUpperCase()
) {
localStorage.setItem("user", input);
setUserID(input);
navigate("/events");
} else if (!response.data.activeMember) {
setErrorType(LoginError.DEACTIVATED);
} else if (response.data.signInBlocked) {
setErrorType(LoginError.BLOCKED);
}
}
})
.catch((_) => {
console.log(_);
setErrorType(LoginError.UNKNOWN);
});
}

/**
Expand All @@ -86,28 +92,30 @@ const LoginPage = (): ReactElement => {
* @returns true if the given member is an active member and is not blocked from sign in, false otherwise
*/
function whetherHasAccess(member: Member): boolean {
return member.activeMember && !member.signInBlocked;
// console.log(member);
// return member.activeMember && !member.signInBlocked;
return true;
}

return (
<div onLoad={checkIfLoginSaved}>
{errorType === 2 ? (
{errorType === LoginError.DEACTIVATED ? (
<PopUp
source={TriangleError}
message1="Your account has been inactivated."
elvincheng3 marked this conversation as resolved.
Show resolved Hide resolved
message1="Your account has been deactivated."
message2="Please contact your administrator if this is a mistake."
useState={setErrorType}
/>
) : null}
{errorType === 3 ? (
{errorType === LoginError.BLOCKED ? (
<PopUp
source={TriangleError}
message1="You are not allowed to log in."
message2="Please contact your administrator if this is a mistake."
useState={setErrorType}
/>
) : null}
{errorType === 4 ? (
{errorType === LoginError.UNKNOWN ? (
<PopUp
source={UnknownError}
message1="We ran into an unknown error."
Expand Down Expand Up @@ -182,7 +190,7 @@ const LoginPage = (): ReactElement => {
>
Log In
</button>
{errorType === 1 && smallErrMsg && (
{errorType === LoginError.OTHER && smallErrMsg && (
<div className="flex flex-start">
<img src={ErrorSvg} alt="Error icon" className="h-5" />
<p className="font-sans text-sga-red px-2">{smallErrMsg}</p>
Expand Down
6 changes: 3 additions & 3 deletions src/pages/UserPreference.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ const UserPreference = (): ReactElement => {

if (id) {
fetchMember(id).then((m) => {
if (m) {
setMember(m);
setNotPresentEmail(m.receiveNotPresentEmail);
if (m.data) {
setMember(m.data);
setNotPresentEmail(m.data.receiveNotPresentEmail);
}
});
}
Expand Down
9 changes: 9 additions & 0 deletions src/util/Types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,12 @@ export type AttendanceRecord = {
};

export type AttendanceTag = "K" | "A" | "L" | "D" | "O" | "N" | "E";

export enum LoginError {
DEACTIVATED,
BLOCKED,
OTHER,
DOES_NOT_EXIST,
NONE,
UNKNOWN,
}
Loading
Loading