224 lines
10 KiB
HTML
224 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html data-bs-theme="light" lang="en">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
|
<title>FinanceTracker | Transactions</title>
|
|
|
|
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
|
<!-- Material Icons -->
|
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
|
|
|
|
</head>
|
|
|
|
<style>
|
|
/* Fixed table layout and numeric alignment */
|
|
#dataTable {
|
|
table-layout: fixed;
|
|
width: 100%;
|
|
}
|
|
|
|
.numeric {
|
|
white-space: nowrap;
|
|
text-align: right;
|
|
}
|
|
|
|
/* Truncate description with ellipsis */
|
|
.description {
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
/* Row color coding */
|
|
.txn-positive td {
|
|
background-color: rgba(0, 255, 0, 0.15);
|
|
}
|
|
|
|
.txn-negative td {
|
|
background-color: rgba(255, 0, 0, 0.15);
|
|
}
|
|
|
|
body {
|
|
background-color: #f8f9fc;
|
|
}
|
|
|
|
.card {
|
|
border: none;
|
|
border-radius: 0.75rem;
|
|
}
|
|
|
|
.card-header {
|
|
background: transparent;
|
|
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.material-icons {
|
|
vertical-align: middle;
|
|
font-size: 20px;
|
|
}
|
|
|
|
.scroll-to-top {
|
|
position: fixed;
|
|
right: 1rem;
|
|
bottom: 1rem;
|
|
width: 40px;
|
|
height: 40px;
|
|
background-color: #0d6efd;
|
|
color: #fff;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-decoration: none;
|
|
}
|
|
</style>
|
|
|
|
<body id="page-top">
|
|
<div id="wrapper">
|
|
<!--Sidebar - Navigation-->
|
|
<div th:replace="~{fragments/sidebar-nav :: sidebar-nav}"></div>
|
|
|
|
|
|
<div class="d-flex flex-column" id="content-wrapper">
|
|
<div id="content">
|
|
<!-- Topbar -->
|
|
<div th:replace="~{fragments/topbar :: topbar}"></div>
|
|
|
|
<div class="container-fluid">
|
|
<div class="card shadow">
|
|
<div class="d-inline-flex align-items-center card-header py-3">
|
|
<p class="text-primary m-0 fw-bold w-100">Transactions</p>
|
|
<a th:href="@{/addTransaction}" class="d-inline-flex btn btn-primary">
|
|
<i class="bi bi-plus"></i>Add
|
|
</a>
|
|
</div>
|
|
|
|
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6 text-nowrap">
|
|
<div id="dataTable_length" class="dataTables_length" aria-controls="dataTable">
|
|
<label class="form-label">Show
|
|
<select th:hx-get="@{/changePageSize}" hx-target="#dataTable"
|
|
hx-trigger="input changed" hx-swap="outerHtml" name="pageSizeCB"
|
|
class="d-inline-block form-select form-select-sm">
|
|
<option value="10" selected="">10</option>
|
|
<option value="25">25</option>
|
|
<option value="50">50</option>
|
|
<option value="100">100</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="text-md-end dataTables_filter" id="dataTable_filter">
|
|
<label class="form-label">
|
|
<input hx-trigger="input changed delay:1s" hx-swap="outerHtml"
|
|
hx-target="#dataTable" hx-get="/searchTransactions" type="search"
|
|
class="form-control form-control-sm" aria-controls="dataTable"
|
|
name="searchValue" placeholder="Search">
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="table-responsive" style="overflow-x: auto;">
|
|
<table th:fragment="transactionTable" class="table my-0" id="dataTable">
|
|
<!-- Fixed column widths -->
|
|
<colgroup>
|
|
<col style="width: 130px;"> <!-- Money In -->
|
|
<col style="width: 130px;"> <!-- Money Out -->
|
|
<col style="width: 110px;"> <!-- Fees -->
|
|
<col style="width: 140px;"> <!-- Balance -->
|
|
<col style="width: 120px;"> <!-- Date -->
|
|
<col style="width: 160px;"> <!-- Category -->
|
|
<col style="width: 260px;"> <!-- Description -->
|
|
</colgroup>
|
|
|
|
<thead>
|
|
<tr>
|
|
<th class="numeric">Money In</th>
|
|
<th class="numeric">Money Out</th>
|
|
<th class="numeric">Fees</th>
|
|
<th class="numeric">Balance</th>
|
|
<th>Date</th>
|
|
<th>Category</th>
|
|
<th>Description</th>
|
|
|
|
</tr>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<tr th:each="transaction : ${transactions}"
|
|
th:with="rowClass=${(transaction.moneyIn + transaction.moneyOut + transaction.fee) < 0 ? 'txn-negative' : 'txn-positive'}"
|
|
th:class="${rowClass}">
|
|
<td class="numeric"
|
|
th:text="${#numbers.formatCurrency(transaction.moneyIn)}"></td>
|
|
<td class="numeric"
|
|
th:text="${#numbers.formatCurrency(transaction.moneyOut)}"></td>
|
|
<td class="numeric" th:text="${#numbers.formatCurrency(transaction.fee)}">
|
|
</td>
|
|
<td class="numeric"
|
|
th:text="${#numbers.formatCurrency(transaction.balance)}"></td>
|
|
<td th:text="${transaction.date}"></td>
|
|
<td th:text="${transaction.category}"></td>
|
|
<td class="description" th:text="${transaction.description}"></td>
|
|
|
|
|
|
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div th:fragment="tableInfo" class="row">
|
|
<div class="col-md-6 align-self-center">
|
|
<p id="dataTable_info" class="dataTables_info" role="status" aria-live="polite"
|
|
th:text="'Showing ' + ${pageNum + 1} + ' to ' + ${pageSize} + ' of ' + ${transactionCount}">
|
|
Showing 1 to 10 of 27</p>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<nav
|
|
class="d-lg-flex justify-content-lg-end dataTables_paginate paging_simple_numbers">
|
|
<ul class="pagination">
|
|
<li th:classappend="${(pageNum + 1 == 1) ? 'disabled' : ''}"
|
|
class="page-item">
|
|
<a th:hx-get="@{/previousPage}" hx-trigger="click"
|
|
hx-target="#dataTable" hx-swap="outerHtml" class="page-link btn"
|
|
aria-label="Previous">
|
|
<span aria-hidden="true">« Previous</span>
|
|
</a>
|
|
</li>
|
|
<li th:classappend="${(pageNum == pageSize - 1) ? 'disabled' : ''}"
|
|
class="page-item">
|
|
<a th:hx-get="@{/nextPage}" hx-trigger="click" hx-target="#dataTable"
|
|
hx-swap="outerHtml" class="page-link btn" aria-label="Next">
|
|
<span aria-hidden="true">Next »</span></a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!--Footer-->
|
|
<div th:replace="~{fragments/footer :: footer}"></div>
|
|
</div>
|
|
|
|
<a class="border rounded d-inline scroll-to-top" href="#page-top">
|
|
<span class="material-icons">keyboard_arrow_up</span>
|
|
</a>
|
|
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js"></script>
|
|
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
|
<script src="assets/js/bs-init.js"></script>
|
|
<script src="assets/js/theme.js"></script>
|
|
</body>
|
|
|
|
</html> |