Add account deletion confirmation page, privacy settings template, and profile view template

- Created a new HTML template for account deletion confirmation with user-friendly messaging and a return link.
- Developed a privacy settings page allowing users to control visibility of their personal information with appropriate messaging for success and error states.
- Implemented a profile view template displaying user information, statistics, teams, and achievements based on user permissions.
- Added responsive design elements and improved user interface with Tailwind CSS classes for better aesthetics and usability.
This commit is contained in:
Christian Krakau-Louis
2025-04-16 21:45:33 +02:00
parent 9815a1a3e0
commit 6c260c5936
16 changed files with 1169 additions and 145 deletions
+28
View File
@@ -0,0 +1,28 @@
{% extends "base.html" %}
{% block content %}
<div class="max-w-md mx-auto my-10 bg-white p-8 rounded-lg shadow-md">
<div class="flex flex-col items-center justify-center">
<div class="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mb-4">
<i class="fas fa-user-slash text-red-600 text-2xl"></i>
</div>
<h1 class="text-2xl font-bold text-gray-800 mb-2">Account Deleted</h1>
<p class="text-gray-600 text-center mb-6">
Your account has been successfully deleted. All your personal information has been removed from our system.
</p>
<div class="border-t border-gray-200 w-full pt-6 mt-2">
<p class="text-gray-600 text-center mb-4">
We're sorry to see you go. You can always create a new account if you wish to return.
</p>
<div class="flex justify-center">
<a href="/" class="bg-irish-green hover:bg-opacity-90 text-white font-semibold py-2 px-4 rounded-md transition">
Return to Homepage
</a>
</div>
</div>
</div>
</div>
{% endblock %}
+152
View File
@@ -0,0 +1,152 @@
{% extends "base.html" %}
{% block content %}
<div class="max-w-3xl mx-auto my-8">
<div class="bg-white p-8 rounded-lg shadow-md">
<h1 class="text-2xl font-bold text-irish-green mb-6">Privacy Settings</h1>
<!-- Display messages if present -->
{% if request.query_params.message %}
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded mb-4">
{{ request.query_params.message }}
</div>
{% endif %}
<!-- Display errors if present -->
{% if error %}
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
{{ error }}
</div>
{% endif %}
<p class="text-gray-600 mb-6">
Control who can see different parts of your profile information. Your information can be visible to everyone,
only members of your teams, or kept private (visible only to you and admins).
</p>
<form method="post" action="/auth/privacy-settings">
<div class="space-y-6">
<!-- Email Visibility -->
<div class="border-b pb-4">
<h3 class="font-medium text-gray-800 mb-3">Email Address</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
{% for option in privacy_options %}
<label class="flex items-center p-4 border rounded-lg {% if privacy_settings.email == option.value %}bg-green-50 border-irish-green{% endif %}">
<input type="radio" name="email_visibility" value="{{ option.value }}"
{% if privacy_settings.email == option.value %}checked{% endif %}
class="mr-2 text-irish-green focus:ring-irish-green">
<div>
<span class="font-medium block text-sm">{{ option.label }}</span>
<span class="text-xs text-gray-500">{{ option.description }}</span>
</div>
</label>
{% endfor %}
</div>
</div>
<!-- Full Name Visibility -->
<div class="border-b pb-4">
<h3 class="font-medium text-gray-800 mb-3">Full Name</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
{% for option in privacy_options %}
<label class="flex items-center p-4 border rounded-lg {% if privacy_settings.full_name == option.value %}bg-green-50 border-irish-green{% endif %}">
<input type="radio" name="full_name_visibility" value="{{ option.value }}"
{% if privacy_settings.full_name == option.value %}checked{% endif %}
class="mr-2 text-irish-green focus:ring-irish-green">
<div>
<span class="font-medium block text-sm">{{ option.label }}</span>
<span class="text-xs text-gray-500">{{ option.description }}</span>
</div>
</label>
{% endfor %}
</div>
</div>
<!-- Teams Visibility -->
<div class="border-b pb-4">
<h3 class="font-medium text-gray-800 mb-3">Teams Membership</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
{% for option in privacy_options %}
<label class="flex items-center p-4 border rounded-lg {% if privacy_settings.teams == option.value %}bg-green-50 border-irish-green{% endif %}">
<input type="radio" name="teams_visibility" value="{{ option.value }}"
{% if privacy_settings.teams == option.value %}checked{% endif %}
class="mr-2 text-irish-green focus:ring-irish-green">
<div>
<span class="font-medium block text-sm">{{ option.label }}</span>
<span class="text-xs text-gray-500">{{ option.description }}</span>
</div>
</label>
{% endfor %}
</div>
</div>
<!-- Points Visibility -->
<div class="border-b pb-4">
<h3 class="font-medium text-gray-800 mb-3">Points & Leaderboard Position</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
{% for option in privacy_options %}
<label class="flex items-center p-4 border rounded-lg {% if privacy_settings.points == option.value %}bg-green-50 border-irish-green{% endif %}">
<input type="radio" name="points_visibility" value="{{ option.value }}"
{% if privacy_settings.points == option.value %}checked{% endif %}
class="mr-2 text-irish-green focus:ring-irish-green">
<div>
<span class="font-medium block text-sm">{{ option.label }}</span>
<span class="text-xs text-gray-500">{{ option.description }}</span>
</div>
</label>
{% endfor %}
</div>
</div>
<!-- Achievements Visibility -->
<div class="border-b pb-4">
<h3 class="font-medium text-gray-800 mb-3">Achievements</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
{% for option in privacy_options %}
<label class="flex items-center p-4 border rounded-lg {% if privacy_settings.achievements == option.value %}bg-green-50 border-irish-green{% endif %}">
<input type="radio" name="achievements_visibility" value="{{ option.value }}"
{% if privacy_settings.achievements == option.value %}checked{% endif %}
class="mr-2 text-irish-green focus:ring-irish-green">
<div>
<span class="font-medium block text-sm">{{ option.label }}</span>
<span class="text-xs text-gray-500">{{ option.description }}</span>
</div>
</label>
{% endfor %}
</div>
</div>
<!-- Events Visibility -->
<div class="border-b pb-4">
<h3 class="font-medium text-gray-800 mb-3">Event Attendance</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
{% for option in privacy_options %}
<label class="flex items-center p-4 border rounded-lg {% if privacy_settings.events == option.value %}bg-green-50 border-irish-green{% endif %}">
<input type="radio" name="events_visibility" value="{{ option.value }}"
{% if privacy_settings.events == option.value %}checked{% endif %}
class="mr-2 text-irish-green focus:ring-irish-green">
<div>
<span class="font-medium block text-sm">{{ option.label }}</span>
<span class="text-xs text-gray-500">{{ option.description }}</span>
</div>
</label>
{% endfor %}
</div>
</div>
<div class="flex justify-between items-center pt-4">
<a href="/auth/profile" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-arrow-left mr-1"></i> Back to Profile
</a>
<button type="submit" class="bg-irish-green text-white py-2 px-6 rounded-md hover:bg-opacity-90 transition">
Save Privacy Settings
</button>
</div>
</div>
</form>
<div class="mt-8 pt-4 border-t border-gray-200 text-sm text-gray-500">
<p><i class="fas fa-shield-alt mr-1"></i> Note: Administrators can always view your complete profile information for support purposes.</p>
</div>
</div>
</div>
{% endblock %}
+49 -4
View File
@@ -9,6 +9,13 @@
</div>
{% endif %}
<!-- Display errors if present -->
{% if error %}
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
{{ error }}
</div>
{% endif %}
<div class="flex flex-col md:flex-row items-center md:items-start md:space-x-8">
<!-- Profile Image -->
<div class="mb-6 md:mb-0">
@@ -19,6 +26,26 @@
{{ user.username[0]|upper }}
</div>
{% endif %}
<!-- Profile Picture Upload Form -->
<div class="mt-3">
<form action="/auth/update-profile-picture" method="post" enctype="multipart/form-data">
<label class="block w-full bg-gray-200 text-center py-2 px-3 rounded{% if not user.picture %}-md{% else %}-t{% endif %} cursor-pointer hover:bg-gray-300 transition">
<i class="fas fa-camera mr-1"></i> Change Picture
<input type="file" name="file" accept="image/jpeg,image/png" class="hidden" onchange="this.form.submit()">
</label>
</form>
{% if user.picture %}
<form action="/auth/delete-profile-picture" method="post">
<button type="submit" class="w-full bg-red-100 text-red-700 text-center py-2 px-3 rounded-b hover:bg-red-200 transition">
<i class="fas fa-trash-alt mr-1"></i> Remove Picture
</button>
</form>
{% endif %}
<p class="text-xs text-gray-500 mt-1 text-center">JPG/PNG only</p>
</div>
</div>
<!-- User Info -->
@@ -41,6 +68,15 @@
<div class="space-y-4">
<h2 class="text-xl font-semibold text-irish-green">Account Settings</h2>
<div class="border-b border-gray-200 pb-4">
<h3 class="text-gray-700 font-medium mb-2">Username</h3>
<form action="/auth/update-username" method="post" class="flex">
<input type="text" name="username" value="{{ user.username }}" class="flex-grow border border-gray-300 rounded-l-md px-3 py-2">
<button type="submit" class="bg-irish-green text-white px-4 py-2 rounded-r-md">Update</button>
</form>
<p class="text-xs text-gray-500 mt-1">Change your username (must be unique)</p>
</div>
<div class="border-b border-gray-200 pb-4">
<h3 class="text-gray-700 font-medium mb-2">Change Password</h3>
<p class="text-sm text-gray-600 mb-3">Update your password to keep your account secure.</p>
@@ -49,13 +85,22 @@
</a>
</div>
<div class="border-b border-gray-200 pb-4">
<h3 class="text-gray-700 font-medium mb-2">Privacy Settings</h3>
<p class="text-sm text-gray-600 mb-3">Control who can see your profile information.</p>
<a href="/auth/privacy-settings" class="inline-block bg-irish-green text-white py-2 px-4 rounded-md hover:bg-opacity-90 transition">
Manage Privacy Settings
</a>
</div>
<div class="pt-4">
<h3 class="text-gray-700 font-medium mb-2">Danger Zone</h3>
<p class="text-sm text-gray-600 mb-3">Permanently delete your account and all of your data.</p>
<button class="border border-red-600 text-red-600 py-2 px-4 rounded-md hover:bg-red-600 hover:text-white transition" disabled>
Delete Account
<span class="text-xs">(Coming Soon)</span>
</button>
<form action="/auth/delete-account" method="post" onsubmit="return confirm('Are you sure you want to delete your account? This action cannot be undone.');">
<button type="submit" class="border border-red-600 text-red-600 py-2 px-4 rounded-md hover:bg-red-600 hover:text-white transition">
Delete Account
</button>
</form>
</div>
</div>
</div>
+123
View File
@@ -0,0 +1,123 @@
{% extends "base.html" %}
{% block content %}
<div class="max-w-4xl mx-auto">
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
<!-- Profile Header -->
<div class="bg-irish-green text-white p-6">
<div class="flex flex-col sm:flex-row items-center">
<div class="w-24 h-24 rounded-full bg-white border-4 border-white overflow-hidden mb-4 sm:mb-0 sm:mr-6">
{% if profile.picture %}
<img src="{{ profile.picture }}" alt="Profile" class="w-full h-full object-cover">
{% else %}
<div class="w-full h-full bg-irish-green flex items-center justify-center text-white text-4xl">
{{ profile.username[0]|upper }}
</div>
{% endif %}
</div>
<div class="text-center sm:text-left">
<h1 class="text-2xl font-bold">{{ profile.username }}</h1>
<p class="text-green-100">Member since {{ profile.created_at.strftime('%B %Y') }}</p>
<p class="mt-2">
{% if profile.is_admin %}
<span class="bg-golden-ale text-black-stout text-xs px-2 py-1 rounded-full font-medium mr-1">Admin</span>
{% endif %}
</p>
</div>
</div>
</div>
<!-- Profile Content -->
<div class="p-6">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<!-- Left Column: Personal Info -->
<div class="md:col-span-1">
<h2 class="text-xl font-semibold text-irish-green mb-4">Profile Information</h2>
<div class="space-y-4">
<div class="bg-cream-white p-4 rounded-lg">
<h3 class="text-sm font-medium text-gray-600 mb-1">Username</h3>
<p class="font-medium">{{ profile.username }}</p>
</div>
{% if "email" in profile %}
<div class="bg-cream-white p-4 rounded-lg">
<h3 class="text-sm font-medium text-gray-600 mb-1">Email</h3>
<p>{{ profile.email }}</p>
</div>
{% endif %}
{% if "first_name" in profile and "last_name" in profile %}
<div class="bg-cream-white p-4 rounded-lg">
<h3 class="text-sm font-medium text-gray-600 mb-1">Full Name</h3>
<p>{{ profile.first_name }} {{ profile.last_name }}</p>
</div>
{% elif "first_name" in profile %}
<div class="bg-cream-white p-4 rounded-lg">
<h3 class="text-sm font-medium text-gray-600 mb-1">First Name</h3>
<p>{{ profile.first_name }}</p>
</div>
{% endif %}
<div class="bg-cream-white p-4 rounded-lg">
<h3 class="text-sm font-medium text-gray-600 mb-1">Account Type</h3>
<p>{% if profile.is_admin %}Administrator{% else %}User{% endif %}</p>
</div>
</div>
</div>
<!-- Right Column: Stats & Teams -->
<div class="md:col-span-2">
{% if profile.can_view_points %}
<div class="mb-6">
<h2 class="text-xl font-semibold text-irish-green mb-4">Statistics</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div class="bg-cream-white p-4 rounded-lg text-center">
<p class="text-sm text-gray-600">Total Points</p>
<p class="text-2xl font-bold text-irish-green">{{ total_points }}</p>
</div>
</div>
</div>
{% endif %}
{% if profile.can_view_teams and teams %}
<div class="mb-6">
<h2 class="text-xl font-semibold text-irish-green mb-4">Teams</h2>
<div class="space-y-4">
{% for team in teams %}
<div class="border rounded-lg overflow-hidden">
<div class="bg-cream-white px-4 py-3 flex justify-between items-center">
<div class="font-medium">{{ team.name }}</div>
{% if team.is_captain %}
<span class="bg-golden-ale text-black-stout text-xs px-2 py-1 rounded-full">Captain</span>
{% else %}
<span class="bg-gray-200 text-gray-700 text-xs px-2 py-1 rounded-full">Member</span>
{% endif %}
</div>
<div class="px-4 py-3">
<a href="/teams/{{ team.id }}" class="text-irish-green hover:underline text-sm">View Team</a>
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if profile.can_view_achievements %}
<div class="mb-6">
<h2 class="text-xl font-semibold text-irish-green mb-4">Achievements</h2>
<p class="text-gray-500 italic">Achievements data will be shown here</p>
</div>
{% endif %}
{% if profile.can_view_events %}
<div>
<h2 class="text-xl font-semibold text-irish-green mb-4">Recent Events</h2>
<p class="text-gray-500 italic">Recent events will be shown here</p>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}
+8 -8
View File
@@ -78,7 +78,7 @@
<i class="fas fa-chevron-down text-xs"></i>
</button>
<div class="dropdown-menu hidden absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1 z-50">
<a href="/profile" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
<a href="/auth/profile" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
<i class="fas fa-user mr-2"></i> Profile
</a>
<a href="/dashboard" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
@@ -90,13 +90,13 @@
</a>
{% endif %}
<div class="border-t border-gray-100 my-1"></div>
<a href="/logout" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
<a href="/auth/logout" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
<i class="fas fa-sign-out-alt mr-2"></i> Logout
</a>
</div>
</div>
{% else %}
<a href="/login" class="bg-golden-ale hover:bg-opacity-90 text-black-stout px-4 py-2 rounded-md transition">Sign In</a>
<a href="/auth/login" class="bg-golden-ale hover:bg-opacity-90 text-black-stout px-4 py-2 rounded-md transition">Sign In</a>
{% endif %}
</div>
@@ -116,14 +116,14 @@
<a href="/leaderboard" class="hover:text-golden-ale transition py-2">Leaderboard</a>
<a href="/dashboard/scan" class="hover:text-golden-ale transition py-2">Scan QR Code</a>
{% if user %}
<a href="/profile" class="hover:text-golden-ale transition py-2">Profile</a>
<a href="/auth/profile" class="hover:text-golden-ale transition py-2">Profile</a>
<a href="/dashboard" class="hover:text-golden-ale transition py-2">Dashboard</a>
{% if user.is_admin %}
<a href="/admin" class="hover:text-golden-ale transition py-2">Admin</a>
{% endif %}
<a href="/logout" class="hover:text-golden-ale transition py-2">Logout</a>
<a href="/auth/logout" class="hover:text-golden-ale transition py-2">Logout</a>
{% else %}
<a href="/login" class="bg-golden-ale hover:bg-opacity-90 text-black-stout px-4 py-2 rounded-md transition text-center">Sign In</a>
<a href="/auth/login" class="bg-golden-ale hover:bg-opacity-90 text-black-stout px-4 py-2 rounded-md transition text-center">Sign In</a>
{% endif %}
</div>
</div>
@@ -161,9 +161,9 @@
<div>
<h3 class="text-golden-ale font-bold mb-4">Account</h3>
<ul class="space-y-2">
<li><a href="/login" class="hover:text-golden-ale transition">Sign In</a></li>
<li><a href="/auth/login" class="hover:text-golden-ale transition">Sign In</a></li>
<li><a href="/register" class="hover:text-golden-ale transition">Register</a></li>
<li><a href="/profile" class="hover:text-golden-ale transition">Profile</a></li>
<li><a href="/auth/profile" class="hover:text-golden-ale transition">Profile</a></li>
<li><a href="/dashboard" class="hover:text-golden-ale transition">Dashboard</a></li>
</ul>
</div>
+1 -1
View File
@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block content %}
<div class="space-y-6">
<div class="max-w-4xl mx-auto space-y-6">
<!-- User Welcome -->
<div class="bg-white rounded-lg shadow-md p-6">
<h1 class="text-2xl md:text-3xl font-garamond text-irish-green mb-2">Welcome, {{ user.username }}!</h1>
+3 -3
View File
@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block content %}
<div class="flex flex-col items-center">
<div class="max-w-4xl mx-auto">
<!-- Hero Section -->
<section class="w-full py-8 md:py-16 text-center">
<h1 class="text-4xl md:text-6xl font-bold text-irish-green mb-4">PubQuiz League Tracker</h1>
@@ -13,9 +13,9 @@
<!-- Features -->
<section class="w-full py-12 bg-white rounded-lg shadow-md my-8">
<div class="container mx-auto">
<div class="container mx-auto px-4">
<h2 class="text-3xl font-bold text-irish-green text-center mb-10">How It Works</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 px-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<div class="flex flex-col items-center text-center">
<div class="bg-cream-white p-4 rounded-full mb-4">
<i class="fas fa-users text-irish-green text-3xl"></i>
+70 -23
View File
@@ -6,13 +6,21 @@
<div class="bg-irish-green text-white p-6">
<div class="flex flex-col sm:flex-row items-center">
<div class="w-24 h-24 rounded-full bg-white border-4 border-white overflow-hidden mb-4 sm:mb-0 sm:mr-6">
<img src="https://picsum.photos/150" alt="Profile" class="w-full h-full object-cover">
{% if user.picture %}
<img src="{{ user.picture }}" alt="Profile" class="w-full h-full object-cover">
{% else %}
<div class="w-full h-full bg-irish-green flex items-center justify-center text-white text-4xl">
{{ user.username[0]|upper }}
</div>
{% endif %}
</div>
<div class="text-center sm:text-left">
<h1 class="text-2xl font-bold">John Quizmaster</h1>
<p class="text-green-100">Member since October 2022</p>
<h1 class="text-2xl font-bold">{{ user.username }}</h1>
<p class="text-green-100">Member since {{ user.created_at.strftime('%B %Y') }}</p>
<p class="mt-2">
<span class="bg-golden-ale text-black-stout text-xs px-2 py-1 rounded-full font-medium mr-1">Quiz Master</span>
{% if user.is_admin %}
<span class="bg-golden-ale text-black-stout text-xs px-2 py-1 rounded-full font-medium mr-1">Admin</span>
{% endif %}
<span class="bg-white text-irish-green text-xs px-2 py-1 rounded-full font-medium">Team Captain</span>
</p>
</div>
@@ -21,45 +29,82 @@
<!-- Profile Content -->
<div class="p-6">
<!-- Display messages if present -->
{% if request.query_params.message %}
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded mb-4">
{{ request.query_params.message }}
</div>
{% endif %}
<!-- Display errors if present -->
{% if error %}
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
{{ error }}
</div>
{% endif %}
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<!-- Left Column: Personal Info -->
<div class="md:col-span-1">
<h2 class="text-xl font-semibold text-irish-green mb-4">Personal Information</h2>
<div class="space-y-4">
<!-- Username -->
<div>
<label class="block text-sm font-medium text-gray-600">Display Name</label>
<div class="mt-1 flex">
<input type="text" value="John Quizmaster" readonly class="flex-grow bg-gray-100 border border-gray-300 rounded-l-md px-3 py-2">
<button class="bg-irish-green text-white px-3 py-2 rounded-r-md">
<i class="fas fa-pencil-alt"></i>
<form action="/auth/update-username" method="post" class="mt-1 flex">
<input type="text" name="username" value="{{ user.username }}" class="flex-grow border border-gray-300 rounded-l-md px-3 py-2">
<button type="submit" class="bg-irish-green text-white px-3 py-2 rounded-r-md">
<i class="fas fa-save"></i>
</button>
</div>
</form>
<p class="text-xs text-gray-500 mt-1">Change your username (must be unique)</p>
</div>
<!-- Email -->
<div>
<label class="block text-sm font-medium text-gray-600">Email</label>
<div class="mt-1 flex">
<input type="email" value="john@example.com" readonly class="flex-grow bg-gray-100 border border-gray-300 rounded-l-md px-3 py-2">
<button class="bg-irish-green text-white px-3 py-2 rounded-r-md">
<i class="fas fa-pencil-alt"></i>
</button>
<input type="email" value="{{ user.email }}" readonly class="flex-grow bg-gray-100 border border-gray-300 rounded-md px-3 py-2">
</div>
</div>
<!-- Profile Picture -->
<div>
<label class="block text-sm font-medium text-gray-600">Profile Picture</label>
<form action="/auth/update-profile-picture" method="post" enctype="multipart/form-data" class="mt-1">
<div class="flex items-center">
<label class="flex-grow bg-golden-ale hover:bg-opacity-90 text-black font-medium py-2 px-4 rounded-l-md cursor-pointer text-center transition">
<i class="fas fa-camera mr-1"></i> Upload Photo
<input type="file" name="file" accept="image/jpeg,image/png" class="hidden" onchange="this.form.submit()">
</label>
<button type="submit" class="bg-irish-green text-white px-3 py-2 rounded-r-md">
<i class="fas fa-upload"></i>
</button>
</div>
<p class="text-xs text-gray-500 mt-1">JPG or PNG formats only</p>
</form>
</div>
<!-- Password -->
<div>
<label class="block text-sm font-medium text-gray-600">Password</label>
<div class="mt-1">
<button class="w-full bg-golden-ale hover:bg-opacity-90 text-black font-medium py-2 px-4 rounded-md transition">
<a href="/auth/change-password" class="block w-full bg-golden-ale hover:bg-opacity-90 text-black font-medium py-2 px-4 rounded-md transition text-center">
Change Password
</button>
</a>
</div>
</div>
<div class="pt-4">
<button class="w-full bg-irish-green hover:bg-opacity-90 text-white font-medium py-2 px-4 rounded-md transition">
Save Changes
</button>
<!-- Privacy Settings -->
<div class="mt-4">
<label class="block text-sm font-medium text-gray-600">Privacy</label>
<div class="mt-1">
<a href="/auth/privacy-settings" class="block w-full bg-golden-ale hover:bg-opacity-90 text-black font-medium py-2 px-4 rounded-md transition text-center">
<i class="fas fa-user-shield mr-1"></i> Privacy Settings
</a>
</div>
<p class="text-xs text-gray-500 mt-1">Control who can see your information</p>
</div>
</div>
</div>
@@ -132,9 +177,11 @@
<p class="text-gray-600 mb-4">The following actions are irreversible. Please proceed with caution.</p>
<div class="flex flex-col sm:flex-row gap-4">
<button class="bg-gray-200 hover:bg-gray-300 text-gray-800 font-medium py-2 px-4 rounded-md transition">
Delete Account
</button>
<form action="/auth/delete-account" method="post" onsubmit="return confirm('Are you sure you want to delete your account? This action cannot be undone.');">
<button type="submit" class="bg-white hover:bg-red-50 text-red-600 border border-red-600 font-medium py-2 px-4 rounded-md transition">
Delete Account
</button>
</form>
<button class="bg-gray-200 hover:bg-gray-300 text-gray-800 font-medium py-2 px-4 rounded-md transition">
Leave All Teams
</button>
+11 -3
View File
@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block content %}
<div class="space-y-6">
<div class="max-w-4xl mx-auto space-y-6">
<!-- Team Header -->
<div class="bg-white rounded-lg shadow-md overflow-hidden">
<div class="bg-irish-green p-6">
@@ -88,10 +88,18 @@
<div class="flex items-center justify-between">
<div class="flex items-center">
<div class="w-10 h-10 rounded-full bg-gray-200 mr-3 overflow-hidden">
<img src="https://picsum.photos/40" alt="User" class="w-full h-full object-cover">
{% if member.user.picture %}
<img src="{{ member.user.picture }}" alt="User" class="w-full h-full object-cover">
{% else %}
<div class="w-full h-full bg-irish-green flex items-center justify-center text-white text-sm">
{{ member.user.username[0]|upper }}
</div>
{% endif %}
</div>
<div>
<p class="font-medium">{{ member.user.username }}</p>
<p class="font-medium">
<a href="/auth/user/{{ member.user.id }}" class="hover:text-irish-green">{{ member.user.username }}</a>
</p>
<p class="text-xs text-gray-500">Joined {{ member.joined }}</p>
</div>
</div>
+94 -92
View File
@@ -1,107 +1,109 @@
{% extends "base.html" %}
{% block content %}
<h2 class="text-2xl font-bold mb-6">Teams</h2>
<div class="max-w-4xl mx-auto">
<h2 class="text-2xl font-bold mb-6">Teams</h2>
{% if error %}
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-6" role="alert">
<span class="block sm:inline">{{ error }}</span>
</div>
{% endif %}
{% if error %}
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-6" role="alert">
<span class="block sm:inline">{{ error }}</span>
</div>
{% endif %}
<div class="grid md:grid-cols-2 gap-6">
<div class="bg-white p-6 rounded-lg shadow-md">
<h3 class="text-xl font-semibold mb-4" style="color: var(--irish-green);">Available Teams</h3>
{% if teams %}
<ul class="space-y-3">
{% for team in teams %}
<li class="border-b pb-2 flex justify-between items-center">
<a href="/teams/{{ team.id }}" class="font-medium hover:text-irish-green">{{ team.name }}</a>
{% if user %}
{% if team.id in user_team_ids %}
<span class="px-3 py-1 text-sm rounded-md bg-gray-200 text-gray-800">Member</span>
<div class="grid md:grid-cols-2 gap-6">
<div class="bg-white p-6 rounded-lg shadow-md">
<h3 class="text-xl font-semibold mb-4" style="color: var(--irish-green);">Available Teams</h3>
{% if teams %}
<ul class="space-y-3">
{% for team in teams %}
<li class="border-b pb-2 flex justify-between items-center">
<a href="/teams/{{ team.id }}" class="font-medium hover:text-irish-green">{{ team.name }}</a>
{% if user %}
{% if team.id in user_team_ids %}
<span class="px-3 py-1 text-sm rounded-md bg-gray-200 text-gray-800">Member</span>
{% else %}
<form action="/teams/join/{{ team.id }}" method="post" class="inline">
<button type="submit"
class="px-3 py-1 text-sm rounded-md"
style="background-color: var(--golden-ale); color: var(--black-stout);">
Join Team
</button>
</form>
{% endif %}
{% else %}
<form action="/teams/join/{{ team.id }}" method="post" class="inline">
<button type="submit"
class="px-3 py-1 text-sm rounded-md"
style="background-color: var(--golden-ale); color: var(--black-stout);">
Join Team
</button>
</form>
<a href="/auth/login?next=/teams"
class="px-3 py-1 text-sm rounded-md"
style="background-color: var(--cream-white); color: var(--irish-green); border: 1px solid var(--irish-green);">
Login to Join
</a>
{% endif %}
{% else %}
<a href="/auth/login?next=/teams"
class="px-3 py-1 text-sm rounded-md"
style="background-color: var(--cream-white); color: var(--irish-green); border: 1px solid var(--irish-green);">
Login to Join
</a>
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<p class="italic text-gray-500">No teams available yet.</p>
{% endif %}
</div>
</li>
{% endfor %}
</ul>
{% else %}
<p class="italic text-gray-500">No teams available yet.</p>
{% endif %}
</div>
<div class="bg-white p-6 rounded-lg shadow-md">
<h3 class="text-xl font-semibold mb-4" style="color: var(--irish-green);">Create New Team</h3>
{% if user %}
<form action="/teams/create" method="post" class="mt-4">
<div class="mb-4">
<label for="name" class="block text-sm font-medium mb-1">Team Name</label>
<input type="text" name="name" id="name" placeholder="Enter team name" required
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2"
style="border-color: var(--irish-green); focus:ring-color: var(--irish-green);">
</div>
<button type="submit"
class="w-full px-4 py-2 text-white rounded-md font-medium"
style="background-color: var(--irish-green);">
Create Team
</button>
</form>
{% else %}
<div class="p-4 bg-gray-100 rounded-md">
<p class="text-center mb-2">You need to be logged in to create a team</p>
<a href="/auth/login"
class="block w-full text-center px-4 py-2 text-white rounded-md font-medium"
style="background-color: var(--irish-green);">
Log In
</a>
</div>
{% endif %}
</div>
</div>
{% if user and user_team_ids %}
<div class="mt-8">
<h2 class="text-2xl font-bold mb-4">Your Teams</h2>
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{% for team in teams %}
{% if team.id in user_team_ids %}
<div class="bg-white p-6 rounded-lg shadow-md">
<h3 class="text-xl font-semibold mb-2" style="color: var(--irish-green);">{{ team.name }}</h3>
<div class="bg-white p-6 rounded-lg shadow-md">
<h3 class="text-xl font-semibold mb-4" style="color: var(--irish-green);">Create New Team</h3>
{% if user %}
<form action="/teams/create" method="post" class="mt-4">
<div class="mb-4">
<span class="text-gray-600">{{ team.description|default("No description available", true)|truncate(120) }}</span>
<label for="name" class="block text-sm font-medium mb-1">Team Name</label>
<input type="text" name="name" id="name" placeholder="Enter team name" required
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2"
style="border-color: var(--irish-green); focus:ring-color: var(--irish-green);">
</div>
<a href="/teams/{{ team.id }}"
class="block text-center w-full px-4 py-2 text-white rounded-md font-medium"
style="background-color: var(--irish-green);">
View Team
<button type="submit"
class="w-full px-4 py-2 text-white rounded-md font-medium"
style="background-color: var(--irish-green);">
Create Team
</button>
</form>
{% else %}
<div class="p-4 bg-gray-100 rounded-md">
<p class="text-center mb-2">You need to be logged in to create a team</p>
<a href="/auth/login"
class="block w-full text-center px-4 py-2 text-white rounded-md font-medium"
style="background-color: var(--irish-green);">
Log In
</a>
</div>
{% endif %}
{% endfor %}
</div>
</div>
{% if user and user_team_ids %}
<div class="mt-8">
<h2 class="text-2xl font-bold mb-4">Your Teams</h2>
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{% for team in teams %}
{% if team.id in user_team_ids %}
<div class="bg-white p-6 rounded-lg shadow-md">
<h3 class="text-xl font-semibold mb-2" style="color: var(--irish-green);">{{ team.name }}</h3>
<div class="mb-4">
<span class="text-gray-600">{{ team.description|default("No description available", true)|truncate(120) }}</span>
</div>
<a href="/teams/{{ team.id }}"
class="block text-center w-full px-4 py-2 text-white rounded-md font-medium"
style="background-color: var(--irish-green);">
View Team
</a>
</div>
{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
<div class="mt-10 bg-white p-6 rounded-lg shadow-md">
<h3 class="text-xl font-semibold mb-4" style="color: var(--irish-green);">About Teams</h3>
<p class="mb-4">
Teams are the heart of LeagueLedger. Join an existing team or create your own to start tracking your pub quiz triumphs!
</p>
<p class="italic">
Every point counts in the journey to becoming pub quiz champions.
</p>
</div>
</div>
{% endif %}
<div class="mt-10 bg-white p-6 rounded-lg shadow-md">
<h3 class="text-xl font-semibold mb-4" style="color: var(--irish-green);">About Teams</h3>
<p class="mb-4">
Teams are the heart of LeagueLedger. Join an existing team or create your own to start tracking your pub quiz triumphs!
</p>
<p class="italic">
Every point counts in the journey to becoming pub quiz champions.
</p>
</div>
{% endblock %}