Skip to content

Commit

Permalink
Merge branch 'release' into feature/uhx-registration-sp
Browse files Browse the repository at this point in the history
  • Loading branch information
vansharora03 committed Jun 20, 2024
2 parents 19c5f32 + ea30d0c commit 9ba94df
Show file tree
Hide file tree
Showing 4 changed files with 449 additions and 159 deletions.
105 changes: 102 additions & 3 deletions projects/mybyte/context/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,7 @@ export const AuthContextProvider = ({
*/
const checkinUser = async (userid: string) => {
try {
const docRef = doc(registerRef, userid);
await updateDoc(docRef, {
await updateDoc(doc(registerRef, userid ? userid : ""), {
checkedIn: true,
});
setUserInformation(userid);
Expand All @@ -560,6 +559,40 @@ export const AuthContextProvider = ({
}
};

/**
* checks if a user is checked in
* @param userid uuid of the user
* @return boolean true if the user is checked in
*/
const isUserCheckedIn = async (userid: string) => {
try {
const docRef = doc(registerRef, userid);
const docSnap = await getDoc(docRef);

return docSnap.exists() && docSnap.data().checkedIn;
} catch (err: any) {
console.log(err);
}
};

/**
* gets a user's tshirt size by userid
* @param userid uuid of the user
* @return string size of the tshirt
*/
const getTShirtSizeOfUser = async (userid: string) => {
try {
const docRef = doc(registerRef, userid);
const docSnap = await getDoc(docRef);
if (!docSnap.exists()) {
return null;
}
return docSnap.data().shirtSize;
} catch (err: any) {
console.log(err);
}
};

/**
* Accepts a user by userid.
* @param userid uuid of a user
Expand Down Expand Up @@ -649,6 +682,38 @@ export const AuthContextProvider = ({
return docSnap.data().first_name;
};

/**
* Get's user's full name from userid
* @param userid user's uuid
* @returns string of their full name
*/
const getNameOfUser = async (userid: string) => {
const docRef = doc(userRef, userid ? userid : "");
const docSnap = await getDoc(docRef);

if (!docSnap.exists()) {
return null;
}

return docSnap.data().name;
};

/**
* Get's a user's registered events
* @param userid user's id
* @returns an array of registered events
*/
const getRegisteredEventsForUser = async (userid: string) => {
const docRef = doc(userRef, userid ? userid : "");
const docSnap = await getDoc(docRef);

if (!docSnap.exists()) {
return null;
}

return docSnap.data().registered;
};

/**
* Get's a user's registered events
* @param first_name user's first_name
Expand Down Expand Up @@ -806,6 +871,35 @@ export const AuthContextProvider = ({
return false;
};

const removePoints = async (uid: string, number: number) => {
if (
user_type == null ||
user_type == undefined ||
user_type != "service_writer"
)
throw new Error("Unauthorized");
const docRef = doc(userRef, uid);
const docSnap = await getDoc(docRef);

if (!docSnap.exists()) throw "User does not exist";
const points = docSnap.data().points;
if (!points || points < number) {
throw `${docSnap.data().name} does not have enough points!`;
}

try {
updateDoc(docRef, {
points: increment(-1 * number),
});
return true;
} catch (error) {
if (error instanceof FirebaseError) handleError(error);
if (error instanceof Error) throw error;
if (typeof error === "string") throw new Error(error);
}
return false;
};

const checkIn = async (uid: string) => {
if (
user_type == null ||
Expand All @@ -816,7 +910,7 @@ export const AuthContextProvider = ({
const docRef = doc(userRef, uid);
try {
updateDoc(docRef, {
checkIn: true,
checkedIn: true,
});
return true;
} catch (error) {
Expand Down Expand Up @@ -956,7 +1050,10 @@ export const AuthContextProvider = ({
hasFirstAndLastName,
validUser,
getFirstName,
getNameOfUser,
getRegisteredEvents,
getRegisteredEventsForUser,
isUserCheckedIn,
storeUserRegistrationInformation,
setUserInformation,
currEvent,
Expand All @@ -971,13 +1068,15 @@ export const AuthContextProvider = ({
denyTeams,
user_type,
givePoints,
removePoints,
checkIn,
confirmEmails,
confirmedOnTeam,
validateEmails,
giveTeamPoints,
checkinUser,
checkoutUser,
getTShirtSizeOfUser,
triggerRegistrationEmail,
triggerESportsRegistrationEmail,
}}
Expand Down
1 change: 1 addition & 0 deletions projects/mybyte/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"react-dom": "18.2.0",
"react-hook-form": "^7.41.5",
"react-phone-number-input": "^3.2.15",
"react-qr-reader": "^3.0.0-beta-1",
"react-select": "^5.7.0",
"react-select-country-list": "^2.2.3",
"react-tsparticles": "2",
Expand Down
160 changes: 93 additions & 67 deletions projects/mybyte/pages/qrRead.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React, {useState} from "react";
import Html5QrcodePlugin from "../components/Html5QrcodePlugin";
import React, { useState } from "react";
import OrganizerRoute from "../components/OrganizerRoute";
import {useAuth} from "../context/AuthContext";
import {Html5QrcodeScannerState} from "html5-qrcode";
import { useAuth } from "../context/AuthContext";
import { QrReader } from "react-qr-reader";

const initialUser = {
name: "N/A",
shirtSize: "N/A",
};

export default function QrRead(props: any) {
const {
Expand All @@ -13,14 +17,20 @@ export default function QrRead(props: any) {
givePoints,
getNameOfUser,
getRegisteredEventsForUser,
getTShirtSizeOfUser
getTShirtSizeOfUser,
user_type,
} = useAuth();
const [data, setData] = useState("No result");
const [scannedUID, setScannedUID] = useState("");
const [user, setUser] = useState(initialUser);
const [status, setStatus] = useState("Waiting for scan");
const ref = React.useRef<Html5QrcodePlugin | null>(null);

const selectWhich: JSX.Element = (
<select id="what-for">
<select
id="what-for"
className={
"bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
}
>
<option value="checkin-first-day">Check in (Day 1)</option>
<option value="checkin-other">Check in (Other)</option>
<option value="checkout">Check out</option>
Expand All @@ -41,54 +51,49 @@ export default function QrRead(props: any) {
</select>
);

function pauseScanner() {
if (ref.current == null || ref.current?.html5QrcodeScanner == null) return
if (ref.current.html5QrcodeScanner.getState() == Html5QrcodeScannerState.SCANNING) {
ref.current.html5QrcodeScanner.pause();
}
}

function resumeScanner() {
if (ref.current == null || ref.current?.html5QrcodeScanner == null) return
if (ref.current.html5QrcodeScanner.getState() == Html5QrcodeScannerState.PAUSED) {
ref.current.html5QrcodeScanner.resume();
}
}

const determineAction = async (uid: string) => {
// action state kept resetting to its default state for some reason
const val = document
.getElementsByTagName("select")
.namedItem("what-for")?.value;

let outcomeMessage = "";
console.log(user_type);
try {
const name = await getNameOfUser(uid)
if (!uid) throw "No QR Code has been scanned!";
// action state kept resetting to its default state for some reason
if (uid.includes("/")) {
window.alert("Not valid User QR-Code");
return;
} // https://stackoverflow.com/questions/52850099/what-is-the-reg-expression-for-firestore-constraints-on-document-ids

const selectedOption = document
.getElementsByTagName("select")
.namedItem("what-for")?.value;

const name = await getNameOfUser(uid);
if (!name) {
throw new Error("User not found!");
throw "User not found!";
}
outcomeMessage = `Successfully completed ${val} for ${name}`;
switch (val) {
const tShirtSize = await getTShirtSizeOfUser(uid);
setUser({ name: name, shirtSize: tShirtSize });
outcomeMessage = `Successfully completed ${selectedOption} for ${name}`;
switch (selectedOption) {
case "checkin-first-day":
if (!("HACKS9" in await getRegisteredEventsForUser(uid))) {
throw new Error(`${name} is not registered for UGAHacks 9!`);
if (!("HACKS9" in (await getRegisteredEventsForUser(uid)))) {
throw `${name} is not registered for UGAHacks 9!`;
}
if (await isUserCheckedIn(uid)) {
throw new Error(`${name} is already checked in!`);
throw `${name} is already checked in!`;
}
await checkinUser(uid);
givePoints(uid, 100);
outcomeMessage = `Checked in ${name}!\nT-Shirt size: ${await getTShirtSizeOfUser(uid)}`;
outcomeMessage = `Checked in ${name}!`;
break;
case "checkin-other":
if (!("HACKS9" in await getRegisteredEventsForUser(uid))) {
throw new Error(`${name} is not registered for UGAHacks 9!`);
if (!("HACKS9" in (await getRegisteredEventsForUser(uid)))) {
throw `${name} is not registered for UGAHacks 9!`;
}
if (await isUserCheckedIn(uid)) {
throw new Error(`${name} is already checked in!`);
throw `${name} is already checked in!`;
}
checkinUser(uid);
outcomeMessage = `Checked in ${name}!\nT-Shirt size: ${await getTShirtSizeOfUser(uid)}`;
outcomeMessage = `Checked in ${name}!`;
break;
case "checkout":
checkoutUser(uid);
Expand Down Expand Up @@ -154,41 +159,62 @@ export default function QrRead(props: any) {
break;
}
} catch (error) {
if (error instanceof Error) {
outcomeMessage = error.message;
if (typeof error === "string") {
outcomeMessage = error;
} else {
throw error;
}
} finally {
setStatus(outcomeMessage);
window.alert(outcomeMessage);
setScannedUID("");
}
};
let lock = false
return (
<OrganizerRoute>
<Html5QrcodePlugin
ref={ref}
fps={10}
qrbox={250}
disableFlip={false}
qrCodeSuccessCallback={async (decodedText: string, decodedResult: any) => {
if (ref.current == null || ref.current?.html5QrcodeScanner == null) return
if (data === decodedText) return;
if (decodedText.includes("/")) {
window.alert("Not valid User QR-Code");
return;
} // https://stackoverflow.com/questions/52850099/what-is-the-reg-expression-for-firestore-constraints-on-document-ids
if (lock) return;
lock = true;
setData(decodedText);
if (ref.current?.html5QrcodeScanner?.getState() !== Html5QrcodeScannerState.PAUSED) {
await determineAction(decodedText);
}
lock = false;
}}
/>
<span>Status: {status} </span>
<div>Scanner Options:</div>
{selectWhich}
<div className={"flex flex-col justify-center items-center space-x-10"}>
<QrReader
className={"w-full h-full"}
videoStyle={{ height: "100%", width: "100%" }}
constraints={{ facingMode: "back" }}
scanDelay={0}
onResult={async (result, _) => {
if (!result) return;
setScannedUID(result.getText());
}}
/>
<div className={"flex flex-col space-y-2"}>
<div>
Scanned UID: {scannedUID} <br /> <br />
<line></line>
Name: {user.name} <br />
Shirt Size: {user.shirtSize} <br />
</div>
<div>Previous Status: {status} </div>
<label
className={
"block mb-2 text-sm font-medium text-gray-900 dark:text-white"
}
>
Scanner Options:
</label>
{selectWhich}
<div>
<button
className={`py-2.5 px-5 me-2 mb-2 text-sm font-medium focus:outline-none bg-white rounded-lg border border-gray-200 ${
scannedUID === ""
? "text-gray-600"
: "text-gray-900 hover:bg-gray-100 hover:text-blue-700 dark:hover:text-white dark:hover:bg-gray-700"
} focus:z-10 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600`}
onClick={async () => await determineAction(scannedUID)}
disabled={scannedUID === ""}
>
{scannedUID === ""
? "Please Scan a QR Code"
: "Run Selected Action"}
</button>
</div>
</div>
</div>
</OrganizerRoute>
);
}
Loading

0 comments on commit 9ba94df

Please sign in to comment.