buhapp-telegram/public/js/views/profile.js
root d44eb2be8d Fix: только cookie auth (без Authorization) — все запросы без preflight
- api.js: убрал Authorization header для всех методов (cookie достаточно)
- убрал refresh block (cookie живёт дольше)
- profile.save: явный feedback (" Сохраняю..." → "✓ Сохранено") + try/catch вокруг TG_APP.haptic
2026-08-20 22:04:27 +00:00

125 lines
5.3 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.

// Profile view (свой профиль)
const ProfileView = {
drinks: new Set(),
activities: new Set(),
purposes: new Set(),
anonymous: false,
DRINKS: [
['beer', '🍺 Пиво'], ['wine', '🍷 Вино'], ['whiskey', '🥃 Виски'], ['vodka', '🍸 Водка'],
['cocktail', '🍹 Коктейль'], ['rum', '🥃 Ром'], ['gin', '🍸 Джин'], ['tequila', '🌵 Текила'],
['champagne', '🍾 Шампанское'], ['non_alcoholic', '🥤 Безалкогольное'],
],
ACTIVITIES: [
['walk', '🚶 Прогулка'], ['dinner', '🍽️ Ужин'], ['bar', '🍻 Бар'], ['cafe', '☕ Кафе'],
['travel', '✈️ Путешествие'], ['movie', '🎬 Кино'], ['concert', '🎵 Концерт'],
['sport', '⚽ Спорт'], ['gaming', '🎮 Игры'], ['reading', '📚 Чтение'],
],
PURPOSES: [
['chat', '💬 Пообщаться'], ['drink', '🍻 Выпить'], ['walk', '🌳 Погулять'],
['dinner', '🍽️ Поужинать'], ['travel', '✈️ Поехать'], ['friendship', '🤝 Дружба'],
['relationship', '❤️ Отношения'],
],
async render(root) {
try {
const me = await API.Auth.me();
API.Store.user = me.user;
const prefs = me.prefs || {};
this.drinks = new Set(prefs.drinks || []);
this.activities = new Set(prefs.activities || []);
this.purposes = new Set(prefs.purposes || []);
this.renderForm(root, me.user);
} catch (e) {
root.innerHTML = '<div class="view"><div class="empty">Не удалось загрузить: ' + e.message + '</div></div>';
}
},
renderForm(root, u) {
root.innerHTML = `
<div class="view">
<h1>👤 Профиль</h1>
<div class="card">
<div style="font-size:22px;font-weight:700;">${escapeHtml(u.name || '')}</div>
${u.telegram_id ? `<div class="sub">@${escapeHtml(u.username || '')}</div>` : ''}
${u.telegram_id ? '' : `<div class="sub">${escapeHtml(u.email || '')}</div>`}
</div>
<label>Имя</label>
<input class="input" id="p-name" value="${escapeHtml(u.name || '')}">
<label>Город</label>
<input class="input" id="p-city" placeholder="Москва" value="${escapeHtml(u.city || '')}">
<label>О себе</label>
<textarea class="input" id="p-bio" rows="3" placeholder="Расскажи о себе" style="resize:none;">${escapeHtml(u.bio || '')}</textarea>
<label>Пол</label>
<select class="input" id="p-gender">
<option value="">Не указан</option>
<option value="m" ${u.gender === 'm' ? 'selected' : ''}>Мужской</option>
<option value="f" ${u.gender === 'f' ? 'selected' : ''}>Женский</option>
<option value="o" ${u.gender === 'o' ? 'selected' : ''}>Другое</option>
</select>
<h2>🍻 Что пью</h2>
<div id="p-drinks"></div>
<h2>🎯 Чем занимаюсь</h2>
<div id="p-activities"></div>
<h2>💡 Цели</h2>
<div id="p-purposes"></div>
<button class="btn" id="p-save">Сохранить</button>
</div>
`;
this.renderChips('p-drinks', this.DRINKS, this.drinks);
this.renderChips('p-activities', this.ACTIVITIES, this.activities);
this.renderChips('p-purposes', this.PURPOSES, this.purposes);
document.getElementById('p-save').onclick = () => this.save();
},
renderChips(elId, items, selected) {
const el = document.getElementById(elId);
if (!el) { console.error('renderChips: no element', elId); return; }
items.forEach(([key, label]) => {
const chip = document.createElement('span');
chip.className = 'chip' + (selected.has(key) ? ' active' : '');
chip.textContent = label;
chip.onclick = () => {
try {
if (selected.has(key)) selected.delete(key); else selected.add(key);
chip.classList.toggle('active');
TG_APP.haptic('selection');
} catch (e) { console.warn('chip click err', e); }
};
el.appendChild(chip);
});
},
async save() {
const btn = document.getElementById('p-save');
const orig = btn ? btn.textContent : null;
if (btn) { btn.disabled = true; btn.textContent = '⏳ Сохраняю…'; }
try {
await API.Auth.updateMe({
name: document.getElementById('p-name').value.trim(),
city: document.getElementById('p-city').value.trim(),
bio: document.getElementById('p-bio').value.trim(),
gender: document.getElementById('p-gender').value,
});
await API.Auth.updatePrefs({
drinks: [...this.drinks],
activities: [...this.activities],
purposes: [...this.purposes],
});
try { TG_APP.haptic('notification'); } catch {}
App.toast('✓ Сохранено');
if (btn) { btn.textContent = '✓ Сохранено'; setTimeout(() => { btn.textContent = orig || 'Сохранить'; btn.disabled = false; }, 1500); }
} catch (e) {
console.error('save profile:', e);
App.toast('⚠️ ' + e.message);
TG_APP.showAlert('Ошибка сохранения: ' + e.message);
if (btn) { btn.disabled = false; btn.textContent = orig || 'Сохранить'; }
}
},
};
window.ProfileView = ProfileView;