Separated weight tracking
This commit is contained in:
Binary file not shown.
@@ -24,6 +24,18 @@ model User {
|
||||
sessions WorkoutSession[]
|
||||
exercises Exercise[]
|
||||
plans WorkoutPlan[]
|
||||
weightRecords BodyWeightRecord[]
|
||||
}
|
||||
|
||||
model BodyWeightRecord {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
weight Float
|
||||
date DateTime @default(now())
|
||||
dateStr String // YYYY-MM-DD for unique constraint
|
||||
|
||||
@@unique([userId, dateStr])
|
||||
}
|
||||
|
||||
model UserProfile {
|
||||
|
||||
@@ -6,6 +6,7 @@ import exerciseRoutes from './routes/exercises';
|
||||
import sessionRoutes from './routes/sessions';
|
||||
import planRoutes from './routes/plans';
|
||||
import aiRoutes from './routes/ai';
|
||||
import weightRoutes from './routes/weight';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
@@ -59,6 +60,7 @@ app.use('/api/exercises', exerciseRoutes);
|
||||
app.use('/api/sessions', sessionRoutes);
|
||||
app.use('/api/plans', planRoutes);
|
||||
app.use('/api/ai', aiRoutes);
|
||||
app.use('/api/weight', weightRoutes);
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
res.send('GymFlow AI API is running');
|
||||
|
||||
21
server/src/middleware/auth.ts
Normal file
21
server/src/middleware/auth.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'secret';
|
||||
|
||||
export const authenticateToken = (req: Request, res: Response, next: NextFunction) => {
|
||||
const authHeader = req.headers['authorization'];
|
||||
const token = authHeader && authHeader.split(' ')[1];
|
||||
|
||||
if (!token) {
|
||||
return res.sendStatus(401);
|
||||
}
|
||||
|
||||
jwt.verify(token, JWT_SECRET, (err: any, user: any) => {
|
||||
if (err) {
|
||||
return res.sendStatus(403);
|
||||
}
|
||||
(req as any).user = user;
|
||||
next();
|
||||
});
|
||||
};
|
||||
78
server/src/routes/weight.ts
Normal file
78
server/src/routes/weight.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import express from 'express';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { authenticateToken } from '../middleware/auth';
|
||||
|
||||
const router = express.Router();
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// Get weight history
|
||||
router.get('/', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
const userId = (req as any).user.userId;
|
||||
const weights = await prisma.bodyWeightRecord.findMany({
|
||||
where: { userId },
|
||||
orderBy: { date: 'desc' },
|
||||
take: 365 // Limit to last year for now
|
||||
});
|
||||
res.json(weights);
|
||||
} catch (error) {
|
||||
console.error('Error fetching weight history:', error);
|
||||
res.status(500).json({ error: 'Failed to fetch weight history' });
|
||||
}
|
||||
});
|
||||
|
||||
// Log weight
|
||||
router.post('/', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
const userId = (req as any).user.userId;
|
||||
const { weight, dateStr } = req.body;
|
||||
|
||||
if (!weight || !dateStr) {
|
||||
return res.status(400).json({ error: 'Weight and dateStr are required' });
|
||||
}
|
||||
|
||||
// Upsert: Update if exists for this day, otherwise create
|
||||
const record = await prisma.bodyWeightRecord.upsert({
|
||||
where: {
|
||||
userId_dateStr: {
|
||||
userId,
|
||||
dateStr
|
||||
}
|
||||
},
|
||||
update: {
|
||||
weight: parseFloat(weight),
|
||||
date: new Date(dateStr) // Update date object just in case
|
||||
},
|
||||
create: {
|
||||
userId,
|
||||
weight: parseFloat(weight),
|
||||
dateStr,
|
||||
date: new Date(dateStr)
|
||||
}
|
||||
});
|
||||
|
||||
// Also update the user profile weight to the latest logged weight
|
||||
// But only if the logged date is today or in the future (or very recent)
|
||||
// For simplicity, let's just update the profile weight if it's the most recent record
|
||||
// Or we can just update it always if the user considers this their "current" weight.
|
||||
// Let's check if this is the latest record by date.
|
||||
const latestRecord = await prisma.bodyWeightRecord.findFirst({
|
||||
where: { userId },
|
||||
orderBy: { date: 'desc' }
|
||||
});
|
||||
|
||||
if (latestRecord && latestRecord.id === record.id) {
|
||||
await prisma.userProfile.update({
|
||||
where: { userId },
|
||||
data: { weight: parseFloat(weight) }
|
||||
});
|
||||
}
|
||||
|
||||
res.json(record);
|
||||
} catch (error) {
|
||||
console.error('Error logging weight:', error);
|
||||
res.status(500).json({ error: 'Failed to log weight' });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user