// ✅ ПОЛНАЯ МОНОЛИТНАЯ СБОРКА РЕЕСТРА КЛИЕНТОВ (БЕЗ УРЕЗАНИЙ И СЖАТИЙ) v50.0
window.renderCustomersTab = function() {
var container = document.getElementById('customers-list-container');
if (!container) return;

var cList = window.st.clients || [];

// 🧠 ИСПРАВЛЕНИЕ БАГА ПУСТОГО ЭКРАНА
if (!cList.length && window.st.deals && window.st.deals.length > 0) {
container.innerHTML = '<div style="color:#999; text-align:center; padding:20px;">⏳ Синхронизация сквозной базы... Секунду.</div>';
return;
}
if (!cList.length) {
container.innerHTML = '<div style="color:#999; text-align:center; padding:20px;">База покупателей пуста. Профили формируются автоматически.</div>';
return;
}

// // Живой поиск по имени, телефону и ID (УНИВЕРСАЛЬНЫЙ ИСПРАВЛЕННЫЙ)
var searchInp = document.getElementById('search-customer') || document.querySelector('#tab-customers input[type="text"]');
if (searchInp && searchInp.value.trim() !== "") {
var query = searchInp.value.trim().toLowerCase();
// Очищаем поисковый запрос до чистых цифр для проверки телефона
var cleanQuery = query.replace(/\D/g, '');
// Хвост запроса без первой 7 или 8
var queryTail = (cleanQuery.indexOf('7') === 0 || cleanQuery.indexOf('8') === 0) ? cleanQuery.substring(1) : cleanQuery;

cList = cList.filter(function(c) {
if (!c) return false;

var nM = String(c.name || '').toLowerCase().indexOf(query) !== -1;
var iM = String(c.id || '').toLowerCase().indexOf(query) !== -1;

// Очищаем телефон клиента из базы до чистых цифр
var phoneRaw = String(c.cleanPhone || c.phone || '').replace(/\D/g, '');
var phoneTail = (phoneRaw.indexOf('7') === 0 || phoneRaw.indexOf('8') === 0) ? phoneRaw.substring(1) : phoneRaw;

// Проверяем прямое вхождение цифр ИЛИ совпадение хвостов (без 7 и 8)
var pM = false;
if (cleanQuery !== '') {
pM = phoneRaw.indexOf(cleanQuery) !== -1 || (queryTail !== '' && phoneTail.indexOf(queryTail) !== -1);
}

return nM || pM || iM;
});
}


var totalClientsFound = cList.length;
if (!totalClientsFound) {
container.innerHTML = '<div style="color:#999; text-align:center; padding:20px;">Покупатели по вашему запросу не найдены.</div>';
return;
}

// ВАЖНО: Строка 1536 (var cList = window.st.clients) УДАЛЕНА, так как она затирала результаты поиска!
var rawVisibleClients = cList.slice(0, window.crmClientsLimit || 30);

// 🔥 ИСПРАВЛЕНО: СИНХРОННЫЙ ПОДСЧЕТ LTV И СТАТИСТИКИ ЗАКАЗОВ ДЛЯ КАРТОЧКИ
var uniqueMap = {};
rawVisibleClients.forEach(function(item) {
if (!item || !item.phone) return;
var cleanP = String(item.phone).replace(/\D/g, "");
var idKey = cleanP.substring(cleanP.length - 7); // Хвост телефона

if (!uniqueMap[idKey]) {
item.buy_count = 0; // Всего обращений
item.done_count = 0; // Выполнено заказов
item.total_ltv = 0; // Общая сумма LTV в рублях
uniqueMap[idKey] = item;
}
});

// // Пробегаемся по общей базе сделок и агрегируем финансовые данные
if (window.st && window.st.deals && window.st.deals.length > 0) {
window.st.deals.forEach(function(deal) {
if (!deal) return;

var dPhone = String(deal.phone || '').replace(/\D/g, '');
var dPhoneTail = dPhone.substring(dPhone.length - 7);

if (dPhoneTail && uniqueMap[dPhoneTail]) {
var clientObj = uniqueMap[dPhoneTail];

// 1. Увеличиваем счетчик общего количества обращений для любого статуса
clientObj.buy_count += 1;

// 2. Получаем чистый статус из заказа
var dStatus = String(deal.status || '').trim();

// 3. Проверяем, входит ли статус в оборот аналитики (countRevenueDeals)
var isRevenueStatus = false;
if (window.st.countRevenueDeals && Array.isArray(window.st.countRevenueDeals)) {
isRevenueStatus = window.st.countRevenueDeals.indexOf(dStatus) !== -1;
} else {
// Дефолтный список на случай, если массив с сервера еще не долетел
var lowStatus = dStatus.toLowerCase();
isRevenueStatus = (lowStatus === 'выполнен' || lowStatus === 'доставлен' || lowStatus === 'оплачен' || lowStatus === 'success' || lowStatus === 'готово');
}

// 4. Суммируем LTV и выполненные только для разрешенных аналитикой статусов
if (isRevenueStatus) {
// Считаем выполненные заказы
clientObj.done_count += 1;

// Вытаскиваем чистую сумму заказа и плюсуем в LTV
var dealAmount = parseFloat(String(deal.total || deal.amount || '0').replace(/[^\d\.]/g, '')) || 0;
clientObj.total_ltv += dealAmount;
}
}
});
}


var visibleClients = Object.values(uniqueMap);
var currentRole = String(window.st.role || '').trim().toLowerCase();
var html = '';

// Запускаем ваш оригинальный цикл по очищенному массиву
visibleClients.forEach(function(c, index) {
var historyHtml = '';

// 🔥 СКВОЗНОЙ ПОИСК ЗАКАЗОВ В ОБЩЕЙ БАЗЕ CRM ПО НОМЕРУ ТЕЛЕФОНА КЛИЕНТА
if (window.st && window.st.deals && window.st.deals.length > 0) {
window.st.deals.forEach(function(deal) {
if (!deal) return;

// Приводим телефоны к общему цифровому знаменателю без плюсов и скобок
var dPhone = String(deal.phone || '').replace(/\D/g, '');
var cleanCustomerPhone = String(c.phone || '').replace(/\D/g, '');
var cPhoneTail = cleanCustomerPhone.substring(cleanCustomerPhone.length - 10);

// Если 10 цифр телефона совпали — этот заказ принадлежит текущему клиенту!
if (dPhone && cPhoneTail && dPhone.indexOf(cPhoneTail) !== -1) {
var rawODate = String(deal.date || '').trim();
var displayODate = (rawODate && rawODate.indexOf('-') !== -1 && typeof window.formatCrmDateToRu === 'function') ? window.formatCrmDateToRu(rawODate) : rawODate;

var dProducts = deal.products || 'Заказ без описания';
var dTotal = deal.total || deal.amount || '0';
var dRow = deal.row_num || deal.row || ''; // Вытаскиваем номер строки в таблице

// Интегрируем вашу родную функцию window.editDealInline для открытия карточки по клику
var clickTrigger = dRow ? ('window.editDealInline(' + dRow + ')') : 'alert(\'Номер строки заказа не найден в базе данных\')';

var orderNumDisplay = deal.id ? deal.id : ('#' + dRow);

historyHtml += '<div class="crm-history-item" onclick="' + clickTrigger + '" style="cursor:pointer; padding:6px 0; border-bottom:1px dashed #f1f3f4; display:flex; justify-content:space-between; font-size:12px; transition:0.2s;" onmouseover="this.style.background=\'#f9f9f9\'" onmouseout="this.style.background=\'none\'">';
historyHtml += '<span>📅 <b>' + displayODate + '</b> | 🆔 <b>' + orderNumDisplay + '</b> | 🎈 ' + dProducts + '</span>';
historyHtml += '<span style="color:#1a73e8; font-weight:700; text-decoration:underline;">' + dTotal + ' ₽</span>';
historyHtml += '</div>';

}
});
}

if (!historyHtml) {
historyHtml = '<div style="padding:6px 0; color:#999; font-style:italic; font-size:12px;">Исторических заказов по этому номеру телефона не найдено</div>';
}

// НАДЕЖНЫЙ ВАРИАНТ СТРОК 1562–1570 ДЛЯ РЕНДЕРИНГА TILDA (БЕЗ СИНИХ ПОЛОС):
var cleanCPhone = String(c.phone || '').replace(/\D/g, '');
var formattedCPhone = cleanCPhone.startsWith('8') ? '7' + cleanCPhone.slice(1) : cleanCPhone;

// Заменяем вслепую 'Заказ шаров' на статус из базы или 'Контакты'
var displayEventText = c.last_event ? String(c.last_event).trim() : 'Контакты';
var rawLastDate = String(c.last_date || '').trim();
var displayLastDate = (rawLastDate && rawLastDate.indexOf('-') !== -1 && typeof window.formatCrmDateToRu === 'function') ? window.formatCrmDateToRu(rawLastDate) : rawLastDate;

// 🔥 ГЛАВНОЕ ИСПРАВЛЕНИЕ СТРОКИ 1572: Привязываем ID к последним 7 цифрам номера телефона!
// Для номера 79089966385 ID станет C-9966385. Для 79088966385 ID станет C-8966385. Они никогда не продублируются!
var phoneTail = formattedCPhone.substring(formattedCPhone.length - 7);
var displayClientId = c.id ? String(c.id) : ('C-' + (phoneTail || (100000 + index)));

// Полностью закрываем HTML-тег и кавычки стиля
var clientBadge = (c.buy_count > 0 && !c.comment) ? '<span style="background:#1a73e8; color:#fff; font-size:10px; padding:2px 6px; border-radius:3px; margin-left:5px;">Повторный</span>' : '';

// Отображение кнопки удаления для роли Owner
var deleteButtonHtml = (currentRole === 'owner')
? '<button class="btn-out" type="button" onclick="deleteCustomerContact(\'' + formattedCPhone + '\')" style="font-size:11px; padding:6px 10px; cursor:pointer; font-weight:bold; background:#ea4335; color:#fff; border:none; border-radius:4px; margin-left:4px;">🗑️ Удалить</button>'
: '';

html += '<div class="customer-profile-card" style="border:1px solid #dadce0; padding:15px; border-radius:8px; margin-bottom:10px; box-shadow:0 1px 2px rgba(0,0,0,0.05);">' +
'<div class="customer-grid-summary" style="display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; width:100%; position:relative;">' +
'<div style="flex:2; min-width:200px; max-width:280px;">' +
'<div style="font-weight:700; font-size:16px; margin-bottom:2px; color:#202124;">' + (c.name || 'Покупатель') + ' ' + clientBadge + '</div>' +
'<div style="font-size:13px; color:#5f6368;"><a href="tel:+' + formattedCPhone + '" style="color:#1a73e8; text-decoration:none; font-weight:700;">+' + formattedCPhone + '</a></div>' +
'<div style="font-size:13px; color:#5f6368; margin-top:2px;">Дата последнего обращения:<br><b>' + (displayLastDate || 'Нет обращений') + '</b></div>' +
'</div>' +

// Внутренний контейнер показателей с жестким правым отступом
'<div style="display:flex; flex:3; justify-content:space-around; align-items:center; min-width:300px; margin-right:20px; z-index:1;">' +
'<div style="text-align:center; padding:0 5px; flex:1; color:#5f6368; font-size:12px;">Всего обращений:<br><b style="font-size:15px; color:#202124;">' + (c.buy_count || 0) + ' шт</b></div>' +
'<div style="text-align:center; padding:0 5px; flex:1; color:#5f6368; font-size:12px;">Выполненных:<br><b style="font-size:15px; color:green;">' + (c.done_count || 0) + ' из ' + (c.buy_count || 0) + '</b></div>' +
'<div style="text-align:center; padding:0 5px; flex:1; color:#5f6368; font-size:12px;">Общая сумма LTV:<br><b style="font-size:15px; color:#1a73e8; white-space:nowrap;">' + (c.total_ltv || 0).toLocaleString('ru-RU') + ' ₽</b></div>' +
'</div>' +

'<div style="text-align:right; display:flex; gap:6px; justify-content:flex-end; flex:1; min-width:150px;">' +
'<button class="btn-out" type="button" onclick="window.toggleCustomerHistory(' + index + ')" style="font-size:11px; padding:6px 10px; cursor:pointer; font-weight:bold;">📋 Все заказы</button>' +
'<a href="https://wa.me' + formattedCPhone + '" target="_blank" class="btn-whatsapp" style="background:#25d366; padding:6px 10px; border-radius:4px; font-size:11px; text-decoration:none; color:#fff; font-weight:bold;">💬 Чат</a>' +
deleteButtonHtml +
'</div>' +
'</div>' +
'<div id="c-hist-' + index + '" class="customer-history-box" style="display:none; margin-top:12px; border-top:1px solid #dadce0; padding-top:10px;">' +
'<h4 style="margin:5px 0 10px 0; font-size:13px; color:#1a73e8; font-weight:700;">Полная сквозная история взаимодействий (нажмите на строку для редактирования):</h4>' + historyHtml +
'</div>' +
'</div>';
});

if (totalClientsFound > window.crmClientsLimit) {
html += '<div style="text-align:center; margin-top:15px; margin-bottom:10px;">' +
'<button type="button" class="btn-action" onclick="window.crmLoadMoreClients()" style="background:#5f6368; padding:10px 24px; width:auto; font-size:13px; font-weight:700;">Загрузить еще клиентов</button>' +
'</div>';
}
container.innerHTML = html;
};

