feat(profile): let guests manage their localStorage username

/profile previously required auth and returned a raw JSON 401 for
guests. Now it renders a guest variant: edit guestUsername in
localStorage, clear it to re-prompt on next visit, or sign in to
claim a permanent username. Unifies the two username flows
(authed DB display_name vs guest localStorage) under one page.
This commit is contained in:
russell@unturf.com 2026-06-10 12:50:51 -04:00
parent b2fb60d1b7
commit f7862bc54a
No known key found for this signature in database
2 changed files with 80 additions and 6 deletions

3
app.py
View file

@ -884,9 +884,8 @@ def logout():
@app.route("/profile")
@auth.require_auth
def profile_page():
"""Profile settings page"""
"""Profile settings page — works for both authenticated users and guests."""
user = auth.get_current_user()
return render_template("profile.html", user=user)

View file

@ -269,14 +269,19 @@
<div class="header-actions">
<a href="/" class="btn">🏠 Home</a>
<a href="/browse" class="btn btn-secondary">📋 Browse Rooms</a>
{% if user %}
<button class="btn btn-secondary" onclick="logout()">🚪 Log Out</button>
{% else %}
<a href="/auth" class="btn btn-secondary">🔐 Sign In</a>
{% endif %}
</div>
</div>
<div class="content-container">
<p class="subtitle">Manage your account preferences</p>
<!-- Username Section -->
{% if user %}
<!-- Authenticated: Change DB-backed Username -->
<div class="section">
<h2>Change Username</h2>
<div class="current-value">
@ -299,6 +304,36 @@
<button type="submit" id="update-username-btn" disabled>Update Username</button>
</form>
</div>
{% else %}
<!-- Guest: Change localStorage guest name -->
<div class="section">
<h2>Guest Name</h2>
<p style="color: var(--text-secondary); font-size: 14px; margin-top: 0;">
You're browsing as a guest. Your name is stored in your browser only.
<a href="/auth" style="color: var(--button-primary);">Sign in</a> to claim a permanent username.
</p>
<div class="current-value">
Current guest name: <strong id="current-guest-name">(none)</strong>
</div>
<div id="guest-message" class="message"></div>
<form id="guest-username-form">
<div class="form-group">
<label for="new-guest-username">New Guest Name</label>
<input
type="text"
id="new-guest-username"
placeholder="Enter new guest name"
required
>
</div>
<button type="submit" id="save-guest-btn">Save Guest Name</button>
</form>
<button type="button" id="clear-guest-btn"
style="background: #6c757d; margin-top: 10px;">
🗑️ Clear Guest Name (re-prompt on next visit)
</button>
</div>
{% endif %}
<!-- Theme Section -->
<div class="section">
@ -317,9 +352,6 @@
</div>
<script>
let checkTimeout;
const currentUsername = "{{ user.display_name }}";
// Theme Management
function setTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
@ -336,6 +368,10 @@
const savedTheme = localStorage.getItem('theme') || 'light';
setTheme(savedTheme);
{% if user %}
let checkTimeout;
const currentUsername = "{{ user.display_name }}";
// Username availability check
document.getElementById('new-username').addEventListener('input', function(e) {
const username = e.target.value.trim();
@ -462,6 +498,45 @@
alert('Network error. Please try again.');
}
}
{% else %}
// Guest username management — mirrors chat.html's GUEST_USERNAME_KEY
const GUEST_USERNAME_KEY = 'guestUsername';
function refreshGuestName() {
const name = localStorage.getItem(GUEST_USERNAME_KEY);
document.getElementById('current-guest-name').textContent = name || '(none — will prompt on next visit)';
document.getElementById('new-guest-username').value = name || '';
}
refreshGuestName();
document.getElementById('guest-username-form').addEventListener('submit', function(e) {
e.preventDefault();
const newName = document.getElementById('new-guest-username').value.trim();
const messageDiv = document.getElementById('guest-message');
if (!newName) {
messageDiv.textContent = 'Guest name cannot be empty.';
messageDiv.className = 'message error show';
return;
}
localStorage.setItem(GUEST_USERNAME_KEY, newName);
refreshGuestName();
messageDiv.textContent = 'Guest name saved! Refresh chat to use it.';
messageDiv.className = 'message success show';
});
document.getElementById('clear-guest-btn').addEventListener('click', function() {
if (!confirm('Clear your guest name? You will be prompted for a new one next time you visit chat.')) {
return;
}
localStorage.removeItem(GUEST_USERNAME_KEY);
refreshGuestName();
const messageDiv = document.getElementById('guest-message');
messageDiv.textContent = 'Guest name cleared.';
messageDiv.className = 'message success show';
});
{% endif %}
</script>
</body>
</html>