diff --git a/trivia-forge/frontend/src/App.css b/trivia-forge/frontend/src/App.css
index c54bafaa..b72f390f 100644
--- a/trivia-forge/frontend/src/App.css
+++ b/trivia-forge/frontend/src/App.css
@@ -104,9 +104,21 @@
background-color: white;
}
+h2 {
+ text-align: center;
+}
+
+.CardPadding {
+ margin: 20px;
+ padding: 10px;
+ 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/Categories.jsx b/trivia-forge/frontend/src/Components/Categories.jsx
new file mode 100644
index 00000000..0e2ff42a
--- /dev/null
+++ b/trivia-forge/frontend/src/Components/Categories.jsx
@@ -0,0 +1,17 @@
+import React from "react";
+import Questions from "../Components/Questions";
+
+function Categories({ category }) {
+ let questions = category.questions;
+ return (
+
+
{category.name}
+ {questions.map((question, index) => {
+ return (
+
+ );
+ })}
+
+ );
+}
+export default Categories;
\ No newline at end of file
diff --git a/trivia-forge/frontend/src/Components/Choices.jsx b/trivia-forge/frontend/src/Components/Choices.jsx
new file mode 100644
index 00000000..15ad2bc7
--- /dev/null
+++ b/trivia-forge/frontend/src/Components/Choices.jsx
@@ -0,0 +1,17 @@
+import React from "react";
+
+
+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..3daaf5cf
--- /dev/null
+++ b/trivia-forge/frontend/src/Components/Questions.jsx
@@ -0,0 +1,31 @@
+import React from "react";
+import Choices from "../Components/Choices";
+import { Card } from "react-bootstrap";
+
+import { Question } from "../Model/Question";
+
+function Questions({ data }) {
+ let choices = data.choices;
+ return (
+
+
+ Question
+
+
+
+ Choices
+
+ Answer
+
+
+
+ Hint
+
+
+
+
+
+
+ )
+}
+export default Questions;
\ No newline at end of file
diff --git a/trivia-forge/frontend/src/Models/Category.jsx b/trivia-forge/frontend/src/Models/Category.jsx
index 71a5f9ec..0e314fa8 100644
--- a/trivia-forge/frontend/src/Models/Category.jsx
+++ b/trivia-forge/frontend/src/Models/Category.jsx
@@ -1,11 +1,15 @@
-export default class Category {
- constructor(id, name, gameID) {
- this.id = id;
+export class Category {
+ 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/Models/Choice.jsx b/trivia-forge/frontend/src/Models/Choice.jsx
index 1c2a0a06..e4b46a17 100644
--- a/trivia-forge/frontend/src/Models/Choice.jsx
+++ b/trivia-forge/frontend/src/Models/Choice.jsx
@@ -1,6 +1,6 @@
-export default class Choice {
- constructor(id, choice, questionID) {
- this.id = id;
+export class Choice {
+ constructor(choice, questionID = null) {
+ this.id = null;
this.choice = choice;
this.questionID = questionID;
}
diff --git a/trivia-forge/frontend/src/Models/Game.jsx b/trivia-forge/frontend/src/Models/Game.jsx
index 8bb00105..9cacab70 100644
--- a/trivia-forge/frontend/src/Models/Game.jsx
+++ b/trivia-forge/frontend/src/Models/Game.jsx
@@ -1,21 +1,20 @@
-export default class Game {
- constructor(id, userID, date, name, questions) {
- this.id = id;
- this.date = date;
+export class Game {
+ constructor(name, theme, userID = null) {
+ this.id = null;
this.name = name;
- this.questions = [];
+ this.theme = theme;
+ 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,
+ theme: this.theme,
userID: this.userID
}
}
diff --git a/trivia-forge/frontend/src/Models/Question.jsx b/trivia-forge/frontend/src/Models/Question.jsx
index 38ff8ba3..5794ed91 100644
--- a/trivia-forge/frontend/src/Models/Question.jsx
+++ b/trivia-forge/frontend/src/Models/Question.jsx
@@ -1,8 +1,9 @@
-export default class Question {
- constructor(id, question, answer, categoryID) {
- this.id = id;
+export class Question {
+ 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/Models/User.jsx b/trivia-forge/frontend/src/Models/User.jsx
index 7b97471f..91896b1e 100644
--- a/trivia-forge/frontend/src/Models/User.jsx
+++ b/trivia-forge/frontend/src/Models/User.jsx
@@ -1,7 +1,7 @@
-export default class User {
- constructor(id, date, email, password, profilePic) {
- this.id = id;
- this.date = date;
+import datetime from 'node-datetime';
+export class User {
+ constructor(date, email, password, profilePic = null) {
+ this.id = null;
this.email = email;
this.password = password;
this.profilePic = profilePic;
@@ -14,7 +14,6 @@ export default 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..dbb96fb0 100644
--- a/trivia-forge/frontend/src/Pages/TriviaGenPage.jsx
+++ b/trivia-forge/frontend/src/Pages/TriviaGenPage.jsx
@@ -1,6 +1,11 @@
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";
+import { Card } from "react-bootstrap";
// initialize openai client using configuration specified in vite environment variables
@@ -14,42 +19,103 @@ function TriviaGenPage() {
// state hooks for managaing number of questions and catergory input by user
const [numberOfQuestions, setNumberOfQuestions] = useState('');
const [category, setCategory] = useState('');
- const [isMultipleChoice, setIsMultipleChoice] = useState(false);
+ const [Title, setTitle] = useState('');
+ const [Theme, setTheme] = useState('');
+ const [categories, setCategories] = useState([]);
+ const [isMultipleChoice, setIsMultipleChoice] = useState(true);
const navigate = useNavigate();
-
+ const handleAddCategory = () => {
+ const newCategory = { name: '' };
+ setCategories([...categories, newCategory]);
+ };
+
+ const handleChangeCategoryDetail = (index, field, value) => {
+ const newCategories = categories.map((category, idx) => {
+ if (idx === index) {
+ return { ...category, [field]: value };
+ }
+ return category;
+ });
+ setCategories(newCategories);
+ };
const handleSubmit = async (event) => {
event.preventDefault(); // prevent default form submission behavior(browser reload)
- 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.";
- } else {
- prompt += "Each question should come with its answer and a fun fact. Separate each component with a newline.";
+ let responses = []
+
+ for (let i = 0; i < categories.length; i++) {
+ let prompt = `Generate ${numberOfQuestions} trivia questions that have an overall theme of ${Theme} about ${categories[i].name}.`;
+ if (isMultipleChoice) {
+ 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 be in the format \nQuestion:...\nAnswer:...\n---\nQuestion:... ect.";
+ }
+
+ // api call
+ try {
+
+ // API call to OpenAI
+ const completion = await openai.chat.completions.create({
+ model: "gpt-3.5-turbo",
+ 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
+ });
+ let response = completion.choices[0].message.content.split('\n');
+
+ responses.push(response);
+ }
+ catch (error) {
+ console.error('Error calling OpenAI API:', error);
+ }
}
+ //create a new game and category object and add category to game
+ let game = new Game(Title, Theme);
+
+ for (let i = 0; i < categories.length; i++) {
+ let newCategory = new Category(categories[i].name);
+ console.log(newCategory.name);
+ game.addCategory(newCategory);
+
+ //parse response from API
+ let sections = responses[i]; // 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];
+ 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]);
+ }
+ }
+
- // api call
- try {
-
- // API call to OpenAI
- const completion = await openai.chat.completions.create({
- model: "gpt-3.5-turbo",
- 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
- // state property to pass data as object to new route
- navigate('/review', { state: { questions } });
- //console.log(completion.choices[0].message);
- } catch (error) {
- console.error('Error calling OpenAI API:', error);
}
+ // state property to pass data as object to new route
+ navigate('/review', { state: { game } });
+ //console.log(completion.choices[0].message);
+
+
};
// render component as a form
@@ -58,43 +124,86 @@ function TriviaGenPage() {
Trivia Generator
-
-
-
+
+
+
+
+
);
}
diff --git a/trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx b/trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx
index a15fa198..3e16ea85 100644
--- a/trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx
+++ b/trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx
@@ -1,22 +1,24 @@
import React from 'react';
import { useLocation } from 'react-router-dom'; // used to access passed state
+import Categories from '../Components/Categories';
+import { Button } from 'react-bootstrap';
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 categories = game.categories;
return (
Review and Edit Trivia Questions
- {questions.map((question, index) => (
-
+
+ {categories.map((cat, 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