236 lines
8.9 KiB
HTML
236 lines
8.9 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}{{ player.player_name }} · Poker Portal{% endblock %}
|
|
{% block content %}
|
|
<section class="hero-card compact">
|
|
<div>
|
|
<p class="eyebrow">Player profile</p>
|
|
<h1>{{ player.player_name }}</h1>
|
|
<p class="muted-text">A quick read on lifetime performance, hit rate, and session-by-session movement.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="grid three-col">
|
|
<article class="panel stat-card"><span>Total Net</span><strong class="{{ 'positive' if player.total_net_cents > 0 else 'negative' if player.total_net_cents < 0 else 'neutral' }}">{{ player.total_net_cents | money }}</strong></article>
|
|
<article class="panel stat-card"><span>Win %</span><strong>{{ "%.1f"|format(player.win_pct) }}%</strong></article>
|
|
<article class="panel stat-card"><span>ROI</span><strong>{{ "%.1f"|format(player.roi_pct) }}%</strong></article>
|
|
<article class="panel stat-card"><span>Total invested</span><strong>{{ player.total_invested_cents | money }}</strong></article>
|
|
<article class="panel stat-card"><span>Paid Buy-ins</span><strong>{{ player.total_buy_in_cents | money }}</strong></article>
|
|
<article class="panel stat-card"><span>Fronted</span><strong>{{ player.total_front_cents | money }}</strong></article>
|
|
<article class="panel stat-card"><span>Cash-outs</span><strong>{{ player.total_cash_out_cents | money }}</strong></article>
|
|
<article class="panel stat-card"><span>Sessions</span><strong>{{ player.sessions_played }}</strong></article>
|
|
<article class="panel stat-card">
|
|
<span>Current Streak</span>
|
|
<strong>
|
|
{% if player.current_win_streak > 0 %}
|
|
W{{ player.current_win_streak }}
|
|
{% elif player.current_loss_streak > 0 %}
|
|
L{{ player.current_loss_streak }}
|
|
{% else %}
|
|
-
|
|
{% endif %}
|
|
</strong>
|
|
</article>
|
|
|
|
<!--<article class="panel stat-card"><span>Longest win streak</span><strong>{{ player.longest_win_streak }}</strong></article>
|
|
<article class="panel stat-card"><span>Longest loss streak</span><strong>{{ player.longest_loss_streak }}</strong></article>-->
|
|
</section>
|
|
|
|
<section class="grid one-col">
|
|
<div class="panel chart-panel">
|
|
<div class="panel-header">
|
|
<div>
|
|
<p class="eyebrow">Trend</p>
|
|
<h2>Cumulative profit</h2>
|
|
</div>
|
|
</div>
|
|
<div class="chart-frame">
|
|
<canvas id="playerCumulativeChart"></canvas>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="grid two-col">
|
|
<div class="panel chart-panel">
|
|
<div class="panel-header">
|
|
<div>
|
|
<p class="eyebrow">Volatility</p>
|
|
<h2>Session results</h2>
|
|
</div>
|
|
</div>
|
|
<div class="chart-frame">
|
|
<canvas id="playerSessionChart"></canvas>
|
|
</div>
|
|
</div>
|
|
<div class="panel chart-panel">
|
|
<div class="panel-header">
|
|
<div>
|
|
<p class="eyebrow">Breakdown</p>
|
|
<h2>Result mix</h2>
|
|
</div>
|
|
</div>
|
|
<div class="chart-frame chart-frame-small">
|
|
<canvas id="playerBreakdownChart"></canvas>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<div class="panel-header">
|
|
<div>
|
|
<p class="eyebrow">Breakdown</p>
|
|
<h2>Detailed stats</h2>
|
|
</div>
|
|
</div>
|
|
<div class="table-wrap">
|
|
<table>
|
|
<tbody>
|
|
<tr><th>Winning Sessions</th><td>{{ player.winning_sessions }}</td></tr>
|
|
<tr><th>Losing Sessions</th><td>{{ player.losing_sessions }}</td></tr>
|
|
<tr><th>Break-even Sessions</th><td>{{ player.break_even_sessions }}</td></tr>
|
|
<tr><th>Average Win</th><td>{{ player.avg_win_cents | money }}</td></tr>
|
|
<tr><th>Average Loss</th><td>{{ player.avg_loss_cents | money }}</td></tr>
|
|
<tr><th>Biggest Win</th><td>{{ player.biggest_win_cents | money }}</td></tr>
|
|
<tr><th>Biggest Loss</th><td>{{ player.biggest_loss_cents | money }}</td></tr>
|
|
<tr><th>Current Win Streak</th><td>{{ player.current_win_streak }}</td></tr>
|
|
<tr><th>Current Loss Streak</th><td>{{ player.current_loss_streak }}</td></tr>
|
|
<tr><th>Longest Win Streak</th><td>{{ player.longest_win_streak }}</td></tr>
|
|
<tr><th>Longest Loss Streak</th><td>{{ player.longest_loss_streak }}</td></tr>
|
|
<tr>
|
|
<th>Best Session</th>
|
|
<td>
|
|
{{ player.best_session_net_cents | money }}
|
|
{% if player.best_session_date %}
|
|
<span class="muted-text small">on {{ player.best_session_date | pretty_date }}</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th>Worst Session</th>
|
|
<td>
|
|
{{ player.worst_session_net_cents | money }}
|
|
{% if player.worst_session_date %}
|
|
<span class="muted-text small">on {{ player.worst_session_date | pretty_date }}</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</section>
|
|
|
|
<script>
|
|
const playerChartData = {{ chart_data | tojson }};
|
|
const rootStyles = getComputedStyle(document.documentElement);
|
|
const textMuted = rootStyles.getPropertyValue('--text-muted').trim();
|
|
const lineColor = rootStyles.getPropertyValue('--line').trim();
|
|
|
|
const sharedScaleOptions = {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom',
|
|
labels: {
|
|
color: textMuted,
|
|
usePointStyle: true,
|
|
boxWidth: 10,
|
|
boxHeight: 10,
|
|
padding: 18,
|
|
},
|
|
},
|
|
},
|
|
scales: {
|
|
x: {
|
|
ticks: { color: textMuted, maxRotation: 0 },
|
|
grid: { color: lineColor },
|
|
},
|
|
y: {
|
|
ticks: { color: textMuted },
|
|
grid: { color: lineColor },
|
|
},
|
|
},
|
|
};
|
|
|
|
const cumulativeCtx = document.getElementById('playerCumulativeChart');
|
|
if (cumulativeCtx) {
|
|
new Chart(cumulativeCtx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: playerChartData.labels,
|
|
datasets: [{
|
|
label: 'Cumulative Profit',
|
|
data: playerChartData.cumulative_values,
|
|
borderColor: playerChartData.color,
|
|
backgroundColor: playerChartData.color,
|
|
borderWidth: 2.5,
|
|
pointRadius: 3,
|
|
pointHoverRadius: 5,
|
|
tension: 0.22,
|
|
}]
|
|
},
|
|
options: sharedScaleOptions,
|
|
});
|
|
}
|
|
|
|
const sessionCtx = document.getElementById('playerSessionChart');
|
|
if (sessionCtx) {
|
|
new Chart(sessionCtx, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: playerChartData.labels,
|
|
datasets: [{
|
|
label: 'Session Net',
|
|
data: playerChartData.net_values,
|
|
backgroundColor: playerChartData.net_colors,
|
|
borderColor: playerChartData.net_colors,
|
|
borderRadius: 8,
|
|
borderSkipped: false,
|
|
}]
|
|
},
|
|
options: sharedScaleOptions,
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<script>
|
|
const breakdownCtx = document.getElementById('playerBreakdownChart');
|
|
if (breakdownCtx) {
|
|
new Chart(breakdownCtx, {
|
|
type: 'doughnut',
|
|
data: {
|
|
labels: ['Wins', 'Losses', 'Break-even'],
|
|
datasets: [{
|
|
data: [
|
|
{{ player.winning_sessions }},
|
|
{{ player.losing_sessions }},
|
|
{{ player.break_even_sessions }}
|
|
],
|
|
backgroundColor: [
|
|
'#59d98e',
|
|
'#f06c72',
|
|
'#e4bf65'
|
|
],
|
|
borderWidth: 0,
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom',
|
|
labels: {
|
|
color: textMuted,
|
|
usePointStyle: true,
|
|
boxWidth: 10,
|
|
boxHeight: 10,
|
|
padding: 18,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}
|
|
</script>
|
|
{% endblock %}
|