← back to Lifestyle Asset Intel

views/portfolio.ejs

133 lines

<%- include('partials/head') %>
<main class="container">
  <p class="crumbs"><a href="/">&larr; 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 &mdash; <%= 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&amp;L $</th>
              <th scope="col">P&amp;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 ? '&mdash;' : (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 ? '&mdash;' : 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) : '&mdash;' %></td>
              <td class="num"><%= avgDays == null ? '&mdash;' : avgDays %></td>
              <td></td>
            </tr>
          </tfoot>
        </table>
      </section>
    <% } %>
  <% } %>
</main>

<%
function money(v){ if(v==null||v==='') return '&mdash;'; var n=parseFloat(v); return isFinite(n)?n.toLocaleString('en-US',{maximumFractionDigits:0}):'&mdash;'; }
function pct(v){ if(v==null||v==='') return '&mdash;'; var n=parseFloat(v); return isFinite(n)?(n*100).toFixed(1)+'%':'&mdash;'; }
function fmtDate(v){ if(!v) return '&mdash;'; 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') %>