diff --git a/client/src/utils/apolloClient.ts b/client/src/utils/apolloClient.ts new file mode 100644 index 0000000..618014c --- /dev/null +++ b/client/src/utils/apolloClient.ts @@ -0,0 +1,16 @@ +import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client'; + +const client = new ApolloClient({ + link: new HttpLink({ + uri: import.meta.env.VITE_API_URL + ? `${import.meta.env.VITE_API_URL}/graphql` + : '/graphql', + credentials: 'include', // πŸ” Send cookies with each request + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token') || ''}`, + } + }), + cache: new InMemoryCache(), +}); + +export default client; diff --git a/client/src/utils/auth.ts b/client/src/utils/auth.ts new file mode 100644 index 0000000..9eea949 --- /dev/null +++ b/client/src/utils/auth.ts @@ -0,0 +1,52 @@ +import { jwtDecode } from 'jwt-decode'; + +interface UserToken { + name?: string; + exp: number; + _id?: string; + email?: string; + username?: string; +} + +// AuthService class to manage login/logout/token logic +class AuthService { + // Get user data from token + getProfile() { + return jwtDecode(this.getToken() || ''); + } + + // Check if user is logged in + loggedIn() { + const token = this.getToken(); + return !!token && !this.isTokenExpired(token); + } + + // Check if token is expired + isTokenExpired(token: string) { + try { + const decoded = jwtDecode(token); + return decoded.exp < Date.now() / 1000; + } catch (err) { + return true; + } + } + + // Get token from localStorage + getToken() { + return localStorage.getItem('id_token'); + } + + // Login - save token to localStorage + login(idToken: string) { + localStorage.setItem('id_token', idToken); + window.location.assign('/'); + } + + // Logout - remove token + logout() { + localStorage.removeItem('id_token'); + window.location.assign('/'); + } +} + +export default new AuthService(); \ No newline at end of file diff --git a/client/src/utils/handleAnswer.ts b/client/src/utils/handleAnswer.ts new file mode 100644 index 0000000..a13f338 --- /dev/null +++ b/client/src/utils/handleAnswer.ts @@ -0,0 +1,34 @@ + + +// Picks a random Danism and matching Sound depending on correct/wrong +export function getRandomDanismAndSound(isCorrect: boolean): { text: string, sound: string } { + const correctDanisms = [ + { text: "πŸ”₯ Wow. You actually got that right. Weird.", sound: "/audio/Dan_correct/Dan-correct-1.wav" }, + { text: "🎯 Well look who remembered a concept. Congrats.", sound: "/audio/Dan_correct/Dan-correct-2.wav" }, + { text: "πŸš€ Miracles *do* happen. Mark the calendar.", sound: "/audio/Dan_correct/Dan-correct-3.wav" }, + { text: "🌟 I guess I *have* to give you a star now", sound: "/audio/Dan_correct/Dan-correctStar.wav" }, + ]; + + const incorrectDanisms = [ + { text: "πŸ’€ Sure, that's *a* choice. It's just not the right one.", sound: "/audio/Dan_incorrect/Dan-incorrect-1.wav" }, + { text: "😬 Oof. That was bold. Boldly incorrect.", sound: "/audio/Dan_incorrect/Dan-incorrect-2.wav" }, + { text: "🧠 Take a 7-minute break to recover from that disaster.", sound: "/audio/Dan_incorrect/Dan-incorrect-3.wav" }, + { text: "πŸ›‘ Fascinating. Bold. Still wrong.", sound: "/audio/Dan_incorrect/Dan-incorrect-4.wav" }, + ]; + + const source = isCorrect ? correctDanisms : incorrectDanisms; + const randomIndex = Math.floor(Math.random() * source.length); + return source[randomIndex]; +} + +// Picks a random Special Legendary Danism (only text) +export function getSpecialDanism(): string { + const specialQuotes = [ + "🌟 Legendary Streak! Even Dr. Dan is impressed... briefly.", + "🌟 5 correct in a row?! You must be an AI in disguise.", + "🌟 Victory streak! Maybe you deserve a 7-minute break after all." + // πŸ‘‰ Add more special quotes if you want! + ]; + const randomIndex = Math.floor(Math.random() * specialQuotes.length); + return specialQuotes[randomIndex]; +} diff --git a/client/src/utils/preloadSounds.ts b/client/src/utils/preloadSounds.ts new file mode 100644 index 0000000..14216ee --- /dev/null +++ b/client/src/utils/preloadSounds.ts @@ -0,0 +1,7 @@ +export function preloadSounds(paths: string[]): void { + paths.forEach((path) => { + const audio = new Audio(path); + audio.load(); + }); + } + \ No newline at end of file diff --git a/client/src/utils/useBodyClass.ts b/client/src/utils/useBodyClass.ts new file mode 100644 index 0000000..71503d3 --- /dev/null +++ b/client/src/utils/useBodyClass.ts @@ -0,0 +1,13 @@ +// src/Utils/useBodyClass.ts +import { useEffect } from 'react'; + +export const useBodyClass = (className: string) => { + useEffect(() => { + console.log(`βœ…applying body class: ${className}`); + + document.body.classList.add(className); + return () => { + document.body.classList.remove(className); + }; + }, [className]); +}; diff --git a/client/src/utils/utils.ts b/client/src/utils/utils.ts new file mode 100644 index 0000000..50df478 --- /dev/null +++ b/client/src/utils/utils.ts @@ -0,0 +1,4 @@ +export function cn(...inputs: (string | undefined | null | false)[]): string { + return inputs.filter(Boolean).join(" "); + } + \ No newline at end of file