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 %}