first commit
This commit is contained in:
142
backend/dist/routes/logs.js
vendored
Normal file
142
backend/dist/routes/logs.js
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
import { z } from 'zod';
|
||||
import { prisma } from '../index.js';
|
||||
function parseTimeToMinutes(timeStr) {
|
||||
const str = timeStr.trim();
|
||||
// Format: "8,5" or "8.5" (decimal hours)
|
||||
if (/^\d+[,\.]\d+$/.test(str)) {
|
||||
const hours = parseFloat(str.replace(',', '.'));
|
||||
return Math.round(hours * 60);
|
||||
}
|
||||
// Format: "8:30" (hours:minutes)
|
||||
if (/^\d+:\d{1,2}$/.test(str)) {
|
||||
const [hours, minutes] = str.split(':').map(Number);
|
||||
return hours * 60 + minutes;
|
||||
}
|
||||
// Format: "8" (just hours)
|
||||
if (/^\d+$/.test(str)) {
|
||||
return parseInt(str, 10) * 60;
|
||||
}
|
||||
throw new Error('Invalid time format');
|
||||
}
|
||||
const createLogSchema = z.object({
|
||||
date: z.string(),
|
||||
time: z.string(),
|
||||
description: z.string().min(1).max(1000),
|
||||
});
|
||||
const updateLogSchema = z.object({
|
||||
date: z.string().optional(),
|
||||
time: z.string().optional(),
|
||||
description: z.string().min(1).max(1000).optional(),
|
||||
});
|
||||
const querySchema = z.object({
|
||||
startDate: z.string().optional(),
|
||||
endDate: z.string().optional(),
|
||||
});
|
||||
export async function logsRoutes(fastify) {
|
||||
fastify.addHook('onRequest', fastify.authenticate);
|
||||
// Get logs (default: current month)
|
||||
fastify.get('/', async (request) => {
|
||||
const user = request.user;
|
||||
const query = querySchema.parse(request.query);
|
||||
const now = new Date();
|
||||
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59);
|
||||
const startDate = query.startDate ? new Date(query.startDate) : startOfMonth;
|
||||
const endDate = query.endDate ? new Date(query.endDate + 'T23:59:59') : endOfMonth;
|
||||
const logs = await prisma.timeLog.findMany({
|
||||
where: {
|
||||
userId: user.id,
|
||||
date: {
|
||||
gte: startDate,
|
||||
lte: endDate,
|
||||
},
|
||||
},
|
||||
orderBy: { date: 'desc' },
|
||||
});
|
||||
return logs.map(log => ({
|
||||
...log,
|
||||
hours: Math.floor(log.minutes / 60),
|
||||
mins: log.minutes % 60,
|
||||
}));
|
||||
});
|
||||
// Create log
|
||||
fastify.post('/', async (request, reply) => {
|
||||
const user = request.user;
|
||||
const result = createLogSchema.safeParse(request.body);
|
||||
if (!result.success) {
|
||||
return reply.status(400).send({ error: 'Invalid input', details: result.error.errors });
|
||||
}
|
||||
const { date, time, description } = result.data;
|
||||
let minutes;
|
||||
try {
|
||||
minutes = parseTimeToMinutes(time);
|
||||
}
|
||||
catch {
|
||||
return reply.status(400).send({ error: 'Invalid time format' });
|
||||
}
|
||||
const log = await prisma.timeLog.create({
|
||||
data: {
|
||||
date: new Date(date),
|
||||
minutes,
|
||||
description,
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
return {
|
||||
...log,
|
||||
hours: Math.floor(log.minutes / 60),
|
||||
mins: log.minutes % 60,
|
||||
};
|
||||
});
|
||||
// Update log
|
||||
fastify.put('/:id', async (request, reply) => {
|
||||
const user = request.user;
|
||||
const { id } = request.params;
|
||||
const result = updateLogSchema.safeParse(request.body);
|
||||
if (!result.success) {
|
||||
return reply.status(400).send({ error: 'Invalid input', details: result.error.errors });
|
||||
}
|
||||
const existing = await prisma.timeLog.findFirst({
|
||||
where: { id, userId: user.id },
|
||||
});
|
||||
if (!existing) {
|
||||
return reply.status(404).send({ error: 'Log not found' });
|
||||
}
|
||||
const { date, time, description } = result.data;
|
||||
let minutes;
|
||||
if (time) {
|
||||
try {
|
||||
minutes = parseTimeToMinutes(time);
|
||||
}
|
||||
catch {
|
||||
return reply.status(400).send({ error: 'Invalid time format' });
|
||||
}
|
||||
}
|
||||
const log = await prisma.timeLog.update({
|
||||
where: { id },
|
||||
data: {
|
||||
...(date && { date: new Date(date) }),
|
||||
...(minutes !== undefined && { minutes }),
|
||||
...(description && { description }),
|
||||
},
|
||||
});
|
||||
return {
|
||||
...log,
|
||||
hours: Math.floor(log.minutes / 60),
|
||||
mins: log.minutes % 60,
|
||||
};
|
||||
});
|
||||
// Delete log
|
||||
fastify.delete('/:id', async (request, reply) => {
|
||||
const user = request.user;
|
||||
const { id } = request.params;
|
||||
const existing = await prisma.timeLog.findFirst({
|
||||
where: { id, userId: user.id },
|
||||
});
|
||||
if (!existing) {
|
||||
return reply.status(404).send({ error: 'Log not found' });
|
||||
}
|
||||
await prisma.timeLog.delete({ where: { id } });
|
||||
return { success: true };
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user