Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions client/src/Utils/apolloClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ const client = new ApolloClient({
? `${import.meta.env.VITE_API_URL}/graphql`
: '/graphql',
credentials: 'include', // 🔐 Send cookies with each request
headers: {
'Authorization': `Bearer ${localStorage.getItem('token') || ''}`,
}
}),
cache: new InMemoryCache(),
});
Expand Down
58 changes: 58 additions & 0 deletions client/src/components/LeaderBoard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { useState } from 'react';
import { useQuery } from '@apollo/client';
import { GET_USERS } from '../graphql/queries'; // Adjust the import path as necessary

function LeaderBoard() {

interface IUser {
_id: string;
username: string;
correctAnswers: number;
avatar: string; // Assuming you have an avatar property
}

// Data for leaderboard
/* const [leaderboardData, setLeaderboardData] = useState([
{ _id: 'kjhd63r9bhsef', username: 'Player1', correctAnswers: 100 },
{ username: 'Player2', score: 90 },
{ username: 'Player3', score: 80 },
{ username: 'Player4', score: 70 },
{ username: 'Player5', score: 60 },
]);
*/
// Fetch leaderboard data from the server (mocked for now)
const [leaderboardData, setLeaderboardData] = useState([]);

// How do we get the data from the server?

const { loading, data, error } = useQuery<IUser[] | undefined>(GET_USERS);

if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
// const { loading, data, errer } = useQuery(GET_LEADERBOARD_DATA, {
// variables: { difficulty_lvl: 'easy' }, // Example variable
// );
const users = data?.users || [];

// Sort the leaderboard data by score in descending order - by what measurement (?)
const sortedLeaderboard = users.sort((a: number, b: number) => b.correctAnswers - a.correctAnswers);


return (
<div>
{ sortedLeaderboard.length > 0 ? sortedLeaderboard.map(user: IUser => (
<div className="leaderboard-container">
<div className="leaderboard-item" key={user._id}>
<img src={user.avatar} alt="Avatar" className="avatar" /> {/* Assuming you have an avatar property */}
<span className="username">{user.username}</span>
<span className="score">{user.correctAnswers}</span>
</div>
))
</div>
}
</div>

)
}

export default LeaderBoard
11 changes: 10 additions & 1 deletion client/src/components/screens/Questions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import ReactMarkdown from 'react-markdown';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';
import { preloadSounds } from '../../utils/preloadSounds';
import { UPDATE_STATS } from '@/graphql/mutations';
import { useMutation } from '@apollo/client';

interface Question {
snippet?: string;
Expand All @@ -14,6 +16,7 @@ interface Question {
}

const Questions: React.FC = () => {
const [updateStats] = useMutation(UPDATE_STATS);
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();

Expand All @@ -23,6 +26,8 @@ const Questions: React.FC = () => {
const [userWasCorrect, setUserWasCorrect] = useState(false);
const [audioUrl, setAudioUrl] = useState('');

const [score, setScore] = useState(0);

useEffect(() => {
preloadSounds([
'/audio/Dan_correct/Dan-correct-1.wav',
Expand Down Expand Up @@ -117,6 +122,10 @@ const Questions: React.FC = () => {
if (!question || !selectedAnswer) return;

const isCorrect = selectedAnswer === question.correctAnswer;
updateStats({ variables: { isCorrect } })
if(isCorrect) {
setScore((prevScore) => prevScore + 1);
}
setUserWasCorrect(isCorrect);
setAudioUrl(getRandomAudio(isCorrect));
setShowResult(true);
Expand All @@ -127,7 +136,7 @@ const Questions: React.FC = () => {
return (
<div className="relative question-screen max-h-screen overflow-y-auto p-6 max-w-xl mx-auto text-center">
<h1 className="text-xl font-semibold mb-2">Question {id?.replace('q', '') || ''}</h1>

<h2 className="text-lg font-semibold mb-4">Score: {score}</h2>
{!question ? (
<p>Loading question...</p>
) : (
Expand Down
38 changes: 36 additions & 2 deletions client/tsconfig.node.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,41 @@
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
"noUncheckedSideEffectImports": true,

/* ← ADD THESE TWO LINES: */
"baseUrl": "src",
"paths": {
"@/*": ["*"]
}
},
"include": ["vite.config.ts"]
"include": [
"vite.config.ts",
"src" /* ← ADD THIS LINE so your utils/ folder is picked up */
]
}

// {
// "compilerOptions": {
// "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
// "target": "ES2022",
// "lib": ["ES2023"],
// "module": "ESNext",
// "skipLibCheck": true,

// /* Bundler mode */
// "moduleResolution": "bundler",
// "allowImportingTsExtensions": true,
// "isolatedModules": true,
// "moduleDetection": "force",
// "noEmit": true,

// /* Linting */
// "strict": true,
// "noUnusedLocals": true,
// "noUnusedParameters": true,
// "noFallthroughCasesInSwitch": true,
// "noUncheckedSideEffectImports": true
// },
// "include": ["vite.config.ts"]
// }
3 changes: 2 additions & 1 deletion server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ const getContext = async ({ req }: { req: Request }) => {
if (!token) return { user: null };

try {
const user = jwt.verify(token, process.env.JWT_SECRET as string);
const user = jwt.verify(token, process.env.JWT_SECRET_KEY as string);
return { user };
} catch (err) {
console.log(err)
console.warn('❌ Invalid JWT');
return { user: null };
}
Expand Down