window.crmLoadMoreClients = function() {
window.crmClientsLimit += 30;
window.renderCustomersTab();
};

window.toggleCustomerHistory = function(idx) {
var box = document.getElementById('c-hist-' + idx);
if (box) box.style.display = (box.style.display === 'none') ? 'block' : 'none';
};


window.crmLoadMoreClients = function() {
window.crmClientsLimit += 30;
window.renderCustomersTab();
};

window.toggleCustomerHistory = function(idx) {
var box = document.getElementById('c-hist-' + idx); if (box) box.style.display = (box.style.display === 'none') ? 'block' : 'none';
};


// ⚡ ТРЕКЕРЫ ЖИВОГО ВВОДА С РАЗДЕЛЬНЫМ ПЕРЕХВАТОМ ЛЕВОГО И ПРАВОГО КАЛЕНДАРЯ ДАТ
document.addEventListener("DOMContentLoaded", function() {
setTimeout(function() {
var dSearch = document.querySelector('#tab-deals input[type="text"]');
if (dSearch) { dSearch.addEventListener('input', function() { window.crmDealsLimit = 30; renderDealsList(); }); }

// ЖЕСТКИЙ ФИКС: Вешаем раздельные обработчики событий change на оба инпута календарей
var dDates = document.querySelectorAll('#tab-deals input[type="date"]');
if (dDates && dDates[0]) {
dDates[0].addEventListener('change', function() { window.crmDealsLimit = 30; renderDealsList(); });
}
if (dDates && dDates[1]) {
dDates[1].addEventListener('change', function() { window.crmDealsLimit = 30; renderDealsList(); });
}

var cSearch = document.querySelector('#tab-customers input[type="text"]');
if (cSearch) { cSearch.addEventListener('input', function() { window.crmClientsLimit = 30; window.renderCustomersTab(); }); }
}, 2000);

// Привязываем клик по кнопке "За все время" к нашему сбросу
var anaResetBtn = document.querySelector('#tab-analytics .btn-out[onclick*="resetAnalytics"]') || document.querySelector('button[onclick*="resetAnalyticsFilter"]');
if (anaResetBtn) {
anaResetBtn.setAttribute('onclick', 'window.resetAnalyticsFilter()');
}

});




</script>



Made on
Tilda