diff --git a/client/public/codezilla_bkgd.png b/client/background/codezilla_bkgd.png
similarity index 100%
rename from client/public/codezilla_bkgd.png
rename to client/background/codezilla_bkgd.png
diff --git a/client/src/components/AnswerResultModal.tsx b/client/src/components/AnswerResultModal.tsx
index e69de29..4bb7a2c 100644
--- a/client/src/components/AnswerResultModal.tsx
+++ b/client/src/components/AnswerResultModal.tsx
@@ -0,0 +1,25 @@
+import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
+
+interface AnswerResultModalProps {
+ isOpen: boolean;
+ onClose: () => void;
+ isCorrect: boolean;
+ drDanQuote: string;
+}
+
+const AnswerResultModal = ({ isOpen, onClose, isCorrect, drDanQuote }: AnswerResultModalProps) => {
+ return (
+
+ );
+};
+
+export default AnswerResultModal;
diff --git a/client/src/components/MinionModal.tsx b/client/src/components/MinionModal.tsx
index e69de29..b575d2c 100644
--- a/client/src/components/MinionModal.tsx
+++ b/client/src/components/MinionModal.tsx
@@ -0,0 +1,23 @@
+import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
+
+interface MinionModalProps {
+ isOpen: boolean;
+ onClose: () => void;
+ minionName: string;
+ minionQuote: string;
+}
+
+const MinionModal = ({ isOpen, onClose, minionName, minionQuote }: MinionModalProps) => {
+ return (
+
+ );
+};
+
+export default MinionModal;
diff --git a/client/src/graphql/queries.ts b/client/src/graphql/queries.ts
index 4b76e20..fec6426 100644
--- a/client/src/graphql/queries.ts
+++ b/client/src/graphql/queries.ts
@@ -1,13 +1,13 @@
import { gql } from '@apollo/client';
-export const GET_QUESTIONS = gql`
- query GetQuestions {
+export const GENERATE_QUESTIONS = gql`
+ query GenerateQuestion($track: String!, level: $level, minion: $minion) {
questions {
- _id
- questionText
- options
- correctAnswer
+ question
+ choices
+ answer
}
}
`;
+
diff --git a/package.json b/package.json
index 7507d76..3c7e013 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"description": "",
"main": "index.js",
"scripts": {
- "start": "node server/server.js",
+ "start": "cd server && npm run start",
"develop": "concurrently \"cd server && npm run watch\" \"cd client && npm run dev\"",
"install": "cd server && npm i && cd ../client && npm i",
"build": "concurrently \"cd server && npm run build\" \"cd client && npm run build\"",
diff --git a/server/package.json b/server/package.json
index ac9f345..b555474 100644
--- a/server/package.json
+++ b/server/package.json
@@ -7,7 +7,8 @@
"start": "node dist/server.js",
"build": "tsc",
"test": "echo \"Error: no test specified\" && exit 1",
- "dev": "nodemon index.ts"
+ "dev": "nodemon index.ts",
+ "watch": "nodemon dist/server.js"
},
"keywords": [],
"author": "",
diff --git a/server/src/schemas/resolvers.ts b/server/src/schemas/resolvers.ts
index 54998fa..70a165d 100644
--- a/server/src/schemas/resolvers.ts
+++ b/server/src/schemas/resolvers.ts
@@ -2,6 +2,13 @@ import User from '../models/User';
import Character from '../models/Characters';
import { signToken } from '../utils/auth';
import { AuthenticationError } from 'apollo-server-express';
+import { OpenAI } from 'openai';
+import { PromptBuilder } from '../utils/PromptBuilder';
+import dotenv from 'dotenv';
+
+dotenv.config();
+
+const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
interface AddUserArgs {
input: {
@@ -24,6 +31,35 @@ 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);
+
+ try {
+ const completion = await openai.chat.completions.create({
+ model: 'gpt-3.5-turbo',
+ messages: [{ role: 'user', content: prompt }],
+ max_tokens: 250,
+ });
+
+ const raw = completion.choices[0].message.content ?? '';
+ const [question, ...choicesAndAnswer] = raw.split('\n').filter(Boolean);
+ const choices = choicesAndAnswer.slice(0, -1);
+ const answer = choicesAndAnswer[choicesAndAnswer.length - 1];
+
+ return { question, choices, answer };
+ } catch (error) {
+ console.error('OpenAI failed, falling back to hardcoded question:', error);
+ const fallback = PromptBuilder.getFallbackQuestion(minion);
+
+ return {
+ question: fallback.question,
+ choices: fallback.choices,
+ answer: fallback.choices[fallback.correctIndex],
+ };
+ }
+=======
users: async () => {
return await User.find();
},
@@ -35,8 +71,10 @@ const resolvers = {
},
character: async (_: any, { id }: { id: string }) => {
return await Character.findById(id);
+>>>>>>> d7567a5c20d729e2d5c004a2d70be9176db8ea33
},
},
+
Mutation: {
addUser: async (_parent: any, { input }: AddUserArgs) => {
const user = await User.create(input);
diff --git a/server/src/schemas/typeDefs.ts b/server/src/schemas/typeDefs.ts
index a9b876e..be51e79 100644
--- a/server/src/schemas/typeDefs.ts
+++ b/server/src/schemas/typeDefs.ts
@@ -16,6 +16,8 @@ const typeDefs = gql`
password: String!
}
+<<<<<<< HEAD
+=======
type Character {
_id: ID!
name: String!
@@ -23,18 +25,29 @@ const typeDefs = gql`
voice: String!
}
+>>>>>>> d7567a5c20d729e2d5c004a2d70be9176db8ea33
type Auth {
token: ID!
user: User
}
+ type Question {
+ question: String!
+ choices: [String!]!
+ answer: String!
+ }
+
type Query {
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 {
diff --git a/server/src/server.ts b/server/src/server.ts
index e527958..4504434 100644
--- a/server/src/server.ts
+++ b/server/src/server.ts
@@ -1,10 +1,10 @@
-import express, { Request, Response } from 'express';
-import cors from 'cors';
+import express, { type Request, type Response } from 'express';
+
import dotenv from 'dotenv';
import { OpenAI } from 'openai';
-// import fs from 'fs';
-// import path from 'path';
-import { ApolloServer } from 'apollo-server-express';
+
+import path from 'path';
+import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import typeDefs from './schemas/typeDefs';
import resolvers from './schemas/resolvers';
@@ -33,22 +33,25 @@ dotenv.config();
resolvers,
});
- await server.start();
+ const startApolloServer = async () => {
+ await server.start();
+ await db;
+
+ app.use(express.static('public')); // serve generated mp3 file
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
- app.use(express.static('public')); // serve generated mp3 file
+
app.use('/graphql', expressMiddleware(server as any,
{
context: authenticateToken as any
}
));
-
// if we're in production, serve client/build as static assets
if (process.env.NODE_ENV === 'production') {
- app.use(express.static(path.join(dirname, '../client/build')));
+ app.use(express.static(path.join(__dirname, '../client/build')));
app.get('*', (_req: Request, res: Response) => {
- res.sendFile(path.join(dirname, '../client/dist/index.html'));
+ res.sendFile(path.join(__dirname, '../client/dist/index.html'));
});
}
diff --git a/server/src/types/express/index.d.ts b/server/src/types/express/index.d.ts
new file mode 100644
index 0000000..e649f26
--- /dev/null
+++ b/server/src/types/express/index.d.ts
@@ -0,0 +1,8 @@
+declare namespace Express {
+ interface Request {
+ user: {
+ _id: unknown;
+ username: string;
+ };
+ }
+}
diff --git a/server/src/utils/PromptBuilder.ts b/server/src/utils/PromptBuilder.ts
index deaa247..14d919b 100644
--- a/server/src/utils/PromptBuilder.ts
+++ b/server/src/utils/PromptBuilder.ts
@@ -1,6 +1,10 @@
+<<<<<<< HEAD
+import { FallbackQuestion, fallbackQuestion } from "../utils/fallbackQuestions";
+=======
import { FallbackQuestion, fallbackQuestion } from "../utils/fallbackQuestions";
+>>>>>>> d7567a5c20d729e2d5c004a2d70be9176db8ea33
export class PromptBuilder {
/**
diff --git a/server/src/utils/auth.ts b/server/src/utils/auth.ts
index 01ef3ac..e0efdd3 100644
--- a/server/src/utils/auth.ts
+++ b/server/src/utils/auth.ts
@@ -11,7 +11,7 @@ interface JwtPayload {
}
export const authMiddleware = ({ req }: { req: any }) => {
- const authHeader = req.headers.authorization;
+ const authHeader = req.headers.get('authorization');
if (authHeader) {
const token = authHeader.split(' ')[1];
@@ -42,20 +42,25 @@ export const authMiddleware = ({ req }: { req: any }) => {
return { user: null };
};
-export const authenticateToken = (token: string) => {
- const secretKey = process.env.JWT_SECRET_KEY || '';
+export const authenticateToken = async ({ req }: { req: Request }) => {
+ const authHeader = req.headers.authorization;
+ let user = null;
+ console.log('AUTH HEADER', authHeader);
- if (!token) {
- throw new Error('No token provided');
- }
+ if (authHeader) {
+ const token = authHeader.split(' ')[1];
+ console.log('TOKEN', token);
+ const secretKey = process.env.JWT_SECRET_KEY || '';
- try {
- const user = jwt.verify(token, secretKey) as JwtPayload;
- return user;
- } catch (err) {
- console.error('Invalid token:', err);
- throw new Error('Invalid or expired token');
+ try {
+ user = jwt.verify(token, secretKey) as JwtPayload;
+ console.log('USER', user);
+ } catch (err) {
+ console.error(err);
+ }
}
+
+ return { user };
};
export const signToken = (username: string, email: string, _id: unknown) => {
diff --git a/server/tsconfig.json b/server/tsconfig.json
index a082141..e3f0e0c 100644
--- a/server/tsconfig.json
+++ b/server/tsconfig.json
@@ -13,6 +13,6 @@
"@/*": ["src/*"] // Map the '@' alias to the 'src' directory
}
},
- "include": ["src/**/*"],
+ "include": ["src/**/*", "src/server.ts"],
"exclude": ["node_modules"]
}
\ No newline at end of file