267 lines
10 KiB
HTML
267 lines
10 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
{% load i18n %}
|
|
|
|
{% block title %}{% trans "User Profile" %} - KAAUH ATS{% endblock %}
|
|
|
|
{% block customCSS %}
|
|
<style>
|
|
/* Theme Variables based on Teal Accent */
|
|
:root {
|
|
--bs-primary: #00636e;
|
|
--bs-primary-rgb: 0, 99, 110;
|
|
--bs-primary-light: #007a88;
|
|
--bs-body-bg: #f3f5f8; /* Soft light gray background */
|
|
--bs-body-color: #212529;
|
|
--bs-border-color: #e9ecef; /* Lighter, softer border */
|
|
}
|
|
|
|
|
|
|
|
/* Card Refinements for Depth and Geometry */
|
|
.card {
|
|
border: none;
|
|
border-radius: 1rem;
|
|
box-shadow: 0 8px 30px rgba(0,0,0,0.08); /* Deeper, softer shadow */
|
|
transition: transform 0.2s ease-out, box-shadow 0.2s ease-out;
|
|
}
|
|
.card:hover {
|
|
transform: translateY(-2px); /* Subtle lift on hover */
|
|
box-shadow: 0 12px 35px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
/* Profile Header Consistency */
|
|
.profile-header {
|
|
border-bottom: 2px solid var(--bs-border-color);
|
|
padding-bottom: 1.5rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
/* Form Consistency */
|
|
.form-control {
|
|
border-radius: 0.5rem;
|
|
padding: 0.75rem 1rem;
|
|
border-color: var(--bs-border-color);
|
|
transition: border-color 0.2s, box-shadow 0.2s;
|
|
font-size: 0.95rem; /* Slightly larger text in fields */
|
|
}
|
|
.form-control:focus {
|
|
border-color: var(--bs-primary-light);
|
|
box-shadow: 0 0 0 0.15rem rgba(0, 99, 110, 0.15);
|
|
}
|
|
.form-label {
|
|
font-size: 0.9rem;
|
|
font-weight: 600;
|
|
color: #495057; /* Slightly darker than default mute */
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
/* Button Consistency (Primary) */
|
|
.btn-primary {
|
|
background-color: var(--bs-primary);
|
|
border-color: var(--bs-primary);
|
|
font-weight: 700;
|
|
border-radius: 0.6rem;
|
|
padding: 0.65rem 1.5rem;
|
|
box-shadow: 0 5px 15px rgba(0, 99, 110, 0.3);
|
|
transition: all 0.2s ease;
|
|
}
|
|
.btn-primary:hover {
|
|
background-color: var(--bs-primary-light);
|
|
border-color: var(--bs-primary-light);
|
|
box-shadow: 0 8px 18px rgba(0, 99, 110, 0.4);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
/* Button Consistency (Outline/Secondary) */
|
|
.btn-outline-secondary {
|
|
color: #495057;
|
|
border-color: var(--bs-border-color);
|
|
font-weight: 500;
|
|
transition: all 0.2s ease;
|
|
}
|
|
.btn-outline-secondary:hover {
|
|
color: var(--bs-primary); /* Accent text color on hover */
|
|
background-color: rgba(0, 99, 110, 0.05);
|
|
border-color: var(--bs-primary);
|
|
}
|
|
|
|
/* Accent & Info Text */
|
|
.text-accent {
|
|
color: var(--bs-primary) !important;
|
|
font-weight: 600;
|
|
}
|
|
.info-value {
|
|
font-weight: 700; /* Bolder status values */
|
|
color: var(--bs-body-color);
|
|
}
|
|
.info-label {
|
|
color: #6c757d;
|
|
font-size: 0.85rem;
|
|
margin-bottom: 0.2rem;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container mt-4" style="max-width: 900px;">
|
|
|
|
<div class="profile-header d-flex align-items-center justify-content-between">
|
|
<div>
|
|
<h1 class="h3 fw-bold mb-1">{% trans "Account Settings" %}</h1>
|
|
<p class="text-muted mb-0">{% trans "Manage your personal details and security." %}</p>
|
|
</div>
|
|
<div class="rounded-circle bg-primary-subtle text-accent d-flex align-items-center justify-content-center" style="width: 50px; height: 50px; font-size: 1.5rem;">
|
|
{% if user.profile_image.url %}
|
|
<img src="{{ user.profile_image.url }}" alt="{{ user.username }}" class="profile-avatar"
|
|
style="width: 100px; height: 100px; object-fit: cover; background-color: var(--kaauh-teal); display: inline-block; vertical-align: middle;"
|
|
title="{% trans 'Your account' %}">
|
|
{% else %}
|
|
{% if user.first_name %}{{ user.first_name.0 }}{% else %}<i class="fas fa-user"></i>{% endif %}
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-4">
|
|
|
|
<div class="col-lg-7">
|
|
<div class="card p-5">
|
|
<h5 class="fw-bold mb-4 text-accent">{% trans "Personal Information" %}</h5>
|
|
|
|
<form method="POST" action="{% url 'user_detail' user.pk %}">
|
|
{% csrf_token %}
|
|
|
|
<div class="row g-4"> <div class="col-md-6">
|
|
<label for="id_first_name" class="form-label">{% trans "First Name" %}</label>
|
|
<input type="text" class="form-control" id="id_first_name" name="first_name" value="{{ user.first_name|default:'' }}">
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<label for="id_last_name" class="form-label">{% trans "Last Name" %}</label>
|
|
<input type="text" class="form-control" id="id_last_name" name="last_name" value="{{ user.last_name|default:'' }}">
|
|
</div>
|
|
|
|
<div class="col-12">
|
|
<label for="id_email" class="form-label">{% trans "Email Address" %}</label>
|
|
<input type="email" class="form-control" id="id_email" value="{{ user.email }}" disabled>
|
|
<div class="form-text mt-2">
|
|
<a href="{% url 'account_email' %}" class="small text-accent">{% trans "Manage email addresses" %}</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 mt-4 pt-2">
|
|
<button type="submit" class="btn btn-primary">{% trans "Save Changes" %}</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-5">
|
|
|
|
<div class="card p-4 mb-4">
|
|
<h5 class="fw-bold mb-4 text-accent">{% trans "Security" %}</h5>
|
|
|
|
<div class="d-grid gap-3">
|
|
<a href="{% url 'account_change_password' %}" class="btn btn-outline-danger w-100 rounded-pill py-2">
|
|
<i class="fas fa-lock me-2"></i> {% trans "Change Password" %}
|
|
</a>
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#myModalForm">
|
|
<i class="fas fa-image me-1"></i> {% trans "Change Profile Image" %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card p-4">
|
|
<h5 class="fw-bold mb-4 text-accent">{% trans "Account Status" %}</h5>
|
|
|
|
<div class="mb-3">
|
|
<div class="info-label">{% trans "Username" %}</div>
|
|
<div class="info-value">{{ user.username }}</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<div class="info-label">{% trans "Last Login" %}</div>
|
|
<div class="info-value">
|
|
{% if user.last_login %}{{ user.last_login|date:"F d, Y P" }}{% else %}N/A{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<div class="info-label">{% trans "Date Joined" %}</div>
|
|
<div class="info-value">{{ user.date_joined|date:"F d, Y" }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!--modal class for image upload-->
|
|
<div class="modal fade mt-4" id="myModalForm" tabindex="-1" aria-labelledby="myModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="myModalLabel">Upload Profile image</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form method="post" action="{% url 'user_profile_image_update' user.pk %}" enctype="multipart/form-data" >
|
|
{% csrf_token %}
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ profile_form.profile_image.id_for_label }}" class="form-label">Profile Image</label>
|
|
|
|
{# 1. Check if an image currently exists on the bound instance #}
|
|
{% if profile_form.instance.profile_image %}
|
|
|
|
<div class="mb-2">
|
|
<small class="text-muted d-block">Current Image:</small>
|
|
|
|
{# Display Link to View Current Image #}
|
|
<a href="{{ profile_form.instance.profile_image.url }}" target="_blank" class="d-inline-block me-3 text-info fw-bold">
|
|
View/Download ({{ profile_form.instance.profile_image.name }})
|
|
</a>
|
|
|
|
{# Image Preview #}
|
|
<div class="mt-2">
|
|
<img src="{{ profile_form.instance.profile_image.url }}"
|
|
alt="Profile Image"
|
|
style="max-width: 150px; height: auto; border: 1px solid #ccc; border-radius: 4px;">
|
|
</div>
|
|
</div>
|
|
|
|
{# 2. Explicitly render the 'Clear' checkbox and the Change input #}
|
|
<div class="form-check mt-3">
|
|
{# The ClearableFileInput widget renders itself here. It provides the "Clear" checkbox and the "Change" input field. #}
|
|
{{ profile_form.profile_image }}
|
|
</div>
|
|
|
|
{% else %}
|
|
{# If no image exists, just render the file input for upload #}
|
|
<div class="form-control p-0 border-0">
|
|
{{ profile_form.profile_image }}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{# Display any validation errors #}
|
|
{% for error in profile_form.profile_image.errors %}
|
|
<div class="text-danger small mt-1">{{ error }}</div>
|
|
{% endfor %}
|
|
|
|
</div>
|
|
|
|
<div class="modal-footer mt-4">
|
|
<button type="button" class="btn btn-lg btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="submit" class="btn btn-primary">Save changes</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %} |