06/02 Optimize app
This commit is contained in:
@@ -90,16 +90,16 @@
|
||||
<div class="d-flex gap-2 mt-3">
|
||||
<a href="{{ url_for('transactions.transfer', to_account_id=acct.id, description='Credit Card Payment — ' ~ acct.name) }}"
|
||||
class="btn btn-sm flex-fill btn-danger" style="font-size:12px;">
|
||||
<i class="bi bi-send me-1"></i>Pay Card
|
||||
<i class="bi bi-send me-1"></i>Pay
|
||||
</a>
|
||||
<a href="{{ url_for('accounts.payments', id=acct.id) }}"
|
||||
class="btn btn-sm flex-fill btn-outline-secondary" style="font-size:12px;">
|
||||
<i class="bi bi-clock-history me-1"></i>Payments
|
||||
</a>
|
||||
<a href="{{ url_for('transactions.index', tab='expense', account_id=acct.id) }}"
|
||||
class="btn btn-sm flex-fill btn-outline-secondary" style="font-size:12px;">
|
||||
<i class="bi bi-list-ul me-1"></i>Charges
|
||||
</a>
|
||||
<a href="{{ url_for('transactions.new', type='expense') }}"
|
||||
class="btn btn-sm" style="font-size:12px;background:#f1f5f9;color:#475569;border:none;" title="Add Charge">
|
||||
<i class="bi bi-plus-lg"></i>
|
||||
</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="d-flex gap-2 mt-3">
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Payments — {{ account.name }}{% endblock %}
|
||||
{% block page_title %}Card Payments{% endblock %}
|
||||
|
||||
{% block topbar_actions %}
|
||||
<a href="{{ url_for('transactions.transfer', to_account_id=account.id, description='Credit Card Payment — ' ~ account.name) }}"
|
||||
class="btn btn-sm btn-danger" style="font-size:12px;">
|
||||
<i class="bi bi-send"></i><span class="btn-label ms-1">Pay Card</span>
|
||||
</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- Account header -->
|
||||
<div class="pcard mb-3" style="border-left: 4px solid {{ account.color }};">
|
||||
<div class="d-flex align-items-center justify-content-between flex-wrap gap-2">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div style="width:36px;height:36px;border-radius:9px;background:{{ account.color }}22;color:{{ account.color }};display:flex;align-items:center;justify-content:center;font-size:18px;">
|
||||
<i class="bi {{ account.icon }}"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-weight:600;font-size:14px;">{{ account.name }}</div>
|
||||
<div style="font-size:11px;color:var(--muted);">Payment History</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-3">
|
||||
<div style="text-align:right;">
|
||||
<div style="font-size:10px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.04em;">Paid This Month</div>
|
||||
<div class="mono text-income" style="font-size:18px;font-weight:700;">+{{ paid_this_month | currency }}</div>
|
||||
</div>
|
||||
<div style="text-align:right;">
|
||||
{% set owed = [0, -account.balance] | max %}
|
||||
<div style="font-size:10px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.04em;">Still Owed</div>
|
||||
<div class="mono {% if owed > 0 %}text-expense{% endif %}" style="font-size:18px;font-weight:700;{% if owed == 0 %}color:#10b981;{% endif %}">
|
||||
{% if owed > 0 %}-{% endif %}{{ owed | currency }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Back link -->
|
||||
<div class="mb-2">
|
||||
<a href="{{ url_for('accounts.index', tab='credit') }}" class="btn btn-sm btn-outline-secondary" style="font-size:12px;">
|
||||
<i class="bi bi-arrow-left me-1"></i>Back to Accounts
|
||||
</a>
|
||||
<a href="{{ url_for('transactions.index', tab='expense', account_id=account.id) }}" class="btn btn-sm btn-outline-secondary ms-1" style="font-size:12px;">
|
||||
<i class="bi bi-list-ul me-1"></i>View Charges
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if payments %}
|
||||
<div class="pcard p-0">
|
||||
<table class="pfm-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="padding-left:20px;">Date</th>
|
||||
<th>Description</th>
|
||||
<th class="d-mob-none">From Account</th>
|
||||
<th class="text-end" style="padding-right:20px;">Amount Paid</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for txn in payments %}
|
||||
<tr>
|
||||
<td style="padding-left:20px;font-size:12px;color:var(--muted);white-space:nowrap;">
|
||||
{{ txn.date.strftime('%b %d, %Y') }}
|
||||
</td>
|
||||
<td>
|
||||
<div style="font-size:13px;font-weight:500;">{{ txn.description }}</div>
|
||||
{% if txn.notes %}<div style="font-size:11px;color:var(--muted);">{{ txn.notes | truncate(60) }}</div>{% endif %}
|
||||
</td>
|
||||
<td class="d-mob-none" style="font-size:12px;color:var(--muted);">
|
||||
{{ txn.account.name if txn.account else '—' }}
|
||||
</td>
|
||||
<td class="text-end mono text-income" style="font-size:13px;font-weight:600;padding-right:20px;">
|
||||
+{{ txn.amount | currency }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% if pagination.pages > 1 %}
|
||||
<div class="d-flex justify-content-between align-items-center px-4 py-3" style="border-top:1px solid var(--border);font-size:12px;color:var(--muted);">
|
||||
<span>{{ ((pagination.page-1)*30)+1 }}–{{ [pagination.page*30, pagination.total]|min }} of {{ pagination.total }}</span>
|
||||
<div class="d-flex gap-1">
|
||||
{% if pagination.has_prev %}
|
||||
<a href="{{ url_for('accounts.payments', id=account.id, page=pagination.prev_num) }}" class="btn btn-sm btn-outline-secondary" style="font-size:11px;">← Prev</a>
|
||||
{% endif %}
|
||||
{% if pagination.has_next %}
|
||||
<a href="{{ url_for('accounts.payments', id=account.id, page=pagination.next_num) }}" class="btn btn-sm btn-outline-secondary" style="font-size:11px;">Next →</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
<div class="pcard text-center py-5">
|
||||
<i class="bi bi-send text-muted" style="font-size:3rem;opacity:.4;"></i>
|
||||
<p class="fw-semibold mt-3 mb-1">No payments recorded yet</p>
|
||||
<p class="text-muted small mb-3">Use "Pay Card" to record a payment from your checking or savings account.</p>
|
||||
<a href="{{ url_for('transactions.transfer', to_account_id=account.id, description='Credit Card Payment — ' ~ account.name) }}"
|
||||
class="btn btn-sm btn-danger">
|
||||
<i class="bi bi-send me-1"></i>Record First Payment
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
+13
-3
@@ -165,12 +165,22 @@
|
||||
.pcard { padding: 14px; }
|
||||
.stat-card { padding: 14px 16px; }
|
||||
.stat-card .stat-value { font-size: 20px; }
|
||||
/* Tables: scroll horizontally on small screens.
|
||||
Targets both manual .table-wrap and the common .pcard.p-0 pattern. */
|
||||
/* Tables: scroll horizontally on small screens */
|
||||
.table-wrap, .pcard.p-0 { overflow-x: auto; -webkit-overflow-scrolling: touch; }
|
||||
.pfm-table { min-width: 560px; }
|
||||
.pfm-table { min-width: 580px; }
|
||||
/* Hide low-priority columns */
|
||||
.d-mob-none { display: none !important; }
|
||||
/* Topbar title: truncate so action buttons always fit */
|
||||
.tb-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
||||
/* Flash: stretch full width */
|
||||
.flash-wrap { left: 8px; right: 8px; max-width: none; }
|
||||
}
|
||||
/* Extra-small screens: hide button label text, keep icons */
|
||||
@media (max-width: 575px) {
|
||||
#main { padding: 10px; }
|
||||
.pcard { padding: 12px; }
|
||||
.btn-label { display: none; }
|
||||
.tb-right .btn { padding-left: 8px; padding-right: 8px; }
|
||||
}
|
||||
.sb-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.4); z-index: 1039; }
|
||||
.sb-overlay.on { display: block; }
|
||||
|
||||
@@ -11,21 +11,21 @@
|
||||
|
||||
{% block topbar_actions %}
|
||||
<div class="d-flex align-items-center gap-1">
|
||||
<a href="?period=this_month" class="btn btn-sm btn-outline-secondary period-btn {% if period=='this_month' %}active{% endif %}" style="font-size:12px;">This Month</a>
|
||||
<a href="?period=last_month" class="btn btn-sm btn-outline-secondary period-btn {% if period=='last_month' %}active{% endif %}" style="font-size:12px;">Last Month</a>
|
||||
<button class="btn btn-sm btn-outline-secondary period-btn {% if period=='custom' %}active{% endif %}" style="font-size:12px;" data-bs-toggle="modal" data-bs-target="#customModal">Custom</button>
|
||||
<a href="?period=this_month" class="btn btn-sm btn-outline-secondary period-btn {% if period=='this_month' %}active{% endif %}" style="font-size:12px;"><i class="bi bi-calendar-check"></i><span class="btn-label ms-1">This Month</span></a>
|
||||
<a href="?period=last_month" class="btn btn-sm btn-outline-secondary period-btn {% if period=='last_month' %}active{% endif %}" style="font-size:12px;"><i class="bi bi-calendar"></i><span class="btn-label ms-1">Last Month</span></a>
|
||||
<button class="btn btn-sm btn-outline-secondary period-btn {% if period=='custom' %}active{% endif %}" style="font-size:12px;" data-bs-toggle="modal" data-bs-target="#customModal"><i class="bi bi-calendar-range"></i><span class="btn-label ms-1">Custom</span></button>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex align-items-center justify-content-between mb-4">
|
||||
<div class="d-flex align-items-start align-items-sm-center justify-content-between flex-wrap gap-2 mb-4">
|
||||
<div>
|
||||
<h5 class="mb-0 fw-semibold">{{ period_label }}</h5>
|
||||
<small class="text-muted">{{ date_from.strftime('%b %d') }} – {{ date_to.strftime('%b %d, %Y') }}</small>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="{{ url_for('transactions.new', type='income') }}" class="btn btn-sm" style="background:#d1fae5;color:#065f46;font-size:12px;"><i class="bi bi-plus-lg me-1"></i>Income</a>
|
||||
<a href="{{ url_for('transactions.new', type='expense') }}" class="btn btn-sm" style="background:#fee2e2;color:#991b1b;font-size:12px;"><i class="bi bi-plus-lg me-1"></i>Expense</a>
|
||||
<a href="{{ url_for('transactions.new', type='income') }}" class="btn btn-sm" style="background:#d1fae5;color:#065f46;font-size:12px;"><i class="bi bi-plus-lg"></i><span class="btn-label ms-1">Income</span></a>
|
||||
<a href="{{ url_for('transactions.new', type='expense') }}" class="btn btn-sm" style="background:#fee2e2;color:#991b1b;font-size:12px;"><i class="bi bi-dash-lg"></i><span class="btn-label ms-1">Expense</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
<tr>
|
||||
<th style="padding-left:20px;">Asset</th>
|
||||
<th class="text-end">Price</th>
|
||||
<th class="text-end">1D Chg</th>
|
||||
<th class="text-end d-mob-none">1D Chg</th>
|
||||
<th class="text-end">Value</th>
|
||||
<th class="text-end" style="padding-right:8px;">P&L</th>
|
||||
<th style="width:36px;"></th>
|
||||
@@ -184,7 +184,7 @@
|
||||
<span class="text-muted" style="font-size:12px;">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-end" id="chg-{{ inv.id }}">
|
||||
<td class="text-end d-mob-none" id="chg-{{ inv.id }}">
|
||||
{% if inv.ticker %}
|
||||
<span class="chg-badge chg-loading">…</span>
|
||||
{% else %}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
{% block page_title %}Transactions{% endblock %}
|
||||
|
||||
{% block topbar_actions %}
|
||||
<a href="{{ url_for('transactions.new', type='income') }}" class="btn btn-sm" style="background:#d1fae5;color:#065f46;font-size:12px;"><i class="bi bi-plus-lg me-1"></i>Income</a>
|
||||
<a href="{{ url_for('transactions.new', type='expense') }}" class="btn btn-sm ms-1" style="background:#fee2e2;color:#991b1b;font-size:12px;"><i class="bi bi-plus-lg me-1"></i>Expense</a>
|
||||
<a href="{{ url_for('transactions.transfer') }}" class="btn btn-sm btn-outline-secondary ms-1" style="font-size:12px;"><i class="bi bi-arrow-left-right me-1"></i>Transfer</a>
|
||||
<a href="{{ url_for('transactions.new', type='income') }}" class="btn btn-sm" style="background:#d1fae5;color:#065f46;font-size:12px;"><i class="bi bi-plus-lg"></i><span class="btn-label ms-1">Income</span></a>
|
||||
<a href="{{ url_for('transactions.new', type='expense') }}" class="btn btn-sm ms-1" style="background:#fee2e2;color:#991b1b;font-size:12px;"><i class="bi bi-dash-lg"></i><span class="btn-label ms-1">Expense</span></a>
|
||||
<a href="{{ url_for('transactions.transfer') }}" class="btn btn-sm btn-outline-secondary ms-1" style="font-size:12px;"><i class="bi bi-arrow-left-right"></i><span class="btn-label ms-1">Transfer</span></a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@@ -68,8 +68,8 @@
|
||||
<tr>
|
||||
<th style="padding-left:20px;">Date</th>
|
||||
<th>Description</th>
|
||||
<th>Category</th>
|
||||
<th>Account</th>
|
||||
<th class="d-mob-none">Category</th>
|
||||
<th class="d-mob-none">Account</th>
|
||||
<th class="text-end">Amount</th>
|
||||
<th class="text-end" style="padding-right:20px;">Actions</th>
|
||||
</tr>
|
||||
@@ -82,14 +82,14 @@
|
||||
<div style="font-size:13px;font-weight:500;">{{ txn.description }}</div>
|
||||
{% if txn.notes %}<div style="font-size:11px;color:var(--muted);">{{ txn.notes | truncate(60) }}</div>{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<td class="d-mob-none">
|
||||
{% if txn.category %}
|
||||
<span style="font-size:12px;white-space:nowrap;">
|
||||
<i class="bi {{ txn.category.icon }}" style="color:{{ txn.category.color }};"></i> {{ txn.category.name }}
|
||||
</span>
|
||||
{% else %}<span class="text-muted" style="font-size:12px;">—</span>{% endif %}
|
||||
</td>
|
||||
<td style="font-size:12px;color:var(--muted);">{{ txn.account.name if txn.account else '—' }}</td>
|
||||
<td class="d-mob-none" style="font-size:12px;color:var(--muted);">{{ txn.account.name if txn.account else '—' }}</td>
|
||||
<td class="text-end mono {% if txn.transaction_type=='income' %}text-income{% else %}text-expense{% endif %}" style="font-size:13px;font-weight:600;white-space:nowrap;">
|
||||
{% if txn.transaction_type=='income' %}+{% else %}-{% endif %}{{ txn.amount | currency }}
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user