import type { User, Team, Expense } from "@prisma/client"; import type { LoaderFunction } from "remix"; import { redirect, useLoaderData, useCatch, Link, Form } from "remix"; import Filter from "~/icons/Filter"; import { db } from "~/utils/db.server"; import { getUser, requireUserId } from "~/utils/session.server"; type LoaderData = { user: (User & { team: Team & { members: User[] } }) | null; expenses: (Expense & { user: User & { team: Team } })[]; expensesCount: number; page: number; filters: { description: string | null | undefined; dateFrom: string | null | undefined; dateTo: string | null | undefined; user: string | null | undefined; }; }; export const loader: LoaderFunction = async ({ request }) => { const userId = requireUserId(request); const user = await getUser(request); if (!user?.id || !userId) { return redirect("/login"); } const expensesCount = await db.expense.count({ where: { teamId: user.teamId }, }); const searchParams = new URL(request.url)?.searchParams; const page = parseInt(searchParams.get("page") || "1", 10); const description = searchParams.get("description"); const dateFrom = searchParams.get("dateFrom"); const dateTo = searchParams.get("dateTo"); const userIdParam = searchParams.get("user"); const filters = { description: description && description.length > 0 ? description : undefined, dateFrom: dateFrom && dateFrom.length > 0 ? dateFrom : undefined, dateTo: dateTo && dateTo.length > 0 ? dateTo : undefined, user: userIdParam && userIdParam?.length > 0 ? userIdParam : undefined, }; const expensesFilters = { ...(filters.description && { description: { contains: filters.description }, }), ...((filters.dateFrom || filters.dateTo) && { createdAt: { ...(filters.dateFrom && { gte: new Date(`${filters.dateFrom}T00:00:00+0100`), }), ...(filters.dateTo && { lte: new Date(`${filters.dateTo}T00:00:00+0100`), }), }, }), ...(filters.user && { userId: filters.user }), }; console.log("FILTERS", filters); const expenses = await db.expense.findMany({ where: { teamId: user.teamId, ...expensesFilters, }, take: 10, skip: (page - 1) * 10, orderBy: { createdAt: "desc", }, include: { user: { include: { team: true, }, }, }, }); const data: LoaderData = { user, expenses, expensesCount, page, filters, }; return data; }; export default function ListExpensesRoute() { const data = useLoaderData(); const hasFilters = Object.values(data.filters).some( (value) => value !== undefined && value !== null ); return ( <>

List expenses

Filters

Clear
{data.expenses?.map((exp) => ( ))}
Date User Amount Description
See {new Intl.DateTimeFormat("it", { dateStyle: "short", }).format(new Date(exp.createdAt))} {exp.user.username} {exp.amount} € {exp.description}
{data.expensesCount > 10 && (
{[...new Array(Math.ceil(data.expensesCount / 10)).keys()].map( (p) => ( {p + 1} ) )}
)} ); } export function CatchBoundary() { const caught = useCatch(); if (caught.status === 401) { return redirect("/login"); } if (caught.status === 404) { return
There is no data to display.
; } throw new Error(`Unexpected caught response with status: ${caught.status}`); } export function ErrorBoundary() { return
I did a whoopsies.
; }