← back to Lifestyle Asset Intel
views/portfolio.ejs
133 lines
<%- include('partials/head') %>
<main class="container">
<p class="crumbs"><a href="/">← Console</a></p>
<% if (!owner) { %>
<h1>Portfolio</h1>
<p class="muted">Enter the owner email to view a portfolio.</p>
<form action="/portfolio" method="get" class="owner-form">
<label for="owner">Owner email</label>
<input type="email" id="owner" name="owner" required placeholder="owner@example.com">
<button type="submit">View portfolio</button>
</form>
<% } else { %>
<h1>Portfolio — <%= owner %></h1>
<% if (flash === 'added') { %><p class="flash ok">Holding added.</p><% } %>
<% if (flash === 'removed') { %><p class="flash ok">Holding removed.</p><% } %>
<% if (flash === 'invalid_email') { %><p class="flash err">Invalid email.</p><% } %>
<% if (flash === 'invalid_asset_slug') { %><p class="flash err">Unknown asset slug.</p><% } %>
<section class="add-holding">
<h2>Add holding</h2>
<form action="/portfolio/add" method="post" class="holding-form">
<input type="hidden" name="owner_email" value="<%= owner %>">
<div class="row">
<label for="asset_slug">Asset</label>
<input list="asset-slugs" id="asset_slug" name="asset_slug" required placeholder="e.g. birkin-30-togo-gold-ghw-us">
<datalist id="asset-slugs">
<% assets.forEach(function(a){ %>
<option value="<%= a.slug %>"><%= a.brand_name %> <%= a.family_name %> <%= a.size || '' %> <%= a.material || '' %></option>
<% }); %>
</datalist>
</div>
<div class="row">
<label for="acquired_at">Acquired</label>
<input type="date" id="acquired_at" name="acquired_at">
</div>
<div class="row">
<label for="acquisition_basis">Basis (USD)</label>
<input type="number" id="acquisition_basis" name="acquisition_basis" min="0" step="0.01">
</div>
<div class="row">
<label for="notes">Notes</label>
<textarea id="notes" name="notes" rows="2"></textarea>
</div>
<button type="submit">Add holding</button>
</form>
</section>
<% if (!holdings.length) { %>
<p class="muted">No holdings yet.</p>
<% } else {
var sumBasis = 0, sumQ50 = 0, sumPL = 0, weightedDays = 0, weightDenom = 0;
holdings.forEach(function(h){
if (h.acquisition_basis != null) sumBasis += h.acquisition_basis;
if (h.q50 != null) sumQ50 += h.q50;
if (h.unrealized_pl != null) sumPL += h.unrealized_pl;
if (h.days_held != null && h.acquisition_basis != null) {
weightedDays += h.days_held * h.acquisition_basis;
weightDenom += h.acquisition_basis;
}
});
var avgDays = weightDenom ? Math.round(weightedDays / weightDenom) : null;
%>
<section class="holdings">
<h2>Holdings (<%= holdings.length %>)</h2>
<table>
<thead>
<tr>
<th scope="col">Brand</th>
<th scope="col">Family / Asset</th>
<th scope="col">Acquired</th>
<th scope="col">Basis</th>
<th scope="col">Current Q50</th>
<th scope="col">P&L $</th>
<th scope="col">P&L %</th>
<th scope="col">Days held</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
<% holdings.forEach(function(h){ %>
<tr>
<td><%= h.brand %></td>
<td>
<a href="/asset/<%= h.asset_slug %>"><%= h.family %></a>
<div class="muted mono"><%= h.asset_slug %></div>
</td>
<td><%= fmtDate(h.acquired_at) %></td>
<td class="num">$<%= money(h.acquisition_basis) %></td>
<td class="num">$<%= money(h.q50) %></td>
<td class="num <%= plClass(h.unrealized_pl) %>">
<%= h.unrealized_pl == null ? '—' : (h.unrealized_pl >= 0 ? '+$' : '-$') + money(Math.abs(h.unrealized_pl)) %>
</td>
<td class="num <%= plClass(h.unrealized_pl) %>"><%= pct(h.pl_pct) %></td>
<td class="num"><%= h.days_held == null ? '—' : h.days_held %></td>
<td>
<form action="/portfolio/remove/<%= h.id %>" method="post" class="inline-remove">
<input type="hidden" name="owner_email" value="<%= owner %>">
<input type="hidden" name="_csrf_skip" value="1">
<button type="submit" class="link-btn" aria-label="Remove holding">Remove</button>
</form>
</td>
</tr>
<% }); %>
</tbody>
<tfoot>
<tr class="totals">
<th scope="row" colspan="3">Totals</th>
<td class="num">$<%= money(sumBasis) %></td>
<td class="num">$<%= money(sumQ50) %></td>
<td class="num <%= plClass(sumPL) %>">
<%= sumPL >= 0 ? '+$' : '-$' %><%= money(Math.abs(sumPL)) %>
</td>
<td class="num"><%= sumBasis ? pct(sumPL / sumBasis) : '—' %></td>
<td class="num"><%= avgDays == null ? '—' : avgDays %></td>
<td></td>
</tr>
</tfoot>
</table>
</section>
<% } %>
<% } %>
</main>
<%
function money(v){ if(v==null||v==='') return '—'; var n=parseFloat(v); return isFinite(n)?n.toLocaleString('en-US',{maximumFractionDigits:0}):'—'; }
function pct(v){ if(v==null||v==='') return '—'; var n=parseFloat(v); return isFinite(n)?(n*100).toFixed(1)+'%':'—'; }
function fmtDate(v){ if(!v) return '—'; try { return new Date(v).toISOString().slice(0,10); } catch(e){ return String(v); } }
function plClass(v){ if(v==null) return ''; return v >= 0 ? 'pl-pos' : 'pl-neg'; }
%>
<%- include('partials/foot') %>