Files
spliit/src/lib/api.ts
2024-01-08 08:28:18 -05:00

224 lines
6.1 KiB
TypeScript

import { getPrisma } from '@/lib/prisma'
import { ExpenseFormValues, GroupFormValues } from '@/lib/schemas'
import { Expense } from '@prisma/client'
import { nanoid } from 'nanoid'
export function randomId() {
return nanoid()
}
export async function createGroup(groupFormValues: GroupFormValues) {
const prisma = await getPrisma()
return prisma.group.create({
data: {
id: randomId(),
name: groupFormValues.name,
currency: groupFormValues.currency,
participants: {
createMany: {
data: groupFormValues.participants.map(({ name }) => ({
id: randomId(),
name,
})),
},
},
},
include: { participants: true },
})
}
export async function createExpense(
expenseFormValues: ExpenseFormValues,
groupId: string,
): Promise<Expense> {
const group = await getGroup(groupId)
if (!group) throw new Error(`Invalid group ID: ${groupId}`)
for (const participant of [
expenseFormValues.paidBy,
...expenseFormValues.paidFor.map((p) => p.participant),
]) {
if (!group.participants.some((p) => p.id === participant))
throw new Error(`Invalid participant ID: ${participant}`)
}
const prisma = await getPrisma()
return prisma.expense.create({
data: {
id: randomId(),
groupId,
amount: expenseFormValues.amount,
title: expenseFormValues.title,
paidById: expenseFormValues.paidBy,
splitMode: expenseFormValues.splitMode,
paidFor: {
createMany: {
data: expenseFormValues.paidFor.map((paidFor) => ({
participantId: paidFor.participant,
shares: paidFor.shares,
})),
},
},
isReimbursement: expenseFormValues.isReimbursement,
},
})
}
export async function deleteExpense(expenseId: string) {
const prisma = await getPrisma()
await prisma.expense.delete({
where: { id: expenseId },
include: { paidFor: true, paidBy: true },
})
}
export async function getGroupExpensesParticipants(groupId: string) {
const expenses = await getGroupExpenses(groupId)
return Array.from(
new Set(
expenses.flatMap((e) => [
e.paidById,
...e.paidFor.map((pf) => pf.participantId),
]),
),
)
}
export async function getGroups(groupIds: string[]) {
const prisma = await getPrisma()
return (
await prisma.group.findMany({
where: { id: { in: groupIds } },
include: { _count: { select: { participants: true } } },
})
).map((group) => ({
...group,
createdAt: group.createdAt.toISOString(),
}))
}
export async function updateExpense(
groupId: string,
expenseId: string,
expenseFormValues: ExpenseFormValues,
) {
const group = await getGroup(groupId)
if (!group) throw new Error(`Invalid group ID: ${groupId}`)
const existingExpense = await getExpense(groupId, expenseId)
if (!existingExpense) throw new Error(`Invalid expense ID: ${expenseId}`)
for (const participant of [
expenseFormValues.paidBy,
...expenseFormValues.paidFor.map((p) => p.participant),
]) {
if (!group.participants.some((p) => p.id === participant))
throw new Error(`Invalid participant ID: ${participant}`)
}
const prisma = await getPrisma()
return prisma.expense.update({
where: { id: expenseId },
data: {
amount: expenseFormValues.amount,
title: expenseFormValues.title,
paidById: expenseFormValues.paidBy,
splitMode: expenseFormValues.splitMode,
paidFor: {
create: expenseFormValues.paidFor
.filter(
(p) =>
!existingExpense.paidFor.some(
(pp) => pp.participantId === p.participant,
),
)
.map((paidFor) => ({
participantId: paidFor.participant,
shares: paidFor.shares,
})),
update: expenseFormValues.paidFor.map((paidFor) => ({
where: {
expenseId_participantId: {
expenseId,
participantId: paidFor.participant,
},
},
data: {
shares: paidFor.shares,
},
})),
deleteMany: existingExpense.paidFor.filter(
(paidFor) =>
!expenseFormValues.paidFor.some(
(pf) => pf.participant === paidFor.participantId,
),
),
},
isReimbursement: expenseFormValues.isReimbursement,
},
})
}
export async function updateGroup(
groupId: string,
groupFormValues: GroupFormValues,
) {
const existingGroup = await getGroup(groupId)
if (!existingGroup) throw new Error('Invalid group ID')
const prisma = await getPrisma()
return prisma.group.update({
where: { id: groupId },
data: {
name: groupFormValues.name,
currency: groupFormValues.currency,
participants: {
deleteMany: existingGroup.participants.filter(
(p) => !groupFormValues.participants.some((p2) => p2.id === p.id),
),
updateMany: groupFormValues.participants
.filter((participant) => participant.id !== undefined)
.map((participant) => ({
where: { id: participant.id },
data: {
name: participant.name,
},
})),
createMany: {
data: groupFormValues.participants
.filter((participant) => participant.id === undefined)
.map((participant) => ({
id: randomId(),
name: participant.name,
})),
},
},
},
})
}
export async function getGroup(groupId: string) {
const prisma = await getPrisma()
return prisma.group.findUnique({
where: { id: groupId },
include: { participants: true },
})
}
export async function getGroupExpenses(groupId: string) {
const prisma = await getPrisma()
return prisma.expense.findMany({
where: { groupId },
include: { paidFor: { include: { participant: true } }, paidBy: true },
orderBy: { createdAt: 'desc' },
})
}
export async function getExpense(groupId: string, expenseId: string) {
const prisma = await getPrisma()
return prisma.expense.findUnique({
where: { id: expenseId },
include: { paidBy: true, paidFor: true },
})
}