Skip to content

Commit

Permalink
Merge pull request #12 from ethanl21/leaderboard
Browse files Browse the repository at this point in the history
Leaderboard
  • Loading branch information
jose-gonzalez1 authored Oct 29, 2023
2 parents bbb9337 + b606015 commit 1afc83f
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { setRating } from "./tasks/setRating";
import { AuthCard } from "./components/AuthCard";
import { RatingPickerCard } from "./components/RatingPickerCard";
import { ProfilePage } from "./components/ProfilePage";
import { Leaderboard } from "./components/Leaderboard";

function App() {
const [authActionType, setAuthActionType] = useState<"signup" | "signin">(
Expand Down Expand Up @@ -192,7 +193,9 @@ function App() {
<ProfilePage handleSignOut={handleSignOut} />
</Tab>

<Tab eventKey="leaderboard" title="Leaderboard"></Tab>
<Tab eventKey="leaderboard" title="Leaderboard" disabled={!auth}>
<Leaderboard />
</Tab>

{/* Tab used to upload new images
<Tab eventKey="uploadItem" title="Upload">
Expand Down
17 changes: 17 additions & 0 deletions src/components/FirebaseImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { getDownloadURL, ref } from "firebase/storage";
import { useEffect, useState } from "react";
import { ImageProps } from "react-bootstrap";
import { storage } from "../config/firebase";
import Image from "react-bootstrap/Image";

export const FirebaseImage = ({ ...props }: ImageProps) => {
const [imageSrc, setImageSrc] = useState("");

useEffect(() => {
getDownloadURL(ref(storage, props.src)).then((val) => {
setImageSrc(val);
});
}, [props.src]);

return <Image {...props} src={imageSrc} />;
};
89 changes: 89 additions & 0 deletions src/components/Leaderboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import Button from "react-bootstrap/Button";
import Table from "react-bootstrap/Table";
import {
RatingItem,
getHighestRatedItems,
getLowestRatedItems,
} from "../tasks/getRatingItems";
import { auth as fAuth } from "../config/firebase";
import { useEffect, useState } from "react";
import { nanoid } from "nanoid";
import { useAuthState } from "react-firebase-hooks/auth";
import {
BsFillHandThumbsDownFill,
BsFillHandThumbsUpFill,
} from "react-icons/bs";
import { FirebaseImage } from "./FirebaseImage";
import Container from "react-bootstrap/Container";

const getTableBody = (items: Array<RatingItem>) => {
return items.map((val, idx) => {
return (
<tr key={nanoid()}>
<td>{idx + 1}</td>
<td>{val.name}</td>
<td>
<FirebaseImage src={val.image} thumbnail width="100" />
</td>
<td>{val.averageRating}</td>
</tr>
);
});
};

export const Leaderboard = () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [auth, authLoading, authError] = useAuthState(fAuth);
const [leaderboardItems, setLeaderboardItems] = useState<Array<RatingItem>>(
[],
);
const [leaderboardSort, setLeaderboardSort] = useState("desc");

useEffect(() => {
if (auth) {
if (leaderboardSort === "desc") {
getHighestRatedItems(10).then((items) => {
setLeaderboardItems(items);
});
} else {
getLowestRatedItems(10).then((items) => {
setLeaderboardItems(items);
});
}
}
}, [auth, leaderboardSort]);

return (
<>
<h1>
{leaderboardSort === "desc" ? "Highest" : "Lowest"} Rated Items&nbsp;
<Button
onClick={() => {
leaderboardSort === "desc"
? setLeaderboardSort("asc")
: setLeaderboardSort("desc");
}}
>
{leaderboardSort === "desc" ? (
<BsFillHandThumbsUpFill />
) : (
<BsFillHandThumbsDownFill />
)}
</Button>
</h1>
<Container>
<Table striped bordered hover responsive>
<thead>
<tr>
<td>#</td>
<td>Name</td>
<td>Image</td>
<td>Average Rating</td>
</tr>
</thead>
<tbody>{leaderboardItems && getTableBody(leaderboardItems)}</tbody>
</Table>
</Container>
</>
);
};
54 changes: 54 additions & 0 deletions src/tasks/getRatingItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
limit,
doc,
Timestamp,
orderBy,
where,
} from "firebase/firestore";
import { ref } from "firebase/storage";
import { auth, db, storage } from "../config/firebase";
Expand Down Expand Up @@ -47,6 +49,58 @@ export const getRatingItems = async (count: number) => {
}
};

export const getHighestRatedItems = async (count: number) => {
if (!auth.currentUser) {
return Promise.reject("Only logged in users can view rating items.");
}

try {
const q = query(
collection(db, "rating-items"),
orderBy("ratingCount"),
where("ratingCount", ">", 0),
orderBy("averageRating", "desc"),
limit(count),
);
const querySnapshot = await getDocs(q);

const returnedRatingItems: Array<RatingItem> = [];
querySnapshot.docs.forEach((doc) => {
returnedRatingItems.push(doc.data() as RatingItem);
});

return Promise.resolve(returnedRatingItems);
} catch (err) {
return Promise.reject(err);
}
};

export const getLowestRatedItems = async (count: number) => {
if (!auth.currentUser) {
return Promise.reject("Only logged in users can view rating items.");
}

try {
const q = query(
collection(db, "rating-items"),
orderBy("ratingCount"),
where("ratingCount", ">", 0),
orderBy("averageRating", "asc"),
limit(count),
);
const querySnapshot = await getDocs(q);

const returnedRatingItems: Array<RatingItem> = [];
querySnapshot.docs.forEach((doc) => {
returnedRatingItems.push(doc.data() as RatingItem);
});

return Promise.resolve(returnedRatingItems);
} catch (err) {
return Promise.reject(err);
}
};

/**
* @brief Gets a single rating item, if it exists
* @param id id of the rating to get
Expand Down

0 comments on commit 1afc83f

Please sign in to comment.