117 lines
3.1 KiB
TypeScript
117 lines
3.1 KiB
TypeScript
import { z } from "zod";
|
|
|
|
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
|
import {
|
|
expenses,
|
|
expenseSplits,
|
|
friendships,
|
|
type ExpenseSplit,
|
|
} from "@/server/db/schema";
|
|
import { expenseSchema, expenseSplitSchema } from "@/lib/validations/expense";
|
|
import { and, eq, inArray, not, notInArray, or } from "drizzle-orm";
|
|
|
|
function restructureExpenseSplits(expenseSplits: Array<ExpenseSplit>) {
|
|
const expensesMap = new Map();
|
|
|
|
expenseSplits.forEach((split) => {
|
|
const expenseId = split.expenseId;
|
|
const expense = split.expense;
|
|
|
|
if (!expensesMap.has(expenseId)) {
|
|
expensesMap.set(expenseId, {
|
|
...expense,
|
|
splits: [],
|
|
});
|
|
}
|
|
|
|
expensesMap.get(expenseId).splits.push(split);
|
|
});
|
|
|
|
return Array.from(expensesMap.values());
|
|
}
|
|
|
|
export const expenseRouter = createTRPCRouter({
|
|
getAll: protectedProcedure.query(async ({ ctx }) => {
|
|
const splits = await ctx.db.query.expenseSplits.findMany({
|
|
where: or(
|
|
eq(expenseSplits.owedFromId, ctx.auth.userId),
|
|
eq(expenseSplits.owedToId, ctx.auth.userId)
|
|
),
|
|
with: {
|
|
owedFrom: true,
|
|
owedTo: true,
|
|
expense: true,
|
|
},
|
|
});
|
|
const expenses = restructureExpenseSplits(splits);
|
|
return expenses;
|
|
}),
|
|
|
|
searchParticipants: protectedProcedure
|
|
.input(z.object({ search: z.string(), excludedIds: z.array(z.string()) }))
|
|
.query(async ({ ctx, input }) => {
|
|
const userId = ctx.auth.userId;
|
|
const friendResult = await ctx.db.query.friendships.findMany({
|
|
where: and(
|
|
or(
|
|
eq(friendships.userOneId, userId),
|
|
eq(friendships.userTwoId, userId)
|
|
),
|
|
notInArray(friendships.userOneId, input.excludedIds),
|
|
notInArray(friendships.userTwoId, input.excludedIds)
|
|
),
|
|
with: {
|
|
userOne: true,
|
|
userTwo: true,
|
|
},
|
|
});
|
|
const friends =
|
|
friendResult?.map(({ userOne, userTwo }) =>
|
|
ctx.auth.userId === userOne.id ? userTwo : userOne
|
|
) ?? [];
|
|
return {
|
|
friends,
|
|
groups: [],
|
|
};
|
|
}),
|
|
|
|
// mutations
|
|
create: protectedProcedure
|
|
.input(
|
|
z.object({
|
|
expense: expenseSchema,
|
|
debs: z.array(
|
|
expenseSplitSchema.pick({
|
|
owedFromId: true,
|
|
owedToId: true,
|
|
amount: true,
|
|
})
|
|
),
|
|
})
|
|
)
|
|
.mutation(async ({ ctx, input }) => {
|
|
const [expense] = await ctx.db
|
|
.insert(expenses)
|
|
.values({
|
|
createdById: ctx.auth.userId,
|
|
...input.expense,
|
|
amount: input.expense.amount.toString(),
|
|
})
|
|
.returning({ id: expenses.id });
|
|
if (!expense?.id?.length) throw new Error("Expense cant get created");
|
|
|
|
await ctx.db
|
|
.insert(expenseSplits)
|
|
.values(
|
|
input.debs.map((deb) => ({
|
|
...deb,
|
|
amount: deb.amount.toString(),
|
|
expenseId: expense.id,
|
|
status: "unpaid",
|
|
}))
|
|
)
|
|
.returning({ id: expenseSplits.id });
|
|
return expense;
|
|
}),
|
|
});
|