Skip to content

Commit

Permalink
date can be passed in, weekly stats, journal
Browse files Browse the repository at this point in the history
  • Loading branch information
nadinedelia committed Oct 11, 2023
1 parent 6c78a98 commit 19a69da
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 6 deletions.
Binary file modified analytics/__pycache__/app.cpython-311.pyc
Binary file not shown.
57 changes: 56 additions & 1 deletion analytics/app.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from dotenv import load_dotenv
from flask import Flask, render_template, jsonify
from flask import Flask, render_template, jsonify, request
from pymongo import MongoClient
from flask_pymongo import PyMongo
from flask_cors import CORS
from urllib.parse import quote_plus
from bson import json_util
import traceback
import os
from datetime import datetime, timedelta
# import config

app = Flask(__name__)
Expand Down Expand Up @@ -105,6 +106,60 @@ def user_stats(username):
return jsonify(stats=stats)


@app.route('/api/stats/weekly/', methods=['GET'])
def weekly_user_stats():
username = request.args.get('user')
start_date_str = request.args.get('start')
end_date_str = request.args.get('end')

# Parse the dates
date_format = "%Y-%m-%d"
start_date = datetime.strptime(start_date_str, date_format)
end_date = datetime.strptime(end_date_str, date_format)

pipeline = [
{
"$match": {
"username": username,
"date": {
"$gte": start_date,
"$lte": end_date
}
}
},
{
"$group": {
"_id": {
"username": "$username",
"exerciseType": "$exerciseType"
},
"totalDuration": {"$sum": "$duration"}
}
},
{
"$group": {
"_id": "$_id.username",
"exercises": {
"$push": {
"exerciseType": "$_id.exerciseType",
"totalDuration": "$totalDuration"
}
}
}
},
{
"$project": {
"username": "$_id",
"exercises": 1,
"_id": 0
}
}
]

stats = list(db.exercises.aggregate(pipeline))
return jsonify(stats=stats)


@app.errorhandler(Exception)
def handle_error(e):
app.logger.error(f"An error occurred: {e}")
Expand Down
14 changes: 14 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"@testing-library/user-event": "^13.2.1",
"axios": "^1.5.1",
"bootstrap": "^5.3.2",
"moment": "^2.29.4",
"react": "^18.2.0",
"react-bootstrap": "^2.9.0",
"react-datepicker": "^4.20.0",
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Statistics from './components/statistics';
import Footer from './components/footer';
import Login from './components/login';
import Signup from './components/signup';
import Journal from './components/journal';

