Learn how to build a comprehensive fitness tracking app using Lovable. Follow step-by-step instructions and expert tips to create a user-friendly, feature-rich tracker.
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
Setting Up Your Lovable Fitness Tracking Project
Defining Dependencies in the Lovable Configuration File
lovable.json
. This file will manage your app’s dependencies and settings.lovable.json
to include any external libraries that your fitness tracking application requires (for example, a charting library to visualize progress and a hypothetical fitness management library):
{
"name": "FitnessTracker",
"version": "1.0.0",
"dependencies": {
"chart.js": "^2.9.3",
"fitness-lib": "^1.0.0"
}
}
Creating the Main HTML Structure
index.html
in your project root.
Fitness Tracker
My Fitness Tracker
Styling Your Fitness Tracker Interface
styles.css
in your project root.
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f0f0f0;
}
header {
text-align: center;
margin-bottom: 20px;
}
#tracker-section {
background: #fff;
padding: 15px;
border-radius: 5px;
max-width: 600px;
margin: 0 auto;
}
#fitnessTracker {
margin-bottom: 20px;
}
Building the Fitness Tracking Logic
fitness.js
.fitness.js
:
document.addEventListener('DOMContentLoaded', function() {
// Simulated fitness data; in a real application, this might come from a sensor or user input.
let fitnessData = {
steps: 0,
calories: 0,
workouts: 0
};
// Function to simulate tracking steps over time
function updateFitnessData() {
fitnessData.steps += Math.floor(Math.random() * 10 + 1);
fitnessData.calories += Math.floor(Math.random() * 5 + 1);
fitnessData.workouts = fitnessData.steps > 100 ? 1 : 0;
displayFitnessData();
updateChart();
}
// Display fitness data on the page
function displayFitnessData() {
const trackerDiv = document.getElementById('fitnessTracker');
trackerDiv.innerHTML = `
Steps: ${fitnessData.steps}
Calories Burned: ${fitnessData.calories}
Workout Session: ${fitnessData.workouts}
`;
}
// Update the fitness progress chart using Chart.js
let chartContext = document.getElementById('fitnessChart').getContext('2d');
let fitnessChart = new Chart(chartContext, {
type: 'line',
data: {
labels: ['Time 1', 'Time 2', 'Time 3'],
datasets: [{
label: 'Steps',
data: [0, fitnessData.steps, fitnessData.steps + 20],
borderColor: 'rgba(75, 192, 192, 1)',
fill: false
}]
},
options: {
responsive: true,
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
// Function to update chart data
function updateChart() {
// For demonstration, we update the chart with a simple logic.
fitnessChart.data.datasets[0].data.push(fitnessData.steps);
fitnessChart.data.labels.push('Time ' + (fitnessChart.data.labels.length + 1));
fitnessChart.update();
}
// Simulate data updates every 5 seconds
setInterval(updateFitnessData, 5000);
// Initial data display
displayFitnessData();
});
Integrating and Testing Your Application
lovable.json
, index.html
, styles.css
, and fitness.js
) are saved in your project’s root directory.lovable.json
.
Deploying and Sharing Your Fitness Tracker
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const app = express();
app.use(bodyParser.json());
// Define the workout schema for fitness tracking
const workoutSchema = new mongoose.Schema({
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
activity: { type: String, required: true },
duration: { type: Number, required: true },
caloriesBurned: { type: Number, required: true },
heartRateData: [{
timestamp: { type: Date, default: Date.now },
heartRate: { type: Number, required: true }
}],
createdAt: { type: Date, default: Date.now }
});
const Workout = mongoose.model('Workout', workoutSchema);
// API endpoint to submit a workout session
app.post('/api/workouts', async (req, res) => {
try {
const { userId, activity, duration, caloriesBurned, heartRateData } = req.body;
if (!userId || !activity || !duration || !caloriesBurned) {
return res.status(400).json({ error: 'Missing required fields' });
}
const workout = new Workout({ userId, activity, duration, caloriesBurned, heartRateData });
await workout.save();
res.status(201).json({ message: 'Workout saved successfully', workout });
} catch (error) {
res.status(500).json({ error: 'Internal server error' });
}
});
// API endpoint to retrieve aggregated fitness stats for a user
app.get('/api/users/:userId/stats', async (req, res) => {
try {
const { userId } = req.params;
const stats = await Workout.aggregate([
{ $match: { userId: mongoose.Types.ObjectId(userId) } },
{ $group: {
\_id: '$activity',
totalDuration: { $sum: '$duration' },
totalCalories: { $sum: '$caloriesBurned' },
avgCaloriesPerMinute: { $avg: { $divide: ['$caloriesBurned', '$duration'] } }
}}
]);
res.json({ stats });
} catch (error) {
res.status(500).json({ error: 'Internal server error' });
}
});
// Connect to MongoDB and start the server
mongoose.connect('mongodb://localhost:27017/lovable\_fitness', {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
app.listen(3000, () => console.log('Server is running on port 3000'));
})
.catch(err => console.error('MongoDB connection error:', err));
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
app.post('/api/workouts/weather', async (req, res) => {
try {
const { latitude, longitude, workoutId } = req.body;
if (latitude === undefined || longitude === undefined || !workoutId) {
return res.status(400).json({ error: 'Missing required fields: latitude, longitude, or workoutId' });
}
const apiKey = 'YOUR_OPENWEATHERMAP_API\_KEY';
const weatherResponse = await axios.get('https://api.openweathermap.org/data/2.5/weather', {
params: {
lat: latitude,
lon: longitude,
appid: apiKey,
units: 'metric'
}
});
const weather = {
temperature: weatherResponse.data.main.temp,
description: weatherResponse.data.weather[0].description,
humidity: weatherResponse.data.main.humidity
};
// Here you would typically associate the retrieved weather data with the workout entry in your database
res.status(200).json({
message: 'Workout weather information retrieved successfully',
workoutId,
weather
});
} catch (error) {
res.status(500).json({ error: 'Failed to retrieve weather data' });
}
});
app.listen(3000, () => console.log('Server running on port 3000'));
const express = require('express');
const mongoose = require('mongoose');
const Redis = require('ioredis');
const app = express();
const redis = new Redis();
const workoutSchema = new mongoose.Schema({
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
activity: { type: String, required: true },
duration: { type: Number, required: true },
caloriesBurned: { type: Number, required: true },
createdAt: { type: Date, default: Date.now }
});
const Workout = mongoose.model('Workout', workoutSchema);
app.get('/api/users/:userId/recent-workouts', async (req, res) => {
try {
const { userId } = req.params;
const cacheKey = `recent:workouts:${userId}`;
const cachedWorkouts = await redis.get(cacheKey);
if (cachedWorkouts) {
return res.json({ source: 'cache', workouts: JSON.parse(cachedWorkouts) });
}
const workouts = await Workout.find({ userId }).sort({ createdAt: -1 }).limit(5).lean();
await redis.set(cacheKey, JSON.stringify(workouts), 'EX', 60);
res.json({ source: 'db', workouts });
} catch (error) {
res.status(500).json({ error: 'Internal server error' });
}
});
mongoose.connect('mongodb://localhost:27017/lovable\_fitness', {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
app.listen(3000, () => console.log('Server running on port 3000'));
})
.catch(err => console.error('DB connection error:', err));
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
Understanding Your Fitness Tracking Project
Gathering Tools and Resources
Planning Your Application Architecture
Utilizing AI Code Generators Effectively
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.