diff --git a/backend/.DS_Store b/backend/.DS_Store index d8eacca..426b8a4 100644 Binary files a/backend/.DS_Store and b/backend/.DS_Store differ diff --git a/backend/app.py b/backend/app.py index 5388434..404ccbd 100644 --- a/backend/app.py +++ b/backend/app.py @@ -3,8 +3,7 @@ from flask import Flask, request, jsonify, g from flask_cors import CORS -from flask import Flask, send_from_directory -from database import SessionLocal, Base, User # Import after loading .env +from database import SessionLocal, Base, User, Profile, Badge from sqlalchemy.exc import IntegrityError from werkzeug.security import generate_password_hash, check_password_hash from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity @@ -38,7 +37,11 @@ app.logger.info(f"CORS enabled for frontend URLs: {ALLOWED_ORIGINS}") # Initialize Redis client -REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379/0") # Default to local Redis +REDIS_URL = os.getenv( + "REDIS_URL", + "redis://:2xctaLdMYomYsJJ2drVp9Ylj5GDnJdZQ@redis-19847.c256.us-east-1-2.ec2.redns.redis-cloud.com:19847/0" +) # Default to your Redis public URL with credentials + try: redis_client = redis.Redis.from_url(REDIS_URL) redis_client.ping() @@ -49,9 +52,6 @@ # Helper Functions for Caching def get_cached_matches(skills): - """ - Retrieve cached matches from Redis based on the provided skills. - """ if not redis_client: return None try: @@ -68,9 +68,6 @@ def get_cached_matches(skills): return None def set_cached_matches(skills, matches): - """ - Cache the matches in Redis for future requests. - """ if not redis_client: return try: @@ -92,11 +89,84 @@ def shutdown_session(exception=None): db.close() # Existing Routes - from matching_engine import get_side_hustles from skill_engine import recommend_skills from habit_engine import get_habit_recommendations +# Profile Management Routes +@app.route("/api/profile", methods=["GET", "PUT"]) +@jwt_required() +def manage_profile(): + user_id = get_jwt_identity() + try: + user = g.db.query(User).filter_by(id=user_id).first() + if not user: + return jsonify({"error": "User not found"}), 404 + + if request.method == "GET": + if not user.profile: + return jsonify({"error": "Profile not found"}), 404 + return jsonify({ + "bio": user.profile.bio, + "avatar_url": user.profile.avatar_url + }), 200 + + if request.method == "PUT": + data = request.get_json() + bio = data.get("bio") + avatar_url = data.get("avatar_url") + + if not user.profile: + user.profile = Profile(bio=bio, avatar_url=avatar_url, user_id=user_id) + else: + user.profile.bio = bio + user.profile.avatar_url = avatar_url + + g.db.commit() + return jsonify({"message": "Profile updated successfully"}), 200 + except Exception as e: + app.logger.error(f"Error in /api/profile: {e}", exc_info=True) + return jsonify({"error": "An unexpected error occurred"}), 500 + +# Badge Management Routes +@app.route("/api/badges", methods=["GET", "POST", "DELETE"]) +@jwt_required() +def manage_badges(): + user_id = get_jwt_identity() + try: + user = g.db.query(User).filter_by(id=user_id).first() + if not user: + return jsonify({"error": "User not found"}), 404 + + if request.method == "GET": + badges = [{"id": badge.id, "name": badge.name, "description": badge.description} for badge in user.badges] + return jsonify(badges), 200 + + if request.method == "POST": + data = request.get_json() + name = data.get("name") + description = data.get("description") + if not name: + return jsonify({"error": "Badge name is required"}), 400 + + new_badge = Badge(name=name, description=description, user_id=user_id) + g.db.add(new_badge) + g.db.commit() + return jsonify({"message": "Badge added successfully"}), 201 + + if request.method == "DELETE": + badge_id = request.args.get("id") + badge = g.db.query(Badge).filter_by(id=badge_id, user_id=user_id).first() + if not badge: + return jsonify({"error": "Badge not found"}), 404 + + g.db.delete(badge) + g.db.commit() + return jsonify({"message": "Badge deleted successfully"}), 200 + except Exception as e: + app.logger.error(f"Error in /api/badges: {e}", exc_info=True) + return jsonify({"error": "An unexpected error occurred"}), 500 + @app.route("/api/matches", methods=["POST"]) def side_hustle_matches(): app.logger.info("Request received at /api/matches") @@ -294,11 +364,13 @@ def login(): app.logger.error(f"Error in /api/login: {e}", exc_info=True) return jsonify({"error": "An unexpected error occurred"}), 500 +# Consolidated Dashboard Route @app.route("/api/dashboard", methods=["GET"]) @jwt_required() def dashboard(): app.logger.info("Request received at /api/dashboard") try: + # Extract the user ID from the token user_id = get_jwt_identity() app.logger.info(f"Extracted user_id from token: {user_id}") @@ -308,14 +380,27 @@ def dashboard(): app.logger.warning("User not found!") return jsonify({"error": "User not found!"}), 404 - # Example user-specific data; adjust as needed + # Handle user profile, ensuring it's safe to access even if not set + profile = { + "bio": user.profile.bio if user.profile else None, + "avatar_url": user.profile.avatar_url if user.profile else None + } + + # Handle badges, ensuring the app works even if no badges are earned yet + badges = [{"id": badge.id, "name": badge.name, "description": badge.description} for badge in user.badges] if user.badges else [] + + # Consolidated data including user, profile, and badges data = { "username": user.username, "email": user.email, - "created_at": user.created_at.isoformat() + "created_at": user.created_at.isoformat(), + "profile": profile, + "badges": badges } app.logger.info(f"Dashboard data for user_id {user_id}: {data}") + return jsonify(data), 200 + except Exception as e: app.logger.error(f"Error in /api/dashboard: {e}", exc_info=True) return jsonify({"error": "An unexpected error occurred"}), 500 diff --git a/backend/database.py b/backend/database.py index a2437fa..f1d32c7 100644 --- a/backend/database.py +++ b/backend/database.py @@ -1,5 +1,5 @@ import os -from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, DateTime +from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, DateTime, Index from sqlalchemy.orm import declarative_base, relationship, sessionmaker from datetime import datetime import logging @@ -15,58 +15,100 @@ logger.error("DATABASE_URL environment variable is not set") raise ValueError("DATABASE_URL environment variable is not set") -# Debugging: Log the database connection string (hide sensitive info in production) -logger.info(f"DATABASE_URL Loaded: {DATABASE_URL}") +# Debugging: Avoid logging sensitive info in production +logger.info("DATABASE_URL Loaded successfully.") # Create SQLAlchemy engine and session engine = create_engine(DATABASE_URL, echo=False) Base = declarative_base() SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) +# Models + # User model class User(Base): __tablename__ = "users" id = Column(Integer, primary_key=True, index=True) - username = Column(String, unique=True, nullable=False, index=True) - email = Column(String, unique=True, nullable=False, index=True) + username = Column(String(150), unique=True, nullable=False, index=True) + email = Column(String(255), unique=True, nullable=False, index=True) hashed_password = Column(String, nullable=False) created_at = Column(DateTime, default=datetime.utcnow) + # Relationships skills = relationship("Skill", back_populates="user", cascade="all, delete-orphan") habits = relationship("Habit", back_populates="user", cascade="all, delete-orphan") + profile = relationship("Profile", back_populates="user", uselist=False, cascade="all, delete-orphan") + badges = relationship("Badge", back_populates="user", cascade="all, delete-orphan") def __repr__(self): return f"" +# Profile model +class Profile(Base): + __tablename__ = "profiles" + + id = Column(Integer, primary_key=True, index=True) + bio = Column(String(500), nullable=True) # Max length of 500 characters for bio + avatar_url = Column(String(2083), nullable=True) # Max length for URLs + user_id = Column(Integer, ForeignKey("users.id"), nullable=False) + + user = relationship("User", back_populates="profile") + + def __repr__(self): + return f"" + + # Add an index for user_id +Index("ix_profiles_user_id", Profile.user_id) + +# Badge model +class Badge(Base): + __tablename__ = "badges" + + id = Column(Integer, primary_key=True, index=True) + name = Column(String(100), nullable=False) # Max length for badge name + description = Column(String(255), nullable=True) # Max length for description + user_id = Column(Integer, ForeignKey("users.id"), nullable=False) + + user = relationship("User", back_populates="badges") + + def __repr__(self): + return f"" + + # Add an index for user_id +Index("ix_badges_user_id", Badge.user_id) + # Skill model class Skill(Base): __tablename__ = "skills" id = Column(Integer, primary_key=True, index=True) - name = Column(String, nullable=False) + name = Column(String(100), nullable=False) # Max length for skill name user_id = Column(Integer, ForeignKey("users.id"), nullable=False) user = relationship("User", back_populates="skills") def __repr__(self): - return f"" + return f"" # Habit model class Habit(Base): __tablename__ = "habits" id = Column(Integer, primary_key=True, index=True) - description = Column(String, nullable=False) + description = Column(String(255), nullable=False) # Max length for description user_id = Column(Integer, ForeignKey("users.id"), nullable=False) user = relationship("User", back_populates="habits") def __repr__(self): - return f"" + return f"" -# Create all tables +# Initialize Database def initialize_database(): + """ + Create all database tables. + """ try: logger.info("Creating database tables...") Base.metadata.create_all(engine) @@ -74,6 +116,6 @@ def initialize_database(): except Exception as e: logger.error(f"Error creating database tables: {e}") -# Initialize database +# Main execution if __name__ == "__main__": initialize_database() diff --git a/frontend/src/components/Dashboard.js b/frontend/src/components/Dashboard.js index 1dbb0f4..a9e16c3 100644 --- a/frontend/src/components/Dashboard.js +++ b/frontend/src/components/Dashboard.js @@ -10,6 +10,7 @@ import AI_DecisionTreeVisualizer from "./DecisionTree"; import PredictiveForecastChart from "./PredictiveForecastChart"; import InteractiveGlobe from "./InteractiveGlobe"; import EconomicSectorBubbleMap from "./EconomicSectorBubbleMap"; +import Game from "./Game"; import { Chart as ChartJS, CategoryScale, @@ -677,6 +678,10 @@ const Dashboard = () => { )} + +
+ +
diff --git a/frontend/src/components/Dashboardupdate.js b/frontend/src/components/Dashboardupdate.js deleted file mode 100644 index 98bd9c1..0000000 --- a/frontend/src/components/Dashboardupdate.js +++ /dev/null @@ -1,473 +0,0 @@ -import React, { useEffect, useState } from "react"; -import axios from "axios"; -import jwtDecode from "jwt-decode"; -import { useNavigate } from "react-router-dom"; -import "./Dashboard.css"; -import { Bar, Line } from "react-chartjs-2"; -import LiveTrendVisualizer from "./LiveTrendVisualizer"; -import LiveHeatmap from "./LiveHeatmap"; -import AI_DecisionTreeVisualizer from "./DecisionTree"; -import PredictiveForecastChart from "./PredictiveForecastChart"; -import InteractiveGlobe from "./InteractiveGlobe"; -import { - Chart as ChartJS, - CategoryScale, - LinearScale, - BarElement, - LineElement, - PointElement, - Title, - Tooltip, - Legend, -} from "chart.js"; - -ChartJS.register(CategoryScale, LinearScale, BarElement, LineElement, PointElement, Title, Tooltip, Legend); - -const Dashboard = () => { - const [userData, setUserData] = useState(null); - const [chartData, setChartData] = useState([]); - const [liveChartData, setLiveChartData] = useState({ labels: [], data: [] }); - const [quote, setQuote] = useState(""); - const [habits, setHabits] = useState([]); - const [selectedHabit, setSelectedHabit] = useState(null); - const [educationResources, setEducationResources] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - const navigate = useNavigate(); - - useEffect(() => { - const fetchAllData = async () => { - const token = localStorage.getItem("authToken"); - - if (!token) { - console.warn("No token found, redirecting to login"); - navigate("/login"); - return; - } - - try { - const decodedToken = jwtDecode(token); - const isTokenExpired = decodedToken.exp * 1000 < Date.now(); - if (isTokenExpired) { - console.warn("Token expired, redirecting to login"); - localStorage.removeItem("authToken"); - navigate("/login"); - return; - } - - await Promise.allSettled([ - fetchDashboardData(token), - fetchChartData(token), - fetchQuote(), - fetchHabits(), - fetchEducationResources(), - ]); - - setLoading(false); - } catch (err) { - console.error("Error fetching data:", err); - setError("An error occurred while loading data. Please try again later."); - setLoading(false); - } - }; - - fetchAllData(); - - const interval = setInterval(() => { - updateLiveChartData(); - }, 1000); // Update every second - - return () => clearInterval(interval); - }, [navigate]); - - const fetchDashboardData = async (token) => { - try { - const response = await axios.get( - `${process.env.REACT_APP_BACKEND_URL}/api/dashboard`, - { - headers: { - Authorization: `Bearer ${token}`, - }, - } - ); - setUserData(response.data); - } catch (err) { - console.error("Error fetching dashboard data:", err); - setUserData({ username: "Guest", email: "guest@example.com" }); // Fallback demo data - } - }; - - const fetchChartData = async (token) => { - try { - const response = await axios.get( - `${process.env.REACT_APP_BACKEND_URL}/api/chart-data`, - { - headers: { - Authorization: `Bearer ${token}`, - }, - } - ); - setChartData(response.data || []); - } catch (err) { - console.error("Error fetching chart data:", err); - setChartData([]); - } - }; - - const fetchQuote = async () => { - try { - const response = await axios.get("https://api.allorigins.win/get?url=" + encodeURIComponent("https://zenquotes.io/api/random")); - const parsedResponse = JSON.parse(response.data.contents); - const quoteText = parsedResponse[0]?.q + " - " + parsedResponse[0]?.a; - setQuote(quoteText); - } catch (err) { - console.error("Error fetching motivational quote:", err); - setQuote("Stay motivated to achieve your goals!"); - } - }; - - const fetchHabits = () => { - const habitList = [ - "Exercise daily", "Read 20 minutes", "Write a journal", "Practice mindfulness", - "Learn a new skill", "Drink more water", "Declutter one area", "Plan tomorrow's tasks", - "Practice gratitude", "Stretch for 10 minutes", "Limit screen time", "Go for a walk", - "Meditate for 5 minutes", "Write a to-do list", "Call a friend or family member", - "Learn a new word", "Cook a healthy meal", "Practice deep breathing", - "Spend time in nature", "Reflect on your day", "Limit caffeine intake", - "Read a motivational quote", "Track your expenses", "Organize your workspace", - "Take a power nap", "Smile at a stranger", "Do 15 minutes of cardio", - "Write down a goal", "Compliment someone", "Focus on a single task", - "Avoid procrastination", "Limit social media", "Journal about gratitude", - "Set a new habit", "Break a bad habit", "Watch an educational video", - "Learn a hobby", "Spend time with loved ones", "Volunteer for a cause", - "Reflect on your strengths", "Set a daily affirmation", - "Do a random act of kindness", "Focus on posture", "Set a digital detox day", - "Drink herbal tea", "Write about your dreams", "Spend time with a pet", - "Work on a personal project", "Learn a new recipe", - ]; - - const generateHabits = () => { - const shuffledHabits = habitList.sort(() => 0.5 - Math.random()); - setHabits(shuffledHabits.slice(0, 3)); - }; - - generateHabits(); - }; - - const displayHabitDetails = (habit) => { - const habitDetails = { - "Exercise daily": "Improve your physical health and energy levels by exercising daily.", - "Read 20 minutes": "Expand your knowledge and vocabulary by reading every day.", - "Write a journal": "Reflect on your thoughts and experiences by keeping a daily journal.", - "Practice mindfulness": "Cultivate awareness and reduce stress through mindfulness practices.", - "Learn a new skill": "Develop yourself by learning something new and exciting.", - "Drink more water": "Stay hydrated to maintain your overall health and energy.", - "Declutter one area": "Organize your space and clear your mind by decluttering daily.", - "Plan tomorrow's tasks": "Stay organized and productive by planning your tasks in advance.", - "Practice gratitude": "Improve your mood and mindset by focusing on things you are grateful for.", - "Stretch for 10 minutes": "Increase your flexibility and relieve tension with a daily stretch.", - "Limit screen time": "Protect your eyes and mental health by reducing screen usage.", - "Go for a walk": "Boost your physical and mental health with a relaxing walk.", - "Meditate for 5 minutes": "Calm your mind and reduce stress with a short meditation session.", - "Write a to-do list": "Organize your day and achieve your goals by creating a to-do list.", - "Call a friend or family member": "Strengthen relationships by connecting with loved ones.", - "Learn a new word": "Expand your vocabulary by learning a new word every day.", - "Cook a healthy meal": "Take control of your diet by preparing a nutritious meal.", - "Practice deep breathing": "Relieve stress and improve focus with deep breathing exercises.", - "Spend time in nature": "Recharge and gain clarity by spending time outdoors.", - "Reflect on your day": "Analyze your achievements and challenges by reflecting daily.", - "Limit caffeine intake": "Improve your sleep and reduce anxiety by moderating caffeine consumption.", - "Read a motivational quote": "Stay inspired and motivated by reading uplifting quotes.", - "Track your expenses": "Take control of your finances by monitoring your spending habits.", - "Organize your workspace": "Increase productivity by keeping your workspace tidy.", - "Take a power nap": "Boost your energy and focus with a short nap during the day.", - "Smile at a stranger": "Spread positivity and kindness with a simple smile.", - "Do 15 minutes of cardio": "Enhance your cardiovascular health with quick daily exercise.", - "Write down a goal": "Clarify your aspirations and track progress by setting a goal.", - "Compliment someone": "Brighten someone's day and foster positivity with a genuine compliment.", - "Focus on a single task": "Increase productivity by concentrating on one task at a time.", - "Avoid procrastination": "Achieve your goals faster by staying disciplined and proactive.", - "Limit social media": "Protect your mental health by spending less time on social media.", - "Journal about gratitude": "Develop a positive mindset by writing about things you are thankful for.", - "Set a new habit": "Take a step toward self-improvement by establishing a new habit.", - "Break a bad habit": "Improve your life by identifying and stopping an unhelpful habit.", - "Watch an educational video": "Learn something new by watching an informative video.", - "Learn a hobby": "Add joy to your life by picking up a fun and creative hobby.", - "Spend time with loved ones": "Strengthen bonds by sharing quality time with those who matter.", - "Volunteer for a cause": "Make a difference by giving your time to a meaningful cause.", - "Reflect on your strengths": "Build confidence by acknowledging your abilities and achievements.", - "Set a daily affirmation": "Encourage positivity with empowering statements each day.", - "Do a random act of kindness": "Brighten someone's day with an unexpected kind gesture.", - "Focus on posture": "Prevent discomfort and boost confidence by improving your posture.", - "Set a digital detox day": "Recharge by spending a day away from electronic devices.", - "Drink herbal tea": "Relax and unwind with a calming cup of herbal tea.", - "Write about your dreams": "Gain insights and inspire creativity by journaling your dreams.", - "Spend time with a pet": "Enjoy companionship and reduce stress by spending time with a pet.", - "Work on a personal project": "Pursue your passion by dedicating time to a personal project.", - "Learn a new recipe": "Expand your culinary skills by trying out a new recipe.", - }; - - return habitDetails[habit] || "Details not available."; - }; - - const fetchEducationResources = async () => { - try { - setEducationResources([ - // Programming & Web Development - { name: "freeCodeCamp", link: "https://www.freecodecamp.org/", category: "Programming & Web Development" }, - { name: "MDN Web Docs", link: "https://developer.mozilla.org/", category: "Programming & Web Development" }, - { name: "W3Schools", link: "https://www.w3schools.com/", category: "Programming & Web Development" }, - { name: "GeeksforGeeks", link: "https://www.geeksforgeeks.org/", category: "Programming & Web Development" }, - { name: "Codecademy", link: "https://www.codecademy.com/", category: "Programming & Web Development" }, - { name: "The Odin Project", link: "https://www.theodinproject.com/", category: "Programming & Web Development" }, - - // Data Science & Machine Learning - { name: "Kaggle Learn", link: "https://www.kaggle.com/learn", category: "Data Science & Machine Learning" }, - { name: "Fast.ai", link: "https://www.fast.ai/", category: "Data Science & Machine Learning" }, - { name: "DataCamp", link: "https://www.datacamp.com/", category: "Data Science & Machine Learning" }, - { name: "Coursera - Machine Learning by Andrew Ng", link: "https://www.coursera.org/learn/machine-learning", category: "Data Science & Machine Learning" }, - - // UI/UX & Design - { name: "Interaction Design Foundation", link: "https://www.interaction-design.org/", category: "UI/UX & Design" }, - { name: "Figma Learn", link: "https://www.figma.com/resources/learn-design/", category: "UI/UX & Design" }, - { name: "Adobe XD Ideas", link: "https://xd.adobe.com/ideas/", category: "UI/UX & Design" }, - { name: "Canva Design School", link: "https://www.canva.com/learn/", category: "UI/UX & Design" }, - - // Mathematics & Sciences - { name: "Khan Academy (Math & Science)", link: "https://www.khanacademy.org/science", category: "Mathematics & Sciences" }, - { name: "MIT OpenCourseWare", link: "https://ocw.mit.edu/", category: "Mathematics & Sciences" }, - { name: "Brilliant", link: "https://www.brilliant.org/", category: "Mathematics & Sciences" }, - { name: "Wolfram MathWorld", link: "https://mathworld.wolfram.com/", category: "Mathematics & Sciences" }, - - // Language Learning - { name: "Duolingo", link: "https://www.duolingo.com/", category: "Language Learning" }, - { name: "Babbel", link: "https://www.babbel.com/", category: "Language Learning" }, - { name: "LingQ", link: "https://www.lingq.com/", category: "Language Learning" }, - { name: "italki", link: "https://www.italki.com/", category: "Language Learning" }, - - // Business & Finance - { name: "edX Business Courses", link: "https://www.edx.org/learn/business", category: "Business & Finance" }, - { name: "Coursera Business Specializations", link: "https://www.coursera.org/browse/business", category: "Business & Finance" }, - { name: "HubSpot Academy", link: "https://academy.hubspot.com/", category: "Business & Finance" }, - { name: "Futureskilling (Udemy)", link: "https://www.udemy.com/topic/business/", category: "Business & Finance" }, - - // Creative Skills - { name: "Skillshare", link: "https://www.skillshare.com/", category: "Creative Skills" }, - { name: "Domestika", link: "https://www.domestika.org/", category: "Creative Skills" }, - { name: "MasterClass", link: "https://www.masterclass.com/", category: "Creative Skills" }, - { name: "LinkedIn Learning (Creative Section)", link: "https://www.linkedin.com/learning/", category: "Creative Skills" }, - - // General Education & MOOCs - { name: "Khan Academy (General)", link: "https://www.khanacademy.org/", category: "General Education & MOOCs" }, - { name: "Coursera", link: "https://www.coursera.org/", category: "General Education & MOOCs" }, - { name: "edX", link: "https://www.edx.org/", category: "General Education & MOOCs" }, - { name: "FutureLearn", link: "https://www.futurelearn.com/", category: "General Education & MOOCs" }, - { name: "OpenLearn (Open University)", link: "https://www.open.edu/openlearn/", category: "General Education & MOOCs" }, - - // Career Development & Professional Skills - { name: "Google Digital Garage", link: "https://digitalgarage.withgoogle.com/", category: "Career Development & Professional Skills" }, - { name: "Alison", link: "https://alison.com/", category: "Career Development & Professional Skills" }, - { name: "Udemy Professional Skills Courses", link: "https://www.udemy.com/", category: "Career Development & Professional Skills" }, - { name: "CareerFoundry", link: "https://careerfoundry.com/", category: "Career Development & Professional Skills" } - ]); - } catch (err) { - console.error("Error fetching education resources:", err); - setEducationResources([]); - } - }; - - const updateLiveChartData = () => { - setLiveChartData((prevState) => { - const now = new Date(); - const timeLabel = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`; - const newData = [...prevState.data, Math.random() * 100]; - const newLabels = [...prevState.labels, timeLabel]; - - if (newData.length > 10) { - newData.shift(); - newLabels.shift(); - } - - return { labels: newLabels, data: newData }; - }); - }; - - const handleLogout = () => { - localStorage.removeItem("authToken"); - navigate("/login"); - }; - - const generatePlaceholderChartData = () => ({ - labels: ["Skill 1", "Skill 2", "Skill 3"], - datasets: [ - { - label: "Progress", - data: [0, 0, 0], - backgroundColor: "rgba(75, 192, 192, 0.6)", - }, - ], - }); - - const chartOptions = { - responsive: true, - plugins: { - legend: { - display: true, - }, - }, - }; - - if (loading) { - return ( -
-

Loading...

-
- ); - } - - const categories = educationResources.reduce((acc, resource) => { - if (!acc[resource.category]) { - acc[resource.category] = []; - } - acc[resource.category].push(resource); - return acc; - }, {}); - - return ( -
-

Dashboard

- {userData && ( -
-

Welcome, {userData.username}

-

Your email: {userData.email}

- -
- )} - -
-

Motivational Quote

-

{quote}

-
- -
-

Habit Ideas

-
    - {habits.map((habit, index) => ( -
  • displayHabitDetails(habit)}> - {habit} -
  • - ))} -
- - {selectedHabit &&

{selectedHabit}

} -
- -
-

Education Resources

- {Object.keys(categories).map((cat) => ( -
-

{cat}

- -
- ))} -
- -
-

Your Progress

- {chartData.length > 0 ? ( - item.name || "Unknown Skill"), - datasets: [ - { - label: "Skill Progress", - data: chartData.map((item) => item.progress || 0), - backgroundColor: "rgba(75, 192, 192, 0.6)", - }, - ], - }} - options={chartOptions} - /> - ) : ( - - )} -
- -
- -
- -
- -
- -
- -
- -
- -
- -
- -
- -
-

