diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 9595004..b335624 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -1,35 +1,35 @@ -name: Python Tests +# name: Python Tests -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] +# on: +# push: +# branches: [ main, master ] +# pull_request: +# branches: [ main, master ] -jobs: - test: - runs-on: ubuntu-latest +# jobs: +# test: +# runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 +# steps: +# - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.10' +# - name: Set up Python +# uses: actions/setup-python@v4 +# with: +# python-version: '3.10' - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt +# - name: Install dependencies +# run: | +# python -m pip install --upgrade pip +# pip install -r requirements.txt - - name: Create dummy text files for testing - run: | - mkdir -p app-backend - echo "Sample Quran verse 1\nSample Quran verse 2" > app-backend/quran.txt - echo "Sample Bible verse 1\nSample Bible verse 2" > app-backend/bible.txt +# - name: Create dummy text files for testing +# run: | +# mkdir -p app-backend +# echo "Sample Quran verse 1\nSample Quran verse 2" > app-backend/quran.txt +# echo "Sample Bible verse 1\nSample Bible verse 2" > app-backend/bible.txt - - name: Run tests - run: | - cd tests - python run_tests.py \ No newline at end of file +# - name: Run tests +# run: | +# cd tests +# python run_tests.py diff --git a/app-backend/app.py b/app-backend/app.py index 14b7b30..330e553 100644 --- a/app-backend/app.py +++ b/app-backend/app.py @@ -18,6 +18,10 @@ from urllib.parse import quote from sentence_transformers import SentenceTransformer import chromadb +from apscheduler.schedulers.background import BackgroundScheduler +from datetime import datetime, timedelta +from collections import Counter +import jwt load_dotenv() @@ -28,10 +32,11 @@ app.secret_key ="zzboss1234" EMAIL_ADDRESS = os.getenv('EMAIL_ADDRESS') +print(EMAIL_ADDRESS) EMAIL_PASSWORD = os.getenv('EMAIL_PASSWORD') logging.basicConfig(level=logging.INFO) -CC_EMAIL = "zainxaidi2003@gmail.com" +CC_EMAIL = "ammarnadeem490@gmail.com" db = SQLAlchemy(app) bcrypt = Bcrypt(app) @@ -67,7 +72,6 @@ class User(db.Model): admin = db.Column(db.Boolean, default=False) treated = db.Column(db.Boolean, default=False) is_active = db.Column(db.Boolean, default=True) - chats = db.relationship('Chat', backref='user', lazy=True) messages = db.relationship('Message', backref='user', lazy=True) user_activities = db.relationship('UserActivity', backref='user', lazy=True) @@ -75,8 +79,9 @@ class User(db.Model): journals = db.relationship('Journal', backref='user', lazy=True) forum_messages = db.relationship('ForumMessage', backref='user', lazy=True) moods = db.relationship('Mood', backref='user', lazy=True) - - + phone = db.Column(db.String(20), nullable=True) + religion = db.Column(db.String(100), nullable=True) + token = db.Column(db.Text, nullable=True) class Chat(db.Model): __tablename__ = 'chats' @@ -123,7 +128,9 @@ class UserActivity(db.Model): recommended_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) completed = db.Column(db.Boolean, default=False, nullable=True) completed_at = db.Column(db.DateTime, nullable=True) - completed_in_time = db.Column(db.Boolean, default=False, nullable=True) + completed_in_time = db.Column(db.Boolean, default=False, nullable=False) + + activity = db.relationship('Activity', backref='user_activity_details', lazy=True) @@ -133,9 +140,8 @@ class Activity(db.Model): mood = db.Column(db.Text, nullable=False) activity_path = db.Column(db.Text, nullable=True) recommended_activity = db.Column(db.Text,db.ForeignKey('subactivities.name'), nullable=True) - - - user_activities = db.relationship('UserActivity', backref='activities', lazy=True) + + # user_activities = db.relationship('UserActivity', backref='activity_parent', lazy=True) class Review(db.Model): __tablename__ = 'reviews' @@ -354,8 +360,9 @@ class Meta: @app.route('/signup', methods=['POST']) def signup(): data = request.get_json() - fname = data.get('firstname') - lname = data.get('lastname') + print("data",data) + fname = data.get('fname') + lname = data.get('lname') email = data.get('email') password = data.get('password') confirm_password = data.get('confirm_password') @@ -398,11 +405,37 @@ def login(): return jsonify({"error": "Email and password are required"}), 400 user = User.query.filter_by(email=email).first() + if not user or not bcrypt.check_password_hash(user.password, password): return jsonify({"error": "Invalid email or password"}), 401 + token = jwt.encode({'email': user.email},"This is my secret key", algorithm='HS256') + user.token = token + db.session.commit() + return jsonify({"message": "Login successful", "user": user_schema.dump(user),"token": token}), 200 + + +@app.route('/logout', methods=['POST']) +def logout(): + token = request.headers.get('Authorization') + + if not token: + return jsonify({'error': 'Token missing'}), 400 + + # Remove "Bearer " from the token if it's in the header + if token.startswith('Bearer '): + token = token.split(' ')[1] + + user = User.query.filter_by(token=token).first() + + if not user: + return jsonify({'error': 'Invalid token'}), 400 + + user.token = None + db.session.commit() + + return jsonify({'message': 'Logout successful'}), 200 - return jsonify({"message": "Login successful", "user": user_schema.dump(user)}), 200 @app.route('/create_chat', methods=['POST']) def create_chat(): @@ -580,14 +613,15 @@ def delete_chat(): db.session.rollback() return jsonify({"error": str(e)}), 500 -@app.route("/contact_us", methods=["POST", "GET"]) +@app.route("/contact_us", methods=["POST"]) def contact_us(): - print(f"Form Data: {request.form}") - if request.method == "POST": + # print(f"Form Data: {request.form}") + # if request.method == "POST": try: - name = request.form['name'] - email = request.form['email'] - query = request.form['query'] + data = request.get_json() + name = data.get('name') + email = data.get('email') + query = data.get('query') contacted_on = datetime.now() # data = request.get_json().get("data", {}) # name = data.get("name") @@ -1216,9 +1250,12 @@ def add_journal(): db.session.commit() try: - prompt = f"Analyze the following journal and determine the mood. Just give a single word answer.\nJournal: {text}" + prompt = f"Analyze the following journal and determine the mood. Just give a single word answer.Mood must be among these [\"happy\", \"sad\", \"angry\", \"calm\", \"stressed\", \"excited\", \"bored\", \"anxious\", \"content\"].Just give a single word answer.\nJournal: {text}" + print(1,prompt) response = model.generate_content(prompt) + print(2,response) detected_mood = response.candidates[0].content.parts[0].text.strip() if response.candidates else "Neutral" + print(3,detected_mood) except Exception as e: detected_mood = "Unknown" @@ -1235,7 +1272,8 @@ def add_journal(): "first_name": user.first_name, "last_name": user.last_name, "text": text, - "mood": detected_mood + "mood": detected_mood, + "created_at":new_journal.created_at }), 201 elif questionaire_flag and mood: @@ -1909,16 +1947,73 @@ def mark_activity_as_done(): }), 200 +# @app.route('/get_activities/', methods=['GET']) +# def get_activities(user_id): +# assigned_activities = UserActivity.query.filter_by(user_id=user_id, completed=False).all() +# completed_activities = UserActivity.query.filter_by(user_id=user_id, completed=True).all() +# print(assigned_activities,completed_activities) +# assigned_list = [ +# { +# "activity_id": act.activity_id, +# "activity_name": act.activity.name, # Assuming 'name' is a field in the Activity model +# "deadline": act.deadline.strftime('%Y-%m-%d %H:%M:%S') if act.deadline else "No deadline" +# } +# for act in assigned_activities +# ] + +# completed_list = [ +# { +# "activity_id": act.activity_id, +# "activity_name": act.activity.name, # Assuming 'name' is a field in the Activity model +# "completed_at": act.completed_at.strftime('%Y-%m-%d %H:%M:%S') if act.completed_at else "Not marked", +# "completed_in_time": act.completed_in_time +# } +# for act in completed_activities +# ] + +# return jsonify({"Assigned Activities": assigned_list, "Completed Activities": completed_list}), 200 +# # assigned_list = [{"activity_id": act.activity_id} for act in assigned_activities] +# # completed_list = [{"activity_id": act.activity_id, "completed_at": act.completed_at.strftime('%Y-%m-%d %H:%M:%S') if act.completed_at else "Not marked"} for act in completed_activities] + +# # return jsonify({"Assigned Activities": assigned_list, "Completed Activities": completed_list}), 200 @app.route('/get_activities/', methods=['GET']) def get_activities(user_id): - assigned_activities = UserActivity.query.filter_by(user_id=user_id, completed=False).all() - completed_activities = UserActivity.query.filter_by(user_id=user_id, completed=True).all() + try: + # Get active and completed activities + assigned_activities = UserActivity.query.filter_by( + user_id=user_id, + completed=False + ).all() - assigned_list = [{"activity_id": act.activity_id} for act in assigned_activities] - completed_list = [{"activity_id": act.activity_id, "completed_at": act.completed_at.strftime('%Y-%m-%d %H:%M:%S') if act.completed_at else "Not marked"} for act in completed_activities] + completed_activities = UserActivity.query.filter_by( + user_id=user_id, + completed=True + ).all() + + # Serialize assigned activities + assigned_list = [{ + "activity_id": ua.activity.id, + "activity_name": ua.activity.recommended_activity, + "mood": ua.activity.mood, + "activity_path": ua.activity.activity_path, + "deadline": ua.deadline.strftime('%Y-%m-%d %H:%M:%S') if ua.deadline else None + } for ua in assigned_activities] + + # Serialize completed activities + completed_list = [{ + "activity_id": ua.activity.id, + "activity_name": ua.activity.recommended_activity, + "completed_at": ua.completed_at.strftime('%Y-%m-%d %H:%M:%S') if ua.completed_at else None, + "completed_in_time": ua.completed_in_time + } for ua in completed_activities] - return jsonify({"Assigned Activities": assigned_list, "Completed Activities": completed_list}), 200 + return jsonify({ + "assigned_activities": assigned_list, + "completed_activities": completed_list + }), 200 + except Exception as e: + return jsonify({"error": str(e)}), 500 @app.route('/recommend_activity', methods=['POST']) def recommend_activity(): @@ -2213,7 +2308,183 @@ def alot_coupons(): except Exception as e: return jsonify({"error": str(e)}), 500 - +@app.route('/profile', methods=['PATCH']) +def update_profile(): + try: + data = request.get_json() + print("data",data) + client_id = data.get('client_id') + if not client_id: + return jsonify({"error": "Client ID is required"}), 400 + + user = db.session.get(User, client_id) + if not user: + return jsonify({"error": "User not found"}), 404 + print(2) + if 'fname' in data: + user.first_name = data['fname'] + if 'lname' in data: + user.last_name = data['lname'] + if 'phone' in data: + user.phone = data['phone'] + if 'religion' in data: + user.religion = data['religion'] + print(3) + user.updated_at = datetime.now(timezone.utc) + db.session.commit() + print(user) + return jsonify({"message": "Profile updated successfully"}), 200 + + except Exception as e: + return jsonify({"error": str(e)}), 500 + + daily_moods.setdefault(day, []).append(mood.mood_category) + +ALLOWED_MOODS = {"happy", "sad", "angry", "calm", "stressed", "excited", "bored", "anxious", "content"} + +@app.route('/user//weekly_moods', methods=['GET']) +def get_weekly_moods(user_id): + try: + end_date = datetime.now() + start_date = end_date - timedelta(days=7) + + moods = ( + db.session.query(Mood) + .filter( + Mood.user_id == user_id, + Mood.date >= start_date, + Mood.date <= end_date + ) + .order_by(Mood.date) + .all() + ) + + # Group moods by day and convert each mood to lowercase. + daily_moods = {} + for mood in moods: + day = mood.date.strftime('%Y-%m-%d') + mood_lower = mood.mood_category.lower() + # Only add if the mood is allowed + if mood_lower in ALLOWED_MOODS: + daily_moods.setdefault(day, []).append(mood_lower) + + weekly_data = {} + for day, moods_list in daily_moods.items(): + if moods_list: + # Determine overall mood as the most common allowed mood + overall_mood = Counter(moods_list).most_common(1)[0][0] + else: + overall_mood = None + weekly_data[day] = { + "overall_mood": overall_mood, + "all_moods": moods_list + } + + return jsonify({ + "user_id": user_id, + "weekly_moods": weekly_data + }), 200 + + except Exception as e: + return jsonify({"error": str(e)}), 500 + + + + + + +# Schduler to respond to journals of day +def check_and_add_activities(): + with app.app_context(): + # Get the current date to filter journals by date + # today_date = (datetime.now() - timedelta(days=1)).date() + today_date = datetime.now().date() + print("today_date",today_date) + + # Get all users who have less than 10 activities + users = User.query.all() + print("users",users) + for user in users: + # Count the number of journals for the user on the current day + journals_today = Journal.query.filter( + Journal.user_id == user.id, + db.func.date(Journal.created_at) == today_date + ).all() + print("journals_today",journals_today) + + if len(journals_today) >= 1: # If there is at least 1 journal for the day + # Get the latest mood of the user + latest_mood = Mood.query.filter(Mood.user_id == user.id).order_by(Mood.date.desc()).first() + + if not latest_mood: + continue # Skip if no mood data is found + + # Check if user has less than 10 activities + user_activities_count = UserActivity.query.filter_by(user_id=user.id).count() + if user_activities_count < 10: + # Get all active subactivities + subactivities = SubActivity.query.filter_by(is_active=True).all() + subactivities_list = [subactivity.name for subactivity in subactivities] + + try: + # Generate activity path based on user's mood + prompt = ( + f"Generate a simple activity path for a user feeling {latest_mood.mood_category}. " + f"Suggest a sequence of these activities: {', '.join(subactivities_list)}. " + "The output should be formatted as a simple comma list." + ) + response = model.generate_content(prompt) + activity_path = response.candidates[0].content.parts[0].text.strip() + + recommended_activities = activity_path.split(', ') + + # Set the deadline for the activity + deadline = datetime.now() + timedelta(days=7) + print(recommended_activities,deadline,response) + # Create a new activity + new_activity = Activity( + mood=latest_mood.mood_category, + activity_path=activity_path, + recommended_activity=', '.join(recommended_activities) + ) + db.session.add(new_activity) + db.session.commit() + + # Add the activity to user_activities + new_user_activity = UserActivity( + user_id=user.id, + activity_id=new_activity.id, + recommended_at=datetime.now(), + deadline=deadline, + completed=False # Explicitly setting the value + ) + db.session.add(new_user_activity) + db.session.commit() + + # Remove the journals for the day once activities are added + for journal in journals_today: + db.session.delete(journal) + db.session.commit() + + print(f"Activities added for user {user.id} and journals removed for {today_date}") + + except Exception as e: + db.session.rollback() + print(f"Error occurred while recommending activity for user {user.id}: {str(e)}") + continue + else: + print(f"User {user.id} already has 10 activities. No new activities added.") + + +# Scheduler to run the check_and_add_activities function every midnight +# scheduler = BackgroundScheduler() +# scheduler.add_job(check_and_add_activities, 'interval', days=1, start_date='2025-04-06 00:00:00') # Start at midnight of a specific date +# scheduler.start() +scheduler = BackgroundScheduler() +start_time = datetime.now() + timedelta(seconds=10) # Set to 10 seconds from now +scheduler.add_job(check_and_add_activities, 'date', run_date=start_time) # Run once at the specified time +scheduler.start() + with app.app_context(): db.create_all() diff --git a/app-backend/chroma_db/d8c988d2-adb9-46c3-817d-005700fdc6fc/data_level0.bin b/app-backend/chroma_db/d8c988d2-adb9-46c3-817d-005700fdc6fc/data_level0.bin new file mode 100644 index 0000000..09cffb6 Binary files /dev/null and b/app-backend/chroma_db/d8c988d2-adb9-46c3-817d-005700fdc6fc/data_level0.bin differ diff --git a/app-backend/chroma_db/d8c988d2-adb9-46c3-817d-005700fdc6fc/header.bin b/app-backend/chroma_db/d8c988d2-adb9-46c3-817d-005700fdc6fc/header.bin new file mode 100644 index 0000000..e85f465 Binary files /dev/null and b/app-backend/chroma_db/d8c988d2-adb9-46c3-817d-005700fdc6fc/header.bin differ diff --git a/app-backend/chroma_db/d8c988d2-adb9-46c3-817d-005700fdc6fc/length.bin b/app-backend/chroma_db/d8c988d2-adb9-46c3-817d-005700fdc6fc/length.bin new file mode 100644 index 0000000..ba4322f Binary files /dev/null and b/app-backend/chroma_db/d8c988d2-adb9-46c3-817d-005700fdc6fc/length.bin differ diff --git a/app-backend/chroma_db/d8c988d2-adb9-46c3-817d-005700fdc6fc/link_lists.bin b/app-backend/chroma_db/d8c988d2-adb9-46c3-817d-005700fdc6fc/link_lists.bin new file mode 100644 index 0000000..e69de29 diff --git a/app-backend/instance/eunoia.db b/app-backend/instance/eunoia.db index 5624aee..dde75d0 100755 Binary files a/app-backend/instance/eunoia.db and b/app-backend/instance/eunoia.db differ diff --git a/app-backend/migrations/versions/6bac0db192e3_add_phone_and_religion_fields_to_user_.py b/app-backend/migrations/versions/6bac0db192e3_add_phone_and_religion_fields_to_user_.py new file mode 100644 index 0000000..ef09d54 --- /dev/null +++ b/app-backend/migrations/versions/6bac0db192e3_add_phone_and_religion_fields_to_user_.py @@ -0,0 +1,54 @@ +"""Add phone and religion fields to User model + +Revision ID: 6bac0db192e3 +Revises: fe5a3cd1718d +Create Date: 2025-04-07 17:54:19.070795 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '6bac0db192e3' +down_revision = 'fe5a3cd1718d' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('user', schema=None) as batch_op: + batch_op.add_column(sa.Column('phone', sa.String(length=20), nullable=True)) + batch_op.add_column(sa.Column('religion', sa.String(length=100), nullable=True)) + + with op.batch_alter_table('user_activities', schema=None) as batch_op: + batch_op.alter_column('completed', + existing_type=sa.BOOLEAN(), + nullable=True, + existing_server_default=sa.text('(false)')) + batch_op.alter_column('completed_in_time', + existing_type=sa.BOOLEAN(), + nullable=False, + existing_server_default=sa.text('(false)')) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('user_activities', schema=None) as batch_op: + batch_op.alter_column('completed_in_time', + existing_type=sa.BOOLEAN(), + nullable=True, + existing_server_default=sa.text('(false)')) + batch_op.alter_column('completed', + existing_type=sa.BOOLEAN(), + nullable=False, + existing_server_default=sa.text('(false)')) + + with op.batch_alter_table('user', schema=None) as batch_op: + batch_op.drop_column('religion') + batch_op.drop_column('phone') + + # ### end Alembic commands ### diff --git a/app-backend/migrations/versions/e23fd24ef6fe_add_token_field_in_the_user_model.py b/app-backend/migrations/versions/e23fd24ef6fe_add_token_field_in_the_user_model.py new file mode 100644 index 0000000..f878c87 --- /dev/null +++ b/app-backend/migrations/versions/e23fd24ef6fe_add_token_field_in_the_user_model.py @@ -0,0 +1,32 @@ +"""add token field in the user model + +Revision ID: e23fd24ef6fe +Revises: 6bac0db192e3 +Create Date: 2025-04-08 10:16:32.646582 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'e23fd24ef6fe' +down_revision = '6bac0db192e3' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('user', schema=None) as batch_op: + batch_op.add_column(sa.Column('token', sa.Text(), nullable=True)) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('user', schema=None) as batch_op: + batch_op.drop_column('token') + + # ### end Alembic commands ### diff --git a/app-frontend/package-lock.json b/app-frontend/package-lock.json index 6d01d84..dbe61f6 100644 --- a/app-frontend/package-lock.json +++ b/app-frontend/package-lock.json @@ -10,12 +10,12 @@ "dependencies": { "@coreui/coreui": "^5.2.0", "@coreui/react": "^5.4.1", - "@emotion/react": "^11.13.3", - "@emotion/styled": "^11.13.0", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", "@heroicons/react": "^2.2.0", "@lottiefiles/dotlottie-react": "^0.12.0", - "@mui/icons-material": "^6.1.5", - "@mui/material": "^6.1.5", + "@mui/icons-material": "^6.4.10", + "@mui/material": "^6.4.10", "@radix-ui/react-avatar": "^1.1.2", "@radix-ui/react-checkbox": "^1.1.3", "@radix-ui/react-dialog": "^1.1.4", @@ -407,16 +407,16 @@ } }, "node_modules/@emotion/babel-plugin": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", - "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", - "@emotion/serialize": "^1.2.0", + "@emotion/serialize": "^1.3.3", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", @@ -432,14 +432,14 @@ "license": "MIT" }, "node_modules/@emotion/cache": { - "version": "11.13.1", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz", - "integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==", + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", "license": "MIT", "dependencies": { "@emotion/memoize": "^0.9.0", "@emotion/sheet": "^1.4.0", - "@emotion/utils": "^1.4.0", + "@emotion/utils": "^1.4.2", "@emotion/weak-memoize": "^0.4.0", "stylis": "4.2.0" } @@ -466,17 +466,17 @@ "license": "MIT" }, "node_modules/@emotion/react": { - "version": "11.13.3", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", - "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.12.0", - "@emotion/cache": "^11.13.0", - "@emotion/serialize": "^1.3.1", - "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", - "@emotion/utils": "^1.4.0", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", "@emotion/weak-memoize": "^0.4.0", "hoist-non-react-statics": "^3.3.1" }, @@ -490,15 +490,15 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz", - "integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", "license": "MIT", "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/unitless": "^0.10.0", - "@emotion/utils": "^1.4.1", + "@emotion/utils": "^1.4.2", "csstype": "^3.0.2" } }, @@ -509,17 +509,17 @@ "license": "MIT" }, "node_modules/@emotion/styled": { - "version": "11.13.0", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", - "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz", + "integrity": "sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.12.0", + "@emotion/babel-plugin": "^11.13.5", "@emotion/is-prop-valid": "^1.3.0", - "@emotion/serialize": "^1.3.0", - "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", - "@emotion/utils": "^1.4.0" + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" }, "peerDependencies": { "@emotion/react": "^11.0.0-rc.0", @@ -538,18 +538,18 @@ "license": "MIT" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", - "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", "license": "MIT", "peerDependencies": { "react": ">=16.8.0" } }, "node_modules/@emotion/utils": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz", - "integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", "license": "MIT" }, "node_modules/@emotion/weak-memoize": { @@ -1275,9 +1275,9 @@ "license": "MIT" }, "node_modules/@mui/core-downloads-tracker": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.5.tgz", - "integrity": "sha512-3J96098GrC95XsLw/TpGNMxhUOnoG9NZ/17Pfk1CrJj+4rcuolsF2RdF3XAFTu/3a/A+5ouxlSIykzYz6Ee87g==", + "version": "6.4.10", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.10.tgz", + "integrity": "sha512-cblGjlM6+xsptwyaALw8RbRIUoqmKxOqLxlk2LkTDhxqUuql1YSOKKLH3w+Yd2QLz28b7MR65sx1OjsRZUfOSQ==", "license": "MIT", "funding": { "type": "opencollective", @@ -1285,12 +1285,12 @@ } }, "node_modules/@mui/icons-material": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.5.tgz", - "integrity": "sha512-SbxFtO5I4cXfvhjAMgGib/t2lQUzcEzcDFYiRHRufZUeMMeXuoKaGsptfwAHTepYkv0VqcCwvxtvtWbpZLAbjQ==", + "version": "6.4.10", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.4.10.tgz", + "integrity": "sha512-c2KdFl4KZ0QYC+JSDTMCNjcuOL2rVSdIx/beo7FwJDh2e9XqC1MoLCjw6L1Jo40zbArkgJyg3oFORbXcRfgZOA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.25.7" + "@babel/runtime": "^7.26.0" }, "engines": { "node": ">=14.0.0" @@ -1300,7 +1300,7 @@ "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^6.1.5", + "@mui/material": "^6.4.10", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -1311,22 +1311,22 @@ } }, "node_modules/@mui/material": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.5.tgz", - "integrity": "sha512-rhaxC7LnlOG8zIVYv7BycNbWkC5dlm9A/tcDUp0CuwA7Zf9B9JP6M3rr50cNKxI7Z0GIUesAT86ceVm44quwnQ==", + "version": "6.4.10", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.4.10.tgz", + "integrity": "sha512-L1B0+Vg9NFjo3NcfODH3bohl6fIkzjyDBHBHb3Al4QI7owaJrFm2sSDyfz++iatzICug6U6q5tHLQrCLO71xkg==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.25.7", - "@mui/core-downloads-tracker": "^6.1.5", - "@mui/system": "^6.1.5", - "@mui/types": "^7.2.18", - "@mui/utils": "^6.1.5", + "@babel/runtime": "^7.26.0", + "@mui/core-downloads-tracker": "^6.4.10", + "@mui/system": "^6.4.10", + "@mui/types": "~7.2.24", + "@mui/utils": "^6.4.9", "@popperjs/core": "^2.11.8", - "@types/react-transition-group": "^4.4.11", + "@types/react-transition-group": "^4.4.12", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1", - "react-is": "^18.3.1", + "react-is": "^19.0.0", "react-transition-group": "^4.4.5" }, "engines": { @@ -1339,7 +1339,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^6.1.5", + "@mui/material-pigment-css": "^6.4.10", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -1360,19 +1360,19 @@ } }, "node_modules/@mui/material/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", "license": "MIT" }, "node_modules/@mui/private-theming": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.5.tgz", - "integrity": "sha512-FJqweqEXk0KdtTho9C2h6JEKXsOT7MAVH2Uj3N5oIqs6YKxnwBn2/zL2QuYYEtj5OJ87rEUnCfFic6ldClvzJw==", + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.9.tgz", + "integrity": "sha512-LktcVmI5X17/Q5SkwjCcdOLBzt1hXuc14jYa7NPShog0GBDCDvKtcnP0V7a2s6EiVRlv7BzbWEJzH6+l/zaCxw==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.25.7", - "@mui/utils": "^6.1.5", + "@babel/runtime": "^7.26.0", + "@mui/utils": "^6.4.9", "prop-types": "^15.8.1" }, "engines": { @@ -1393,14 +1393,14 @@ } }, "node_modules/@mui/styled-engine": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.5.tgz", - "integrity": "sha512-tiyWzMkHeWlOoE6AqomWvYvdml8Nv5k5T+LDwOiwHEawx8P9Lyja6ZwWPU6xljwPXYYPT2KBp1XvMly7dsK46A==", + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.4.9.tgz", + "integrity": "sha512-qZRWO0cT407NI4ZRjZcH+1SOu8f3JzLHqdMlg52GyEufM9pkSZFnf7xjpwnlvkixcGjco6wLlMD0VB43KRcBuA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.25.7", - "@emotion/cache": "^11.13.1", - "@emotion/serialize": "^1.3.2", + "@babel/runtime": "^7.26.0", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", "@emotion/sheet": "^1.4.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -1427,16 +1427,16 @@ } }, "node_modules/@mui/system": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.5.tgz", - "integrity": "sha512-vPM9ocQ8qquRDByTG3XF/wfYTL7IWL/20EiiKqByLDps8wOmbrDG9rVznSE3ZbcjFCFfMRMhtxvN92bwe/63SA==", + "version": "6.4.10", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.4.10.tgz", + "integrity": "sha512-RyBGQwP3tgo4JEibK+RwVu1a6nQ6y8urMCNsb2aiN/nvTxxumq6P26aoG4GTUf8L4O1sthC4lMXlP4r8ixDkMg==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.25.7", - "@mui/private-theming": "^6.1.5", - "@mui/styled-engine": "^6.1.5", - "@mui/types": "^7.2.18", - "@mui/utils": "^6.1.5", + "@babel/runtime": "^7.26.0", + "@mui/private-theming": "^6.4.9", + "@mui/styled-engine": "^6.4.9", + "@mui/types": "~7.2.24", + "@mui/utils": "^6.4.9", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -1467,9 +1467,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.18", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.18.tgz", - "integrity": "sha512-uvK9dWeyCJl/3ocVnTOS6nlji/Knj8/tVqVX03UVTpdmTJYu/s4jtDd9Kvv0nRGE0CUSNW1UYAci7PYypjealg==", + "version": "7.2.24", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz", + "integrity": "sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==", "license": "MIT", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -1481,17 +1481,17 @@ } }, "node_modules/@mui/utils": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.5.tgz", - "integrity": "sha512-vp2WfNDY+IbKUIGg+eqX1Ry4t/BilMjzp6p9xO1rfqpYjH1mj8coQxxDfKxcQLzBQkmBJjymjoGOak5VUYwXug==", + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.9.tgz", + "integrity": "sha512-Y12Q9hbK9g+ZY0T3Rxrx9m2m10gaphDuUMgWxyV5kNJevVxXYCLclYUCC9vXaIk1/NdNDTcW2Yfr2OGvNFNmHg==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.25.7", - "@mui/types": "^7.2.18", - "@types/prop-types": "^15.7.13", + "@babel/runtime": "^7.26.0", + "@mui/types": "~7.2.24", + "@types/prop-types": "^15.7.14", "clsx": "^2.1.1", "prop-types": "^15.8.1", - "react-is": "^18.3.1" + "react-is": "^19.0.0" }, "engines": { "node": ">=14.0.0" @@ -1511,9 +1511,9 @@ } }, "node_modules/@mui/utils/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", "license": "MIT" }, "node_modules/@nodelib/fs.scandir": { @@ -2792,9 +2792,9 @@ "license": "MIT" }, "node_modules/@types/prop-types": { - "version": "15.7.13", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", - "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", "license": "MIT" }, "node_modules/@types/react": { @@ -2818,11 +2818,11 @@ } }, "node_modules/@types/react-transition-group": { - "version": "4.4.11", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", - "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", "license": "MIT", - "dependencies": { + "peerDependencies": { "@types/react": "*" } }, @@ -3215,18 +3215,21 @@ } }, "node_modules/babel-plugin-macros/node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5533,9 +5536,9 @@ } }, "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "license": "MIT", "dependencies": { "hasown": "^2.0.2" diff --git a/app-frontend/package.json b/app-frontend/package.json index aca482a..338c61b 100644 --- a/app-frontend/package.json +++ b/app-frontend/package.json @@ -12,12 +12,12 @@ "dependencies": { "@coreui/coreui": "^5.2.0", "@coreui/react": "^5.4.1", - "@emotion/react": "^11.13.3", - "@emotion/styled": "^11.13.0", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", "@heroicons/react": "^2.2.0", "@lottiefiles/dotlottie-react": "^0.12.0", - "@mui/icons-material": "^6.1.5", - "@mui/material": "^6.1.5", + "@mui/icons-material": "^6.4.10", + "@mui/material": "^6.4.10", "@radix-ui/react-avatar": "^1.1.2", "@radix-ui/react-checkbox": "^1.1.3", "@radix-ui/react-dialog": "^1.1.4", diff --git a/app-frontend/src/App.jsx b/app-frontend/src/App.jsx index 0fbdc54..6936837 100644 --- a/app-frontend/src/App.jsx +++ b/app-frontend/src/App.jsx @@ -36,6 +36,7 @@ import SignUp from "./pages/auth/SignUp"; import EmailSent from "./pages/auth/EmailSent"; import PasswordUpdated from "./pages/auth/PasswordUpdated"; import ArticleDetails from "./pages/user/Articles/ArticleDetails"; +import { ToastContainer } from "react-toastify"; function App() { const location = useLocation(); @@ -50,6 +51,14 @@ function App() { return (
+ {showNavbar && } } /> diff --git a/app-frontend/src/components/atoms/Chat.jsx b/app-frontend/src/components/atoms/Chat.jsx index bc26838..cedf3aa 100644 --- a/app-frontend/src/components/atoms/Chat.jsx +++ b/app-frontend/src/components/atoms/Chat.jsx @@ -40,7 +40,7 @@ function Chat({ info, removeChat }) { }); return (
diff --git a/app-frontend/src/components/atoms/Message.jsx b/app-frontend/src/components/atoms/Message.jsx index cd0420d..4272583 100644 --- a/app-frontend/src/components/atoms/Message.jsx +++ b/app-frontend/src/components/atoms/Message.jsx @@ -1,5 +1,5 @@ import React, { useEffect } from "react"; - +import ReactMarkdown from "react-markdown"; function Message({ content }) { useEffect(() => { console.log(content); @@ -10,7 +10,9 @@ function Message({ content }) {
)}
-

{content.content}

+

+ {content.content} +

{content.role !== "bot" && (
diff --git a/app-frontend/src/components/molecules/DropDown.jsx b/app-frontend/src/components/molecules/DropDown.jsx index ce50e38..a2ba9e2 100644 --- a/app-frontend/src/components/molecules/DropDown.jsx +++ b/app-frontend/src/components/molecules/DropDown.jsx @@ -2,7 +2,7 @@ import { useState, useEffect, useRef } from "react"; import MoreVertIcon from "@mui/icons-material/MoreVert"; import Boy from "../../assets/Images/depression.png"; import { useLocation } from "react-router-dom"; -const CustomDropdown = ({ table }) => { +const CustomDropdown = ({ table = [] }) => { const [isOpen, setIsOpen] = useState(false); const dropdownRef = useRef(null); const location = useLocation(); @@ -49,15 +49,17 @@ const CustomDropdown = ({ table }) => { {isOpen && (
- {table.map(({ option, action }) => ( - - ))} + {table && + table.length > 0 && + table.map(({ option, action }) => ( + + ))}
)} diff --git a/app-frontend/src/components/molecules/Footer.jsx b/app-frontend/src/components/molecules/Footer.jsx index 3d001cf..1fa258b 100644 --- a/app-frontend/src/components/molecules/Footer.jsx +++ b/app-frontend/src/components/molecules/Footer.jsx @@ -64,21 +64,13 @@ function Footer() { fgColor="white" style={{ width: size, height: size }} /> - {/* */} + - {/* */} +
- {/*

- Download App for Android and IOS mobile phone -

*/}

-

+

Copyright Β© 2024 All rights reserved

-

+

Terms Of Service Privacy Policy

diff --git a/app-frontend/src/components/molecules/Navbar.jsx b/app-frontend/src/components/molecules/Navbar.jsx index bf53231..e78fdcc 100644 --- a/app-frontend/src/components/molecules/Navbar.jsx +++ b/app-frontend/src/components/molecules/Navbar.jsx @@ -12,6 +12,7 @@ import useStore from "@/useStore"; function Navbar() { const nav = useNavigate(); const isAdmin = useStore((state) => state.isAdmin); + const token = useStore((state) => state.token); const [isOpen, setIsOpen] = useState(false); const toggleMenu = () => { setIsOpen(!isOpen); @@ -122,15 +123,20 @@ function Navbar() { > goTo("/login") }, - { - option: "User Dashboard", - action: () => goTo("/dashboard"), - }, - { - option: "Admin Dashboard", - action: () => goTo("/admin"), + !token && { + option: "SignUp / Login", + action: () => goTo("/login"), }, + token && + !isAdmin && { + option: "User Dashboard", + action: () => goTo("/dashboard"), + }, + token && + isAdmin && { + option: "Admin Dashboard", + action: () => goTo("/admin"), + }, ]} />
diff --git a/app-frontend/src/components/user/AssignedActivities.jsx b/app-frontend/src/components/user/AssignedActivities.jsx index eb5adb5..7db5814 100644 --- a/app-frontend/src/components/user/AssignedActivities.jsx +++ b/app-frontend/src/components/user/AssignedActivities.jsx @@ -1,24 +1,54 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { CheckCircle } from "lucide-react"; +import useStore from "@/useStore"; +import axios from "axios"; -const initialActivities = [ - { id: 1, name: "10-minute meditation", completed: false }, - { id: 2, name: "Write in gratitude journal", completed: false }, - { id: 3, name: "30-minute walk outside", completed: false }, - { id: 4, name: "Practice deep breathing", completed: false }, -]; +export default function AssignedActivities({ className, onActivityCompleted }) { + const [activities, setActivities] = useState([]); + const user_id = useStore((state) => state.clientId); + const getActivities = async () => { + try { + const res = await axios.get( + `http://localhost:5000/get_activities/${user_id}` + ); + setActivities(res.data.assigned_activities); + console.log("res", res.data.assigned_activities[0]); + } catch (error) { + console.log("Error fetching activities:", error); + } + }; + + useEffect(() => { + getActivities(); + }, [user_id]); -export default function AssignedActivities({ className }) { - const [activities, setActivities] = useState(initialActivities); + const handleMarkAsDone = async (id) => { + try { + axios + .post(`http://localhost:5000/mark_activity_as_done`, { + user_id, + activity_id: id, + }) + .then((res) => { + console.log(res); + onActivityCompleted(); + }) + .catch((err) => { + console.log(err); + }); - const handleMarkAsDone = (id) => { - setActivities( - activities.map((activity) => - activity.id === id ? { ...activity, completed: true } : activity - ) - ); + setActivities( + activities.map((activity) => + activity.activity_id === id + ? { ...activity, completed: true } + : activity + ) + ); + } catch (error) { + console.log("Error updating activity:", error); + } }; return ( @@ -28,24 +58,35 @@ export default function AssignedActivities({ className }) {
- {activities.map((activity) => ( -
- {activity.name} - + {activities?.length > 0 ? ( +
+ {activities && + activities.map((activity) => ( +
+ + {activity.activity_name} + + +
+ ))} +
+ ) : ( +
+ No activities to show
- ))} + )}
diff --git a/app-frontend/src/components/user/CompletedActivities.jsx b/app-frontend/src/components/user/CompletedActivities.jsx index 7933b42..e96aefa 100644 --- a/app-frontend/src/components/user/CompletedActivities.jsx +++ b/app-frontend/src/components/user/CompletedActivities.jsx @@ -1,29 +1,47 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { CheckCircle } from "lucide-react"; +import axios from "axios"; +import useStore from "@/useStore"; -const completedActivities = [ - "Morning meditation", - "Journaling session", - "Yoga practice", - "Mindful eating exercise", -]; +export default function CompletedActivities({ className, refresh }) { + const [completedActivities, setCompletedActivities] = useState([]); + const user_id = useStore((state) => state.clientId); + const getActivities = async () => { + try { + const res = await axios.get( + `http://localhost:5000/get_activities/${user_id}` + ); + setCompletedActivities(res.data.completed_activities); + console.log(res.data.completed_activities); + } catch (error) { + console.log("Error fetching activities:", error); + } + }; -export default function CompletedActivities({ className }) { + useEffect(() => { + getActivities(); + }, [user_id, refresh]); return ( Completed Activities -
- {completedActivities.map((activity, index) => ( -
- - {activity} -
- ))} -
+ {completedActivities?.length > 0 ? ( +
+ {completedActivities.map((activity, index) => ( +
+ + {activity.activity_name} +
+ ))} +
+ ) : ( +
+ No activities completed yet +
+ )}
); diff --git a/app-frontend/src/components/user/MoodTracker.jsx b/app-frontend/src/components/user/MoodTracker.jsx index 03889c3..dc632c2 100644 --- a/app-frontend/src/components/user/MoodTracker.jsx +++ b/app-frontend/src/components/user/MoodTracker.jsx @@ -1,19 +1,54 @@ import React, { useState } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; -import { Smile, Meh, Frown, ThumbsUp, Heart, Star } from "lucide-react"; +import { + Smile, + Frown, + Meh, + AlertTriangle, + ThumbsDown, + Star, + Coffee, + AlertCircle, + CheckCircle, +} from "lucide-react"; +import axios from "axios"; +import useStore from "@/useStore"; +import { toast } from "react-toastify"; const moodOptions = [ - { mood: "Fantastic", icon: Star, color: "text-yellow-500" }, { mood: "Happy", icon: Smile, color: "text-green-500" }, - { mood: "Okay", icon: Meh, color: "text-blue-500" }, { mood: "Sad", icon: Frown, color: "text-red-500" }, - { mood: "Grateful", icon: Heart, color: "text-pink-500" }, - { mood: "Confident", icon: ThumbsUp, color: "text-purple-500" }, + { mood: "Angry", icon: AlertTriangle, color: "text-orange-500" }, + { mood: "Calm", icon: Meh, color: "text-teal-500" }, + { mood: "Stressed", icon: ThumbsDown, color: "text-purple-500" }, + { mood: "Excited", icon: Star, color: "text-yellow-500" }, + { mood: "Bored", icon: Coffee, color: "text-gray-500" }, + { mood: "Anxious", icon: AlertCircle, color: "text-indigo-500" }, + { mood: "Content", icon: CheckCircle, color: "text-cyan-500" }, ]; export default function MoodTracker({ className }) { const [selectedMood, setSelectedMood] = useState(null); + const clientId = useStore((state) => state.clientId); + function addJournal(option) { + setSelectedMood(() => option.mood); + let values = { + user_id: clientId, + mood: option.mood, + questionaire: true, + }; + + axios + .post("http://localhost:5000/add_journal", values) + .then((res) => { + console.log(res); + toast.success("Mood logged successfully."); + }) + .catch((err) => { + toast.error("Please try againa after some time."); + }); + } return ( @@ -29,7 +64,7 @@ export default function MoodTracker({ className }) { className={`h-24 flex flex-col items-center justify-center ${ selectedMood === option.mood ? "ring-2 ring-primary" : "" }`} - onClick={() => setSelectedMood(option.mood)} + onClick={() => addJournal(option)} > {option.mood} diff --git a/app-frontend/src/components/user/Overview.jsx b/app-frontend/src/components/user/Overview.jsx index cb20944..493e9dc 100644 --- a/app-frontend/src/components/user/Overview.jsx +++ b/app-frontend/src/components/user/Overview.jsx @@ -1,91 +1,3 @@ -// import { -// Bar, -// BarChart, -// ResponsiveContainer, -// XAxis, -// YAxis, -// Tooltip, -// } from "recharts"; -// import { -// Card, -// CardContent, -// CardDescription, -// CardHeader, -// CardTitle, -// } from "@/components/ui/card"; -// const moods = [ -// "😊", -// "😞", -// "😑", -// "πŸ˜…", -// "😒", -// "πŸ₯°", -// "😎", -// "😴", -// "😌", -// "πŸ€”", -// "😱", -// "😜", -// "πŸ€—", -// "😬", -// "πŸ₯Ί", -// "🀩", -// ]; -// const data = [ -// { name: "Mon", mood: 4, activities: 2 }, -// { name: "Tue", mood: 3, activities: 3 }, -// { name: "Wed", mood: 5, activities: 1 }, -// { name: "Thu", mood: 2, activities: 4 }, -// { name: "Fri", mood: 4, activities: 3 }, -// { name: "Sat", mood: 5, activities: 2 }, -// { name: "Sun", mood: 4, activities: 5 }, -// ]; - -// function Overview({ className }) { -// return ( -// -// -// Weekly Overview -// -// Your mood and activities for the past week -// -// -// -// -// -// -// `${value}`} -// /> -// -// -// -// -// -// -// -// ); -// } - -// export default Overview; import { Bar, BarChart, @@ -93,7 +5,11 @@ import { XAxis, YAxis, Tooltip, + Legend, } from "recharts"; +import { useEffect, useState } from "react"; +import axios from "axios"; +import useStore from "@/useStore"; import { Card, CardContent, @@ -102,88 +18,69 @@ import { CardTitle, } from "@/components/ui/card"; -const moods = [ - "😊", - "😞", - "😑", - "πŸ˜…", - "😒", - "πŸ₯°", - "😎", - "😴", - "😌", - "πŸ€”", - "😱", - "😜", - "πŸ€—", - "😬", - "πŸ₯Ί", - "🀩", -]; +function Overview({ className }) { + const user_id = useStore((state) => state.clientId); + const [weeklyData, setWeeklyData] = useState([]); -const data = [ - { name: "Mon", mood: 4, activities: 2, emoji: "😒" }, - { name: "Tue", mood: 3, activities: 3, emoji: "😎" }, - { name: "Wed", mood: 5, activities: 1, emoji: "😊" }, - { name: "Thu", mood: 2, activities: 4, emoji: "😞" }, - { name: "Fri", mood: 4, activities: 3, emoji: "πŸ₯°" }, - { name: "Sat", mood: 5, activities: 2, emoji: "🀩" }, - { name: "Sun", mood: 4, activities: 5, emoji: "😴" }, -]; + useEffect(() => { + axios + .get(`http://localhost:5000/user/${user_id}/weekly_moods`) + .then((res) => { + const formattedData = Object.keys(res.data.weekly_moods).map((day) => { + const dayData = res.data.weekly_moods[day]; + const moodCount = { + happy: 0, + sad: 0, + angry: 0, + calm: 0, + stressed: 0, + excited: 0, + bored: 0, + anxious: 0, + content: 0, + }; + + dayData.all_moods.forEach((mood) => { + if (moodCount.hasOwnProperty(mood)) { + moodCount[mood] += 1; + } + }); + + return { + name: day, + ...moodCount, + overall_mood: dayData.overall_mood, // Optional: for further display + }; + }); + + setWeeklyData(formattedData); + }) + .catch((err) => { + console.log("Error fetching mood data: ", err); + }); + }, [user_id]); -function Overview({ className }) { return ( - Weekly Overview - - Your mood and activities for the past week - + Weekly Mood Overview + Your mood breakdown for the past week - + { - const item = data.find((d) => d.name === payload.value); - return ( - - - {payload.value} - - - {item?.emoji} - - - ); - }} /> `${value}`} /> - - + + + + + + + + + + diff --git a/app-frontend/src/components/user/QuickJournalEntry.jsx b/app-frontend/src/components/user/QuickJournalEntry.jsx index 098d65f..4af0bae 100644 --- a/app-frontend/src/components/user/QuickJournalEntry.jsx +++ b/app-frontend/src/components/user/QuickJournalEntry.jsx @@ -3,13 +3,29 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Textarea } from "@/components/ui/textarea"; import { BookOpen, Sparkles } from "lucide-react"; +import useStore from "@/useStore"; +import axios from "axios"; +import { toast } from "react-toastify"; export default function QuickJournalEntry({ className }) { const [entry, setEntry] = useState(""); - + const clientId = useStore((state) => state.clientId); const handleSubmit = (e) => { e.preventDefault(); - console.log("Journal entry submitted:", entry); + let values = { + user_id: clientId, + text: entry, + journal: true, + }; + axios + .post("http://localhost:5000/add_journal", values) + .then((res) => { + console.log(res); + toast.success("Journal added successfully."); + }) + .catch((err) => { + toast.error("Please try againa after some time."); + }); setEntry(""); }; diff --git a/app-frontend/src/components/user/UserSidebar.jsx b/app-frontend/src/components/user/UserSidebar.jsx index cfca6f9..3ac956e 100644 --- a/app-frontend/src/components/user/UserSidebar.jsx +++ b/app-frontend/src/components/user/UserSidebar.jsx @@ -1,5 +1,10 @@ import React from "react"; -import { BrowserRouter as Router, Link, useLocation } from "react-router-dom"; // Changed to react-router-dom +import { + BrowserRouter as Router, + Link, + useLocation, + useNavigate, +} from "react-router-dom"; // Changed to react-router-dom import { BarChart, Calendar, @@ -25,6 +30,8 @@ import { SidebarMenuItem, } from "@/components/ui/sidebar"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import useStore from "@/useStore"; +import axios from "axios"; // import { ThemeToggle } from "@/components/theme-toggle"; const navItems = [ @@ -41,6 +48,29 @@ const navItems = [ export default function UserSidebar() { const location = useLocation(); // useLocation is the React Router equivalent of usePathname + const { clearUserData } = useStore(); + const nav = useNavigate(); + const token = useStore((state) => { + return state.token; + }); + const logoutUser = () => { + console.log(token); + axios + .post( + `http://localhost:5000/logout`, + {}, + { + headers: { Authorization: `Bearer ${token}` }, + } + ) + .then(() => { + clearUserData(); + nav("/login"); + }) + .catch((err) => { + console.log(err); + }); + }; return ( @@ -77,7 +107,7 @@ export default function UserSidebar() { - diff --git a/app-frontend/src/components/user/WellnessQuote.jsx b/app-frontend/src/components/user/WellnessQuote.jsx index ff52518..cf9481f 100644 --- a/app-frontend/src/components/user/WellnessQuote.jsx +++ b/app-frontend/src/components/user/WellnessQuote.jsx @@ -1,24 +1,150 @@ import { useState, useEffect } from "react"; import { Card, CardContent } from "@/components/ui/card"; import { Quote } from "lucide-react"; - const quotes = [ - { text: "Self-care is how you take your power back.", author: "Lalah Delia" }, - { text: "You are your best thing.", author: "Toni Morrison" }, { - text: "Be patient with yourself. Self-growth is tender; it's holy ground. There's no greater investment.", - author: "Stephen Covey", + text: "Self-care is not a luxury; it is a necessity.", + author: "Audre Lorde", + }, + { + text: "Caring for myself is not self-indulgence, it is self-preservation.", + author: "Audre Lorde", + }, + { + text: "You are allowed to be both a masterpiece and a work in progress simultaneously.", + author: "Sophia Bush", }, { - text: "To love oneself is the beginning of a lifelong romance.", + text: "Be yourself; everyone else is already taken.", author: "Oscar Wilde", }, { - text: "Talk to yourself like you would to someone you love.", - author: "BrenΓ© Brown", + text: "Loving yourself isn't vanity; it's sanity.", + author: "Katrina Mayer", + }, + { + text: "The better you feel about yourself, the less you feel the need to show off.", + author: "Robert Hand", + }, + { text: "You are enough just as you are.", author: "Meghan Markle" }, + { + text: "Self-love is the source of all our other loves.", + author: "Pierre Corneille", + }, + { + text: "Love yourself first and everything else falls into line.", + author: "Lucille Ball", + }, + { + text: "Self-care is not about self-indulgence, it's about self-respect.", + author: "Joanne O'Connor", + }, + { + text: "Self-care is never a selfish actβ€”it is simply good stewardship of the only gift I have...", + author: "Parker Palmer", + }, + { + text: "One of the greatest regrets in life is being what others would want you to be...", + author: "Shannon L. Alder", + }, + { + text: "Don't worry if people think you're crazy. You have that kind of intoxicating insanity...", + author: "Jennifer Elisabeth", + }, + { + text: "It's all about falling in love with yourself and sharing that love...", + author: "Eartha Kitt", + }, + { + text: "It is interesting how often we can't see all the ways in which we are being strong.", + author: "Lena Dunham", + }, + { + text: "Self love is an ocean and your heart is a vessel...", + author: "Beau Taplin", + }, + { + text: "I took a deep breath and listened to the old brag of my heart. I am, I am, I am.", + author: "Sylvia Plath", + }, + { + text: "Do not feel lonely, the entire universe is inside you...", + author: "Rumi", + }, + { text: "Your self-worth is determined by you...", author: "BeyoncΓ©" }, + { + text: "Once you've accepted your flaws, no one can use them against you.", + author: "George R.R. Martin", + }, + { + text: "The hardest challenge is to be yourself in a world where everyone is trying...", + author: "E.E Cummings", + }, + { + text: "Life isn't about finding yourself. Life is about creating yourself.", + author: "George Bernard Shaw", + }, + { + text: "If you're not someone who has a natural love for yourself...", + author: "Anne Hathaway", + }, + { + text: "My mission... is to find peace with exactly who and what I am.", + author: "AnaΓ―s Nin", + }, + { + text: "There is you and you. This is a relationship. This is the most important relationship.", + author: "Nayyirah Waheed", + }, + { + text: "Not only do self-love and love of others go hand in hand...", + author: "M. Scott Peck", + }, + { + text: "I must undertake to love myself and to respect myself...", + author: "Maya Angelou", + }, + { + text: "When you take care of yourself, you're a better person for others...", + author: "Solange Knowles", + }, + { + text: "Self-love, my liege, is not so vile a sin, as self-neglecting.", + author: "William Shakespeare", + }, + { + text: "For me, self-love is like, 'Am I sleeping enough? Eating well?'...", + author: "Kerry Washington", + }, + { + text: "If you have no confidence in self, you are twice defeated in the race of life.", + author: "Marcus Garvey", + }, + { + text: "Who looks outside, dreams; who looks inside, awakes.", + author: "Carl Gustav Jung", + }, + { + text: "Be a first-rate version of yourself, not a second-rate version of someone else.", + author: "Judy Garland", + }, + { + text: "Your relationship with yourself sets the tone for every other relationship...", + author: "Robert Holden", + }, + { + text: "Respect yourself, love yourself, because there has never been a person like you...", + author: "Osho", + }, + { + text: "Remind yourself that you cannot fail at being yourself.", + author: "Wayne Dyer", + }, + { + text: "You have to believe in yourself when no one else doesβ€”that makes you a winner.", + author: "Jack Canfield", }, ]; - function WellnessQuote() { const [quote, setQuote] = useState(quotes[0]); diff --git a/app-frontend/src/pages/Agreements/TermsOfService.jsx b/app-frontend/src/pages/Agreements/TermsOfService.jsx index bbc7f7e..12c0347 100644 --- a/app-frontend/src/pages/Agreements/TermsOfService.jsx +++ b/app-frontend/src/pages/Agreements/TermsOfService.jsx @@ -15,10 +15,9 @@ const TermsOfService = () => { 1. Acceptance of Terms

- By downloading or using the{" "} - Eunoia app, you agree to these - Terms of Service. If you do not agree, please stop using the app - immediately. + By visiting the Eunoia website, + you agree to these Terms of Service. If you do not agree, please stop + using the app immediately.

diff --git a/app-frontend/src/pages/auth/Login.jsx b/app-frontend/src/pages/auth/Login.jsx index 34af513..50de6a2 100644 --- a/app-frontend/src/pages/auth/Login.jsx +++ b/app-frontend/src/pages/auth/Login.jsx @@ -1,156 +1,3 @@ -// import React from "react"; -// import { Formik, Field, Form, ErrorMessage } from "formik"; -// import * as Yup from "yup"; -// import { Link, NavLink } from "react-router-dom"; -// import { Mail, Lock } from "lucide-react"; -// import { Button } from "@/components/ui/button"; -// import { Input } from "@/components/ui/input"; -// import { Checkbox } from "@/components/ui/checkbox"; - -// const Login = ({ showRegisterForm }) => { -// const validationSchema = Yup.object({ -// email: Yup.string() -// .email("Invalid email address") -// .required("Email is required"), -// password: Yup.string() -// .min(6, "Password must be at least 6 characters") -// .required("Password is required"), -// }); - -// const handleSubmit = (values) => { -// console.log("Form submitted with values:", values); -// }; - -// return ( -//
-//
-//
-//

-// Welcome Back ! -//

-//

-// Don't have an account? -// -// {" "} -// Sign Up -// -//

-//
- -// -//
-//
-//
-// -// -// -//
- -//
-// -// -// -//
- -//
-// -// Forgot Password -// -//
- -// -//
-//
-//
- -//
-//
-//
-//
-//
-// Or -//
-//
- -// {/* Social Login Buttons */} -//
-// -// -//
-//
-//
-// ); -// }; - -// export default Login; - import React, { useState } from "react"; import { Formik, Field, Form, ErrorMessage } from "formik"; import * as Yup from "yup"; @@ -163,28 +10,36 @@ import axios from "axios"; const Login = () => { const navigate = useNavigate(); - const updateClientId = (newId) => { - useStore.getState().setClientId(newId); - }; - const updateClientName = (newName) => { - useStore.getState().setFirstName(newName); - }; + // const updateClientId = (newId) => { + // useStore.getState().setClientId(newId); + // }; + // const updateClientName = (newName) => { + // useStore.getState().setFirstName(newName); + // }; const [errorMessage, setErrorMessage] = useState(""); - const setIsAdmin = useStore((state) => state.setIsAdmin); + const setClientId = useStore((state) => state.setClientId); + const setFirstName = useStore((state) => state.setFirstName); const setLastName = useStore((state) => state.setLastName); + const setIsAdmin = useStore((state) => state.setIsAdmin); + const setToken = useStore((state) => state.setToken); + const loginUser = (values) => { axios .post(`http://localhost:5000/login`, values) .then((res) => { - console.log(res); + console.log(res.data.user.token); const user = res.data.user; - console.log(user.id); + const token = res.data.user.token; // setClientId(user.id); // setFirstName(user.first_name); - setIsAdmin(user.admin); + setToken(user.token); + setClientId(user.id); + setFirstName(user.first_name); setLastName(user.last_name); - updateClientId(user.id); - updateClientName(user.first_name); + setIsAdmin(user.admin); + // setIsAdmin(user.admin); + // updateClientId(user.id); + // updateClientName(user.first_name); navigate("/dashboard"); }) .catch((err) => { diff --git a/app-frontend/src/pages/auth/SignUp.jsx b/app-frontend/src/pages/auth/SignUp.jsx index 78f9dc2..c7c2f83 100644 --- a/app-frontend/src/pages/auth/SignUp.jsx +++ b/app-frontend/src/pages/auth/SignUp.jsx @@ -1,222 +1,3 @@ -// import React from "react"; -// import { Formik, Field, Form, ErrorMessage } from "formik"; -// import * as Yup from "yup"; -// import { Mail, Lock, User, LockKeyhole } from "lucide-react"; -// import { Button } from "@/components/ui/button"; -// import { Checkbox } from "@mui/material"; -// import { NavLink } from "react-router-dom"; - -// const Signup = ({ showLoginForm }) => { -// const validationSchema = Yup.object({ -// fullName: Yup.string().required("Full Name is required"), -// email: Yup.string() -// .email("Invalid email address") -// .required("Email Address is required"), -// password: Yup.string() -// .min(8, "Password must be at least 8 characters") -// .required("Password is required"), -// confirmPassword: Yup.string() -// .oneOf([Yup.ref("password"), null], "Passwords must match") -// .required("Confirm Password is required"), -// }); - -// return ( -//
-//
-//
-//

-// Join now for Emotional Clarity. -//

-//

-// Already have an account? -// -// {" "} -// Sign In -// -//

-//
- -// { -// console.log("Form submitted with values:", values); -// }} -// > -//
-//
-// -// -// -//
- -//
-// -// -// -//
- -//
-// -// -// -//
- -//
-// -// -// -//
-//
-// -// -//
- -// - -//
-//
-//
-//
-//
-// Or -//
-//
- -// {/* Social Login Buttons */} -//
-// -// -// {/* -// */} -//
-//
-//
-//
-//
-// ); -// }; - -// export default Signup; import React, { useState } from "react"; import { Formik, Field, Form, ErrorMessage } from "formik"; import * as Yup from "yup"; @@ -254,15 +35,15 @@ function SignUp() { }; const validationSchema = Yup.object({ - firstName: Yup.string().required("First Name is required"), - lastName: Yup.string().required("Last Name is required"), + fname: Yup.string().required("First Name is required"), + lname: Yup.string().required("Last Name is required"), email: Yup.string() .email("Invalid email address") .required("Email is required"), password: Yup.string() .min(6, "Password must be at least 6 characters") .required("Password is required"), - confirmPassword: Yup.string() + confirm_password: Yup.string() .oneOf([Yup.ref("password"), null], "Passwords must match") .required("Confirm Password is required"), }); @@ -297,11 +78,11 @@ function SignUp() { @@ -335,7 +116,7 @@ function SignUp() {
@@ -398,7 +179,7 @@ function SignUp() {
diff --git a/app-frontend/src/pages/user/Forum/ForumDetail.jsx b/app-frontend/src/pages/user/Forum/ForumDetail.jsx index cacca01..971da8b 100644 --- a/app-frontend/src/pages/user/Forum/ForumDetail.jsx +++ b/app-frontend/src/pages/user/Forum/ForumDetail.jsx @@ -22,7 +22,10 @@ const ForumDetail = () => { const getForumDetails = () => { axios .get(`http://localhost:5000/get_forum/${forum_id}`) - .then((res) => setForum(res.data)) + .then((res) => { + console.log(res.data); + setForum(res.data); + }) .catch((err) => console.log("e", err)); }; const getReplies = () => { diff --git a/app-frontend/src/pages/user/LandingPage/ContactUs.jsx b/app-frontend/src/pages/user/LandingPage/ContactUs.jsx index 74d73d7..27345f9 100644 --- a/app-frontend/src/pages/user/LandingPage/ContactUs.jsx +++ b/app-frontend/src/pages/user/LandingPage/ContactUs.jsx @@ -7,13 +7,14 @@ import { SocialIcon } from "react-social-icons"; import { Formik, Form, Field, ErrorMessage } from "formik"; import * as Yup from "yup"; import axios from "axios"; +import { toast } from "react-toastify"; function ContactUs() { // Initial Values const initialValues = { name: "", email: "", - message: "", + query: "", }; // Validation Schema const validationSchema = Yup.object({ @@ -23,7 +24,7 @@ function ContactUs() { email: Yup.string() .email("Invalid email address") .required("Email is required"), - message: Yup.string() + query: Yup.string() .min(10, "Message must be at least 10 characters") .required("Message is required"), }); @@ -31,18 +32,14 @@ function ContactUs() { const onSubmit = (values, { resetForm }) => { console.log(values); axios - .post("http://localhost:5000/contact_us", values, { - headers: { - "Content-Type": "application/json", - }, - }) + .post("http://localhost:5000/contact_us", values) .then((res) => { console.log(res); - alert("Form submitted successfully...."); + toast.success("Form submitted successfully...."); }) .catch((err) => { console.log(err); - alert("nah"); + toast.error("An error occured while submitting. Please try again."); }); resetForm(); @@ -153,14 +150,14 @@ function ContactUs() { diff --git a/app-frontend/src/pages/user/chatbot/ChatList.jsx b/app-frontend/src/pages/user/chatbot/ChatList.jsx index cd8e524..6cf9b48 100644 --- a/app-frontend/src/pages/user/chatbot/ChatList.jsx +++ b/app-frontend/src/pages/user/chatbot/ChatList.jsx @@ -1,12 +1,316 @@ -import React, { useEffect, useState } from "react"; -import ArrowBackIosIcon from "@mui/icons-material/ArrowBackIos"; -import PostAddIcon from "@mui/icons-material/PostAdd"; -import Chat from "../../../components/atoms/Chat"; -import { NavLink } from "react-router-dom"; +// // // import React, { useEffect, useState } from "react"; +// // // import ArrowBackIosIcon from "@mui/icons-material/ArrowBackIos"; +// // // import PostAddIcon from "@mui/icons-material/PostAdd"; +// // // import Chat from "../../../components/atoms/Chat"; +// // // import { NavLink } from "react-router-dom"; +// // // import axios from "axios"; +// // // import useStore from "../../../useStore"; + +// // // function ChatList() { +// const setCurrentChatId = useStore((state) => state.setCurrentChatId); +// const clientId = useStore((state) => state.clientId); +// const setCurrentChat = useStore((state) => state.setCurrentChat); +// const currentChatId = useStore((state) => state.currentChatId); +// const [chat_ids, setChat_ids] = useState([]); +// // const [chatTitles, setChatTitle] = useState([]); +// const [chats, setChats] = useState([]); +// function removeChat(chatId) { +// setChat_ids((prevChatIds) => prevChatIds.filter((id) => id !== chatId)); +// } +// function startNewChat() { +// setCurrentChatId(null); +// setCurrentChat([]); +// axios +// .post("http://localhost:5000/create_chat", { +// user_id: clientId, +// }) +// .then((data) => { +// console.log("data", data); +// console.log("data.chatId", data.data.chat_id); +// setCurrentChatId(data.data.chat_id); +// }) +// .catch((err) => { +// console.log("err in chatid creation : ", err); +// }); +// } +// useEffect(() => { +// console.log("clientId clientId", clientId); +// function getAllChats() { +// axios +// .post("http://localhost:5000/get_all_chats", { +// user_id: clientId, +// }) +// .then((response) => { +// console.log("response huh", response); +// const chats = response.data.chats; +// setChats(chats); +// console.log("nope", response); +// }) +// .catch((err) => { +// console.log(err); +// }); +// } +// getAllChats(); +// console.log("chat_ids", chat_ids); +// }, [currentChatId, chats, chat_ids]); +// // // return ( +// // //
+// // //
+// // // +// // // +// // // Home +// // // +// // //
+// // // +// // // +// // // +// // //
+// // //
+ +// // //
+// // //
+// {chats && +// chats.map((chat, id) => ( +// +// ))} +// // //
+// // //
+// // //
+// // // ); +// // // } + +// // // export default ChatList; +// // import React, { useEffect, useState } from "react"; +// // import ArrowBackIosIcon from "@mui/icons-material/ArrowBackIos"; +// // import PostAddIcon from "@mui/icons-material/PostAdd"; +// // import Chat from "../../../components/atoms/Chat"; +// // import { NavLink } from "react-router-dom"; +// // import axios from "axios"; +// // import useStore from "../../../useStore"; + +// // function ChatList() { +// // const setCurrentChatId = useStore((state) => state.setCurrentChatId); +// // const clientId = useStore((state) => state.clientId); +// // const setCurrentChat = useStore((state) => state.setCurrentChat); +// // const currentChatId = useStore((state) => state.currentChatId); +// // const [chat_ids, setChat_ids] = useState([]); +// // const [chats, setChats] = useState([]); + +// // function removeChat(chatId) { +// // setChat_ids((prevChatIds) => prevChatIds.filter((id) => id !== chatId)); +// // } + +// // function startNewChat() { +// // setCurrentChatId(null); +// // setCurrentChat([]); +// // axios +// // .post("http://localhost:5000/create_chat", { +// // user_id: clientId, +// // }) +// // .then((data) => { +// // setCurrentChatId(data.data.chat_id); +// // }) +// // .catch((err) => { +// // console.log("Error creating chat:", err); +// // }); +// // } + +// // useEffect(() => { +// // function getAllChats() { +// // axios +// // .post("http://localhost:5000/get_all_chats", { +// // user_id: clientId, +// // }) +// // .then((response) => { +// // const chats = response.data.chats; +// // setChats(chats); +// // }) +// // .catch((err) => { +// // console.log(err); +// // }); +// // } +// // getAllChats(); +// // }, [currentChatId, chats, chat_ids]); + +// // return ( +// //
+// //
+// // +// // +// // Home +// // +// //
+// // +// // +// // +// //
+// //
+ +// //
+// //
+// // {chats && +// // chats.map((chat, id) => ( +// // +// // ))} +// //
+// //
+// //
+// // ); +// // } + +// // export default ChatList; +// import React, { useState } from "react"; +// import { +// Drawer, +// IconButton, +// List, +// ListItem, +// ListItemIcon, +// ListItemText, +// CssBaseline, +// Box, +// useTheme, +// useMediaQuery, +// } from "@mui/material"; +// import MenuIcon from "@mui/icons-material/Menu"; +// import DashboardIcon from "@mui/icons-material/Dashboard"; +// import AccountCircleIcon from "@mui/icons-material/AccountCircle"; + +// const drawerWidth = 240; + +// const ChatList = () => { +// const [mobileOpen, setMobileOpen] = useState(false); +// const theme = useTheme(); +// // Check if screen is small (sm and below) +// const isSmallScreen = useMediaQuery(theme.breakpoints.down("sm")); + +// const handleDrawerToggle = () => { +// setMobileOpen(!mobileOpen); +// }; + +// const drawerContent = ( +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// {/* Add more list items as needed */} +// +// +// ); + +// return ( +// +// +// {/* Toggle button is placed at a fixed position so it stays visible even when sidebar is collapsed */} +// theme.zIndex.drawer + 1, +// }} +// > +// +// +// {/* Temporary drawer for small screens */} +// {isSmallScreen && ( +// +// {drawerContent} +// +// )} +// {/* Permanent drawer for larger screens */} +// {!isSmallScreen && ( +// +// {drawerContent} +// +// )} +// {/* Main content +// +// +//

Main Content

+//

+// This area is your main content. On small screens the sidebar is +// hidden by default; click the button in the top-left corner to toggle +// its visibility. +//

+//
+//
*/} +//
+// ); +// }; + +// export default ChatList; +import React, { useState, useEffect } from "react"; +import { Drawer, IconButton, useMediaQuery, useTheme } from "@mui/material"; +import MenuIcon from "@mui/icons-material/Menu"; +import ChevronLeftIcon from "@mui/icons-material/ChevronLeft"; +import Chat from "@/components/atoms/Chat"; +import useStore from "@/useStore"; import axios from "axios"; -import useStore from "../../../useStore"; +import CurrentChat from "./CurrentChat"; + +const ChatList = () => { + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down("sm")); + const [isOpen, setIsOpen] = useState(!isMobile); + + useEffect(() => { + // Adjust sidebar state when screen size changes + if (isMobile) { + setIsOpen(false); + } else { + setIsOpen(true); + } + }, [isMobile]); -function ChatList() { + const toggleDrawer = () => { + setIsOpen(!isOpen); + }; const setCurrentChatId = useStore((state) => state.setCurrentChatId); const clientId = useStore((state) => state.clientId); const setCurrentChat = useStore((state) => state.setCurrentChat); @@ -44,11 +348,6 @@ function ChatList() { console.log("response huh", response); const chats = response.data.chats; setChats(chats); - // const chatIds = chats.map((item) => item.chat_id); - // const chatTit = chats.map((item) => item.title); - // console.log("chatIds", chatIds); - // setChat_ids(chatIds); - // setChatTitle(chatTit); console.log("nope", response); }) .catch((err) => { @@ -59,43 +358,69 @@ function ChatList() { console.log("chat_ids", chat_ids); }, [currentChatId, chats, chat_ids]); return ( -
-
- - - Home - -
- - - -
-
+
+ {/* Toggle Button */} + + {isOpen ? : } + -
-
- {/* For API */} - {/* {chat_ids && - chat_ids.map((chat, id) => ( - - ))} */} + {/* Sidebar */} + +
+ {/*

Sidebar Content

*/} {chats && chats.map((chat, id) => ( ))} - {/* Dummy */} - {/* {chatTitles.map((chat, id) => ( - - ))} */}
+
+ + {/* Main Content */} +
+
); -} +}; export default ChatList; diff --git a/app-frontend/src/pages/user/chatbot/Chatbot.jsx b/app-frontend/src/pages/user/chatbot/Chatbot.jsx index 35cde64..697a50a 100644 --- a/app-frontend/src/pages/user/chatbot/Chatbot.jsx +++ b/app-frontend/src/pages/user/chatbot/Chatbot.jsx @@ -14,7 +14,7 @@ function Chatbot() { />
- + {/* */}
); diff --git a/app-frontend/src/pages/user/chatbot/CurrentChat.jsx b/app-frontend/src/pages/user/chatbot/CurrentChat.jsx index 7e02001..346c8a2 100644 --- a/app-frontend/src/pages/user/chatbot/CurrentChat.jsx +++ b/app-frontend/src/pages/user/chatbot/CurrentChat.jsx @@ -56,7 +56,7 @@ function CurrentChat() { }, [currentChat]); return ( -
+
{ + setRefresh((prev) => !prev); + }; return (
- - - Activites | Dashboard - + + Activites | Dashboard + + + - - -
- - -
-
+
+ + +
+
); } diff --git a/app-frontend/src/pages/userDashboard/Dashboard.jsx b/app-frontend/src/pages/userDashboard/Dashboard.jsx index 42357f2..97aed4e 100644 --- a/app-frontend/src/pages/userDashboard/Dashboard.jsx +++ b/app-frontend/src/pages/userDashboard/Dashboard.jsx @@ -36,13 +36,13 @@ export default function Dashboard() { - -
- - + {/* */} +
+ +
- + {/* */} ); } diff --git a/app-frontend/src/pages/userDashboard/Forums.jsx b/app-frontend/src/pages/userDashboard/Forums.jsx index 7258843..d3221d4 100644 --- a/app-frontend/src/pages/userDashboard/Forums.jsx +++ b/app-frontend/src/pages/userDashboard/Forums.jsx @@ -30,28 +30,25 @@ const Forum = () => { axios .get(`http://localhost:5000/list_forums`) .then((res) => { - console.log(res.data); + console.log("forums", res.data); setForums(res.data); }) .catch((err) => { console.log(err); }); }; - const createForum = () => { - axios - .post(`http://localhost:5000/create_forum`, { + const createForum = async () => { + try { + await axios.post(`http://localhost:5000/create_forum`, { created_by: clientId, category: forumCategory, title: forumTitle, - }) - .then((res) => { - console.log(res.data); - setForums((prevForums) => [...prevForums, res.data]); - }) - .catch((err) => { - console.log("Err", err); }); - // getAllForums(); + + await getAllForums(); // always get latest data from DB + } catch (err) { + console.log("Err", err); + } }; useEffect(() => { getAllForums(); @@ -89,7 +86,7 @@ const Forum = () => { {forums.map((forum) => (
diff --git a/app-frontend/src/pages/userDashboard/Journal.jsx b/app-frontend/src/pages/userDashboard/Journal.jsx index f563dee..e0a2fe4 100644 --- a/app-frontend/src/pages/userDashboard/Journal.jsx +++ b/app-frontend/src/pages/userDashboard/Journal.jsx @@ -72,19 +72,12 @@ function Journal() { { emoji: "😊", label: "Happy" }, { emoji: "😞", label: "Sad" }, { emoji: "😑", label: "Angry" }, - { emoji: "πŸ˜…", label: "Nervous" }, - { emoji: "😒", label: "Crying" }, - { emoji: "πŸ₯°", label: "Loved" }, - { emoji: "😎", label: "Cool" }, - { emoji: "😴", label: "Tired" }, - { emoji: "😌", label: "Relaxed" }, - { emoji: "πŸ€”", label: "Thoughtful" }, - { emoji: "😱", label: "Scared" }, - { emoji: "😜", label: "Playful" }, - { emoji: "πŸ€—", label: "Hugged" }, - { emoji: "😬", label: "Embarrassed" }, - { emoji: "πŸ₯Ί", label: "Feeling small" }, + { emoji: "😌", label: "Calm" }, + { emoji: "πŸ˜…", label: "Stressed" }, { emoji: "🀩", label: "Excited" }, + { emoji: "😴", label: "Bored" }, + { emoji: "😬", label: "Anxious" }, + { emoji: "πŸ₯°", label: "Content" }, ]; return ( @@ -116,7 +109,7 @@ function Journal() {

How are you feeling?

-
+
{moods.map((mood, index) => (
*/}
setPhone(e.target.value)} />
diff --git a/app-frontend/src/useStore.jsx b/app-frontend/src/useStore.jsx index 5bfe66d..1c90bbb 100644 --- a/app-frontend/src/useStore.jsx +++ b/app-frontend/src/useStore.jsx @@ -1,6 +1,12 @@ import { create } from "zustand"; const useStore = create((set) => ({ + token: localStorage.getItem("token") || null, + setToken: (token) => { + localStorage.setItem("token", token); + set({ token }); + }, + clientId: localStorage.getItem("clientId") || null, setClientId: (clientId) => { localStorage.setItem("clientId", clientId); @@ -13,12 +19,17 @@ const useStore = create((set) => ({ set({ firstName }); }, - lastName: "", - setLastName: (lastName) => set({ lastName }), - - isAdmin: false, - setIsAdmin: (isAdmin) => set({ isAdmin }), + lastName: localStorage.getItem("lastName") || "", + setLastName: (lastName) => { + localStorage.setItem("lastName", lastName); + set({ lastName }); + }, + isAdmin: JSON.parse(localStorage.getItem("isAdmin")) || false, + setIsAdmin: (isAdmin) => { + localStorage.setItem("isAdmin", JSON.stringify(isAdmin)); + set({ isAdmin }); + }, currentChatId: null, setCurrentChatId: (currentChatId) => set({ currentChatId }), @@ -27,6 +38,19 @@ const useStore = create((set) => ({ addNewMessage: (newMessage) => set((state) => ({ currentChat: [...state.currentChat, newMessage] })), + + clearUserData: () => { + localStorage.clear(); + set({ + token: null, + clientId: null, + firstName: "", + lastName: "", + isAdmin: false, + currentChatId: null, + currentChat: [], + }); + }, })); export default useStore;