Skip to content

Commit

Permalink
transaction table
Browse files Browse the repository at this point in the history
  • Loading branch information
itsbekas committed Jan 12, 2025
1 parent 6def9ee commit 67c6c80
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 0 deletions.
46 changes: 46 additions & 0 deletions frontend/app/components/TransactionsTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useState } from "react";
import cx from "clsx";
import { ScrollArea, Table } from "@mantine/core";
import classes from "~/styles/TransactionsTable.module.css";

export type Transaction = {
id: string;
account_id: string;
amount: number;
date: string;
description: string;
counterparty: string;
subcategory_id: string;
user_description: string;
};

type TransactionsTableProps = {
transactions: Transaction[];
};

export function TransactionsTable({ transactions }: TransactionsTableProps) {
const [scrolled, setScrolled] = useState(false);

const rows = transactions.map((transaction) => (
<Table.Tr key={transaction.id}>
<Table.Td>{transaction.description}</Table.Td>
<Table.Td>{transaction.amount.toFixed(2)}</Table.Td>
</Table.Tr>
));

return (
<ScrollArea onScrollPositionChange={({ y }) => setScrolled(y !== 0)}>
<Table miw={700}>
<Table.Thead
className={cx(classes.header, { [classes.scrolled]: scrolled })}
>
<Table.Tr>
<Table.Th>Description</Table.Th>
<Table.Th>Amount</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>{rows}</Table.Tbody>
</Table>
</ScrollArea>
);
}
40 changes: 40 additions & 0 deletions frontend/app/routes/dashboard.finance.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { fetchWithAuth } from "~/utils/apiClient";
import { TransactionsTable } from "~/components/TransactionsTable";
import type { Route } from "./+types/dashboard.finance";

export type Transaction = {
id: string;
account_id: string;
amount: number;
date: string;
description: string;
counterparty: string;
subcategory_id: string;
user_description: string;
};

export async function loader({ request }: Route.LoaderArgs) {
const res = await fetchWithAuth(
"/finance/bank/transactions",
undefined,
request
);
if (!res.ok) {
throw new Error(`Failed to fetch transactions: ${res.statusText}`);
}

const transactions: Transaction[] = await res.json();

return transactions;
}

export default function FinancePage({ loaderData }: Route.ComponentProps) {
const transactions = loaderData;

return (
<div>
<h1>Finance Dashboard</h1>
<TransactionsTable transactions={transactions} />
</div>
);
}
20 changes: 20 additions & 0 deletions frontend/app/styles/TransactionsTable.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.header {
position: sticky;
top: 0;
background-color: var(--mantine-color-body);
transition: box-shadow 150ms ease;

&::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 0;
border-bottom: 1px solid
light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-3));
}
}

.scrolled {
box-shadow: var(--mantine-shadow-sm);
}
31 changes: 31 additions & 0 deletions frontend/app/utils/apiClient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { getSession } from "~/utils/session";

const BASE_URL = import.meta.env.VITE_BACKEND_URL;

export async function fetchWithAuth(
endpoint: string,
init: RequestInit = {},
request?: Request
) {
const session = await getSession(request?.headers.get("Cookie"));
const token = session.get("access_token");

if (!token) {
throw new Error("Authentication token not found");
}

// Add the Authorization header
const headers = {
...init.headers,
Authorization: `Bearer ${token}`,
};

// Construct the full URL
const url = `${BASE_URL}/api/v0${endpoint}`;

// Perform the fetch
return fetch(url, {
...init,
headers,
});
}

0 comments on commit 67c6c80

Please sign in to comment.