Skip to content

Commit

Permalink
Merge pull request #197 from ugahacks/feature/scanner_hotfix
Browse files Browse the repository at this point in the history
Hopefully fixing scanner
  • Loading branch information
Kasra-G authored Feb 10, 2024
2 parents e614fc6 + 3e64bfb commit 9914542
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 64 deletions.
105 changes: 102 additions & 3 deletions projects/mybyte/context/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -527,8 +527,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 @@ -553,6 +552,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 @@ -642,6 +675,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 @@ -799,6 +864,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 @@ -809,7 +903,7 @@ export const AuthContextProvider = ({
const docRef = doc(userRef, uid);
try {
updateDoc(docRef, {
checkIn: true,
checkedIn: true,
});
return true;
} catch (error) {
Expand Down Expand Up @@ -949,7 +1043,10 @@ export const AuthContextProvider = ({
hasFirstAndLastName,
validUser,
getFirstName,
getNameOfUser,
getRegisteredEvents,
getRegisteredEventsForUser,
isUserCheckedIn,
storeUserRegistrationInformation,
setUserInformation,
currEvent,
Expand All @@ -964,13 +1061,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
133 changes: 72 additions & 61 deletions projects/mybyte/pages/qrRead.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import React, {useState} from "react";
import Html5QrcodePlugin from "../components/Html5QrcodePlugin";
import OrganizerRoute from "../components/OrganizerRoute";
import {useAuth} from "../context/AuthContext";
import {Html5QrcodeScannerState} from "html5-qrcode";
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 +18,15 @@ 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 +47,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 {
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!`);
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!`);
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 +155,51 @@ 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);
setScannedUID("")
window.alert(outcomeMessage);
}
};
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-row justify-center items-center space-x-10"}>
<QrReader
className={"w-1/3 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 9914542

Please sign in to comment.