Deep / static /script.js
nicolaydef's picture
Update static/script.js
3455ee3 verified
document.addEventListener('DOMContentLoaded', async () => {
let currentUser = null;
let supabase;
let ws;
let pingInterval;
// --- 0. INIT ---
try {
const config = await (await fetch('/api/config')).json();
supabase = window.supabase.createClient(config.supabase_url, config.supabase_key);
} catch(e) { console.error("Config failed", e); }
// --- 1. LOGIN ---
document.getElementById('login-form').addEventListener('submit', async (e) => {
e.preventDefault();
const u = document.getElementById('login-user').value.trim();
const p = document.getElementById('login-pass').value.trim();
const { data: user } = await supabase.from('users').select('*').eq('username', u).single();
if (user && dcodeIO.bcrypt.compareSync(p, user.password_hash)) {
currentUser = user;
document.getElementById('login-modal').classList.remove('open');
document.getElementById('app-interface').classList.remove('hidden');
document.getElementById('current-username').textContent = user.username;
// Инициализация чекбокса настроек
document.getElementById('setting-discovery').checked = user.is_looking_for_friends || false;
initApp();
} else {
const err = document.getElementById('login-error');
err.textContent = "INVALID ACCESS"; err.classList.remove('hidden');
}
});
// --- 2. TABS LOGIC ---
const navBtns = document.querySelectorAll('.nav-btn[data-tab]');
const viewChats = document.getElementById('view-chats');
const viewDiscovery = document.getElementById('view-discovery');
const sidebarTitle = document.getElementById('sidebar-title');
navBtns.forEach(btn => {
btn.addEventListener('click', () => {
// Remove active class
navBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
const tab = btn.dataset.tab;
if (tab === 'chats') {
viewChats.classList.remove('hidden');
viewDiscovery.classList.add('hidden');
sidebarTitle.textContent = "CHANNELS";
} else if (tab === 'discovery') {
viewChats.classList.add('hidden');
viewDiscovery.classList.remove('hidden');
sidebarTitle.textContent = "FIND FRIENDS";
loadDiscoveryUsers();
}
});
});
// --- 3. DISCOVERY & SETTINGS ---
const settingsModal = document.getElementById('settings-modal');
document.getElementById('open-settings').addEventListener('click', () => settingsModal.classList.add('open'));
document.getElementById('save-settings').addEventListener('click', async () => {
const isLooking = document.getElementById('setting-discovery').checked;
// Update DB
await supabase.from('users').update({ is_looking_for_friends: isLooking }).eq('id', currentUser.id);
currentUser.is_looking_for_friends = isLooking; // local update
settingsModal.classList.remove('open');
if(isLooking) alert("You are now visible in Discovery!");
});
async function loadDiscoveryUsers() {
const list = document.getElementById('discovery-list');
list.innerHTML = '<div class="text-white/30 text-xs italic">Scanning sector...</div>';
const { data: users } = await supabase
.from('users')
.select('*')
.eq('is_looking_for_friends', true)
.neq('username', currentUser.username); // Exclude self
list.innerHTML = '';
if (!users || users.length === 0) {
list.innerHTML = '<div class="text-white/30 text-xs p-2">No signals found.</div>';
return;
}
users.forEach(u => {
const div = document.createElement('div');
div.className = 'flex items-center justify-between p-2 bg-white/5 rounded hover:bg-white/10 transition cursor-pointer';
div.innerHTML = `
<div class="flex items-center gap-2">
<div class="w-6 h-6 rounded-full bg-gray-500"></div>
<span class="text-sm font-bold">${u.username}</span>
</div>
<button class="text-[10px] border border-cyan-400 text-cyan-400 px-2 py-1 rounded hover:bg-cyan-400 hover:text-black">
CONNECT
</button>
`;
// Logic for "Connect" -> Create DM channel would go here
list.appendChild(div);
});
}
// --- 4. ADMIN & CHAT ---
// (Admin Logic code from previous answer remains similar but linked to new modals)
document.getElementById('admin-trigger').addEventListener('click', () => {
document.getElementById('admin-modal').classList.add('open');
});
document.getElementById('admin-code').addEventListener('input', (e) => {
if(e.target.value.length >= 4) {
document.getElementById('admin-create-form').classList.remove('hidden');
}
});
document.getElementById('admin-create-form').addEventListener('submit', async (e) => {
e.preventDefault();
const code = document.getElementById('admin-code').value;
const newU = document.getElementById('new-user').value;
const newP = document.getElementById('new-pass').value;
try {
const res = await fetch('/api/admin/create_user', {
method: 'POST', headers: {'Content-Type': 'application/json'},
body: JSON.stringify({admin_code: code, new_username: newU, new_password: newP})
});
if(!res.ok) throw new Error("DENIED");
const data = await res.json();
await supabase.from('users').insert({
username: data.username,
password_hash: data.password_hash,
badge: "BETA"
});
alert("CREATED");
document.getElementById('admin-modal').classList.remove('open');
} catch(e) { alert("ACCESS DENIED"); }
});
// --- 5. APP INIT & WEBSOCKET FIX ---
function initApp() {
const msgContainer = document.getElementById('messages-container');
// Load Chat History
supabase.from('messages').select('*').eq('channel_id', 'general').order('created_at')
.then(({data}) => { if(data) data.forEach(renderMessage); });
// Realtime Subscription
supabase.channel('public:messages')
.on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages' }, payload => {
if(payload.new.channel_id === 'general') renderMessage(payload.new);
})
.subscribe();
// WebSocket for Voice/Signaling
connectWebSocket();
}
function connectWebSocket() {
// Secure WebSocket handling for HF Spaces
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
// Remove trailing slash if present
const host = window.location.host;
const wsUrl = `${protocol}//${host}/ws/signal`;
console.log("Attempting WS connect to:", wsUrl);
ws = new WebSocket(wsUrl);
ws.onopen = () => console.log("Signal Line Established");
ws.onerror = (e) => console.log("Signal Error (Ignore if not using Voice)", e);
}
const chatForm = document.getElementById('chat-form');
chatForm.addEventListener('submit', async (e) => {
e.preventDefault();
const inp = document.getElementById('msg-input');
const text = inp.value.trim();
if(!text) return;
inp.value = '';
const moodRes = await fetch('/api/analyze_mood', {
method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({text})
});
const mood = await moodRes.json();
await supabase.from('messages').insert({
content: text, user_id: currentUser.id, username: currentUser.username,
mood_color: mood.mood_color, channel_id: 'general'
});
});
function renderMessage(msg) {
const div = document.createElement('div');
const isOwn = msg.username === currentUser.username;
div.className = `flex gap-2 mb-4 ${isOwn ? 'flex-row-reverse' : ''} px-4`;
div.innerHTML = `
<div class="bg-white/5 border border-white/5 p-3 rounded-xl max-w-[80%] text-sm"
style="border-left: 3px solid ${msg.mood_color}">
<div class="text-[10px] text-white/40 mb-1">${msg.username}</div>
${msg.content}
</div>
`;
const c = document.getElementById('messages-container');
c.appendChild(div);
c.scrollTop = c.scrollHeight;
}
});