267 lines
9.4 KiB
Twig
267 lines
9.4 KiB
Twig
{% extends 'layouts/base.twig' %}
|
|
|
|
{% block title %}{{ title }}{% endblock %}
|
|
|
|
{% block styles %}
|
|
<style>
|
|
.profile-header {
|
|
text-align: center;
|
|
padding: 2rem 0;
|
|
}
|
|
|
|
.avatar-container {
|
|
position: relative;
|
|
width: 120px;
|
|
height: 120px;
|
|
margin: 0 auto 1rem;
|
|
}
|
|
|
|
.avatar-img {
|
|
width: 120px;
|
|
height: 120px;
|
|
border-radius: 50%;
|
|
object-fit: cover;
|
|
border: 4px solid #fff;
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.avatar-placeholder {
|
|
width: 120px;
|
|
height: 120px;
|
|
border-radius: 50%;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 48px;
|
|
color: white;
|
|
border: 4px solid #fff;
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.avatar-upload-btn {
|
|
position: absolute;
|
|
bottom: 0;
|
|
right: 0;
|
|
width: 36px;
|
|
height: 36px;
|
|
border-radius: 50%;
|
|
background: #0d6efd;
|
|
color: white;
|
|
border: 3px solid #fff;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
transition: all 0.2s;
|
|
z-index: 10;
|
|
}
|
|
|
|
.avatar-upload-btn:hover {
|
|
background: #0b5ed7;
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
.nav-pills .nav-link {
|
|
color: #495057;
|
|
border-radius: 0.5rem;
|
|
padding: 0.75rem 1.5rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.nav-pills .nav-link.active {
|
|
background-color: #0d6efd;
|
|
color: white;
|
|
}
|
|
|
|
.nav-pills .nav-link:hover:not(.active) {
|
|
background-color: #e9ecef;
|
|
}
|
|
|
|
.form-label {
|
|
font-weight: 500;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.btn-save {
|
|
min-width: 150px;
|
|
}
|
|
|
|
#avatarPreviewModal {
|
|
max-width: 200px;
|
|
max-height: 200px;
|
|
border-radius: 50%;
|
|
object-fit: cover;
|
|
border: 4px solid #fff;
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="row justify-content-center">
|
|
<div class="col-md-3">
|
|
<!-- Боковая панель навигации -->
|
|
<div class="card mb-4">
|
|
<div class="card-body">
|
|
<div class="profile-header">
|
|
<div class="avatar-container">
|
|
{% if user.avatar %}
|
|
<img src="{{ base_url('/uploads/avatars/' ~ user.avatar) }}" alt="Аватар" class="avatar-img">
|
|
{% else %}
|
|
<div class="avatar-placeholder">
|
|
{{ user.name|first|upper }}
|
|
</div>
|
|
{% endif %}
|
|
<label for="avatarInput" class="avatar-upload-btn" title="Изменить аватар">
|
|
<i class="fa-solid fa-camera"></i>
|
|
</label>
|
|
<input type="file" id="avatarInput" name="avatar" accept="image/jpeg,image/png,image/gif" style="display: none;">
|
|
</div>
|
|
<h5 class="mb-1">{{ user.name }}</h5>
|
|
<p class="text-muted mb-0">{{ user.email }}</p>
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
<nav class="nav-pills flex-column">
|
|
<a href="{{ base_url('/profile') }}" class="nav-link {{ active_tab == 'general' ? 'active' : '' }}">
|
|
<i class="fa-solid fa-user me-2"></i> Основное
|
|
</a>
|
|
<a href="{{ base_url('/profile/organizations') }}" class="nav-link {{ active_tab == 'organizations' ? 'active' : '' }}">
|
|
<i class="fa-solid fa-building me-2"></i> Мои организации
|
|
</a>
|
|
<a href="{{ base_url('/profile/security') }}" class="nav-link {{ active_tab == 'security' ? 'active' : '' }}">
|
|
<i class="fa-solid fa-shield-halved me-2"></i> Безопасность
|
|
</a>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-9">
|
|
<!-- Основной контент -->
|
|
<div class="card">
|
|
<div class="card-header bg-white">
|
|
<h4 class="mb-0">Основная информация</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<form action="{{ base_url('/profile/update-name') }}" method="post">
|
|
{{ csrf_field()|raw }}
|
|
|
|
<div class="mb-3">
|
|
<label for="name" class="form-label">Имя</label>
|
|
<input type="text" class="form-control" id="name" name="name" value="{{ user.name }}" required minlength="3">
|
|
<div class="form-text">Ваше имя будет отображаться в системе</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="email" class="form-label">Email</label>
|
|
<input type="email" class="form-control" id="email" value="{{ user.email }}" disabled>
|
|
<div class="form-text">Email нельзя изменить (он является вашим логином)</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="created_at" class="form-label">Дата регистрации</label>
|
|
<input type="text" class="form-control" id="created_at" value="{{ user.created_at|date('d.m.Y H:i') }}" disabled>
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-primary btn-save">
|
|
<i class="fa-solid fa-check me-1"></i> Сохранить
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Модальное окно загрузки аватара -->
|
|
<div class="modal fade" id="avatarModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Загрузка аватара</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<form action="{{ base_url('/profile/upload-avatar') }}" method="post" enctype="multipart/form-data" id="avatarForm">
|
|
{{ csrf_field()|raw }}
|
|
<div class="modal-body text-center">
|
|
<p class="text-muted mb-3">Выберите изображение JPG, PNG или GIF (максимум 2 МБ)</p>
|
|
|
|
<div id="avatarPreviewContainer" style="display: none; margin-bottom: 15px;">
|
|
<img id="avatarPreviewModal" src="" alt="Превью аватара">
|
|
</div>
|
|
|
|
<input type="file" class="form-control" id="avatarFile" name="avatar" accept="image/jpeg,image/png,image/gif" required>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fa-solid fa-upload me-1"></i> Загрузить
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const avatarInput = document.getElementById('avatarInput');
|
|
const avatarFile = document.getElementById('avatarFile');
|
|
const avatarModal = new bootstrap.Modal(document.getElementById('avatarModal'));
|
|
const avatarPreviewModal = document.getElementById('avatarPreviewModal');
|
|
const avatarPreviewContainer = document.getElementById('avatarPreviewContainer');
|
|
|
|
// При клике на кнопку камеры - открываем модалку
|
|
avatarInput.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
avatarModal.show();
|
|
});
|
|
|
|
// При изменении файла в модалке - показываем превью
|
|
avatarFile.addEventListener('change', function(e) {
|
|
const file = e.target.files[0];
|
|
if (!file) {
|
|
avatarPreviewContainer.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
// Проверка типа файла
|
|
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
|
|
if (!allowedTypes.includes(file.type)) {
|
|
alert('Разрешены только файлы JPG, PNG и GIF');
|
|
this.value = '';
|
|
avatarPreviewContainer.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
// Проверка размера (2 МБ)
|
|
if (file.size > 2 * 1024 * 1024) {
|
|
alert('Максимальный размер файла - 2 МБ');
|
|
this.value = '';
|
|
avatarPreviewContainer.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
// Показываем превью
|
|
const reader = new FileReader();
|
|
reader.onload = function(event) {
|
|
avatarPreviewModal.src = event.target.result;
|
|
avatarPreviewContainer.style.display = 'block';
|
|
};
|
|
reader.readAsDataURL(file);
|
|
});
|
|
|
|
// Очистка при закрытии модалки
|
|
avatarModal._element.addEventListener('hidden.bs.modal', function() {
|
|
avatarFile.value = '';
|
|
avatarPreviewContainer.style.display = 'none';
|
|
avatarPreviewModal.src = '';
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|