import type { LoaderFunction } from "remix"; import { useLoaderData, Link, useCatch, redirect } from "remix"; import type { Expense, User } from "@prisma/client"; import { db } from "~/utils/db.server"; import { getUser } from "~/utils/session.server"; import Group from "~/icons/Group"; type LoaderData = { lastExpenses: (Expense & { user: User })[]; user: User; teamCounts: { id: string; username: string; icon: string; count: number; spent: number; dueAmount: number; }[]; totalExpenses: { count: number; amount: number; }; }; export const loader: LoaderFunction = async ({ request }) => { const user = await getUser(request); if (!user) { return redirect("/login"); } const lastExpenses = await db.expense.findMany({ include: { user: true, }, take: 6, orderBy: { createdAt: "desc" }, where: { teamId: user.teamId }, }); let teamExpenses = await db.expense.groupBy({ by: ["userId"], _count: { _all: true, }, _sum: { amount: true, }, where: { user: { teamId: user.teamId } }, }); let expensesByUser = user.team.members.map((m) => ({ id: m.id, username: m.username, icon: m.icon, count: teamExpenses.find((e) => e.userId === m.id)?._count?._all ?? 0, spent: teamExpenses.find((e) => e.userId === m.id)?._sum?.amount ?? 0, dueAmount: 0, })); let totalExpenses = expensesByUser.reduce( (acc, { count, spent }) => ({ count: acc.count + count, amount: acc.amount + spent, }), { count: 0, amount: 0 } ); const avgPerUser = totalExpenses.amount / user.team.members.length; let teamCounts = expensesByUser.map((userData) => ({ ...userData, dueAmount: avgPerUser - userData.spent, })); console.log("totalExpenses", totalExpenses); console.log("expensesByUser", expensesByUser); const data: LoaderData = { lastExpenses, user, totalExpenses, teamCounts, }; return data; }; export default function JokesIndexRoute() { const data = useLoaderData(); return (

Last expenses

    {data.lastExpenses?.map((exp) => (
  • {exp.user.icon ?? exp.user.username[0]}
    0 ? "text-error" : "text-success" }`} > {-exp.amount} €
    {new Intl.DateTimeFormat("it", { dateStyle: "short", timeStyle: "short", }).format(new Date(exp.createdAt))} {exp.description}
  • ))}
See all

Who needs to pay who

    {data.teamCounts?.map((user) => (
  • {user.icon ?? user.username[0]}
    {user.username}
    0 ? `You owe others` : `Others owe you` } className="tooltip" > 0 ? "text-error" : "text-success" }`} > {user.dueAmount > 0 ? user.dueAmount : -user.dueAmount} €
  • ))}
New
Trasfer
); } export function CatchBoundary() { const caught = useCatch(); if (caught.status === 404) { return (
There are no expenses to display.
); } throw new Error(`Unexpected caught response with status: ${caught.status}`); } export function ErrorBoundary() { return
I did a whoopsies.
; }