diff --git a/client/package.json b/client/package.json index aa73012..5128e72 100644 --- a/client/package.json +++ b/client/package.json @@ -20,7 +20,7 @@ "react": "^19.0.0", "react-dom": "^19.0.0", - "react-howler": "^5.2.0" + "react-howler": "^5.2.0", "react-router-dom": "^7.5.2" diff --git a/client/src/components/screens/GameMap.tsx b/client/src/components/screens/GameMap.tsx index 539f283..b205062 100644 --- a/client/src/components/screens/GameMap.tsx +++ b/client/src/components/screens/GameMap.tsx @@ -2,8 +2,6 @@ // src/components/screens/GameMap.tsx // IMPORT LIBRARIES -import * as React from 'react'; - import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; diff --git a/client/src/graphql/mutations.ts b/client/src/graphql/mutations.ts index 9c840a7..06cc80a 100644 --- a/client/src/graphql/mutations.ts +++ b/client/src/graphql/mutations.ts @@ -1,10 +1,59 @@ import { gql } from '@apollo/client'; -export const SUBMIT_ANSWER = gql` - mutation SubmitAnswer($questionId: ID!, $selectedOption: String!) { - submitAnswer(questionId: $questionId, selectedOption: $selectedOption) { - isCorrect - feedback +// Mutation to update player stats +export const UPDATE_STATS = gql` + mutation UpdateStats($isCorrect: Boolean!) { + updateStats(isCorrect: $isCorrect) { + correctAnswers + wrongAnswers + } + } +`; + +// Mutation to login +export const LOGIN = gql` + mutation Login($email: String!, $password: String!) { + login(email: $email, password: $password) { + token + user { + _id + username + } + } + } +`; + +// Mutation to add a new user +export const ADD_USER = gql` + mutation AddUser($input: UserInput!) { + addUser(input: $input) { + token + user { + _id + username + } + } + } +`; + +// Mutation to create a new character +export const CREATE_CHARACTER = gql` + mutation CreateCharacter($name: String!, $picture: String!, $voice: String!) { + createCharacter(name: $name, picture: $picture, voice: $voice) { + _id + name + picture + voice + } + } +`; + +// Mutation to delete a character +export const DELETE_CHARACTER = gql` + mutation DeleteCharacter($id: ID!) { + deleteCharacter(id: $id) { + _id + name } } `; diff --git a/client/src/graphql/queries.ts b/client/src/graphql/queries.ts index fec6426..db88688 100644 --- a/client/src/graphql/queries.ts +++ b/client/src/graphql/queries.ts @@ -1,8 +1,9 @@ import { gql } from '@apollo/client'; -export const GENERATE_QUESTIONS = gql` - query GenerateQuestion($track: String!, level: $level, minion: $minion) { - questions { +// Query to generate a new coding question +export const GENERATE_QUESTION = gql` + query GenerateQuestion($track: String!, $level: String!, $minion: String!) { + generateQuestion(track: $track, level: $level, minion: $minion) { question choices answer @@ -10,4 +11,14 @@ export const GENERATE_QUESTIONS = gql` } `; - +// (Optional bonus if someone else pulls user stats for leaderboard) +export const ME = gql` + query Me { + me { + _id + username + correctAnswers + wrongAnswers + } + } +`; diff --git a/client/src/pages/CodezillaArena.tsx b/client/src/pages/CodezillaArena.tsx deleted file mode 100644 index d529067..0000000 --- a/client/src/pages/CodezillaArena.tsx +++ /dev/null @@ -1,130 +0,0 @@ -// import { useEffect, useState } from "react"; -// import { preloadSounds } from "../Utils/preloadSounds"; -// import { -// Dialog, -// DialogTrigger, -// DialogContent, -// DialogHeader, -// DialogTitle, -// } from "@/components/ui/dialog"; -// import { getRandomDanism, getSoundPath } from "../Utils/handleAnswer"; -// import SoundPlayer from "@/components/SoundPlayer"; - -// const CodezillaArena = () => { -// const [showModal, setShowModal] = useState(false); -// const [audioSrc, setAudioSrc] = useState(null); -// const [playing, setPlaying] = useState(false); -// const [dialogText, setDialogText] = useState(""); -// const [fallbackAudio, setFallbackAudio] = useState(null); - -// // 👉 PRELOAD ALL YOUR AUDIO FILES ONCE -// useEffect(() => { -// preloadSounds([ -// '/audio/Dan_correct/Dan-correct-1.wav', -// '/audio/Dan_correct/Dan-correct-2.wav', -// '/audio/Dan_correct/Dan-correct-3.wav', -// '/audio/Dan_correct/Dan-correct-4.wav', -// '/audio/Dan_incorrect/Dan-incorrect-1.wav', -// '/audio/Dan_incorrect/Dan-incorrect-2.wav', -// '/audio/Dan_incorrect/Dan-incorrect-3.wav', -// '/audio/Dan_incorrect/Dan-incorrect-4.wav', -// '/audio/drdan_fallback.mp3' // also preload fallback voice -// ]); -// }, []); - -// useEffect(() => { -// if (showModal && dialogText) { -// const fetchVoice = async () => { -// try { -// const res = await fetch("/api/tts", { -// method: "POST", -// headers: { "Content-Type": "application/json" }, -// body: JSON.stringify({ -// text: dialogText, -// character: "Dr. Dan", -// }), -// }); - -// if (!res.ok) throw new Error("TTS API failed"); - -// const blob = await res.blob(); -// const url = URL.createObjectURL(blob); -// setAudioSrc(url); -// setPlaying(true); -// } catch (err) { -// console.error("TTS Error:", err); -// setFallbackAudio("/audio/drdan_fallback.mp3"); -// setPlaying(true); -// } -// }; - -// fetchVoice(); -// } -// }, [showModal, dialogText]); - -// const handleAnswer = (isCorrect: boolean) => { -// setDialogText(getRandomDanism(isCorrect)); -// setAudioSrc(getSoundPath(isCorrect)); // Play correct/wrong sound while TTS loads -// setShowModal(true); -// setPlaying(true); -// }; - -// return ( -//
-//
-//

