148 lines
7.7 KiB
HTML
148 lines
7.7 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}My Profile{% endblock %}
|
|
{% block page_title %}My Profile{% endblock %}
|
|
|
|
{% block head %}
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/password-strength.css') }}"/>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="row justify-content-center">
|
|
<div class="col-lg-7">
|
|
<div class="card">
|
|
<div class="card-header"><i class="bi bi-person-circle me-2"></i>Account Settings</div>
|
|
<div class="card-body">
|
|
<form method="POST" enctype="multipart/form-data">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
|
<!-- Avatar -->
|
|
<div class="text-center mb-4">
|
|
{% if current_user.avatar_url %}
|
|
<img src="{{ url_for('auth.serve_avatar', filename=current_user.avatar_url) }}"
|
|
alt="Avatar"
|
|
style="width:80px;height:80px;border-radius:50%;object-fit:cover;border:2px solid var(--border);margin:0 auto 10px;display:block;"/>
|
|
{% else %}
|
|
<div style="width:80px;height:80px;border-radius:50%;background:var(--accent2);display:flex;align-items:center;justify-content:center;font-size:32px;font-weight:700;color:#fff;margin:0 auto 10px;">
|
|
{{ current_user.full_name[0].upper() }}
|
|
</div>
|
|
{% endif %}
|
|
<div style="font-size:12px;color:var(--muted);">{{ current_user.email }}</div>
|
|
<div style="font-size:11px;background:rgba(0,180,216,.1);color:var(--accent3);display:inline-block;padding:2px 10px;border-radius:12px;margin-top:4px;">
|
|
{{ current_user.role.replace('_',' ').upper() }}
|
|
</div>
|
|
<div class="mt-3">
|
|
<label class="form-label" style="font-size:12px;">Profile Picture
|
|
<span style="color:var(--muted);font-weight:400;">(PNG, JPG, GIF, WebP — max 5 MB)</span>
|
|
</label>
|
|
<input type="file" class="form-control form-control-sm" name="avatar"
|
|
accept=".png,.jpg,.jpeg,.gif,.webp" style="max-width:300px;margin:0 auto;"/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label">Full Name</label>
|
|
<input type="text" class="form-control" name="full_name" value="{{ current_user.full_name }}" required/>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Department</label>
|
|
<input type="text" class="form-control" name="department" value="{{ current_user.department or '' }}"/>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Phone</label>
|
|
<input type="text" class="form-control" name="phone" value="{{ current_user.phone or '' }}"/>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Username</label>
|
|
<input type="text" class="form-control" value="{{ current_user.username }}" disabled/>
|
|
</div>
|
|
</div>
|
|
|
|
<hr style="border-color:var(--border);margin:24px 0;"/>
|
|
<h6 style="font-size:14px;font-weight:700;margin-bottom:16px;">Notification Preferences</h6>
|
|
<div class="d-flex flex-column gap-2 mb-4">
|
|
<label style="display:flex;align-items:center;gap:10px;cursor:pointer;">
|
|
<input type="checkbox" name="email_notif" {% if current_user.email_notif %}checked{% endif %}
|
|
style="accent-color:var(--accent3);width:16px;height:16px;"/>
|
|
<span style="font-size:14px;"><i class="bi bi-envelope me-2" style="color:var(--accent3);"></i>Email Notifications</span>
|
|
</label>
|
|
<label style="display:flex;align-items:center;gap:10px;cursor:pointer;">
|
|
<input type="checkbox" name="web_notif" {% if current_user.web_notif %}checked{% endif %}
|
|
style="accent-color:var(--accent3);width:16px;height:16px;"/>
|
|
<span style="font-size:14px;"><i class="bi bi-bell me-2" style="color:var(--accent3);"></i>In-App Notifications</span>
|
|
</label>
|
|
</div>
|
|
|
|
<hr style="border-color:var(--border);margin:24px 0;"/>
|
|
<h6 style="font-size:14px;font-weight:700;margin-bottom:16px;">Change Password <span style="font-size:12px;color:var(--muted);font-weight:400;">(leave blank to keep current)</span></h6>
|
|
<div class="row g-3 mb-4">
|
|
<div class="col-md-6">
|
|
<label class="form-label">New Password</label>
|
|
<div class="pw-wrap">
|
|
<input type="password" class="form-control pw-input" name="new_password"
|
|
id="prof-pw" maxlength="128" placeholder="Min. 8 characters"
|
|
autocomplete="new-password"/>
|
|
<button type="button" class="pw-toggle" id="prof-pw-toggle"
|
|
title="Show / hide password" tabindex="-1">
|
|
<i class="bi bi-eye"></i>
|
|
</button>
|
|
</div>
|
|
<!-- Strength bar (hidden until typing starts) -->
|
|
<div class="pw-strength-wrap" id="prof-strength-wrap" style="display:none;">
|
|
<div class="pw-strength-track">
|
|
<div class="pw-strength-fill" id="prof-strength-bar"></div>
|
|
</div>
|
|
<div class="pw-strength-label" id="prof-strength-label"></div>
|
|
</div>
|
|
<!-- Rule checklist -->
|
|
<div class="pw-rules" id="prof-rules" style="display:none;" aria-live="polite" aria-atomic="true">
|
|
<div class="pw-rule unmet" id="prof-rule-len"><span class="ri"><i class="bi bi-circle"></i></span> 8+ characters</div>
|
|
<div class="pw-rule unmet" id="prof-rule-upper"><span class="ri"><i class="bi bi-circle"></i></span> Uppercase letter</div>
|
|
<div class="pw-rule unmet" id="prof-rule-digit"><span class="ri"><i class="bi bi-circle"></i></span> Number</div>
|
|
<div class="pw-rule unmet" id="prof-rule-special"><span class="ri"><i class="bi bi-circle"></i></span> Special character</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Confirm Password</label>
|
|
<div class="pw-wrap">
|
|
<input type="password" class="form-control pw-input" name="confirm_password"
|
|
id="prof-pw2" maxlength="128" placeholder="Repeat password"
|
|
autocomplete="new-password"/>
|
|
<button type="button" class="pw-toggle" id="prof-pw2-toggle"
|
|
title="Show / hide password" tabindex="-1">
|
|
<i class="bi bi-eye"></i>
|
|
</button>
|
|
</div>
|
|
<div class="pw-match" id="prof-match-msg" aria-live="polite" aria-atomic="true"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex gap-2">
|
|
<button type="submit" class="btn btn-primary"><i class="bi bi-check2 me-2"></i>Save Changes</button>
|
|
<a href="{{ url_for('tickets.dashboard') }}" class="btn btn-secondary">Cancel</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% block scripts %}
|
|
<script src="{{ url_for('static', filename='js/password-strength.js') }}"></script>
|
|
<script>
|
|
PasswordStrength.init({
|
|
password : 'prof-pw',
|
|
confirm : 'prof-pw2',
|
|
strengthBar : 'prof-strength-bar',
|
|
strengthLabel: 'prof-strength-label',
|
|
strengthWrap : 'prof-strength-wrap',
|
|
rulesWrap : 'prof-rules',
|
|
rules: { len: 'prof-rule-len', upper: 'prof-rule-upper', digit: 'prof-rule-digit', special: 'prof-rule-special' },
|
|
matchMsg : 'prof-match-msg',
|
|
toggles: [
|
|
{ input: 'prof-pw', button: 'prof-pw-toggle' },
|
|
{ input: 'prof-pw2', button: 'prof-pw2-toggle' },
|
|
],
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
{% endblock %} |