adding player profiles
All checks were successful
Build Images and Deploy / Update-PROD-Stack (push) Successful in 28s

This commit is contained in:
2026-02-28 00:51:43 -05:00
parent 30f0c98102
commit 79ee7064a8
11 changed files with 256 additions and 31 deletions

View File

@@ -58,8 +58,8 @@
<td><strong><%= pkg.card_number %></strong></td>
<td style="font-family: monospace;"><%= pkg.unique_code %></td>
<td><%= pkg.scan_count %></td>
<td><%= pkg.first_scanner_name || '&mdash;' %></td>
<td><%= pkg.last_scanner_name || '&mdash;' %></td>
<td><% if (pkg.first_scanner_name) { %><a href="/player/<%= pkg.first_scanner_name %>"><%= pkg.first_scanner_name %></a><% } else { %>---<% } %></td>
<td><% if (pkg.last_scanner_name) { %><a href="/player/<%= pkg.last_scanner_name %>"><%= pkg.last_scanner_name %></a><% } else { %>---<% } %></td>
<td>
<a href="/hunt/<%= hunt.short_name %>/<%= pkg.card_number %>" class="btn btn-sm btn-outline">View</a>
</td>

View File

@@ -27,7 +27,7 @@
<% leaderboard.forEach((entry, i) => { %>
<tr>
<td class="rank-cell rank-<%= i + 1 %>"><%= i + 1 %></td>
<td><strong><%= entry.username %></strong></td>
<td><strong><a href="/player/<%= entry.username %>"><%= entry.username %></a></strong></td>
<td><span class="points-badge"><%= entry.total_points %></span></td>
<td><%= entry.scans %></td>
</tr>

View File

@@ -25,7 +25,7 @@
<td class="rank-cell rank-<%= i + 1 %>">
<% if (i === 0) { %>&#x1F947;<% } else if (i === 1) { %>&#x1F948;<% } else if (i === 2) { %>&#x1F949;<% } else { %><%= i + 1 %><% } %>
</td>
<td><strong><%= entry.username %></strong></td>
<td><strong><a href="/player/<%= entry.username %>"><%= entry.username %></a></strong></td>
<td><span class="points-badge"><%= entry.total_points %></span></td>
<td><%= entry.scans %></td>
</tr>

View File

@@ -17,11 +17,11 @@
<div class="label">Total Scans</div>
</div>
<div class="stat-box">
<div class="value"><%= pkg.first_scanner_name || '---' %></div>
<div class="value"><% if (pkg.first_scanner_name) { %><a href="/player/<%= pkg.first_scanner_name %>"><%= pkg.first_scanner_name %></a><% } else { %>---<% } %></div>
<div class="label">First Finder</div>
</div>
<div class="stat-box">
<div class="value"><%= pkg.last_scanner_name || '---' %></div>
<div class="value"><% if (pkg.last_scanner_name) { %><a href="/player/<%= pkg.last_scanner_name %>"><%= pkg.last_scanner_name %></a><% } else { %>---<% } %></div>
<div class="label">Most Recent</div>
</div>
</div>
@@ -52,7 +52,7 @@
<div class="card-header">&#x1F4AC; Package Hint</div>
<% if (pkg.last_scan_hint) { %>
<p style="font-style: italic; font-size: 1.05rem;">"<%= pkg.last_scan_hint %>"</p>
<p style="font-size: 0.8rem; color: var(--muted);">Left by <%= pkg.last_scanner_name %></p>
<p style="font-size: 0.8rem; color: var(--muted);">Left by <a href="/player/<%= pkg.last_scanner_name %>"><%= pkg.last_scanner_name %></a></p>
<% } else { %>
<p style="color: var(--muted);">No hint has been left yet.</p>
<% } %>
@@ -85,7 +85,7 @@
<% scanHistory.forEach((scan, i) => { %>
<tr>
<td><%= i + 1 %></td>
<td><%= scan.username %></td>
<td><a href="/player/<%= scan.username %>"><%= scan.username %></a></td>
<td><% if (scan.points_awarded > 0) { %><span class="points-badge">+<%= scan.points_awarded %></span><% } else { %><span style="color: var(--muted);">0</span><% } %></td>
<td style="font-size: 0.85rem; color: var(--muted);"><%= new Date(scan.scanned_at).toLocaleString() %></td>
</tr>

View File

@@ -31,11 +31,11 @@
<div class="label">Total Scans</div>
</div>
<div class="stat-box">
<div class="value"><%= pkg.first_scanner_name || '---' %></div>
<div class="value"><% if (pkg.first_scanner_name) { %><a href="/player/<%= pkg.first_scanner_name %>"><%= pkg.first_scanner_name %></a><% } else { %>---<% } %></div>
<div class="label">First Finder</div>
</div>
<div class="stat-box">
<div class="value"><%= pkg.last_scanner_name || '---' %></div>
<div class="value"><% if (pkg.last_scanner_name) { %><a href="/player/<%= pkg.last_scanner_name %>"><%= pkg.last_scanner_name %></a><% } else { %>---<% } %></div>
<div class="label">Most Recent</div>
</div>
</div>
@@ -67,7 +67,7 @@
<div class="card-header">&#x1F4AC; Package Hint</div>
<% if (pkg.last_scan_hint) { %>
<p style="font-style: italic; font-size: 1.05rem;">"<%= pkg.last_scan_hint %>"</p>
<p style="font-size: 0.8rem; color: var(--muted);">Left by <%= pkg.last_scanner_name %></p>
<p style="font-size: 0.8rem; color: var(--muted);">Left by <a href="/player/<%= pkg.last_scanner_name %>"><%= pkg.last_scanner_name %></a></p>
<% } else { %>
<p style="color: var(--muted);">No hint has been left yet.</p>
<% } %>
@@ -101,7 +101,7 @@
<% scanHistory.forEach((scan, i) => { %>
<tr>
<td><%= i + 1 %></td>
<td><%= scan.username %></td>
<td><a href="/player/<%= scan.username %>"><%= scan.username %></a></td>
<td><% if (scan.points_awarded > 0) { %><span class="points-badge">+<%= scan.points_awarded %></span><% } else { %><span style="color: var(--muted);">0</span><% } %></td>
<td style="font-size: 0.85rem; color: var(--muted);"><%= new Date(scan.scanned_at).toLocaleString() %></td>
</tr>

View File

@@ -9,10 +9,14 @@
<body>
<nav class="navbar">
<a href="/" class="navbar-brand">&#x1F3AF; Loot Hunt</a>
<button class="nav-toggle" aria-label="Toggle menu" onclick="document.querySelector('.navbar-nav').classList.toggle('open')">
<span></span><span></span><span></span>
</button>
<ul class="navbar-nav">
<li><a href="/hunts">Hunts</a></li>
<li><a href="/leaderboard">Leaderboard</a></li>
<% if (currentUser) { %>
<li><a href="/player/<%= currentUser.username %>">My Profile</a></li>
<% if (currentUser.isAdmin) { %>
<li><a href="/admin">Admin</a></li>
<% } %>

View File

@@ -0,0 +1,87 @@
<%- include('../partials/header') %>
<div class="container">
<div style="text-align: center; margin-bottom: 1.5rem;">
<h1 style="margin-bottom: 0.25rem;">&#x1F464; <%= profile.username %></h1>
<p style="color: var(--muted); margin: 0;">Joined <%= new Date(profile.created_at).toLocaleDateString() %></p>
</div>
<div class="stats-row">
<div class="stat-box">
<div class="value"><%= profile.totalPoints %></div>
<div class="label">Total Points</div>
</div>
<div class="stat-box">
<div class="value"><%= profile.scanCount %></div>
<div class="label">Finds</div>
</div>
<div class="stat-box">
<div class="value"><%= rank ? '#' + rank : '---' %></div>
<div class="label">Rank<% if (totalPlayers) { %> / <%= totalPlayers %><% } %></div>
</div>
</div>
<% if (huntBreakdown.length > 0) { %>
<div class="card">
<div class="card-header">Hunts Participated</div>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>Hunt</th>
<th>Finds</th>
<th>Points</th>
</tr>
</thead>
<tbody>
<% huntBreakdown.forEach(h => { %>
<tr>
<td><a href="/hunt/<%= h.hunt_short_name %>"><%= h.hunt_name %></a></td>
<td><%= h.scans %></td>
<td><span class="points-badge">+<%= h.points %></span></td>
</tr>
<% }) %>
</tbody>
</table>
</div>
</div>
<% } %>
<% if (recentScans.length > 0) { %>
<div class="card">
<div class="card-header">Recent Activity</div>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>Package</th>
<th>Hunt</th>
<th>Points</th>
<th>When</th>
</tr>
</thead>
<tbody>
<% recentScans.forEach(scan => { %>
<tr>
<td><a href="/hunt/<%= scan.hunt_short_name %>/<%= scan.card_number %>"><%= scan.card_number %> of <%= scan.package_count %></a></td>
<td><a href="/hunt/<%= scan.hunt_short_name %>"><%= scan.hunt_name %></a></td>
<td><% if (scan.points_awarded > 0) { %><span class="points-badge">+<%= scan.points_awarded %></span><% } else { %><span style="color: var(--muted);">0</span><% } %></td>
<td style="font-size: 0.85rem; color: var(--muted);"><%= new Date(scan.scanned_at).toLocaleString() %></td>
</tr>
<% }) %>
</tbody>
</table>
</div>
</div>
<% } else { %>
<div class="card" style="text-align: center; color: var(--muted); padding: 2rem;">
No scans yet. Get out there and find some loot!
</div>
<% } %>
<div style="text-align: center; margin-top: 1rem;">
<a href="/leaderboard" class="btn btn-outline">Global Leaderboard</a>
</div>
</div>
<%- include('../partials/footer') %>