-// 🧠 Codezilla Arena (Prototype Mode) -//

- -//
-// -// -//
- -// -// -// -// - -// -// -// 🧬 Dr. Dan Speaks -// -//

-// {dialogText} -//

- -// {audioSrc && ( -// setPlaying(false)} -// /> -// )} -// {fallbackAudio && !audioSrc && ( -// setPlaying(false)} -// /> -// )} -//
-//
-//
-//
-// ); -// }; - -// export default CodezillaArena; diff --git a/server/src/models/User.ts b/server/src/models/User.ts index a354aee..1fcb883 100644 --- a/server/src/models/User.ts +++ b/server/src/models/User.ts @@ -6,6 +6,8 @@ interface IUser extends Document { username: string; email: string; password: string; + correctAnswers: number; + wrongAnswers: number; isCorrectPassword(password: string): Promise; } @@ -29,6 +31,14 @@ const userSchema = new Schema( required: true, minlength: 5, }, + correctAnswers: { + type: Number, + default: 0, + }, + wrongAnswers: { + type: Number, + default: 0, + }, }, { timestamps: true, @@ -53,3 +63,4 @@ userSchema.methods.isCorrectPassword = async function (password: string): Promis const User = model('User', userSchema); export default User; + diff --git a/server/src/schemas/resolvers.ts b/server/src/schemas/resolvers.ts index 70a165d..b601e26 100644 --- a/server/src/schemas/resolvers.ts +++ b/server/src/schemas/resolvers.ts @@ -31,7 +31,6 @@ const resolvers = { } throw new AuthenticationError('You need to be logged in!'); }, -<<<<<<< HEAD generateQuestion: async (_parent: any, args: { track: string; level: string; minion: string }) => { const { track, level, minion } = args; const prompt = PromptBuilder.getPrompt(track, level); @@ -59,19 +58,6 @@ const resolvers = { answer: fallback.choices[fallback.correctIndex], }; } -======= - users: async () => { - return await User.find(); - }, - user: async (_: any, { username }: { username: string }) => { - return await User.findOne({ username }); - }, - characters: async () => { - return await Character.find(); - }, - character: async (_: any, { id }: { id: string }) => { - return await Character.findById(id); ->>>>>>> d7567a5c20d729e2d5c004a2d70be9176db8ea33 }, }, @@ -104,6 +90,20 @@ const resolvers = { deleteCharacter: async (_: any, { id }: { id: string }) => { return await Character.findByIdAndDelete(id); }, + updateStats: async (_parent: any, { isCorrect }: { isCorrect: boolean }, context: any) => { + if (!context.user) { + throw new AuthenticationError('You need to be logged in!'); + } + + const update = isCorrect + ? { $inc: { correctAnswers: 1 } } + : { $inc: { wrongAnswers: 1 } }; + + const user = await User.findByIdAndUpdate(context.user._id, update, { new: true }); + + return user; +}, + }, }; diff --git a/server/src/schemas/typeDefs.ts b/server/src/schemas/typeDefs.ts index be51e79..cb40de0 100644 --- a/server/src/schemas/typeDefs.ts +++ b/server/src/schemas/typeDefs.ts @@ -16,16 +16,6 @@ const typeDefs = gql` password: String! } -<<<<<<< HEAD -======= - type Character { - _id: ID! - name: String! - picture: String! - voice: String! - } - ->>>>>>> d7567a5c20d729e2d5c004a2d70be9176db8ea33 type Auth { token: ID! user: User @@ -41,13 +31,7 @@ const typeDefs = gql` users: [User] user(username: String!): User me: User -<<<<<<< HEAD generateQuestion(track: String!, level: String!, minion: String!): Question -======= - updateStats(isCorrect: Boolean!): User - characters: [Character] - character(id: ID!): Character ->>>>>>> d7567a5c20d729e2d5c004a2d70be9176db8ea33 } type Mutation { @@ -55,6 +39,7 @@ const typeDefs = gql` login(email: String!, password: String!): Auth createCharacter(name: String!, picture: String!, voice: String!): Character deleteCharacter(id: ID!): Character + updateStats(isCorrect: Boolean!): User } `; diff --git a/server/src/utils/PromptBuilder.ts b/server/src/utils/PromptBuilder.ts index 14d919b..3198f4a 100644 --- a/server/src/utils/PromptBuilder.ts +++ b/server/src/utils/PromptBuilder.ts @@ -1,10 +1,4 @@ -<<<<<<< HEAD import { FallbackQuestion, fallbackQuestion } from "../utils/fallbackQuestions"; -======= - -import { FallbackQuestion, fallbackQuestion } from "../utils/fallbackQuestions"; - ->>>>>>> d7567a5c20d729e2d5c004a2d70be9176db8ea33 export class PromptBuilder { /**