From fc20266da2547d1ec004c9854c684883fbbf4101 Mon Sep 17 00:00:00 2001 From: Dustin Do Date: Sun, 9 Jun 2024 15:43:35 +0700 Subject: [PATCH] feat(api): [Transaction] add list transactions (#56) --- apps/api/v1/routes/transactions.ts | 59 ++++++++++++++++++--- apps/api/v1/services/transaction.service.ts | 52 ++++++++++++++++++ 2 files changed, 103 insertions(+), 8 deletions(-) diff --git a/apps/api/v1/routes/transactions.ts b/apps/api/v1/routes/transactions.ts index 729bb11b..862d005f 100644 --- a/apps/api/v1/routes/transactions.ts +++ b/apps/api/v1/routes/transactions.ts @@ -11,6 +11,7 @@ import { createTransaction, deleteTransaction, findTransaction, + listTransactions, updateTransaction, } from '../services/transaction.service' import { findUserWallet } from '../services/wallet.service' @@ -26,19 +27,61 @@ const router = new Hono() zValidator( 'query', z.object({ - order_by: z.enum(['date']).optional(), - order: z.enum(['asc', 'desc']).optional(), wallet_id: z.string().optional(), budget_id: z.string().optional(), - from_date: z.string().optional(), - to_date: z.string().optional(), - take: z.number().optional(), - skip: z.number().optional(), - cursor: z.string().optional(), + before: z.date().optional(), + after: z.date().optional(), + first: z.number().optional(), + last: z.number().optional(), }), ), async (c) => { - return c.json([]) + const user = getAuthUserStrict(c) + const { + wallet_id: walletAccountId, + budget_id: budgetId, + before, + after, + first, + last, + } = c.req.valid('query') + + const query: { + createdByUserId?: string + budgetId?: string + walletAccountId?: string + } = { + budgetId, + walletAccountId, + } + + // If both budget and wallet are not provided, user can only see their own transactions + if (!budgetId && !walletAccountId) { + query.createdByUserId = user.id + } + + // If budget is provided, user must be a member of the budget + if (budgetId) { + const budget = await findBudget({ budgetId }) + if (!budget || !(await canUserReadBudget({ user, budget }))) { + return c.json({ message: 'budget not found' }, 404) + } + } + + // If wallet is provided, user must have access to the wallet + if (walletAccountId) { + const wallet = await findUserWallet({ user, walletId: walletAccountId }) + if (!wallet) { + return c.json({ message: 'wallet not found' }, 404) + } + } + + return c.json( + await listTransactions({ + query, + pagination: { before, after, first, last }, + }), + ) }, ) diff --git a/apps/api/v1/services/transaction.service.ts b/apps/api/v1/services/transaction.service.ts index 5d71c045..83b8fd6c 100644 --- a/apps/api/v1/services/transaction.service.ts +++ b/apps/api/v1/services/transaction.service.ts @@ -153,3 +153,55 @@ export async function deleteTransaction({ }, }) } + +export async function listTransactions({ + query, + pagination, +}: { + query: { + createdByUserId?: string + budgetId?: string + walletAccountId?: string + } + pagination: { + before?: Date + last?: number + after?: Date + first?: number + } +}) { + const transactions = await prisma.transaction.findMany({ + where: { + ...query, + createdAt: { + ...(pagination.before && { + lt: pagination.before, + }), + ...(pagination.after && { + gt: pagination.after, + }), + }, + }, + orderBy: { + createdAt: 'desc', + }, + take: pagination.first || pagination.last, + }) + + const totalCount = await prisma.transaction.count({ + where: query, + }) + + const paginationMeta = { + hasMore: transactions.length > (pagination.first || pagination.last || 0), + totalCount, + ...(pagination.first && { + before: transactions[0]?.createdAt, + }), + ...(pagination.last && { + after: transactions[transactions.length - 1]?.createdAt, + }), + } + + return { transactions, meta: { paginationMeta } } +}