- Redesign landing page hero with split layout, features section, and in-app session/result demos - Add fixed sidebar scroll isolation (app-shell overflow lock pattern) - Redesign leagues index cards with initial badge, podium leader chips, and action links - Redesign league dashboard: color-coded nav tiles, cash/stats overview strip, session history heatmap calendar - Dashboard cash stats use real cash only (excludes rollovers and carry-ins) - Session history calendar: JS-driven full-year grid, year navigation, hover tooltips, full-width responsive layout - Bump leaderboard tile color from gold to blue (distinct from ledger orange) - Bump version to 2.3.1
164 lines
6.7 KiB
HTML
164 lines
6.7 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Account settings · myboker.org{% endblock %}
|
|
{% block content %}
|
|
|
|
<div class="settings-profile">
|
|
<div class="settings-avatar">{{ user.email[0] | upper }}</div>
|
|
<div class="settings-profile__meta">
|
|
<h1 class="settings-profile__title">Account Settings</h1>
|
|
<p class="settings-profile__email">{{ user.email }}</p>
|
|
</div>
|
|
<div style="margin-left:auto;">
|
|
<a class="btn btn--ghost btn--sm" href="{{ url_for('leagues.index') }}">My leagues</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="stack">
|
|
|
|
<form class="panel form-card" method="post" action="{{ url_for('account.update_email') }}">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
<div>
|
|
<p class="eyebrow">Profile</p>
|
|
<h2 class="panel__title" style="margin-top:4px;">Email address</h2>
|
|
</div>
|
|
<label>
|
|
<span>Email</span>
|
|
<input type="email" name="email" value="{{ user.email }}" required autocomplete="email">
|
|
</label>
|
|
<label>
|
|
<span>Current password <span class="form-opt-hint">(required to change)</span></span>
|
|
<input type="password" name="current_password" required autocomplete="current-password">
|
|
</label>
|
|
<div>
|
|
<button class="btn btn--primary" type="submit">Update email</button>
|
|
</div>
|
|
</form>
|
|
|
|
<form class="panel form-card" method="post" action="{{ url_for('account.update_password') }}">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
<div>
|
|
<p class="eyebrow">Security</p>
|
|
<h2 class="panel__title" style="margin-top:4px;">Change password</h2>
|
|
</div>
|
|
<label>
|
|
<span>Current password</span>
|
|
<input type="password" name="current_password" required autocomplete="current-password">
|
|
</label>
|
|
<label>
|
|
<span>New password</span>
|
|
<input type="password" name="new_password" required autocomplete="new-password">
|
|
</label>
|
|
<label>
|
|
<span>Confirm new password</span>
|
|
<input type="password" name="confirm_password" required autocomplete="new-password">
|
|
</label>
|
|
<div>
|
|
<button class="btn btn--primary" type="submit">Change password</button>
|
|
</div>
|
|
</form>
|
|
|
|
<div class="panel">
|
|
<div class="panel__head">
|
|
<div>
|
|
<p class="kicker" style="margin:0;color:var(--neg);">Danger zone</p>
|
|
<h2 class="panel__title">Destructive actions</h2>
|
|
</div>
|
|
</div>
|
|
<div class="panel__body">
|
|
<div class="danger-row">
|
|
<div>
|
|
<strong class="danger-row__title">Delete account</strong>
|
|
<p class="muted-text">Permanently disables your account and archives all leagues you own. This cannot be undone.</p>
|
|
</div>
|
|
<button class="btn btn--ghost btn--sm" type="button" data-modal="modal-delete-account">Delete account</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="modal-backdrop" id="modal-delete-account" hidden>
|
|
<div class="modal-card">
|
|
<div class="modal-card__head">
|
|
<h2 style="font-size:18px;margin:0;">Delete account</h2>
|
|
</div>
|
|
<p class="modal-card__text">
|
|
Your account will be <strong>permanently disabled</strong> and all leagues you own will be archived. This cannot be undone.<br><br>
|
|
Type <strong>DELETE</strong> and enter your password to confirm.
|
|
</p>
|
|
<form method="post" action="{{ url_for('account.delete_account') }}">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
<div style="padding:0 20px 16px;display:grid;gap:10px;">
|
|
<input
|
|
class="modal-confirm-input"
|
|
type="text"
|
|
name="confirm"
|
|
placeholder='Type "DELETE"'
|
|
autocomplete="off"
|
|
data-match="DELETE"
|
|
data-target="delete-confirm-btn"
|
|
data-also-requires="delete-password-input"
|
|
>
|
|
<input
|
|
class="modal-password-input"
|
|
id="delete-password-input"
|
|
type="password"
|
|
name="current_password"
|
|
placeholder="Your password"
|
|
autocomplete="current-password"
|
|
data-target="delete-confirm-btn"
|
|
data-confirm-input="modal-delete-account"
|
|
>
|
|
</div>
|
|
<div class="modal-card__actions">
|
|
<button class="btn btn--ghost btn--sm" type="button" data-close-modal>Cancel</button>
|
|
<button class="btn btn--sm btn--danger" id="delete-confirm-btn" type="submit" disabled>Delete my account</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function () {
|
|
function openModal(id) {
|
|
const el = document.getElementById(id);
|
|
if (el) {
|
|
el.removeAttribute('hidden');
|
|
const inp = el.querySelector('.modal-confirm-input');
|
|
if (inp) { inp.value = ''; inp.focus(); }
|
|
const pwd = el.querySelector('.modal-password-input');
|
|
if (pwd) pwd.value = '';
|
|
refreshDeleteBtn();
|
|
}
|
|
}
|
|
function closeModal(el) {
|
|
el.closest('.modal-backdrop').setAttribute('hidden', '');
|
|
}
|
|
|
|
function refreshDeleteBtn() {
|
|
const confirmInp = document.querySelector('#modal-delete-account .modal-confirm-input');
|
|
const pwdInp = document.getElementById('delete-password-input');
|
|
const btn = document.getElementById('delete-confirm-btn');
|
|
if (!confirmInp || !pwdInp || !btn) return;
|
|
btn.disabled = !(confirmInp.value === 'DELETE' && pwdInp.value.length >= 1);
|
|
}
|
|
|
|
document.querySelectorAll('[data-modal]').forEach(trigger => {
|
|
trigger.addEventListener('click', () => openModal(trigger.dataset.modal));
|
|
});
|
|
document.querySelectorAll('[data-close-modal]').forEach(btn => {
|
|
btn.addEventListener('click', () => closeModal(btn));
|
|
});
|
|
document.querySelectorAll('.modal-backdrop').forEach(backdrop => {
|
|
backdrop.addEventListener('click', e => { if (e.target === backdrop) backdrop.setAttribute('hidden', ''); });
|
|
});
|
|
|
|
const confirmInp = document.querySelector('#modal-delete-account .modal-confirm-input');
|
|
const pwdInp = document.getElementById('delete-password-input');
|
|
if (confirmInp) confirmInp.addEventListener('input', refreshDeleteBtn);
|
|
if (pwdInp) pwdInp.addEventListener('input', refreshDeleteBtn);
|
|
})();
|
|
</script>
|
|
|
|
{% endblock %}
|