function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
Expand Down Expand Up @@ -36,9 +37,13 @@ function App() {
<div className="componentContainer">
<Routes>
<Route path="/login" element={isLoggedIn ? <Navigate to="/" /> : <Login onLogin={handleLogin} />} />
<Route path="/signup" element={isLoggedIn ? <Navigate to="/" /> : <Signup onSignup={() => setIsLoggedIn(true)} />} />
<Route path="/signup" element={isLoggedIn ? <Navigate to="/" /> : <Signup onSignup={(username) => {
setIsLoggedIn(true);
setCurrentUser(username);
}} />} />
<Route path="/trackExercise" element={isLoggedIn ? <TrackExercise currentUser={currentUser} /> : <Navigate to="/login" />} />
<Route path="/statistics" element={isLoggedIn ? <Statistics currentUser={currentUser} /> : <Navigate to="/login" />} />
<Route path="/journal" element={isLoggedIn ? <Journal currentUser={currentUser} /> : <Navigate to="/login" />} />
<Route path="/" element={isLoggedIn ? <Navigate to="/trackExercise" /> : <Navigate to="/login" />} />
</Routes>
</div>
Expand Down
38 changes: 38 additions & 0 deletions frontend/src/components/journal.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.journal-container {
max-width: 600px;
margin: auto;
background-color: #f5f5f5;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}

.exercise-journal-data {
margin-bottom: 10px;
padding-top: 20px;
}

.date-range {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
margin-bottom: 20px;
}

ul {
padding-left: 0;
}

li {
list-style-type: none;
background: #e0e0e0;
margin-bottom: 5px;
padding: 10px;
border-radius: 3px;
}

.button-small {
padding: 5px 10px;
font-size: 0.8rem;
}
57 changes: 57 additions & 0 deletions frontend/src/components/journal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { Button } from 'react-bootstrap';
import moment from 'moment';
import './journal.css';

const Journal = ({ currentUser }) => {
const [startDate, setStartDate] = useState(moment().startOf('week').toDate());
const [endDate, setEndDate] = useState(moment().endOf('week').toDate());
const [exercises, setExercises] = useState([]);

const fetchExercises = async () => {
try {
const url = `http://localhost:5050/api/stats/weekly/?user=${currentUser}&start=${moment(startDate).format('YYYY-MM-DD')}&end=${moment(endDate).format('YYYY-MM-DD')}`;
const response = await axios.get(url);
console.log('API Response:', response.data);
setExercises(response.data.stats); // Updated this line
} catch (error) {
console.error('Failed to fetch exercises', error);
}
};

useEffect(() => {
fetchExercises();
}, [currentUser, startDate, endDate]);

const goToPreviousWeek = () => {
setStartDate(moment(startDate).subtract(1, 'weeks').startOf('week').toDate());
setEndDate(moment(endDate).subtract(1, 'weeks').endOf('week').toDate());
};

const goToNextWeek = () => {
setStartDate(moment(startDate).add(1, 'weeks').startOf('week').toDate());
setEndDate(moment(endDate).add(1, 'weeks').endOf('week').toDate());
};

return (
<div className="journal-container">
<h4>Weekly Exercise Journal</h4>
<br></br>
<div className="date-range">
<Button className="button-small" onClick={goToPreviousWeek}>&larr; Previous</Button>
<span>{moment(startDate).format('YYYY-MM-DD')} to {moment(endDate).format('YYYY-MM-DD')}</span>
<Button className="button-small" onClick={goToNextWeek}>Next &rarr;</Button>
</div>
<ul>
{exercises && exercises.length > 0 && exercises[0].exercises.map((exercise, index) => (
<li key={index} className="exercise-journal-data">
{exercise.exerciseType} - {exercise.totalDuration} minutes
</li>
))}
</ul>
</div>
);
};

export default Journal;
5 changes: 4 additions & 1 deletion frontend/src/components/navbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const NavbarComponent = ({ onLogout }) => {
case 'Statistics':
navigate('/statistics');
break;
case 'Journal':
navigate('/journal');
break;
default:
console.error('Invalid route:', route);
}
Expand All @@ -28,7 +31,7 @@ const NavbarComponent = ({ onLogout }) => {
<Nav>
<Nav.Link className="custom-nav-link" onClick={() => onNavigate('TrackExercise')}>Track New Exercise</Nav.Link>
<Nav.Link className="custom-nav-link" onClick={() => onNavigate('Statistics')}>Statistics</Nav.Link>
<Nav.Link className="custom-nav-link" onClick={() => onNavigate('Journal')}>Journal</Nav.Link>
<Nav.Link className="custom-nav-link" onClick={() => onNavigate('Journal')}>Weekly Journal</Nav.Link>
<Nav.Link className="custom-nav-link" onClick={onLogout}>Logout</Nav.Link>
</Nav>
</Nav>
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/signup.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const Signup = ({ onSignup }) => {
setFormData((prevData) => ({ ...prevData, [name]: value }));
};


const handleSignup = async (e) => {
e.preventDefault();
setError('');
Expand All @@ -21,15 +22,15 @@ const Signup = ({ onSignup }) => {

if (response.data === 'User registered successfully!') {
console.log('User registered successfully');
onSignup();
onSignup(formData.username); // Pass the username to the onSignup callback
} else {
setError(response.data);
}
} catch (error) {
console.error('Error during registration', error);
setError(error.response?.data || 'An error occurred during registration. Please try again.');
}
};
};


return (
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/statistics.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const Statistics = ({ currentUser }) => {

return (
<div className="stats-container">
<h4>Well done, {currentUser}! Here are your stats:</h4>
<h4>Well done, {currentUser}! This is your overall effort:</h4>
{currentUserData ? (
currentUserData.exercises.map((item, index) => (
<div key={index} className="exercise-data">
Expand Down

0 comments on commit 19a69da

Please sign in to comment.