diff --git a/frontend/src/components/RawTransactionModal.tsx b/frontend/src/components/RawTransactionModal.tsx
new file mode 100644
index 0000000..d97e7af
--- /dev/null
+++ b/frontend/src/components/RawTransactionModal.tsx
@@ -0,0 +1,116 @@
+import { X, Copy, Check } from "lucide-react";
+import { useState } from "react";
+import type { RawTransactionData } from "../types/api";
+
+interface RawTransactionModalProps {
+ isOpen: boolean;
+ onClose: () => void;
+ rawTransaction: RawTransactionData | undefined;
+ transactionId: string;
+}
+
+export default function RawTransactionModal({
+ isOpen,
+ onClose,
+ rawTransaction,
+ transactionId,
+}: RawTransactionModalProps) {
+ const [copied, setCopied] = useState(false);
+
+ if (!isOpen) return null;
+
+ const handleCopy = async () => {
+ if (!rawTransaction) return;
+
+ try {
+ await navigator.clipboard.writeText(
+ JSON.stringify(rawTransaction, null, 2)
+ );
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ } catch (err) {
+ console.error("Failed to copy to clipboard:", err);
+ }
+ };
+
+ return (
+
+
+ {/* Background overlay */}
+
+
+ {/* Modal panel */}
+
+
+
+
+ Raw Transaction Data
+
+
+
+
+
+
+
+
+
+ Transaction ID: {transactionId}
+
+
+
+ {rawTransaction ? (
+
+
+ {JSON.stringify(rawTransaction, null, 2)}
+
+
+ ) : (
+
+
+ Raw transaction data is not available for this transaction.
+
+
+ Try refreshing the page or check if the transaction was fetched with summary_only=false.
+
+
+ )}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/components/TransactionsList.tsx b/frontend/src/components/TransactionsList.tsx
index 23c64d0..a210116 100644
--- a/frontend/src/components/TransactionsList.tsx
+++ b/frontend/src/components/TransactionsList.tsx
@@ -9,10 +9,12 @@ import {
RefreshCw,
AlertCircle,
X,
+ Eye,
} from "lucide-react";
import { apiClient } from "../lib/api";
import { formatCurrency, formatDate } from "../lib/utils";
import LoadingSpinner from "./LoadingSpinner";
+import RawTransactionModal from "./RawTransactionModal";
import type { Account, Transaction } from "../types/api";
export default function TransactionsList() {
@@ -21,6 +23,8 @@ export default function TransactionsList() {
const [startDate, setStartDate] = useState("");
const [endDate, setEndDate] = useState("");
const [showFilters, setShowFilters] = useState(false);
+ const [showRawModal, setShowRawModal] = useState(false);
+ const [selectedTransaction, setSelectedTransaction] = useState(null);
const { data: accounts } = useQuery({
queryKey: ["accounts"],
@@ -39,6 +43,7 @@ export default function TransactionsList() {
accountId: selectedAccount || undefined,
startDate: startDate || undefined,
endDate: endDate || undefined,
+ summaryOnly: false, // Always fetch raw transaction data
}),
});
@@ -74,6 +79,16 @@ export default function TransactionsList() {
setEndDate("");
};
+ const handleViewRaw = (transaction: Transaction) => {
+ setSelectedTransaction(transaction);
+ setShowRawModal(true);
+ };
+
+ const handleCloseModal = () => {
+ setShowRawModal(false);
+ setSelectedTransaction(null);
+ };
+
const hasActiveFilters =
searchTerm || selectedAccount || startDate || endDate;
@@ -248,13 +263,13 @@ export default function TransactionsList() {
const account = accounts?.find(
(acc) => acc.id === transaction.account_id,
);
- const isPositive = transaction.amount > 0;
+ const isPositive = transaction.transaction_value > 0;
return (
@@ -307,33 +322,51 @@ export default function TransactionsList() {
-
-
- {isPositive ? "+" : ""}
- {formatCurrency(transaction.amount, transaction.currency)}
-
-
- {transaction.date
- ? formatDate(transaction.date)
- : "No date"}
-
- {transaction.booking_date &&
- transaction.booking_date !== transaction.date && (
-
- Booked: {formatDate(transaction.booking_date)}
-
- )}
-
+
+
+
+
+
+ {isPositive ? "+" : ""}
+ {formatCurrency(transaction.transaction_value, transaction.transaction_currency)}
+
+
+ {transaction.transaction_date
+ ? formatDate(transaction.transaction_date)
+ : "No date"}
+
+ {transaction.booking_date &&
+ transaction.booking_date !== transaction.transaction_date && (
+
+ Booked: {formatDate(transaction.booking_date)}
+
+ )}
+
);
})}
)}
+
+ {/* Raw Transaction Modal */}
+
);
}
diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts
index c03ef8a..1818cb0 100644
--- a/frontend/src/lib/api.ts
+++ b/frontend/src/lib/api.ts
@@ -56,6 +56,7 @@ export const apiClient = {
page?: number;
perPage?: number;
search?: string;
+ summaryOnly?: boolean;
}): Promise => {
const queryParams = new URLSearchParams();
@@ -66,6 +67,9 @@ export const apiClient = {
if (params?.perPage)
queryParams.append("per_page", params.perPage.toString());
if (params?.search) queryParams.append("search", params.search);
+ if (params?.summaryOnly !== undefined) {
+ queryParams.append("summary_only", params.summaryOnly.toString());
+ }
const response = await api.get>(
`/transactions?${queryParams.toString()}`,
diff --git a/frontend/src/types/api.ts b/frontend/src/types/api.ts
index 1111845..de7db2c 100644
--- a/frontend/src/types/api.ts
+++ b/frontend/src/types/api.ts
@@ -17,15 +17,55 @@ export interface Account {
balances: AccountBalance[];
}
+export interface RawTransactionData {
+ transactionId?: string;
+ bookingDate?: string;
+ valueDate?: string;
+ bookingDateTime?: string;
+ valueDateTime?: string;
+ transactionAmount?: {
+ amount: string;
+ currency: string;
+ };
+ currencyExchange?: {
+ instructedAmount?: {
+ amount: string;
+ currency: string;
+ };
+ sourceCurrency?: string;
+ exchangeRate?: string;
+ unitCurrency?: string;
+ targetCurrency?: string;
+ };
+ creditorName?: string;
+ debtorName?: string;
+ debtorAccount?: {
+ iban?: string;
+ };
+ remittanceInformationUnstructuredArray?: string[];
+ proprietaryBankTransactionCode?: string;
+ balanceAfterTransaction?: {
+ balanceAmount: {
+ amount: string;
+ currency: string;
+ };
+ balanceType: string;
+ };
+ internalTransactionId?: string;
+ [key: string]: unknown; // Allow additional fields
+}
+
export interface Transaction {
internal_transaction_id: string | null;
account_id: string;
- amount: number;
- currency: string;
+ transaction_value: number;
+ transaction_currency: string;
description: string;
- date: string;
- status: string;
+ transaction_date: string;
+ transaction_status: string;
// Optional fields that may be present in some transactions
+ institution_id?: string;
+ iban?: string;
booking_date?: string;
value_date?: string;
creditor_name?: string;
@@ -34,6 +74,8 @@ export interface Transaction {
category?: string;
created_at?: string;
updated_at?: string;
+ // Raw transaction data (only present when summary_only=false)
+ raw_transaction?: RawTransactionData;
}
// Type for raw transaction data from API (before sanitization)