buhapp-telegram/public/js/views/chats.js
root c5f8ac67ad UX overhaul: единый стиль BuhApp на всех экранах
ДИЗАЙН-СИСТЕМА в app.css:
- --primary #FF6B35, --success #3dd68c, --danger #ff5c5c
- --bg #0f0f12, --bg-elev #1a1a22, --bg-input #121218
- Компоненты: .card-b, .row-b, .field-b, .btn-b, .switch-b, .chip, .avatar-b, .bubble-b, .composer-b, .toast-b, .stars-b, .pulse-b, .empty-b

ПЕРЕПИСАНЫ на единый стиль:

Settings:
- Карточка с аватаром пользователя
- Card-row для юр.документов (📄 / 🔒 / ⚠️)
- 'Выйти' — danger btn-b с state machine (idle→load→ok)

Profile:
- Карточка аватара + кнопка 'Загрузить фото' через multipart /api/v1/me/photo
- Поля: field-b (ctrl + hint)
- Чипы в chip-list, новый стиль с .on
- Счётчик bio символов
- 'Сохранить' со state machine + toast

Review (создание):
- Звёзды в stars-b с center hint
- textarea с counter
- switch-b 'Анонимно' (вместо checkbox)
- Submit со state machine + toast 'Спасибо за отзыв!'

UserReviews:
- Средний рейтинг + звёзды
- Список карточек с отзывами

Chats:
- Список с avatar-b + last message + время + badge непрочитанных
- Пустое состояние с эмодзи
- formatChatTime() — 'сейчас' / '5м' / '3ч' / '2д'

Chat (один):
- Header с аватаром и кнопками 👤 ⭐
- composer-b: 📎 + input + ➤ (sticky bottom)
- bubble-b .in / .out с .ticks.read
- Send со state + toast
- sendPhoto() для фоток в чате

App.js _toast(msg, kind):
- Единый toast-b с классами ok / err

Всё в одном стиле. CSS variables, padding 16, radius 14, no disabled кнопок.
2026-08-21 11:42:16 +00:00

64 lines
3.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Chats list — единый стиль BuhApp
const ChatsView = {
async render(root) {
root.innerHTML = `
<div class="view">
<h1 style="margin:0 0 14px;font-size:22px;">💬 Чаты</h1>
<div id="chats-list" class="empty-b">⏳ Загрузка…</div>
</div>
`;
try {
const r = await API.ChatApi.listChats();
const list = document.getElementById('chats-list');
if (!r.chats || r.chats.length === 0) {
list.innerHTML = '<div class="empty-b"><div class="em">💬</div>Пока нет чатов<br><small>Открой карту и напиши кому-нибудь!</small></div>';
return;
}
list.className = 'row-list';
list.innerHTML = '';
r.chats.forEach((item) => {
const row = document.createElement('div');
row.className = 'card-b row-list-item';
row.style.padding = '12px';
row.style.cursor = 'pointer';
row.style.display = 'flex';
row.style.gap = '12px';
row.style.alignItems = 'center';
const init = (item.other_name || '?')[0].toUpperCase();
const lastText = item.last_message ? escapeHtml(item.last_message) : '<em style="color:var(--text-mute);">Нет сообщений</em>';
row.innerHTML = `
<div class="avatar-b" style="${item.other_photo ? `background-image:url(${item.other_photo});background-size:cover;color:transparent;` : ''}">${item.other_photo ? '' : init}</div>
<div style="flex:1;min-width:0;">
<div style="display:flex;justify-content:space-between;align-items:center;">
<div style="font-weight:600;font-size:15px;">${escapeHtml(item.other_name || 'Без имени')}</div>
${item.last_ts ? `<div style="font-size:11px;color:var(--text-mute);">${formatChatTime(item.last_ts)}</div>` : ''}
</div>
<div style="font-size:13px;color:var(--text-dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px;">${lastText}</div>
</div>
${item.unread_count > 0 ? `<div style="background:var(--primary);color:#fff;font-size:11px;font-weight:700;min-width:20px;height:20px;padding:0 6px;border-radius:10px;display:flex;align-items:center;justify-content:center;">${item.unread_count}</div>` : ''}
`;
row.onclick = () => App.openChat(item.chat.id, item.other_id, item.other_name);
list.appendChild(row);
});
} catch (e) {
document.getElementById('chats-list').innerHTML = '<div class="empty-b"><div class="em">⚠️</div>Ошибка загрузки<br><small>Попробуй позже</small></div>';
App._toast('Не удалось загрузить чаты', 'err');
}
},
};
function formatChatTime(ts) {
try {
const d = new Date(ts);
const now = new Date();
const diff = (now - d) / 1000;
if (diff < 60) return 'сейчас';
if (diff < 3600) return Math.floor(diff / 60) + 'м';
if (diff < 86400) return Math.floor(diff / 3600) + 'ч';
if (diff < 604800) return Math.floor(diff / 86400) + 'д';
return d.toLocaleDateString('ru-RU', { day: 'numeric', month: 'short' });
} catch { return ''; }
}
window.ChatsView = ChatsView;