import type { FastifyPluginAsync } from 'fastify'; import { ZodError } from 'zod'; import { createRecurringExpenseSchema, recurringExpenseParamsSchema, recurringExpenseUserParamsSchema, updateRecurringExpenseSchema, } from './recurring-expenses.schema'; import * as recurringService from './recurring-expenses.service'; const recurringExpensesRoutes: FastifyPluginAsync = async (fastify) => { /** GET /users/:userId/recurring-expenses — Lista todos os gastos recorrentes */ fastify.get<{ Params: { userId: string } }>( '/users/:userId/recurring-expenses', async (request, reply) => { const { userId } = recurringExpenseUserParamsSchema.parse(request.params); const result = await recurringService.findRecurringExpensesByUser(userId); return reply.send({ data: result }); }, ); /** GET /users/:userId/recurring-expenses/:id — Busca um gasto recorrente específico */ fastify.get<{ Params: { userId: string; id: string } }>( '/users/:userId/recurring-expenses/:id', async (request, reply) => { const { userId, id } = recurringExpenseParamsSchema.parse(request.params); const expense = await recurringService.findRecurringExpenseById(userId, id); if (!expense) { return reply.status(404).send({ error: 'Gasto recorrente não encontrado.' }); } return reply.send({ data: expense }); }, ); /** POST /users/:userId/recurring-expenses — Cadastra um novo gasto fixo */ fastify.post<{ Params: { userId: string } }>( '/users/:userId/recurring-expenses', async (request, reply) => { try { const { userId } = recurringExpenseUserParamsSchema.parse(request.params); const body = createRecurringExpenseSchema.parse(request.body); const expense = await recurringService.createRecurringExpense(userId, body); return reply.status(201).send({ data: expense }); } catch (err) { if (err instanceof ZodError) { return reply.status(400).send({ error: 'Dados inválidos.', details: err.errors }); } throw err; } }, ); /** PUT /users/:userId/recurring-expenses/:id — Atualiza um gasto recorrente */ fastify.put<{ Params: { userId: string; id: string } }>( '/users/:userId/recurring-expenses/:id', async (request, reply) => { try { const { userId, id } = recurringExpenseParamsSchema.parse(request.params); const body = updateRecurringExpenseSchema.parse(request.body); const expense = await recurringService.updateRecurringExpense(userId, id, body); if (!expense) { return reply.status(404).send({ error: 'Gasto recorrente não encontrado.' }); } return reply.send({ data: expense }); } catch (err) { if (err instanceof ZodError) { return reply.status(400).send({ error: 'Dados inválidos.', details: err.errors }); } throw err; } }, ); /** * PATCH /users/:userId/recurring-expenses/:id/toggle * Ativa ou desativa um gasto recorrente sem precisar deletar. */ fastify.patch<{ Params: { userId: string; id: string } }>( '/users/:userId/recurring-expenses/:id/toggle', async (request, reply) => { const { userId, id } = recurringExpenseParamsSchema.parse(request.params); const expense = await recurringService.toggleRecurringExpense(userId, id); if (!expense) { return reply.status(404).send({ error: 'Gasto recorrente não encontrado.' }); } return reply.send({ data: expense }); }, ); /** DELETE /users/:userId/recurring-expenses/:id — Remove um gasto recorrente */ fastify.delete<{ Params: { userId: string; id: string } }>( '/users/:userId/recurring-expenses/:id', async (request, reply) => { const { userId, id } = recurringExpenseParamsSchema.parse(request.params); const deleted = await recurringService.deleteRecurringExpense(userId, id); if (!deleted) { return reply.status(404).send({ error: 'Gasto recorrente não encontrado.' }); } return reply.status(200).send({ data: deleted, message: 'Gasto recorrente removido com sucesso.' }); }, ); }; export default recurringExpensesRoutes;