227 lines
9.9 KiB
Twig
227 lines
9.9 KiB
Twig
{#
|
||
# Модальное окно просмотра клиента
|
||
#}
|
||
|
||
{# Скрытый модальный контейнер - будет показан при клике на строку таблицы #}
|
||
<div class="modal fade" id="viewClientModal" tabindex="-1" aria-hidden="true">
|
||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||
<div class="modal-content">
|
||
{# Header #}
|
||
<div class="modal-header">
|
||
<div class="d-flex align-items-center">
|
||
<div id="clientAvatar" class="bg-primary text-white rounded-circle d-flex align-items-center justify-content-center me-3" style="width: 48px; height: 48px;">
|
||
<i class="fa-solid fa-user fs-5"></i>
|
||
</div>
|
||
<div>
|
||
<h5 class="modal-title mb-0" id="clientName">—</h5>
|
||
<span id="clientStatus" class="badge bg-success">Активен</span>
|
||
</div>
|
||
</div>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||
</div>
|
||
|
||
{# Body #}
|
||
<div class="modal-body">
|
||
{# Навигация по вкладкам #}
|
||
<ul class="nav nav-tabs mb-3" id="clientTabs" role="tablist">
|
||
<li class="nav-item" role="presentation">
|
||
<button class="nav-link active" id="general-tab" data-bs-toggle="tab" data-bs-target="#general" type="button" role="tab">
|
||
<i class="fa-solid fa-user me-2"></i>Основное
|
||
</button>
|
||
</li>
|
||
<li class="nav-item" role="presentation">
|
||
<button class="nav-link" id="contact-tab" data-bs-toggle="tab" data-bs-target="#contact" type="button" role="tab">
|
||
<i class="fa-solid fa-address-book me-2"></i>Контакты
|
||
</button>
|
||
</li>
|
||
<li class="nav-item" role="presentation">
|
||
<button class="nav-link" id="notes-tab" data-bs-toggle="tab" data-bs-target="#notes" type="button" role="tab">
|
||
<i class="fa-solid fa-note-sticky me-2"></i>Заметки
|
||
</button>
|
||
</li>
|
||
</ul>
|
||
|
||
{# Контент вкладок #}
|
||
<div class="tab-content" id="clientTabsContent">
|
||
{# Вкладка: Основное #}
|
||
<div class="tab-pane fade show active" id="general" role="tabpanel">
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label class="text-muted small mb-1">Email</label>
|
||
<div id="clientEmail" class="fw-medium">—</div>
|
||
</div>
|
||
<div class="col-md-6 mb-3">
|
||
<label class="text-muted small mb-1">Телефон</label>
|
||
<div id="clientPhone" class="fw-medium">—</div>
|
||
</div>
|
||
<div class="col-md-6 mb-3">
|
||
<label class="text-muted small mb-1">Дата создания</label>
|
||
<div id="clientCreated" class="fw-medium">—</div>
|
||
</div>
|
||
<div class="col-md-6 mb-3">
|
||
<label class="text-muted small mb-1">Последнее обновление</label>
|
||
<div id="clientUpdated" class="fw-medium">—</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{# Вкладка: Контакты #}
|
||
<div class="tab-pane fade" id="contact" role="tabpanel">
|
||
<div class="text-center py-4 text-muted">
|
||
<i class="fa-solid fa-envelope fa-3x mb-3"></i>
|
||
<p class="mb-0">Email: <a id="contactEmail" href="#">—</a></p>
|
||
<p>Телефон: <a id="contactPhone" href="#">—</a></p>
|
||
</div>
|
||
</div>
|
||
|
||
{# Вкладка: Заметки #}
|
||
<div class="tab-pane fade" id="notes" role="tabpanel">
|
||
<div id="clientNotes" class="p-3 bg-light rounded">
|
||
—
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{# Footer #}
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||
<i class="fa-solid fa-times me-2"></i>Закрыть
|
||
</button>
|
||
<a id="clientEditLink" href="#" class="btn btn-primary">
|
||
<i class="fa-solid fa-pen me-2"></i>Редактировать
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
let viewClientModal = null;
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// Инициализируем модальное окно
|
||
viewClientModal = new bootstrap.Modal(document.getElementById('viewClientModal'));
|
||
});
|
||
|
||
/**
|
||
* Открыть карточку клиента
|
||
*/
|
||
function viewClient(clientId) {
|
||
// Показываем модалку с лоадером
|
||
showClientLoader();
|
||
viewClientModal.show();
|
||
|
||
// Загружаем данные
|
||
fetch('/clients/view/' + clientId)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
renderClientData(data.data);
|
||
} else {
|
||
showClientError(data.error || 'Ошибка загрузки');
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('Error:', error);
|
||
showClientError('Ошибка соединения');
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Показать лоадер в модальном окне
|
||
*/
|
||
function showClientLoader() {
|
||
document.getElementById('clientName').textContent = 'Загрузка...';
|
||
document.getElementById('clientStatus').className = 'badge bg-secondary';
|
||
document.getElementById('clientStatus').textContent = '—';
|
||
|
||
// Очищаем поля
|
||
document.getElementById('clientEmail').textContent = '—';
|
||
document.getElementById('clientPhone').textContent = '—';
|
||
document.getElementById('clientCreated').textContent = '—';
|
||
document.getElementById('clientUpdated').textContent = '—';
|
||
document.getElementById('clientNotes').innerHTML = '—';
|
||
document.getElementById('clientNotes').classList.remove('bg-light');
|
||
|
||
document.getElementById('contactEmail').textContent = '—';
|
||
document.getElementById('contactEmail').href = '#';
|
||
document.getElementById('contactPhone').textContent = '—';
|
||
document.getElementById('contactPhone').href = '#';
|
||
|
||
document.getElementById('clientEditLink').href = '#';
|
||
}
|
||
|
||
/**
|
||
* Показать ошибку загрузки
|
||
*/
|
||
function showClientError(message) {
|
||
document.getElementById('clientName').textContent = 'Ошибка';
|
||
document.getElementById('clientNotes').innerHTML = '<span class="text-danger">' + message + '</span>';
|
||
document.getElementById('clientNotes').classList.add('bg-light');
|
||
}
|
||
|
||
/**
|
||
* Отобразить данные клиента
|
||
*/
|
||
function renderClientData(client) {
|
||
// Имя и аватар
|
||
const initials = client.name ? client.name.split(' ').map(n => n[0]).join('').substring(0, 2).toUpperCase() : '?';
|
||
const avatarEl = document.getElementById('clientAvatar');
|
||
avatarEl.innerHTML = initials;
|
||
|
||
document.getElementById('clientName').textContent = client.name || '—';
|
||
|
||
// Статус
|
||
const statusEl = document.getElementById('clientStatus');
|
||
if (client.status === 'active') {
|
||
statusEl.className = 'badge bg-success';
|
||
statusEl.textContent = 'Активен';
|
||
} else if (client.status === 'blocked') {
|
||
statusEl.className = 'badge bg-danger';
|
||
statusEl.textContent = 'Заблокирован';
|
||
} else {
|
||
statusEl.className = 'badge bg-secondary';
|
||
statusEl.textContent = client.status || '—';
|
||
}
|
||
|
||
// Основная информация
|
||
document.getElementById('clientEmail').textContent = client.email || '—';
|
||
document.getElementById('clientPhone').textContent = client.phone || '—';
|
||
document.getElementById('clientCreated').textContent = client.created_at || '—';
|
||
document.getElementById('clientUpdated').textContent = client.updated_at || '—';
|
||
|
||
// Заметки
|
||
const notesEl = document.getElementById('clientNotes');
|
||
if (client.notes && client.notes.trim()) {
|
||
notesEl.textContent = client.notes;
|
||
notesEl.classList.add('bg-light');
|
||
} else {
|
||
notesEl.innerHTML = '<em class="text-muted">Заметок нет</em>';
|
||
notesEl.classList.add('bg-light');
|
||
}
|
||
|
||
// Контакты для клика
|
||
const contactEmail = document.getElementById('contactEmail');
|
||
if (client.email) {
|
||
contactEmail.textContent = client.email;
|
||
contactEmail.href = 'mailto:' + client.email;
|
||
} else {
|
||
contactEmail.textContent = '—';
|
||
contactEmail.href = '#';
|
||
}
|
||
|
||
const contactPhone = document.getElementById('contactPhone');
|
||
if (client.phone) {
|
||
contactPhone.textContent = client.phone;
|
||
contactPhone.href = 'tel:' + client.phone;
|
||
} else {
|
||
contactPhone.textContent = '—';
|
||
contactPhone.href = '#';
|
||
}
|
||
|
||
// Ссылка на редактирование
|
||
document.getElementById('clientEditLink').href = '/clients/edit/' + client.id;
|
||
}
|
||
</script>
|