Skip to content

Commit

Permalink
added trivia page
Browse files Browse the repository at this point in the history
  • Loading branch information
vjnvisakh-jtc committed May 25, 2024
1 parent f4f550a commit fabfa31
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 21 deletions.
7 changes: 4 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "./App.css";
// import BrainIcon from './assets/brain_ai.svg';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { Categories, Login, NotFound } from "./pages";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { Categories, Login, NotFound, Trivia } from "./pages";

// import { Coin, Header, Hero, Logo, Trivia } from "./components/index";

Expand All @@ -11,9 +11,10 @@ function App() {
<Routes>
<Route path="/" index element={<Login />} />
<Route path="/categories" index element={<Categories />} />
<Route path="/trivia" element={<Trivia />} />
<Route path="*" index element={<NotFound />} />
</Routes>
</BrowserRouter>
</BrowserRouter>
// <div className="flex flex-col w-full items-center justify-center text-black">
// <Header>
// <div className="flex justify-between w-full">
Expand Down
10 changes: 5 additions & 5 deletions src/components/trivia/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable react-hooks/exhaustive-deps */
import React, { useEffect, useState } from "react";
import { getTriviaFromGemini } from "../../services/gemini";
import Loader from "../loader";
Expand Down Expand Up @@ -71,15 +70,16 @@ const Trivia: React.FC = () => {
onClick={() => onOptionClick(index)}
key={index}
disabled={isAttempted}
className={`p-4 text-white ${!isAttempted && "bg-black"} ${isAttempted &&
className={`p-4 text-white ${!isAttempted && "bg-black"} ${
isAttempted &&
(index === clickedOptionIndex
? clickedOptionIndex === correctOptionIndex
? "bg-green-500"
: "bg-red-500"
: index === correctOptionIndex
? "bg-green-500"
: "")
}`}
? "bg-green-500"
: "")
}`}
>
{option}
</button>
Expand Down
3 changes: 0 additions & 3 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,4 @@ button:focus-visible {
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
32 changes: 27 additions & 5 deletions src/pages/Categories.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import React, { useEffect, useState } from "react";
import { getTriviaCategoriesFromGemini } from "../services/gemini";
import { useNavigate } from "react-router-dom";

const Categories: React.FC = () => {
const [categories, setCategories] = useState<string[]>(
(JSON.parse(localStorage.getItem("categories") as string) as string[]) || []
);
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);

const navigate = useNavigate();

useEffect(() => {
// So that selected categories are removed from cache.
localStorage.removeItem("selectedCategories");

if (!categories.length) {
getTriviaCategoriesFromGemini().then((result) => {
const sortedResults = result.sort();
Expand All @@ -19,13 +25,26 @@ const Categories: React.FC = () => {
}, []);

const onClickCategory = (category: string) => {
if (!selectedCategories.includes(category)) {
setSelectedCategories([...selectedCategories, category]);
let _selectedCategories = selectedCategories;

if (!_selectedCategories.includes(category)) {
_selectedCategories.push(category);
} else {
setSelectedCategories(
selectedCategories.filter((_category) => _category !== category)
_selectedCategories = _selectedCategories.filter(
(_category) => _category !== category
);
}

localStorage.setItem(
"selectedCategories",
JSON.stringify(_selectedCategories)
);

setSelectedCategories([..._selectedCategories]);
};

const onGetStarted = () => {
navigate("/trivia");
};

return (
Expand All @@ -50,7 +69,10 @@ const Categories: React.FC = () => {
})}
</div>
<div className="mt-10 flex">
<button className="px-10 py-3 m-1 border border-black bg-black text-white shadow-lg tracking-widest flex items-center">
<button
className="px-10 py-3 m-1 border border-black bg-black text-white shadow-lg tracking-widest flex items-center"
onClick={onGetStarted}
>
Get Started{""}
{!!selectedCategories.length && (
<span className="bg-white text-black rounded-full w-6 h-6 items-center justify-center ml-2">
Expand Down
103 changes: 103 additions & 0 deletions src/pages/Trivia.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React, { useEffect, useState } from "react";
import Loader from "../components/loader/index";
import { useQuery } from "@tanstack/react-query";
import { useCoinContext } from "../context/coin";
import { getTriviaFromGemini } from "../services/gemini";

const Trivia: React.FC = () => {
const { isLoading, data, refetch, isRefetching } = useQuery({
queryKey: ["trivia"],
queryFn: async () => {
const selectedCategories = localStorage.getItem("selectedCategories");
return getTriviaFromGemini(
selectedCategories ? JSON.parse(selectedCategories) : []
);
},
});

const { addCoin } = useCoinContext();

const [isAttempted, setIsAttempted] = useState(false);

const [correctOptionIndex, setCorrectOptionIndex] = useState<number>(-1);
const [clickedOptionIndex, setClickedOptionIndex] = useState<number>(-1);

const onOptionClick = (optionIndex: number) => {
setClickedOptionIndex(optionIndex);
setIsAttempted(true);

if (correctOptionIndex === optionIndex) {
addCoin(1);
}
};

const onNexTriviaClick = () => {
setIsAttempted(false);
refetch();
};

useEffect(() => {
if (!isLoading && data?.correctOption) {
setCorrectOptionIndex(
data?.options?.findIndex(
(option: string) => option === data?.correctOption
)
);
}
}, [isLoading, isRefetching]);

return (
<div>
{(isLoading || isRefetching) && <Loader />}
{!isLoading && !isRefetching && (
<div className="flex flex-col text-left">
<div>
<h2 className="font-bold text-2xl">{data?.question}</h2>
</div>
<div className="grid grid-cols-1 mt-4 md:grid-cols-2 gap-1">
{data?.options?.map((option, index) => (
<button
onClick={() => onOptionClick(index)}
key={index}
disabled={isAttempted}
className={`p-4 border border-black ${
!isAttempted &&
"text-black bg-white hover:bg-black hover:text-white"
} ${
isAttempted &&
(index === clickedOptionIndex
? clickedOptionIndex === correctOptionIndex
? "bg-green-500"
: "bg-red-500"
: index === correctOptionIndex
? "bg-green-500"
: "")
}`}
>
{option}
</button>
))}
</div>
{isAttempted && (
<div>
<div className="my-2">
<p className="text-slate-500">{data?.summary}</p>
</div>
<div>
<button
className="text-white bg-black px-4 py-3"
disabled={!isAttempted}
onClick={onNexTriviaClick}
>
Next Question
</button>
</div>
</div>
)}
</div>
)}
</div>
);
};

export default Trivia;
3 changes: 2 additions & 1 deletion src/pages/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Categories from "./Categories";
import Login from "./Login";
import NotFound from "./NotFound";
import Trivia from "./Trivia";

export { Categories, Login, NotFound };
export { Categories, Login, NotFound, Trivia };
14 changes: 10 additions & 4 deletions src/services/gemini.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Trivia } from "../types";
const MODEL_NAME = "gemini-1.0-pro";
const API_KEY = import.meta.env.VITE_GEMINI_API_KEY;

export const getTriviaFromGemini = async (): Promise<Trivia> => {
export const getTriviaFromGemini = async (categories: string[] = []): Promise<Trivia> => {
const genAI = new GoogleGenerativeAI(API_KEY);
const model = genAI.getGenerativeModel({ model: MODEL_NAME });

Expand Down Expand Up @@ -39,9 +39,15 @@ export const getTriviaFromGemini = async (): Promise<Trivia> => {
safetySettings,
});

const result = await chat.sendMessage(
"Give me a unique question with 4 options and one correct option and a medium summary about the correct option. The json should have keys question, options (array of strings with no option number), correctOption, summary and category",
);
let message = '';

if (categories.length) {
message = `Give me a unique question that belongs to categories=${categories.join(',')} with 4 options and one correct option and a medium summary about the correct option. The json should have keys question, options (array of strings with no option number), correctOption, summary and category`;
} else {
message = `Give me a unique question with 4 options and one correct option and a medium summary about the correct option. The json should have keys question, options (array of strings with no option number), correctOption, summary and category`;
}

const result = await chat.sendMessage(message);

const response = result.response;
return JSON.parse(response.text().replace(/^```json|```$/g, '')) as Trivia;
Expand Down

0 comments on commit fabfa31

Please sign in to comment.