AI Adaptive Pulse

- -
-
- ); -}; - -export default Dashboard; diff --git a/frontend/src/components/Game.css b/frontend/src/components/Game.css new file mode 100644 index 0000000..f88c3dc --- /dev/null +++ b/frontend/src/components/Game.css @@ -0,0 +1,104 @@ +/* Game Container */ +.game-container { + font-family: Arial, sans-serif; + text-align: center; + background: #f9f9f9; + padding: 20px; + max-width: 600px; + margin: 0 auto; + border-radius: 10px; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); + } + + /* Header */ + .game-header { + background-color: #6200ea; + color: #fff; + padding: 10px; + border-radius: 10px 10px 0 0; + } + + .stats { + display: flex; + justify-content: space-around; + margin-top: 10px; + } + + .stats p { + margin: 0; + } + + /* Game Area */ + .game-area { + padding: 20px; + } + + h2 { + margin-bottom: 10px; + } + + .options { + display: flex; + flex-direction: column; + gap: 10px; + } + + .option-button { + background-color: #6200ea; + color: white; + border: none; + padding: 10px; + border-radius: 5px; + cursor: pointer; + font-size: 16px; + transition: background-color 0.3s ease; + } + + .option-button:hover { + background-color: #3700b3; + } + + .feedback { + margin-top: 10px; + font-weight: bold; + color: #4caf50; + } + + /* Footer */ + .game-footer { + margin-top: 20px; + } + + .progress-bar-container { + background-color: #e0e0e0; + border-radius: 10px; + height: 10px; + overflow: hidden; + } + + .progress-bar { + background-color: #6200ea; + height: 10px; + transition: width 0.3s ease; + } + + /* Game Over Section */ + .game-over { + padding: 20px; + } + + .restart-button { + background-color: #03dac6; + color: white; + border: none; + padding: 10px; + border-radius: 5px; + cursor: pointer; + font-size: 16px; + transition: background-color 0.3s ease; + } + + .restart-button:hover { + background-color: #018786; + } + \ No newline at end of file diff --git a/frontend/src/components/Game.jsx b/frontend/src/components/Game.jsx new file mode 100644 index 0000000..15edb2b --- /dev/null +++ b/frontend/src/components/Game.jsx @@ -0,0 +1,118 @@ +import React, { useState } from 'react'; +import './Game.css'; + +const scenarios = [ + { + id: 1, + title: "Time Crunch", + description: "You have 3 tasks due at the same time. How do you prioritize?", + options: [ + { text: "Finish the easiest task first", score: 5 }, + { text: "Complete the hardest task first", score: 10 }, + { text: "Delegate to your team", score: 8 }, + ], + }, + { + id: 2, + title: "Budget Balancer", + description: "You have $500 left in your monthly budget. What do you do?", + options: [ + { text: "Save for emergencies", score: 10 }, + { text: "Invest in a course to improve skills", score: 8 }, + { text: "Buy a new gadget", score: 3 }, + ], + }, + { + id: 3, + title: "Conflict Resolver", + description: + "Your team is in disagreement over a project direction. How do you handle it?", + options: [ + { text: "Listen to everyone's input and find a compromise", score: 10 }, + { text: "Decide quickly to avoid delays", score: 5 }, + { text: "Let someone else decide", score: 2 }, + ], + }, +]; + +function Game() { + const [score, setScore] = useState(0); + const [progress, setProgress] = useState(0); + const [currentScenarioIndex, setCurrentScenarioIndex] = useState(0); + const [feedback, setFeedback] = useState(""); + + const maxProgress = scenarios.length; + + const handleOptionClick = (optionScore) => { + setScore(score + optionScore); + setProgress(progress + 1); + setFeedback(`You earned ${optionScore} points!`); + + // Proceed to the next scenario or reset if completed + if (currentScenarioIndex + 1 < scenarios.length) { + setCurrentScenarioIndex(currentScenarioIndex + 1); + } else { + setFeedback("Game Over! Well done!"); + } + }; + + const currentScenario = scenarios[currentScenarioIndex]; + + return ( +
+
+

MindVault Quest

+
+

Score: {score}

+

Progress: {progress}/{maxProgress}

+
+
+
+ {progress < maxProgress ? ( + <> +

{currentScenario.title}

+

{currentScenario.description}

+
+ {currentScenario.options.map((option, index) => ( + + ))} +
+ {feedback &&

{feedback}

} + + ) : ( +
+

Congratulations!

+

Your final score: {score}

+ +
+ )} +
+ +
+ ); +} + +export default Game;