From a78457d7f01a8156cc19dd52be7ec1fa57b54674 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 30 Apr 2024 19:37:19 -0700 Subject: [PATCH 1/2] added Services and Models. Need to add category and choice model still --- trivia-forge/frontend/package-lock.json | 55 +++++ trivia-forge/frontend/package.json | 1 + trivia-forge/frontend/src/Model/Game.jsx | 22 ++ trivia-forge/frontend/src/Model/Question.jsx | 22 ++ trivia-forge/frontend/src/Model/User.jsx | 23 ++ .../frontend/src/Services/TF-db_services.jsx | 226 ++++++++++++++++++ 6 files changed, 349 insertions(+) create mode 100644 trivia-forge/frontend/src/Model/Game.jsx create mode 100644 trivia-forge/frontend/src/Model/Question.jsx create mode 100644 trivia-forge/frontend/src/Model/User.jsx create mode 100644 trivia-forge/frontend/src/Services/TF-db_services.jsx diff --git a/trivia-forge/frontend/package-lock.json b/trivia-forge/frontend/package-lock.json index 807ff39f..0b28825e 100644 --- a/trivia-forge/frontend/package-lock.json +++ b/trivia-forge/frontend/package-lock.json @@ -8,6 +8,7 @@ "name": "trivia-forge", "version": "0.0.0", "dependencies": { + "axios": "^1.6.8", "bootstrap": "^5.3.3", "openai": "^4.38.3", "react": "^18.2.0", @@ -1599,6 +1600,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2541,6 +2552,25 @@ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -3829,6 +3859,11 @@ "react": ">=0.14.0" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -5820,6 +5855,16 @@ "possible-typed-array-names": "^1.0.0" } }, + "axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "requires": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -6512,6 +6557,11 @@ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, + "follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -7397,6 +7447,11 @@ "warning": "^4.0.0" } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/trivia-forge/frontend/package.json b/trivia-forge/frontend/package.json index 7c522d71..e3c539bd 100644 --- a/trivia-forge/frontend/package.json +++ b/trivia-forge/frontend/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "axios": "^1.6.8", "bootstrap": "^5.3.3", "openai": "^4.38.3", "react": "^18.2.0", diff --git a/trivia-forge/frontend/src/Model/Game.jsx b/trivia-forge/frontend/src/Model/Game.jsx new file mode 100644 index 00000000..8f2e23b1 --- /dev/null +++ b/trivia-forge/frontend/src/Model/Game.jsx @@ -0,0 +1,22 @@ +export class Game { + constructor(id, userID, date, name, questions) { + this.id = id; + this.date = date; + this.name = name; + this.questions = []; + this.userID = userID; + } + + addGame(question) { + this.questions.push(question); + } + + toJsonObject() { + return { + id: this.id, + date: this.date, + name: this.name, + userID: this.userID + } + } +} \ No newline at end of file diff --git a/trivia-forge/frontend/src/Model/Question.jsx b/trivia-forge/frontend/src/Model/Question.jsx new file mode 100644 index 00000000..9616795d --- /dev/null +++ b/trivia-forge/frontend/src/Model/Question.jsx @@ -0,0 +1,22 @@ +export class Question { + constructor(id, question, answer, categoryID) { + this.id = id; + this.question = question; + this.answer = answer; + this.categoryID = categoryID; + this.choices = []; + } + + addChoice(choice) { + this.choices.push(choice); + } + + toJsonObject() { + return { + id: this.id, + question: this.question, + answer: this.answer, + categoryID: this.category + } + } +} \ No newline at end of file diff --git a/trivia-forge/frontend/src/Model/User.jsx b/trivia-forge/frontend/src/Model/User.jsx new file mode 100644 index 00000000..fa3f6982 --- /dev/null +++ b/trivia-forge/frontend/src/Model/User.jsx @@ -0,0 +1,23 @@ +export class User { + constructor(id, date, email, password, profilePic) { + this.id = id; + this.date = date; + this.email = email; + this.password = password; + this.profilePic = profilePic; + this.games = []; + } + + addGame(game) { + this.games.push(game); + } + toJsonObject() { + return { + id: this.id, + date: this.date, + email: this.email, + password: this.password, + profilePic: this.profilePic + } + } +} \ No newline at end of file diff --git a/trivia-forge/frontend/src/Services/TF-db_services.jsx b/trivia-forge/frontend/src/Services/TF-db_services.jsx new file mode 100644 index 00000000..63541228 --- /dev/null +++ b/trivia-forge/frontend/src/Services/TF-db_services.jsx @@ -0,0 +1,226 @@ +import axios from 'axios'; +import User from '../Models/User'; +import Game from '../Models/Game'; + +const API_URL = 'http://localhost:5000/api'; + +/* ************************************ User ************************************ */ + +export const getUser = async () => { + try { + const response = await axios.get(`${API_URL}/user`); + const { id, date, email, password, profilePic } = response.data; + return new User(id, date, email, password, profilePic); + } catch (error) { + console.error('Failed to fetch user'); + return []; + } +} + +export const addUser = async (user) => { + try { + const response = await axios.post(`${API_URL}/user`, user.toJsonObject()); + return response.data; + } catch (error) { + console.error('Failed to add user'); + return []; + } +} + +export const deleteUser = async (User) => { + try { + const response = await axios.delete(`${API_URL}/user/${User.id}`); + return response.data; + } catch (error) { + console.error('Failed to delete user'); + return []; + } +} + +export const updateUser = async (user) => { + try { + const response = await axios.put(`${API_URL}/user/${user.id}`, user.toJsonObject()); + return response.data; + } catch (error) { + console.error('Failed to update user'); + return []; + } +} + +/* ************************************************************************************ */ + +/* ************************************ Game ************************************ */ + +export const getGame = async () => { + try { + const response = await axios.get(`${API_URL}/game`); + const { id, date, name, userID, questions } = response.data; + return new Game(id, date, name, userID, questions); + } catch (error) { + console.error('Failed to fetch game'); + return []; + } +} + +export const addGame = async (game) => { + try { + const response = await axios.post(`${API_URL}/game`, game.toJsonObject()); + return response.data; + } catch (error) { + console.error('Failed to add game'); + return []; + } +} + +export const deleteGame = async (game) => { + try { + const response = await axios.delete(`${API_URL}/game/${game.id}`); + return response.data; + } catch (error) { + console.error('Failed to delete game'); + return []; + } +} + +export const updateGame = async (game) => { + try { + const response = await axios.put(`${API_URL}/game/${game.id}`, game.toJsonObject()); + return response.data; + } catch (error) { + console.error('Failed to update game'); + return []; + } +} + +/* ************************************************************************************ */ + +/* ************************************ Questions ************************************** */ +export const getQuestions = async () => { + try { + const response = await axios.get(`${API_URL}/questions`); + const { id, question, answer, categoryID } = response.data; + return new Question(id, question, answer, categoryID); + } catch (error) { + console.error('Failed to fetch questions'); + return []; + } + +}; + +export const addQuestion = async (question) => { + try { + const response = await axios.post(`${API_URL}/questions`, question.toJsonObject()); + return response.data; + } catch (error) { + console.error('Failed to add question'); + return []; + } +} + +export const deleteQuestion = async (question) => { + try { + const response = await axios.delete(`${API_URL}/questions/${question.id}`); + return response.data; + } catch (error) { + console.error('Failed to delete question'); + return []; + } +} + +export const updateQuestion = async (question) => { + try { + const response = await axios.put(`${API_URL}/questions/${question.id}`, question.toJsonObject()); + return response.data; + } catch (error) { + console.error('Failed to update question'); + return []; + } +} +/* ************************************************************************************ */ + +/* ************************************ Categories ************************************ */ +export const getCategories = async () => { + try { + const response = await axios.get(`${API_URL}/categories`); + return response.data; + } catch (error) { + console.error('Failed to fetch categories'); + return []; + } +}; + +export const addCategory = async (category) => { + try { + const response = await axios.post(`${API_URL}/categories`, category); + return response.data; + } catch (error) { + console.error('Failed to add category'); + return []; + } +} + +export const deleteCategory = async (categoryId) => { + try { + const response = await axios.delete(`${API_URL}/categories/${categoryId}`); + return response.data; + } catch (error) { + console.error('Failed to delete category'); + return []; + } +} + +export const updateCategory = async (categoryId, category) => { + try { + const response = await axios.put(`${API_URL}/categories/${categoryId}`, category); + return response.data; + } catch (error) { + console.error('Failed to update category'); + return []; + } +} + +/* ************************************************************************************ */ + +/* ************************************ Choice ************************************ */ + +export const getChoice = async () => { + try { + const response = await axios.get(`${API_URL}/choice`); + return response.data; + } catch (error) { + console.error('Failed to fetch choice'); + return []; + } +} + +export const addChoice = async (choice) => { + try { + const response = await axios.post(`${API_URL}/choice`, choice); + return response.data; + } catch (error) { + console.error('Failed to add choice'); + return []; + } +} + +export const deleteChoice = async (choiceId) => { + try { + const response = await axios.delete(`${API_URL}/choice/${choiceId}`); + return response.data; + } catch (error) { + console.error('Failed to delete choice'); + return []; + } +} + +export const updateChoice = async (choiceId, choice) => { + try { + const response = await axios.put(`${API_URL}/choice/${choiceId}`, choice); + return response.data; + } catch (error) { + console.error('Failed to update choice'); + return []; + } +} + +/* ************************************************************************************ */ \ No newline at end of file From be2307ee9616bb091e57158923c05d5cdf5d981f Mon Sep 17 00:00:00 2001 From: Justin Date: Sun, 5 May 2024 13:24:40 -0700 Subject: [PATCH 2/2] more on classes and services --- trivia-forge/frontend/src/App.css | 66 +++++++++++++------ trivia-forge/frontend/src/Model/Category.jsx | 16 +++++ trivia-forge/frontend/src/Model/Choice.jsx | 15 +++++ .../frontend/src/Services/TF-db_services.jsx | 39 +++++------ 4 files changed, 96 insertions(+), 40 deletions(-) create mode 100644 trivia-forge/frontend/src/Model/Category.jsx create mode 100644 trivia-forge/frontend/src/Model/Choice.jsx diff --git a/trivia-forge/frontend/src/App.css b/trivia-forge/frontend/src/App.css index 4431dc5b..b4ccd15b 100644 --- a/trivia-forge/frontend/src/App.css +++ b/trivia-forge/frontend/src/App.css @@ -5,29 +5,52 @@ /* Header Animation */ .header-animation { - font-family: "Russo One", sans-serif; - width: 100%; height: 100%; + font-family: "Russo One", sans-serif; + width: 100%; + height: 100%; } + .header-animation text { - animation: stroke 5s infinite alternate; - stroke-width: 2; - stroke: #365FA0; - font-size: 100px; + animation: stroke 5s infinite alternate; + stroke-width: 2; + stroke: #365FA0; + font-size: 100px; } + @keyframes stroke { - 0% { - fill: rgba(72,138,204,0); stroke: rgba(54,95,160,1); - stroke-dashoffset: 25%; stroke-dasharray: 0 50%; stroke-width: 2; - } - 70% {fill: rgba(72,138,204,0); stroke: rgba(54,95,160,1); } - 80% {fill: rgba(72,138,204,0); stroke: rgba(54,95,160,1); stroke-width: 3; } - 100% { - fill: rgba(72,138,204,1); stroke: rgba(54,95,160,0); - stroke-dashoffset: -25%; stroke-dasharray: 50% 0; stroke-width: 0; - } -} - -.wrapper {background-color: #FFFFFF}; + 0% { + fill: rgba(72, 138, 204, 0); + stroke: rgba(54, 95, 160, 1); + stroke-dashoffset: 25%; + stroke-dasharray: 0 50%; + stroke-width: 2; + } + + 70% { + fill: rgba(72, 138, 204, 0); + stroke: rgba(54, 95, 160, 1); + } + + 80% { + fill: rgba(72, 138, 204, 0); + stroke: rgba(54, 95, 160, 1); + stroke-width: 3; + } + + 100% { + fill: rgba(72, 138, 204, 1); + stroke: rgba(54, 95, 160, 0); + stroke-dashoffset: -25%; + stroke-dasharray: 50% 0; + stroke-width: 0; + } +} + +.wrapper { + background-color: #FFFFFF +} + +; /* End Header Animation */ .App { @@ -106,7 +129,8 @@ footer { border: 3px solid #ee7600; font-family: 'Fredoka One', cursive; font-size: 40px; - border-radius: 70px; /* Rounded corners */ + border-radius: 70px; + /* Rounded corners */ box-shadow: 0 8px #999; /* box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3), 0 6px 20px rgba(0, 0, 0, 0.1); */ width: 40%; @@ -120,4 +144,4 @@ footer { background: linear-gradient(to bottom, #ff6700, #ff8c00); border: 3px solid #ee7600; outline: none; -} +} \ No newline at end of file diff --git a/trivia-forge/frontend/src/Model/Category.jsx b/trivia-forge/frontend/src/Model/Category.jsx new file mode 100644 index 00000000..c6eef12c --- /dev/null +++ b/trivia-forge/frontend/src/Model/Category.jsx @@ -0,0 +1,16 @@ +export class Category { + constructor(id, name, gameID) { + this.id = id; + this.name = name; + this.gameID = gameID + this.questions = []; + } + + toJsonObject() { + return { + id: this.id, + name: this.name, + gameID: this.gameID + } + } +} \ No newline at end of file diff --git a/trivia-forge/frontend/src/Model/Choice.jsx b/trivia-forge/frontend/src/Model/Choice.jsx new file mode 100644 index 00000000..b00ed292 --- /dev/null +++ b/trivia-forge/frontend/src/Model/Choice.jsx @@ -0,0 +1,15 @@ +export class Choice { + constructor(id, choice, questionID) { + this.id = id; + this.choice = choice; + this.questionID = questionID; + } + + toJsonObject() { + return { + id: this.id, + choice: this.choice, + questionID: this.questionID + } + } +} \ No newline at end of file diff --git a/trivia-forge/frontend/src/Services/TF-db_services.jsx b/trivia-forge/frontend/src/Services/TF-db_services.jsx index 63541228..eb51b203 100644 --- a/trivia-forge/frontend/src/Services/TF-db_services.jsx +++ b/trivia-forge/frontend/src/Services/TF-db_services.jsx @@ -1,6 +1,7 @@ import axios from 'axios'; import User from '../Models/User'; import Game from '../Models/Game'; +import Question from '../Models/Question'; const API_URL = 'http://localhost:5000/api'; @@ -8,7 +9,7 @@ const API_URL = 'http://localhost:5000/api'; export const getUser = async () => { try { - const response = await axios.get(`${API_URL}/user`); + const response = await axios.get(`${API_URL}/users`); const { id, date, email, password, profilePic } = response.data; return new User(id, date, email, password, profilePic); } catch (error) { @@ -19,7 +20,7 @@ export const getUser = async () => { export const addUser = async (user) => { try { - const response = await axios.post(`${API_URL}/user`, user.toJsonObject()); + const response = await axios.post(`${API_URL}/users`, user.toJsonObject()); return response.data; } catch (error) { console.error('Failed to add user'); @@ -29,7 +30,7 @@ export const addUser = async (user) => { export const deleteUser = async (User) => { try { - const response = await axios.delete(`${API_URL}/user/${User.id}`); + const response = await axios.delete(`${API_URL}/users/${User.id}`); return response.data; } catch (error) { console.error('Failed to delete user'); @@ -39,7 +40,7 @@ export const deleteUser = async (User) => { export const updateUser = async (user) => { try { - const response = await axios.put(`${API_URL}/user/${user.id}`, user.toJsonObject()); + const response = await axios.put(`${API_URL}/users/${user.id}`, user.toJsonObject()); return response.data; } catch (error) { console.error('Failed to update user'); @@ -53,7 +54,7 @@ export const updateUser = async (user) => { export const getGame = async () => { try { - const response = await axios.get(`${API_URL}/game`); + const response = await axios.get(`${API_URL}/games`); const { id, date, name, userID, questions } = response.data; return new Game(id, date, name, userID, questions); } catch (error) { @@ -64,7 +65,7 @@ export const getGame = async () => { export const addGame = async (game) => { try { - const response = await axios.post(`${API_URL}/game`, game.toJsonObject()); + const response = await axios.post(`${API_URL}/games`, game.toJsonObject()); return response.data; } catch (error) { console.error('Failed to add game'); @@ -74,7 +75,7 @@ export const addGame = async (game) => { export const deleteGame = async (game) => { try { - const response = await axios.delete(`${API_URL}/game/${game.id}`); + const response = await axios.delete(`${API_URL}/games/${game.id}`); return response.data; } catch (error) { console.error('Failed to delete game'); @@ -84,7 +85,7 @@ export const deleteGame = async (game) => { export const updateGame = async (game) => { try { - const response = await axios.put(`${API_URL}/game/${game.id}`, game.toJsonObject()); + const response = await axios.put(`${API_URL}/games/${game.id}`, game.toJsonObject()); return response.data; } catch (error) { console.error('Failed to update game'); @@ -151,7 +152,7 @@ export const getCategories = async () => { export const addCategory = async (category) => { try { - const response = await axios.post(`${API_URL}/categories`, category); + const response = await axios.post(`${API_URL}/categories`, category.toJsonObject()); return response.data; } catch (error) { console.error('Failed to add category'); @@ -159,9 +160,9 @@ export const addCategory = async (category) => { } } -export const deleteCategory = async (categoryId) => { +export const deleteCategory = async (category) => { try { - const response = await axios.delete(`${API_URL}/categories/${categoryId}`); + const response = await axios.delete(`${API_URL}/categories/${category.id}`); return response.data; } catch (error) { console.error('Failed to delete category'); @@ -169,9 +170,9 @@ export const deleteCategory = async (categoryId) => { } } -export const updateCategory = async (categoryId, category) => { +export const updateCategory = async (category) => { try { - const response = await axios.put(`${API_URL}/categories/${categoryId}`, category); + const response = await axios.put(`${API_URL}/categories/${category.id}`, category.toJsonObject()); return response.data; } catch (error) { console.error('Failed to update category'); @@ -185,7 +186,7 @@ export const updateCategory = async (categoryId, category) => { export const getChoice = async () => { try { - const response = await axios.get(`${API_URL}/choice`); + const response = await axios.get(`${API_URL}/choices`); return response.data; } catch (error) { console.error('Failed to fetch choice'); @@ -195,7 +196,7 @@ export const getChoice = async () => { export const addChoice = async (choice) => { try { - const response = await axios.post(`${API_URL}/choice`, choice); + const response = await axios.post(`${API_URL}/choices`, choice.toJsonObject()); return response.data; } catch (error) { console.error('Failed to add choice'); @@ -203,9 +204,9 @@ export const addChoice = async (choice) => { } } -export const deleteChoice = async (choiceId) => { +export const deleteChoice = async (choice) => { try { - const response = await axios.delete(`${API_URL}/choice/${choiceId}`); + const response = await axios.delete(`${API_URL}/choices/${choice.id}`); return response.data; } catch (error) { console.error('Failed to delete choice'); @@ -213,9 +214,9 @@ export const deleteChoice = async (choiceId) => { } } -export const updateChoice = async (choiceId, choice) => { +export const updateChoice = async (choice) => { try { - const response = await axios.put(`${API_URL}/choice/${choiceId}`, choice); + const response = await axios.put(`${API_URL}/choices/${choice.id}`, choice.toJsonObject()); return response.data; } catch (error) { console.error('Failed to update choice');