const express = require('express'); const cors = require('cors'); const mysql = require('mysql2/promise'); const app = express(); app.use(cors()); app.use(express.json()); const dbConfig = { host: process.env.DB_HOST || 'db', user: process.env.DB_USER || 'root', password: process.env.DB_PASSWORD || 'password', database: process.env.DB_NAME || 'nutrition', waitForConnections: true, connectionLimit: 10, queueLimit: 0 }; let pool; // Wait for DB to be ready const connectDB = async () => { let retries = 5; while (retries) { try { pool = mysql.createPool(dbConfig); await pool.query('SELECT 1'); console.log('Connected to MariaDB'); break; } catch (err) { console.error('Failed to connect to MariaDB, retrying...', err); retries -= 1; await new Promise(res => setTimeout(res, 5000)); } } }; connectDB(); // Get Profile app.get('/api/profile/:userId', async (req, res) => { try { const [rows] = await pool.query('SELECT * FROM users WHERE id = ?', [req.params.userId]); if (rows.length > 0) { res.json(rows[0]); } else { res.status(404).json({ error: 'Profile not found' }); } } catch (err) { res.status(500).json({ error: err.message }); } }); // Save Profile app.post('/api/profile', async (req, res) => { const p = req.body; const userId = p.id || 'default_user'; try { await pool.query(` INSERT INTO users (id, height, weight, age, gender, activityLevel, goal, bmi, tdee, targetCalories, targetProtein, targetFat, targetCarbs, targetWater) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE height=?, weight=?, age=?, gender=?, activityLevel=?, goal=?, bmi=?, tdee=?, targetCalories=?, targetProtein=?, targetFat=?, targetCarbs=?, targetWater=? `, [ userId, p.height, p.weight, p.age, p.gender, p.activityLevel, p.goal, p.bmi, p.tdee, p.targetCalories, p.targetProtein, p.targetFat, p.targetCarbs, p.targetWater, p.height, p.weight, p.age, p.gender, p.activityLevel, p.goal, p.bmi, p.tdee, p.targetCalories, p.targetProtein, p.targetFat, p.targetCarbs, p.targetWater ]); res.json({ success: true }); } catch (err) { res.status(500).json({ error: err.message }); } }); // Get Logs (returns a mapped object { "YYYY-MM-DD": DailyLog }) app.get('/api/logs/:userId', async (req, res) => { try { const [logRows] = await pool.query('SELECT * FROM daily_logs WHERE user_id = ?', [req.params.userId]); const [mealRows] = await pool.query('SELECT * FROM meals WHERE user_id = ?', [req.params.userId]); const logs = {}; logRows.forEach(row => { // row.date is Date object, format to YYYY-MM-DD const dateStr = new Date(row.date).toISOString().split('T')[0]; logs[dateStr] = { date: dateStr, waterIntake: row.waterIntake, weight: row.weight, meals: [] }; }); mealRows.forEach(row => { const dateStr = new Date(row.date).toISOString().split('T')[0]; if (!logs[dateStr]) { logs[dateStr] = { date: dateStr, waterIntake: 0, meals: [] }; } logs[dateStr].meals.push({ id: row.id, name: row.name, time: row.time, calories: row.calories, protein: row.protein, fat: row.fat, carbs: row.carbs }); }); res.json(logs); } catch (err) { res.status(500).json({ error: err.message }); } }); // Add Meal app.post('/api/logs/meal', async (req, res) => { const { userId, date, meal } = req.body; try { await pool.query(` INSERT INTO meals (id, user_id, date, name, time, calories, protein, fat, carbs) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) `, [meal.id, userId, date, meal.name, meal.time, meal.calories, meal.protein, meal.fat, meal.carbs]); res.json({ success: true }); } catch (err) { res.status(500).json({ error: err.message }); } }); // Add Water app.post('/api/logs/water', async (req, res) => { const { userId, date, amount } = req.body; try { await pool.query(` INSERT INTO daily_logs (date, user_id, waterIntake) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE waterIntake = waterIntake + ? `, [date, userId, amount, amount]); res.json({ success: true }); } catch (err) { res.status(500).json({ error: err.message }); } }); // Log Weight app.post('/api/logs/weight', async (req, res) => { const { userId, date, weight } = req.body; try { await pool.query(` INSERT INTO daily_logs (date, user_id, weight) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE weight = ? `, [date, userId, weight, weight]); res.json({ success: true }); } catch (err) { res.status(500).json({ error: err.message }); } }); // Clear Data app.delete('/api/data/:userId', async (req, res) => { try { await pool.query('DELETE FROM users WHERE id = ?', [req.params.userId]); res.json({ success: true }); } catch (err) { res.status(500).json({ error: err.message }); } }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`API server running on port ${PORT}`); });