From af5a387d692a80b8880e34ab9e8684b91c6fef30 Mon Sep 17 00:00:00 2001 From: Justin Date: Mon, 6 May 2024 09:36:08 -0700 Subject: [PATCH 1/2] updated trivia gen page using classes and components --- .../frontend/src/Components/Choices.jsx | 17 +++++ .../frontend/src/Components/Questions.jsx | 23 +++++++ trivia-forge/frontend/src/Model/Category.jsx | 8 ++- trivia-forge/frontend/src/Model/Choice.jsx | 4 +- trivia-forge/frontend/src/Model/Game.jsx | 12 ++-- trivia-forge/frontend/src/Model/Question.jsx | 5 +- trivia-forge/frontend/src/Model/User.jsx | 7 +- .../frontend/src/Pages/TriviaGenPage.jsx | 69 ++++++++++++++----- .../frontend/src/Pages/TriviaReviewPage.jsx | 16 ++--- .../frontend/src/Services/Services.jsx | 18 +++++ 10 files changed, 136 insertions(+), 43 deletions(-) create mode 100644 trivia-forge/frontend/src/Components/Choices.jsx create mode 100644 trivia-forge/frontend/src/Components/Questions.jsx create mode 100644 trivia-forge/frontend/src/Services/Services.jsx diff --git a/trivia-forge/frontend/src/Components/Choices.jsx b/trivia-forge/frontend/src/Components/Choices.jsx new file mode 100644 index 00000000..02c090a9 --- /dev/null +++ b/trivia-forge/frontend/src/Components/Choices.jsx @@ -0,0 +1,17 @@ +import React from "react"; +import { Choice } from "../Model/Choice"; + +function Choices({ choices }) { + return ( +
+ {choices.map((choice, index) => { + return ( +
+ +
+ ); + })} +
+ ); +} +export default Choices; \ No newline at end of file diff --git a/trivia-forge/frontend/src/Components/Questions.jsx b/trivia-forge/frontend/src/Components/Questions.jsx new file mode 100644 index 00000000..9bfc4967 --- /dev/null +++ b/trivia-forge/frontend/src/Components/Questions.jsx @@ -0,0 +1,23 @@ +import React from "react"; +import Choices from "../Components/Choices"; + +import { Question } from "../Model/Question"; + +function Questions({ data }) { + let choices = data.choices; + return ( +
+
+ +
+ +
+ +
+
+ +
+
+ ) +} +export default Questions; \ No newline at end of file diff --git a/trivia-forge/frontend/src/Model/Category.jsx b/trivia-forge/frontend/src/Model/Category.jsx index c6eef12c..0e314fa8 100644 --- a/trivia-forge/frontend/src/Model/Category.jsx +++ b/trivia-forge/frontend/src/Model/Category.jsx @@ -1,11 +1,15 @@ export class Category { - constructor(id, name, gameID) { - this.id = id; + constructor(name, gameID = null) { + this.id = null; this.name = name; this.gameID = gameID this.questions = []; } + addQuestion(question) { + this.questions.push(question); + } + toJsonObject() { return { id: this.id, diff --git a/trivia-forge/frontend/src/Model/Choice.jsx b/trivia-forge/frontend/src/Model/Choice.jsx index b00ed292..e4b46a17 100644 --- a/trivia-forge/frontend/src/Model/Choice.jsx +++ b/trivia-forge/frontend/src/Model/Choice.jsx @@ -1,6 +1,6 @@ export class Choice { - constructor(id, choice, questionID) { - this.id = id; + constructor(choice, questionID = null) { + this.id = null; this.choice = choice; this.questionID = questionID; } diff --git a/trivia-forge/frontend/src/Model/Game.jsx b/trivia-forge/frontend/src/Model/Game.jsx index 8f2e23b1..9b5be3b4 100644 --- a/trivia-forge/frontend/src/Model/Game.jsx +++ b/trivia-forge/frontend/src/Model/Game.jsx @@ -1,20 +1,18 @@ export class Game { - constructor(id, userID, date, name, questions) { - this.id = id; - this.date = date; + constructor(name, date, userID = null) { + this.id = null; this.name = name; - this.questions = []; + this.categories = []; this.userID = userID; } - addGame(question) { - this.questions.push(question); + addCategory(category) { + this.categories.push(category); } toJsonObject() { return { id: this.id, - date: this.date, name: this.name, userID: this.userID } diff --git a/trivia-forge/frontend/src/Model/Question.jsx b/trivia-forge/frontend/src/Model/Question.jsx index 9616795d..5794ed91 100644 --- a/trivia-forge/frontend/src/Model/Question.jsx +++ b/trivia-forge/frontend/src/Model/Question.jsx @@ -1,8 +1,9 @@ export class Question { - constructor(id, question, answer, categoryID) { - this.id = id; + constructor(question, answer, hint, categoryID = null) { + this.id = null; this.question = question; this.answer = answer; + this.hint = hint; this.categoryID = categoryID; this.choices = []; } diff --git a/trivia-forge/frontend/src/Model/User.jsx b/trivia-forge/frontend/src/Model/User.jsx index fa3f6982..91896b1e 100644 --- a/trivia-forge/frontend/src/Model/User.jsx +++ b/trivia-forge/frontend/src/Model/User.jsx @@ -1,7 +1,7 @@ +import datetime from 'node-datetime'; export class User { - constructor(id, date, email, password, profilePic) { - this.id = id; - this.date = date; + constructor(date, email, password, profilePic = null) { + this.id = null; this.email = email; this.password = password; this.profilePic = profilePic; @@ -14,7 +14,6 @@ export class User { toJsonObject() { return { id: this.id, - date: this.date, email: this.email, password: this.password, profilePic: this.profilePic diff --git a/trivia-forge/frontend/src/Pages/TriviaGenPage.jsx b/trivia-forge/frontend/src/Pages/TriviaGenPage.jsx index 4d53adfb..b1e8f197 100644 --- a/trivia-forge/frontend/src/Pages/TriviaGenPage.jsx +++ b/trivia-forge/frontend/src/Pages/TriviaGenPage.jsx @@ -1,6 +1,10 @@ import React, { useState } from "react"; // variables that cause the component to re-render when they change import OpenAI from "openai"; +import { Game } from "../Model/Game"; import { useNavigate } from "react-router-dom"; +import { Question } from "../Model/Question"; +import { Choice } from "../Model/Choice"; +import { Category } from "../Model/Category"; // initialize openai client using configuration specified in vite environment variables @@ -16,17 +20,17 @@ function TriviaGenPage() { const [category, setCategory] = useState(''); const [isMultipleChoice, setIsMultipleChoice] = useState(false); const navigate = useNavigate(); - + const handleSubmit = async (event) => { event.preventDefault(); // prevent default form submission behavior(browser reload) - + //for each category let prompt = `Generate ${numberOfQuestions} trivia questions about ${category}.`; if (isMultipleChoice) { - prompt += "Each question should include four multiple-choice options, the correct answer, and a fun fact. Separate each component with a newline."; + prompt += "Each question should be in the format Question:...\nChoice:...\nChoice:...\nChoice:...\nChoice:...\nAnswer:...\nHint:...\n---\nQuestion:... ect. include four multiple-choice options"; } else { - prompt += "Each question should come with its answer and a fun fact. Separate each component with a newline."; + prompt += "Each question should be in the format \nQuestion:...\nAnswer:...\n---\nQuestion:... ect."; } // api call @@ -35,17 +39,46 @@ function TriviaGenPage() { // API call to OpenAI const completion = await openai.chat.completions.create({ model: "gpt-3.5-turbo", - messages: [{role: "user", content: prompt }], + messages: [{ role: "user", content: prompt }], // adjust and use token limit if necessary // max_tokens: 200 // implment and adjust temperature if needed // temperature scale is 0-1 and used to tune randomness of output // temperature: .5 }); - - const questions = completion.choices[0].message.content.split('\n'); // store trivia questions + //create a new game and category object and add category to game + let game = new Game(); + let newCategory = new Category(category); + game.addCategory(newCategory); + + //parse response from API + let sections = completion.choices[0].message.content.split('\n'); // store trivia questions + + //loop through sections and create question and choice objects + for (let i = 0; i < sections.length; i += 7) { + let question = sections[i]; + let choices = []; + for (let k = 0; k < 4; k++) { + let choice = sections[i + k + 1]; + let newChoice = new Choice(choice); + choices.push(newChoice); + } + let answer = sections[i + 5]; + let hint = sections[i + 6]; + + //create question object and add it to category + let newQuestion = new Question(question, answer, hint); + newCategory.addQuestion(newQuestion); + + //add choices to question object + for (let i = 0; i < choices.length; i++) { + newQuestion.addChoice(choices[i]); + } + + + } // state property to pass data as object to new route - navigate('/review', { state: { questions } }); + navigate('/review', { state: { game } }); //console.log(completion.choices[0].message); } catch (error) { console.error('Error calling OpenAI API:', error); @@ -61,34 +94,34 @@ function TriviaGenPage() {
- setNumberOfQuestions(Math.min(10, Math.max(1, parseInt(e.target.value, 10))))} - className="form-control" - id="triviaTitle" - placeholder="Number of Questions" + className="form-control" + id="triviaTitle" + placeholder="Number of Questions" />
- setCategory(e.target.value)} - className="form-control" - id="triviaCategory" - placeholder="Category" + className="form-control" + id="triviaCategory" + placeholder="Category" />
- setIsMultipleChoice(e.target.value)} //className="form-control" - id="multipleChoice" + id="multipleChoice" />
diff --git a/trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx b/trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx index a15fa198..37d6aab5 100644 --- a/trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx +++ b/trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx @@ -1,21 +1,21 @@ import React from 'react'; import { useLocation } from 'react-router-dom'; // used to access passed state +import Questions from '../Components/Questions'; function TriviaReviewPage() { // Reference: https://reactrouter.com/en/main/hooks/use-location // pulls object from state property in TriviaGenPage const location = useLocation(); - const { questions } = location.state; - + const { game } = location.state; + let category = game.categories[0]; + let questions = category.questions; return (

Review and Edit Trivia Questions

- {questions.map((question, index) => ( -
-
- -
-
+ + {questions.map((q, index) => ( + + ))}
); diff --git a/trivia-forge/frontend/src/Services/Services.jsx b/trivia-forge/frontend/src/Services/Services.jsx new file mode 100644 index 00000000..1f02d816 --- /dev/null +++ b/trivia-forge/frontend/src/Services/Services.jsx @@ -0,0 +1,18 @@ +import * as db from './TF-db_services'; + +export const addAllForGame = async (game) => { + const newGame = await db.addGame(game); + game.categories.forEach(async (category) => { + category.gameID = newGame.id; + const newCategory = await db.addCategory(category); + category.questions.forEach(async (question) => { + question.categoryID = newCategory.id; + const newQuestion = await db.addQuestion(question); + question.choices.forEach(async (choice) => { + choice.questionID = newQuestion.id; + await db.addChoice(choice); + }); + }); + }); + return newGame; +} \ No newline at end of file From e70b29d78911e545ff654ef270b1e920d0aaa1bc Mon Sep 17 00:00:00 2001 From: Justin Date: Mon, 6 May 2024 10:24:15 -0700 Subject: [PATCH 2/2] more stuff --- trivia-forge/frontend/src/App.css | 13 ++++++++- .../frontend/src/Components/Questions.jsx | 27 ++++++++++++------- .../frontend/src/Pages/TriviaGenPage.jsx | 4 ++- .../frontend/src/Pages/TriviaReviewPage.jsx | 3 +++ 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/trivia-forge/frontend/src/App.css b/trivia-forge/frontend/src/App.css index b4ccd15b..df652cc9 100644 --- a/trivia-forge/frontend/src/App.css +++ b/trivia-forge/frontend/src/App.css @@ -104,9 +104,20 @@ background-color: white; } +h2 { + text-align: center; +} + +.CardPadding { + margin: 20px; + background-color: bisque; +} + footer { - position: absolute; + position: fixed; bottom: 0; + background-color: #282c34; + color: white; text-align: center; width: 100%; } diff --git a/trivia-forge/frontend/src/Components/Questions.jsx b/trivia-forge/frontend/src/Components/Questions.jsx index 9bfc4967..d1b5895e 100644 --- a/trivia-forge/frontend/src/Components/Questions.jsx +++ b/trivia-forge/frontend/src/Components/Questions.jsx @@ -1,5 +1,6 @@ import React from "react"; import Choices from "../Components/Choices"; +import { Card } from "react-bootstrap"; import { Question } from "../Model/Question"; @@ -7,16 +8,22 @@ function Questions({ data }) { let choices = data.choices; return (
-
- -
- -
- -
-
- -
+ +

Question

+
+ +
+

Choices

+ +

Answer

+
+ +
+

Hint

+
+ +
+
) } diff --git a/trivia-forge/frontend/src/Pages/TriviaGenPage.jsx b/trivia-forge/frontend/src/Pages/TriviaGenPage.jsx index b1e8f197..c3e4f09d 100644 --- a/trivia-forge/frontend/src/Pages/TriviaGenPage.jsx +++ b/trivia-forge/frontend/src/Pages/TriviaGenPage.jsx @@ -53,7 +53,9 @@ function TriviaGenPage() { //parse response from API let sections = completion.choices[0].message.content.split('\n'); // store trivia questions - + for (let i = 0; i < sections.length; i++) { + if (sections[i] === '') { sections.splice(i, 1); } + } //loop through sections and create question and choice objects for (let i = 0; i < sections.length; i += 7) { let question = sections[i]; diff --git a/trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx b/trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx index 37d6aab5..dfd7607f 100644 --- a/trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx +++ b/trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx @@ -1,6 +1,7 @@ import React from 'react'; import { useLocation } from 'react-router-dom'; // used to access passed state import Questions from '../Components/Questions'; +import { Button } from 'react-bootstrap'; function TriviaReviewPage() { // Reference: https://reactrouter.com/en/main/hooks/use-location @@ -17,6 +18,8 @@ function TriviaReviewPage() { ))} + ); }