Initial commit — Moon Household Budget
This commit is contained in:
486
templates/assets.html
Normal file
486
templates/assets.html
Normal file
@@ -0,0 +1,486 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
||||
<div class="page-header">
|
||||
<h1>Assets</h1>
|
||||
<input type="text" id="asset-search" placeholder="Search assets…" class="budget-input" style="width:220px;" oninput="filterAssets(this.value)">
|
||||
</div>
|
||||
|
||||
<!-- Net worth summary -->
|
||||
{% if net_worth_assets %}
|
||||
<div class="sinking-total-bar" style="margin-bottom:1.75rem;">
|
||||
<div>
|
||||
<div class="sinking-total-label">Total Tracked Asset Value</div>
|
||||
<div class="sinking-total-amount">${{ "{:,.2f}".format(net_worth_assets) }}</div>
|
||||
</div>
|
||||
<div class="sinking-total-note">Based on estimated / current values entered below</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Add Asset button -->
|
||||
<details class="add-debt-details" style="margin-bottom:2rem;">
|
||||
<summary class="btn btn-primary" style="display:inline-block;cursor:pointer;">+ Add Asset</summary>
|
||||
<div class="card-wide" style="margin-top:0.75rem;">
|
||||
<h3 style="margin-bottom:1rem;font-family:'DM Serif Display',serif;font-weight:400;">What type of asset?</h3>
|
||||
<div class="asset-type-grid">
|
||||
|
||||
<!-- Vehicle -->
|
||||
<details class="add-debt-details">
|
||||
<summary class="asset-type-btn">🚗 Vehicle</summary>
|
||||
<form method="POST" action="{{ url_for('vehicle_add') }}" style="margin-top:1rem;">
|
||||
<div class="bill-form-grid">
|
||||
<div class="form-group" style="grid-column:1/-1;">
|
||||
<label>Vehicle Type</label>
|
||||
<div style="display:flex;gap:1rem;margin-top:0.25rem;">
|
||||
<label style="display:flex;align-items:center;gap:0.4rem;font-weight:400;cursor:pointer;">
|
||||
<input type="radio" name="vehicle_type" value="personal" checked> Personal / Daily Driver
|
||||
</label>
|
||||
<label style="display:flex;align-items:center;gap:0.4rem;font-weight:400;cursor:pointer;">
|
||||
<input type="radio" name="vehicle_type" value="flip"> Flip Car
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group"><label>Year</label><input type="number" name="year" placeholder="e.g. 2020" required></div>
|
||||
<div class="form-group"><label>Make</label><input type="text" name="make" placeholder="e.g. Toyota" required></div>
|
||||
<div class="form-group"><label>Model</label><input type="text" name="model" placeholder="e.g. Camry" required></div>
|
||||
<div class="form-group"><label>Trim</label><input type="text" name="trim" placeholder="e.g. LE, 2.5L"></div>
|
||||
<div class="form-group"><label>Color</label><input type="text" name="color"></div>
|
||||
<div class="form-group"><label>Owner</label>
|
||||
<select name="owner">
|
||||
<option value="Bonna">Bonna</option>
|
||||
<option value="Tony">Tony</option>
|
||||
<option value="Both">Both</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group"><label>Purchase Price</label><input type="number" name="purchase_price" step="0.01" placeholder="0.00"></div>
|
||||
<div class="form-group"><label>Purchase Date</label><input type="date" name="purchase_date"></div>
|
||||
<div class="form-group"><label>Estimated Current Value</label><input type="number" name="estimated_value" step="0.01" placeholder="0.00"></div>
|
||||
<div class="form-group"><label>Notes</label><input type="text" name="notes"></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Vehicle</button>
|
||||
</form>
|
||||
</details>
|
||||
|
||||
<!-- Investments -->
|
||||
<details class="add-debt-details">
|
||||
<summary class="asset-type-btn">📈 Investments</summary>
|
||||
<form method="POST" action="{{ url_for('other_asset_add') }}" style="margin-top:1rem;">
|
||||
<input type="hidden" name="category" value="Investments">
|
||||
<div class="bill-form-grid">
|
||||
<div class="form-group"><label>Account / Asset Name</label><input type="text" name="name" placeholder="e.g. Roth IRA, 401k, Brokerage" required></div>
|
||||
<div class="form-group"><label>Owner</label><select name="owner"><option value="Bonna">Bonna</option><option value="Tony">Tony</option><option value="Both">Both</option></select></div>
|
||||
<div class="form-group"><label>Date Opened</label><input type="date" name="purchase_date"></div>
|
||||
<div class="form-group"><label>Current Value</label><input type="number" name="value" step="0.01" placeholder="0.00"></div>
|
||||
<div class="form-group"><label>Notes</label><input type="text" name="notes" placeholder="e.g. Fidelity, employer match, contribution limit..."></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Investment</button>
|
||||
</form>
|
||||
</details>
|
||||
|
||||
<!-- Real Estate -->
|
||||
<details class="add-debt-details">
|
||||
<summary class="asset-type-btn">🏠 Real Estate</summary>
|
||||
<form method="POST" action="{{ url_for('other_asset_add') }}" style="margin-top:1rem;">
|
||||
<input type="hidden" name="category" value="Real Estate">
|
||||
<div class="bill-form-grid">
|
||||
<div class="form-group"><label>Description</label><input type="text" name="name" placeholder="e.g. Primary Home, Rental Property" required></div>
|
||||
<div class="form-group"><label>Owner</label><select name="owner"><option value="Both">Both</option><option value="Bonna">Bonna</option><option value="Tony">Tony</option></select></div>
|
||||
<div class="form-group"><label>Purchase Price</label><input type="number" name="purchase_price" step="0.01" placeholder="0.00"></div>
|
||||
<div class="form-group"><label>Purchase Date</label><input type="date" name="purchase_date"></div>
|
||||
<div class="form-group"><label>Current Estimated Value</label><input type="number" name="value" step="0.01" placeholder="0.00"></div>
|
||||
<div class="form-group"><label>Notes</label><input type="text" name="notes" placeholder="Address, details..."></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Real Estate</button>
|
||||
</form>
|
||||
</details>
|
||||
|
||||
<!-- Equipment -->
|
||||
<details class="add-debt-details">
|
||||
<summary class="asset-type-btn">🔧 Equipment</summary>
|
||||
<form method="POST" action="{{ url_for('other_asset_add') }}" style="margin-top:1rem;">
|
||||
<input type="hidden" name="category" value="Equipment">
|
||||
<div class="bill-form-grid">
|
||||
<div class="form-group"><label>Item Name</label><input type="text" name="name" placeholder="e.g. Studio Camera, Stand Mixer" required></div>
|
||||
<div class="form-group"><label>Owner</label><select name="owner"><option value="Bonna">Bonna</option><option value="Tony">Tony</option><option value="Both">Both</option></select></div>
|
||||
<div class="form-group"><label>Purchase Price</label><input type="number" name="purchase_price" step="0.01" placeholder="0.00"></div>
|
||||
<div class="form-group"><label>Purchase Date</label><input type="date" name="purchase_date"></div>
|
||||
<div class="form-group"><label>Current Value</label><input type="number" name="value" step="0.01" placeholder="0.00"></div>
|
||||
<div class="form-group"><label>Notes</label><input type="text" name="notes" placeholder="Serial #, warranty..."></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Equipment</button>
|
||||
</form>
|
||||
</details>
|
||||
|
||||
<!-- Other Valuables -->
|
||||
<details class="add-debt-details">
|
||||
<summary class="asset-type-btn">✨ Other Valuables</summary>
|
||||
<form method="POST" action="{{ url_for('other_asset_add') }}" style="margin-top:1rem;">
|
||||
<input type="hidden" name="category" value="Other Valuables">
|
||||
<div class="bill-form-grid">
|
||||
<div class="form-group"><label>Item Name</label><input type="text" name="name" placeholder="e.g. Engagement Ring, Art" required></div>
|
||||
<div class="form-group"><label>Owner</label><select name="owner"><option value="Bonna">Bonna</option><option value="Tony">Tony</option><option value="Both">Both</option></select></div>
|
||||
<div class="form-group"><label>Purchase Price</label><input type="number" name="purchase_price" step="0.01" placeholder="0.00"></div>
|
||||
<div class="form-group"><label>Purchase Date</label><input type="date" name="purchase_date"></div>
|
||||
<div class="form-group"><label>Current / Appraised Value</label><input type="number" name="value" step="0.01" placeholder="0.00"></div>
|
||||
<div class="form-group"><label>Notes</label><input type="text" name="notes"></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Item</button>
|
||||
</form>
|
||||
</details>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<!-- Vehicles -->
|
||||
<section class="section">
|
||||
<h2>Vehicles</h2>
|
||||
|
||||
<h3 class="asset-subheading">Personal</h3>
|
||||
<div class="asset-grid">
|
||||
{% for car in personal %}
|
||||
<div class="asset-card">
|
||||
<div class="asset-card-header">
|
||||
<div>
|
||||
<div class="asset-car-name">{{ car.display_name }}</div>
|
||||
<div class="asset-car-trim muted">{{ car.trim }}{% if car.color %} · {{ car.color }}{% endif %}</div>
|
||||
</div>
|
||||
<span class="owner-tag" style="background:{{ owner_colors.get(car.owner, '#ddd') }};">{{ car.owner }}</span>
|
||||
</div>
|
||||
<div class="asset-stat-row">
|
||||
<div class="asset-stat"><div class="asset-stat-label">Total Spent</div><div class="asset-stat-value">${{ car.total_spent | money }}</div></div>
|
||||
<div class="asset-stat"><div class="asset-stat-label">Est. Value</div><div class="asset-stat-value">{% if car.estimated_value %}${{ "{:,.0f}".format(car.estimated_value) }}{% else %}<span class="muted">—</span>{% endif %}</div></div>
|
||||
<div class="asset-stat"><div class="asset-stat-label">Gas Logs</div><div class="asset-stat-value">{{ car.gas_log | length }}</div></div>
|
||||
<div class="asset-stat"><div class="asset-stat-label">Service Logs</div><div class="asset-stat-value">{{ car.maintenance_log | length }}</div></div>
|
||||
</div>
|
||||
<details class="asset-details"><summary class="asset-details-toggle">+ Log Gas Fill-up</summary>
|
||||
<form method="POST" action="{{ url_for('personal_car_log', car_id=car.id) }}" class="asset-log-form">
|
||||
<input type="hidden" name="log_type" value="gas">
|
||||
<div class="asset-log-grid">
|
||||
<div class="form-group"><label>Date</label><input type="date" name="date" required></div>
|
||||
<div class="form-group"><label>Amount Paid</label><input type="number" name="amount" step="0.01" placeholder="0.00" required></div>
|
||||
<div class="form-group"><label>Gallons <span class="optional">(optional)</span></label><input type="number" name="gallons" step="0.001" placeholder="0.000"></div>
|
||||
<div class="form-group"><label>Notes</label><input type="text" name="notes" placeholder="Station, grade..."></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-accept">Save</button>
|
||||
</form>
|
||||
</details>
|
||||
<details class="asset-details"><summary class="asset-details-toggle">+ Log Maintenance / Repair</summary>
|
||||
<form method="POST" action="{{ url_for('personal_car_log', car_id=car.id) }}" class="asset-log-form">
|
||||
<input type="hidden" name="log_type" value="maintenance">
|
||||
<div class="asset-log-grid">
|
||||
<div class="form-group"><label>Date</label><input type="date" name="date" required></div>
|
||||
<div class="form-group"><label>Amount</label><input type="number" name="amount" step="0.01" placeholder="0.00" required></div>
|
||||
<div class="form-group"><label>Description</label><input type="text" name="description" placeholder="e.g. Oil change" required></div>
|
||||
<div class="form-group"><label>Notes</label><input type="text" name="notes" placeholder="Shop, details..."></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-accept">Save</button>
|
||||
</form>
|
||||
</details>
|
||||
{% set recent_gas = car.gas_log[-3:] | reverse | list %}
|
||||
{% set recent_maint = car.maintenance_log[-3:] | reverse | list %}
|
||||
{% if recent_gas or recent_maint %}
|
||||
<details class="asset-details"><summary class="asset-details-toggle">Recent Activity</summary>
|
||||
{% if recent_gas %}<div class="asset-log-section-label">Gas</div>{% for e in recent_gas %}<div class="asset-log-entry"><span class="muted">{{ e.date }}</span><span>${{ e.amount | money }}</span><span class="muted">{% if e.gallons %}{{ e.gallons }} gal{% endif %} {{ e.notes }}</span></div>{% endfor %}{% endif %}
|
||||
{% if recent_maint %}<div class="asset-log-section-label" style="margin-top:0.5rem;">Maintenance</div>{% for e in recent_maint %}<div class="asset-log-entry"><span class="muted">{{ e.date }}</span><span>${{ e.amount | money }}</span><span class="muted">{{ e.get('description','') }} {{ e.notes }}</span></div>{% endfor %}{% endif %}
|
||||
</details>
|
||||
{% endif %}
|
||||
<details class="asset-details"><summary class="asset-details-toggle">Edit Details</summary>
|
||||
<form method="POST" action="{{ url_for('personal_car_update', car_id=car.id) }}" class="asset-log-form">
|
||||
<div class="asset-log-grid">
|
||||
<div class="form-group"><label>Color</label><input type="text" name="color" value="{{ car.color }}"></div>
|
||||
<div class="form-group"><label>Owner</label><select name="owner">{% for o in ['Bonna','Tony','Both'] %}<option value="{{ o }}" {% if car.owner == o %}selected{% endif %}>{{ o }}</option>{% endfor %}</select></div>
|
||||
<div class="form-group"><label>Purchase Price</label><input type="number" name="purchase_price" step="0.01" value="{{ car.purchase_price or '' }}" placeholder="0.00"></div>
|
||||
<div class="form-group"><label>Purchase Date</label><input type="date" name="purchase_date" value="{{ car.purchase_date or '' }}"></div>
|
||||
<div class="form-group"><label>Estimated Value (KBB)</label><input type="number" name="estimated_value" step="0.01" value="{{ car.estimated_value or '' }}" placeholder="0.00"></div>
|
||||
<div class="form-group"><label>Notes</label><input type="text" name="notes" value="{{ car.notes or '' }}"></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
</form>
|
||||
</details>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if active_flips %}
|
||||
<h3 class="asset-subheading" style="margin-top:1.5rem;">Flip Inventory</h3>
|
||||
<div style="margin-bottom:1rem;">
|
||||
<details class="add-debt-details">
|
||||
<summary class="btn btn-powder-blue" style="display:inline-block;cursor:pointer;">+ Add Flip Car</summary>
|
||||
<div class="card-wide" style="margin-top:0.75rem;">
|
||||
<form method="POST" action="{{ url_for('flip_add') }}" class="bill-form">
|
||||
<div class="bill-form-grid">
|
||||
<div class="form-group"><label>Year</label><input type="number" name="year" placeholder="e.g. 2018" required></div>
|
||||
<div class="form-group"><label>Make</label><input type="text" name="make" required></div>
|
||||
<div class="form-group"><label>Model</label><input type="text" name="model" required></div>
|
||||
<div class="form-group"><label>Trim</label><input type="text" name="trim"></div>
|
||||
<div class="form-group"><label>Color</label><input type="text" name="color"></div>
|
||||
<div class="form-group"><label>Purchase Price</label><input type="number" name="purchase_price" step="0.01" placeholder="0.00" required></div>
|
||||
<div class="form-group"><label>Purchase Date</label><input type="date" name="purchase_date"></div>
|
||||
<div class="form-group"><label>Personal Funds Used</label><input type="number" name="personal_contribution" step="0.01" placeholder="0.00"></div>
|
||||
<div class="form-group"><label>Notes</label><input type="text" name="notes"></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-powder-blue">Add Flip Car</button>
|
||||
</form>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
<div class="asset-grid">
|
||||
{% for flip in active_flips %}
|
||||
<div class="asset-card asset-flip-card">
|
||||
<div class="asset-card-header">
|
||||
<div><div class="asset-car-name">{{ flip.display_name }}</div><div class="asset-car-trim muted">{{ flip.trim }}{% if flip.color %} · {{ flip.color }}{% endif %}</div></div>
|
||||
<div style="display:flex;align-items:center;gap:0.5rem;">
|
||||
<span class="flip-badge">Flip</span>
|
||||
<button class="edit-link" style="background:none;border:none;cursor:pointer;font-size:0.78rem;"
|
||||
onclick="openEditFlip('{{ flip.id }}','{{ flip.year }}','{{ flip.make }}','{{ flip.model }}','{{ flip.trim or '' }}','{{ flip.color or '' }}','{{ flip.purchase_price or 0 }}','{{ flip.purchase_date or '' }}','{{ flip.notes or '' }}')">
|
||||
✏️ Edit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="asset-stat-row">
|
||||
<div class="asset-stat"><div class="asset-stat-label">Purchased</div><div class="asset-stat-value">${{ "{:,.0f}".format(flip.purchase_price) }}</div></div>
|
||||
<div class="asset-stat"><div class="asset-stat-label">Total In</div><div class="asset-stat-value">${{ "{:,.0f}".format(flip.total_invested) }}</div></div>
|
||||
<div class="asset-stat"><div class="asset-stat-label">Expenses</div><div class="asset-stat-value">{{ flip.expense_log | length }}</div></div>
|
||||
</div>
|
||||
<details class="asset-details"><summary class="asset-details-toggle">+ Log Personal Expense</summary>
|
||||
<form method="POST" action="{{ url_for('flip_expense', flip_id=flip.id) }}" class="asset-log-form">
|
||||
<div class="asset-log-grid">
|
||||
<div class="form-group"><label>Date</label><input type="date" name="date" required></div>
|
||||
<div class="form-group"><label>Amount</label><input type="number" name="amount" step="0.01" placeholder="0.00" required></div>
|
||||
<div class="form-group"><label>Description</label><input type="text" name="description" placeholder="Parts, paint..." required></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-accept">Save</button>
|
||||
</form>
|
||||
</details>
|
||||
{% if flip.expense_log %}<details class="asset-details"><summary class="asset-details-toggle">Expense Log</summary>{% for e in flip.expense_log | reverse %}<div class="asset-log-entry"><span class="muted">{{ e.date }}</span><span>${{ e.amount | money }}</span><span class="muted">{{ e.description }}</span></div>{% endfor %}</details>{% endif %}
|
||||
<details class="asset-details"><summary class="asset-details-toggle" style="color:#7A9E78;">✓ Mark as Sold</summary>
|
||||
<form method="POST" action="{{ url_for('flip_sell', flip_id=flip.id) }}" class="asset-log-form">
|
||||
<div class="asset-log-grid">
|
||||
<div class="form-group"><label>Sale Price</label><input type="number" name="sale_price" step="0.01" placeholder="0.00" required></div>
|
||||
<div class="form-group"><label>Sale Date</label><input type="date" name="sold_date" required></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Mark Sold</button>
|
||||
</form>
|
||||
</details>
|
||||
<form method="POST" action="{{ url_for('flip_delete', flip_id=flip.id) }}"
|
||||
onsubmit="return confirm('Remove {{ flip.display_name }} from flips? This cannot be undone.');">
|
||||
<button type="submit" class="debt-delete-btn">Remove</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<h3 class="asset-subheading" style="margin-top:1.5rem;">Flip Inventory</h3>
|
||||
<details class="add-debt-details" style="margin-bottom:1rem;">
|
||||
<summary class="btn btn-powder-blue" style="display:inline-block;cursor:pointer;">+ Add Flip Car</summary>
|
||||
<div class="card-wide" style="margin-top:0.75rem;">
|
||||
<form method="POST" action="{{ url_for('flip_add') }}" class="bill-form">
|
||||
<div class="bill-form-grid">
|
||||
<div class="form-group"><label>Year</label><input type="number" name="year" placeholder="e.g. 2018" required></div>
|
||||
<div class="form-group"><label>Make</label><input type="text" name="make" required></div>
|
||||
<div class="form-group"><label>Model</label><input type="text" name="model" required></div>
|
||||
<div class="form-group"><label>Trim</label><input type="text" name="trim"></div>
|
||||
<div class="form-group"><label>Color</label><input type="text" name="color"></div>
|
||||
<div class="form-group"><label>Purchase Price</label><input type="number" name="purchase_price" step="0.01" placeholder="0.00" required></div>
|
||||
<div class="form-group"><label>Purchase Date</label><input type="date" name="purchase_date"></div>
|
||||
<div class="form-group"><label>Personal Funds Used</label><input type="number" name="personal_contribution" step="0.01" placeholder="0.00"></div>
|
||||
<div class="form-group"><label>Notes</label><input type="text" name="notes"></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-powder-blue">Add Flip Car</button>
|
||||
</form>
|
||||
</div>
|
||||
</details>
|
||||
<p class="muted">No active flips.</p>
|
||||
{% endif %}
|
||||
|
||||
{% if sold_flips %}
|
||||
<h3 class="asset-subheading" style="margin-top:1.5rem;">Sold Flips</h3>
|
||||
<table class="txn-table txn-table-full">
|
||||
<thead><tr><th>Car</th><th>Bought For</th><th>Total Invested</th><th>Sold For</th><th>Profit / Loss</th><th>Sold</th></tr></thead>
|
||||
<tbody>
|
||||
{% for flip in sold_flips %}
|
||||
{% set profit = flip.profit %}
|
||||
<tr>
|
||||
<td>{{ flip.display_name }}{% if flip.color %} <span class="muted">{{ flip.color }}</span>{% endif %}</td>
|
||||
<td class="amount">${{ "{:,.2f}".format(flip.purchase_price) }}</td>
|
||||
<td class="amount">${{ "{:,.2f}".format(flip.total_invested) }}</td>
|
||||
<td class="amount">${{ "{:,.2f}".format(flip.sale_price) }}</td>
|
||||
<td class="amount {% if profit and profit > 0 %}accent{% elif profit and profit < 0 %}text-red{% endif %}">{% if profit is not none %}{{ '+' if profit > 0 else '' }}${{ "{:,.2f}".format(profit) }}{% else %}—{% endif %}</td>
|
||||
<td class="muted">{{ flip.sold_date }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
<!-- Investment tracking instructions -->
|
||||
<div class="card-wide" style="margin-bottom:1.5rem;">
|
||||
<h3 style="margin-bottom:0.5rem;">📈 How Investment Tracking Works</h3>
|
||||
<p class="helper-text" style="margin-bottom:0.5rem;">Add each investment account (Roth IRA, 401k, brokerage, etc.) using the <strong>+ Add Asset</strong> button above and select <strong>Investments</strong>.</p>
|
||||
<p class="helper-text" style="margin-bottom:0.5rem;">Once added, each card has an editable <strong>Current Value</strong> field. Update it whenever you check your account — once a month is a good habit. Every time you update the value, the app logs a snapshot with today's date.</p>
|
||||
<p class="helper-text">After two or more updates on different days, a <strong>growth chart</strong> will appear on the card automatically, showing your balance over time in green (growth) or red (decline) with the total change displayed.</p>
|
||||
</div>
|
||||
|
||||
<!-- Other asset categories -->
|
||||
{% for cat in asset_categories %}
|
||||
<section class="section">
|
||||
<h2>{{ cat }}</h2>
|
||||
{% set cat_assets = by_category[cat] %}
|
||||
{% if cat_assets %}
|
||||
<div class="asset-grid">
|
||||
{% for a in cat_assets %}
|
||||
<div class="asset-card">
|
||||
<div class="asset-card-header">
|
||||
<div><div class="asset-car-name">{{ a.name }}</div>{% if a.notes %}<div class="asset-car-trim muted">{{ a.notes }}</div>{% endif %}</div>
|
||||
<span class="owner-tag" style="background:{{ owner_colors.get(a.owner, '#ddd') }};">{{ a.owner }}</span>
|
||||
</div>
|
||||
<div class="asset-stat-row">
|
||||
<div class="asset-stat"><div class="asset-stat-label">Paid</div><div class="asset-stat-value">{% if a.purchase_price %}${{ "{:,.0f}".format(a.purchase_price) }}{% else %}<span class="muted">—</span>{% endif %}</div></div>
|
||||
<div class="asset-stat">
|
||||
<div class="asset-stat-label">Current Value</div>
|
||||
<div class="asset-stat-value">
|
||||
$<input type="number" step="0.01" min="0"
|
||||
value="{{ a.value or 0 }}"
|
||||
class="budget-input" style="width:90px;display:inline;"
|
||||
onchange="updateAssetValue('{{ a.id }}', this.value)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="asset-stat"><div class="asset-stat-label">Date</div><div class="asset-stat-value muted" style="font-size:0.78rem;">{{ a.purchase_date or '—' }}</div></div>
|
||||
</div>
|
||||
{% if a.value_history and a.value_history | length > 1 %}
|
||||
<div style="margin:0.75rem 0 0.5rem;">
|
||||
<div style="font-size:0.72rem;color:var(--text-light);margin-bottom:0.25rem;">
|
||||
Value History
|
||||
{% set first = a.value_history[0].value | float %}
|
||||
{% set last = a.value_history[-1].value | float %}
|
||||
{% set change = last - first %}
|
||||
{% if change >= 0 %}
|
||||
<span style="color:#5A9E68;margin-left:0.4rem;">▲ ${{ change | money }}</span>
|
||||
{% else %}
|
||||
<span style="color:#c07070;margin-left:0.4rem;">▼ ${{ change | abs | money }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<canvas id="chart-{{ a.id }}" height="60"
|
||||
data-labels="{{ a.value_history | map(attribute='date') | list | tojson }}"
|
||||
data-values="{{ a.value_history | map(attribute='value') | list | tojson }}">
|
||||
</canvas>
|
||||
</div>
|
||||
{% elif a.value_history and a.value_history | length == 1 %}
|
||||
<div style="font-size:0.72rem;color:var(--text-light);margin:0.5rem 0;">Update value again next month to start seeing growth chart.</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="POST" action="{{ url_for('other_asset_delete', asset_id=a.id) }}"
|
||||
onsubmit="return confirm('Remove {{ a.name }}?');">
|
||||
<button type="submit" class="debt-delete-btn">Remove</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="muted" style="margin-bottom:0.5rem;">No {{ cat | lower }} added yet.</p>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endfor %}
|
||||
|
||||
<!-- Edit Flip Modal -->
|
||||
<div id="edit-flip-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.3);z-index:200;align-items:center;justify-content:center;">
|
||||
<div style="background:#fff;border-radius:12px;padding:1.5rem;width:90%;max-width:480px;box-shadow:0 8px 32px rgba(0,0,0,0.18);">
|
||||
<h3 style="margin:0 0 1rem;" id="edit-flip-title">Edit Flip</h3>
|
||||
<form method="POST" id="edit-flip-form" action="">
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:0.75rem;">
|
||||
<div class="form-group"><label style="font-size:0.85rem;">Year</label><input type="number" name="year" id="ef-year" class="budget-input" style="width:100%;" required></div>
|
||||
<div class="form-group"><label style="font-size:0.85rem;">Make</label><input type="text" name="make" id="ef-make" class="budget-input" style="width:100%;" required></div>
|
||||
<div class="form-group"><label style="font-size:0.85rem;">Model</label><input type="text" name="model" id="ef-model" class="budget-input" style="width:100%;" required></div>
|
||||
<div class="form-group"><label style="font-size:0.85rem;">Trim</label><input type="text" name="trim" id="ef-trim" class="budget-input" style="width:100%;"></div>
|
||||
<div class="form-group"><label style="font-size:0.85rem;">Color</label><input type="text" name="color" id="ef-color" class="budget-input" style="width:100%;"></div>
|
||||
<div class="form-group"><label style="font-size:0.85rem;">Purchase Price</label><input type="number" step="0.01" name="purchase_price" id="ef-price" class="budget-input" style="width:100%;"></div>
|
||||
<div class="form-group"><label style="font-size:0.85rem;">Purchase Date</label><input type="date" name="purchase_date" id="ef-date" class="budget-input" style="width:100%;"></div>
|
||||
<div class="form-group"><label style="font-size:0.85rem;">Notes</label><input type="text" name="notes" id="ef-notes" class="budget-input" style="width:100%;"></div>
|
||||
</div>
|
||||
<div style="display:flex;gap:0.75rem;justify-content:flex-end;margin-top:1rem;">
|
||||
<button type="button" class="btn btn-ghost" onclick="closeEditFlip()">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">Save Changes</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function updateAssetValue(id, value) {
|
||||
fetch('/assets/other/update/' + id, {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
body: new URLSearchParams({value: value})
|
||||
}).then(() => location.reload());
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('canvas[id^="chart-"]').forEach(canvas => {
|
||||
const labels = JSON.parse(canvas.dataset.labels);
|
||||
const values = JSON.parse(canvas.dataset.values);
|
||||
const color = values[values.length-1] >= values[0] ? '#5A9E68' : '#c07070';
|
||||
new Chart(canvas, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
data: values,
|
||||
borderColor: color,
|
||||
backgroundColor: color + '22',
|
||||
borderWidth: 2,
|
||||
pointRadius: 3,
|
||||
pointBackgroundColor: color,
|
||||
fill: true,
|
||||
tension: 0.3,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
plugins: { legend: { display: false }, tooltip: {
|
||||
callbacks: { label: ctx => '$' + ctx.parsed.y.toFixed(2) }
|
||||
}},
|
||||
scales: {
|
||||
x: { display: false },
|
||||
y: { display: false }
|
||||
},
|
||||
animation: false,
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function openEditFlip(id, year, make, model, trim, color, price, purchaseDate, notes) {
|
||||
document.getElementById('edit-flip-title').textContent = 'Edit — ' + year + ' ' + make + ' ' + model;
|
||||
document.getElementById('edit-flip-form').action = '/assets/flip/edit/' + id;
|
||||
document.getElementById('ef-year').value = year;
|
||||
document.getElementById('ef-make').value = make;
|
||||
document.getElementById('ef-model').value = model;
|
||||
document.getElementById('ef-trim').value = trim;
|
||||
document.getElementById('ef-color').value = color;
|
||||
document.getElementById('ef-price').value = price != '0' ? price : '';
|
||||
document.getElementById('ef-date').value = purchaseDate;
|
||||
document.getElementById('ef-notes').value = notes;
|
||||
document.getElementById('edit-flip-modal').style.display = 'flex';
|
||||
}
|
||||
|
||||
function closeEditFlip() {
|
||||
document.getElementById('edit-flip-modal').style.display = 'none';
|
||||
}
|
||||
|
||||
document.getElementById('edit-flip-modal').addEventListener('click', function(e) {
|
||||
if (e.target === this) closeEditFlip();
|
||||
});
|
||||
|
||||
function filterAssets(q) {
|
||||
q = q.toLowerCase();
|
||||
document.querySelectorAll('.sinking-card, .debt-card, .asset-card').forEach(card => {
|
||||
card.style.display = card.textContent.toLowerCase().includes(q) ? '' : 'none';
|
||||
});
|
||||
// Also filter table rows in the flips section
|
||||
document.querySelectorAll('tbody tr').forEach(row => {
|
||||
row.style.display = row.textContent.toLowerCase().includes(q) ? '' : 'none';
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user