ATS/templates/user/profile.html
2026-01-29 14:19:03 +03:00

453 lines
22 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% block title %}{% trans "User Profile" %} - ATS{% endblock %}
{% block customCSS %}
<style>
/* Profile Avatar Animation */
.profile-avatar-wrapper {
transition: all 0.3s ease;
}
.profile-avatar-wrapper:hover {
transform: scale(1.05);
box-shadow: 0 0 0 4px rgba(157, 34, 53, 0.2);
}
.profile-avatar {
transition: all 0.3s ease;
}
/* Card Hover Effects */
.profile-card {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.profile-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
}
/* Button Hover Effects */
.btn-primary {
transition: all 0.2s ease;
}
.btn-primary:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(157, 34, 53, 0.4);
}
.btn-secondary {
transition: all 0.2s ease;
}
.btn-secondary:hover {
background-color: rgba(157, 34, 53, 0.05);
border-color: rgba(157, 34, 53, 0.3);
}
/* Input Focus Animation */
.form-input {
transition: all 0.2s ease;
}
.form-input:focus {
transform: translateY(-1px);
}
/* Status Indicators */
.status-dot {
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
/* Modal Animation */
.modal-backdrop {
animation: fadeIn 0.2s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.modal-content {
animation: slideUp 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
/* Info Item Styling */
.info-item {
transition: all 0.2s ease;
}
.info-item:hover {
background-color: rgba(157, 34, 53, 0.02);
}
</style>
{% endblock %}
{% block content %}
<div class="max-w-7xl mx-auto py-8 px-4 sm:px-6 lg:px-8">
<!-- Profile Header -->
<div class="bg-gradient-to-r from-temple-red to-red-700 rounded-2xl shadow-2xl p-6 sm:p-8 mb-8 relative overflow-hidden">
<!-- Decorative Elements -->
<div class="absolute top-0 right-0 w-64 h-64 bg-white/5 rounded-full -translate-y-1/2 translate-x-1/2"></div>
<div class="absolute bottom-0 left-0 w-48 h-48 bg-white/5 rounded-full translate-y-1/2 -translate-x-1/2"></div>
<div class="relative flex flex-col sm:flex-row items-center sm:items-start gap-6 sm:gap-8">
<!-- Avatar -->
<div class="profile-avatar-wrapper relative">
<div class="absolute -bottom-1 -right-1 w-6 h-6 bg-temple-cream rounded-full flex items-center justify-center shadow-md border-2 border-temple-red">
<div class="w-3 h-3 bg-green-500 rounded-full status-dot"></div>
</div>
{% if user.profile_image %}
<img src="{{ user.profile_image.url }}"
alt="{{ user.get_full_name|default:user.username }}"
class="profile-avatar w-28 h-28 sm:w-32 sm:h-32 rounded-full border-4 border-temple-cream shadow-lg object-cover">
{% else %}
<div class="profile-avatar w-28 h-28 sm:w-32 sm:h-32 rounded-full border-4 border-temple-cream shadow-lg bg-temple-cream flex items-center justify-center">
<i data-lucide="user" class="w-16 h-16 text-temple-red"></i>
</div>
{% endif %}
</div>
<!-- User Info -->
<div class="text-center sm:text-left flex-1">
<h1 class="text-2xl sm:text-3xl font-bold text-white mb-2">
{{ user.get_full_name|default:user.username }}
</h1>
<p class="text-white/80 text-sm sm:text-base mb-3">
{{ user.email }}
</p>
<div class="flex flex-wrap items-center justify-center sm:justify-start gap-3">
<span class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-white/20 backdrop-blur-sm rounded-full text-white text-sm font-medium">
<i data-lucide="shield-check" class="w-4 h-4"></i>
{% trans "Verified Account" %}
</span>
<span class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-white/20 backdrop-blur-sm rounded-full text-white text-sm font-medium">
<i data-lucide="calendar" class="w-4 h-4"></i>
{{ user.date_joined|date:"F Y" }}
</span>
</div>
</div>
<!-- Quick Actions -->
<div class="flex flex-col gap-2">
<button type="button"
onclick="document.getElementById('imageModal').classList.remove('hidden')"
class="btn-primary inline-flex items-center justify-center gap-2 px-5 py-2.5 bg-white text-temple-red rounded-lg font-semibold shadow-lg hover:shadow-xl">
<i data-lucide="camera" class="w-4 h-4"></i>
{% trans "Change Photo" %}
</button>
</div>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 lg:gap-8">
<!-- Left Column - Personal Information (2/3 width) -->
<div class="lg:col-span-2 space-y-6">
<!-- Personal Info Card -->
<div class="profile-card bg-white rounded-2xl shadow-sm border border-gray-200 overflow-hidden">
<!-- Card Header -->
<div class="px-6 py-4 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-temple-red/10 flex items-center justify-center">
<i data-lucide="user-circle" class="w-5 h-5 text-temple-red"></i>
</div>
<div>
<h2 class="text-lg font-bold text-gray-900">{% trans "Personal Information" %}</h2>
<p class="text-sm text-gray-500">{% trans "Update your personal details" %}</p>
</div>
</div>
</div>
<!-- Card Body -->
<div class="p-6 sm:p-8">
<form method="POST" action="{% url 'user_detail' user.pk %}" class="space-y-6">
{% csrf_token %}
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- First Name -->
<div class="space-y-2">
<label for="id_first_name" class="flex items-center gap-2 text-sm font-semibold text-gray-700">
<i data-lucide="user" class="w-4 h-4 text-gray-400"></i>
{% trans "First Name" %}
</label>
<input type="text"
class="form-input w-full px-4 py-3 rounded-xl border-2 border-gray-200 bg-white focus:outline-none focus:border-temple-red focus:ring-4 focus:ring-temple-red/10 text-gray-900 placeholder-gray-400"
id="id_first_name"
name="first_name"
value="{{ user.first_name|default:'' }}"
placeholder="{% trans 'Enter your first name' %}">
</div>
<!-- Last Name -->
<div class="space-y-2">
<label for="id_last_name" class="flex items-center gap-2 text-sm font-semibold text-gray-700">
<i data-lucide="user" class="w-4 h-4 text-gray-400"></i>
{% trans "Last Name" %}
</label>
<input type="text"
class="form-input w-full px-4 py-3 rounded-xl border-2 border-gray-200 bg-white focus:outline-none focus:border-temple-red focus:ring-4 focus:ring-temple-red/10 text-gray-900 placeholder-gray-400"
id="id_last_name"
name="last_name"
value="{{ user.last_name|default:'' }}"
placeholder="{% trans 'Enter your last name' %}">
</div>
<!-- Email -->
<div class="md:col-span-2 space-y-2">
<label for="id_email" class="flex items-center gap-2 text-sm font-semibold text-gray-700">
<i data-lucide="mail" class="w-4 h-4 text-gray-400"></i>
{% trans "Email Address" %}
</label>
<div class="relative">
<input type="email"
class="form-input w-full px-4 py-3 pr-12 rounded-xl border-2 border-gray-200 bg-gray-50 text-gray-500 cursor-not-allowed"
id="id_email"
value="{{ user.email }}"
disabled>
<i data-lucide="lock" class="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"></i>
</div>
<div class="flex items-center gap-2 text-sm text-gray-600">
<i data-lucide="info" class="w-4 h-4"></i>
<a href="{% url 'account_email' %}"
class="font-medium text-temple-red hover:text-red-700 transition-colors">
{% trans "Manage email addresses →" %}
</a>
</div>
</div>
</div>
<!-- Save Button -->
<div class="pt-4 flex items-center gap-3">
<button type="submit"
class="btn-primary inline-flex items-center gap-2 px-8 py-3 bg-temple-red text-white rounded-xl font-semibold shadow-lg hover:shadow-xl">
<i data-lucide="save" class="w-5 h-5"></i>
{% trans "Save Changes" %}
</button>
<span class="text-sm text-gray-500">
{% trans "Changes are saved automatically" %}
</span>
</div>
</form>
</div>
</div>
</div>
<!-- Right Column - Security & Status (1/3 width) -->
<div class="space-y-6">
<!-- Security Card -->
<div class="profile-card bg-white rounded-2xl shadow-sm border border-gray-200 overflow-hidden">
<!-- Card Header -->
<div class="px-6 py-4 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-temple-red/10 flex items-center justify-center">
<i data-lucide="shield" class="w-5 h-5 text-temple-red"></i>
</div>
<div>
<h2 class="text-lg font-bold text-gray-900">{% trans "Security" %}</h2>
<p class="text-sm text-gray-500">{% trans "Protect your account" %}</p>
</div>
</div>
</div>
<!-- Card Body -->
<div class="p-6 space-y-3">
<a href="{% url 'account_change_password' %}"
class="btn-primary w-full inline-flex items-center justify-center gap-2 px-5 py-3.5 bg-temple-red text-white rounded-xl font-semibold shadow-md hover:shadow-lg">
<i data-lucide="lock" class="w-5 h-5"></i>
{% trans "Change Password" %}
</a>
<button type="button"
onclick="document.getElementById('imageModal').classList.remove('hidden')"
class="btn-secondary w-full inline-flex items-center justify-center gap-2 px-5 py-3.5 border-2 border-gray-200 text-gray-700 rounded-xl font-semibold hover:border-temple-red">
<i data-lucide="image" class="w-5 h-5"></i>
{% trans "Change Profile Image" %}
</button>
</div>
</div>
<!-- Account Status Card -->
<div class="profile-card bg-white rounded-2xl shadow-sm border border-gray-200 overflow-hidden">
<!-- Card Header -->
<div class="px-6 py-4 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-temple-red/10 flex items-center justify-center">
<i data-lucide="activity" class="w-5 h-5 text-temple-red"></i>
</div>
<div>
<h2 class="text-lg font-bold text-gray-900">{% trans "Account Details" %}</h2>
<p class="text-sm text-gray-500">{% trans "Your account info" %}</p>
</div>
</div>
</div>
<!-- Card Body -->
<div class="p-6 space-y-4">
<div class="info-item p-3 rounded-xl bg-gray-50">
<div class="flex items-center gap-2 text-sm text-gray-500 mb-1">
<i data-lucide="user" class="w-4 h-4"></i>
{% trans "Username" %}
</div>
<div class="text-base font-bold text-gray-900">{{ user.username }}</div>
</div>
<div class="info-item p-3 rounded-xl bg-gray-50">
<div class="flex items-center gap-2 text-sm text-gray-500 mb-1">
<i data-lucide="clock" class="w-4 h-4"></i>
{% trans "Last Login" %}
</div>
<div class="text-base font-bold text-gray-900">
{% if user.last_login %}{{ user.last_login|date:"F d, Y P" }}{% else %}N/A{% endif %}
</div>
</div>
<div class="info-item p-3 rounded-xl bg-gray-50">
<div class="flex items-center gap-2 text-sm text-gray-500 mb-1">
<i data-lucide="calendar-plus" class="w-4 h-4"></i>
{% trans "Date Joined" %}
</div>
<div class="text-base font-bold text-gray-900">{{ user.date_joined|date:"F d, Y" }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Image Upload Modal -->
<div id="imageModal" class="fixed inset-0 modal-backdrop bg-black/60 backdrop-blur-sm hidden items-center justify-center z-50 p-4">
<div class="modal-content bg-white rounded-2xl shadow-2xl w-full max-w-lg mx-auto">
<!-- Modal Header -->
<div class="flex items-center justify-between px-6 py-5 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white rounded-t-2xl">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-temple-red/10 flex items-center justify-center">
<i data-lucide="upload" class="w-5 h-5 text-temple-red"></i>
</div>
<h3 class="text-xl font-bold text-gray-900">{% trans "Upload Profile Image" %}</h3>
</div>
<button onclick="document.getElementById('imageModal').classList.add('hidden')"
class="w-10 h-10 rounded-xl bg-gray-100 hover:bg-gray-200 flex items-center justify-center text-gray-400 hover:text-gray-600 transition-colors">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<!-- Modal Body -->
<div class="p-6 sm:p-8">
<form method="post" action="{% url 'user_profile_image_update' user.pk %}" enctype="multipart/form-data" class="space-y-6">
{% csrf_token %}
<div class="space-y-4">
<label for="{{ profile_form.profile_image.id_for_label }}" class="flex items-center gap-2 text-sm font-semibold text-gray-700">
<i data-lucide="image" class="w-4 h-4 text-gray-400"></i>
{% trans "Profile Image" %}
</label>
{% if profile_form.instance.profile_image %}
<!-- Current Image -->
<div class="p-4 rounded-xl bg-gray-50 border-2 border-dashed border-gray-200">
<div class="flex items-center gap-4 mb-3">
<div class="w-16 h-16 rounded-xl bg-temple-red/10 flex items-center justify-center shrink-0">
<i data-lucide="check" class="w-8 h-8 text-temple-red"></i>
</div>
<div class="flex-1 min-w-0">
<div class="text-sm font-semibold text-gray-900">{% trans "Current Image" %}</div>
<div class="text-xs text-gray-500 truncate">{{ profile_form.instance.profile_image.name }}</div>
</div>
</div>
<div class="flex items-center gap-4">
<a href="{{ profile_form.instance.profile_image.url }}" target="_blank"
class="btn-primary inline-flex items-center gap-2 px-4 py-2.5 bg-temple-red text-white rounded-lg font-semibold text-sm">
<i data-lucide="eye" class="w-4 h-4"></i>
{% trans "View Original" %}
</a>
<img src="{{ profile_form.instance.profile_image.url }}"
alt="Current Profile Image"
class="w-20 h-20 rounded-xl object-cover border-2 border-white shadow-md">
</div>
</div>
<!-- Upload New -->
<div class="pt-4">
{{ profile_form.profile_image }}
</div>
{% else %}
<!-- No Current Image -->
<div class="p-8 rounded-xl border-2 border-dashed border-gray-200 bg-gray-50 hover:border-temple-red/50 hover:bg-temple-red/5 transition-all cursor-pointer">
<div class="flex flex-col items-center gap-3 text-center">
<div class="w-16 h-16 rounded-full bg-temple-red/10 flex items-center justify-center">
<i data-lucide="upload-cloud" class="w-8 h-8 text-temple-red"></i>
</div>
<div>
<div class="font-semibold text-gray-900">{% trans "No profile image yet" %}</div>
<div class="text-sm text-gray-500">{% trans "Upload your first profile picture" %}</div>
</div>
</div>
{{ profile_form.profile_image }}
</div>
{% endif %}
{% for error in profile_form.profile_image.errors %}
<div class="flex items-start gap-2 p-3 bg-red-50 border border-red-200 rounded-xl text-red-600 text-sm">
<i data-lucide="alert-circle" class="w-4 h-4 shrink-0 mt-0.5"></i>
{{ error }}
</div>
{% endfor %}
</div>
<!-- Modal Actions -->
<div class="flex gap-3 pt-4 border-t border-gray-100">
<button type="button"
onclick="document.getElementById('imageModal').classList.add('hidden')"
class="btn-secondary flex-1 inline-flex items-center justify-center gap-2 px-6 py-3 border-2 border-gray-200 text-gray-700 rounded-xl font-semibold hover:border-gray-300">
{% trans "Cancel" %}
</button>
<button type="submit"
class="btn-primary flex-1 inline-flex items-center justify-center gap-2 px-6 py-3 bg-temple-red text-white rounded-xl font-semibold shadow-lg hover:shadow-xl">
<i data-lucide="upload" class="w-5 h-5"></i>
{% trans "Upload Image" %}
</button>
</div>
</form>
</div>
</div>
</div>
<script>
// Initialize Lucide icons
lucide.createIcons();
</script>
{% endblock %}