From 48d18ce85b538999f8df611a52a47835dcfb3503 Mon Sep 17 00:00:00 2001 From: Shni Date: Wed, 15 Oct 2025 11:13:57 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20Agregar=20l=C3=B3gica=20para=20verifica?= =?UTF-8?q?r=20la=20presencia=20del=20bot=20en=20los=20gremios=20y=20actua?= =?UTF-8?q?lizar=20la=20interfaz=20de=20usuario?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/server.ts | 23 +++++++++++++ .../partials/dashboard/dashboard_sidebar.ejs | 28 ++++++++++++---- src/server/views/partials/dashboard_nav.ejs | 33 +++++++++++++++++++ 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/src/server/server.ts b/src/server/server.ts index bd5a7e0..014ad19 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -1418,6 +1418,29 @@ export const server = createServer( // ignore; fallback to no roles } // Render dashboard with selected guild context; show dashboard nav + // Ensure we know whether the bot is in each guild (so small selectors/nav show correct state) + try { + const botToken = process.env.DISCORD_BOT_TOKEN ?? process.env.TOKEN; + if (botToken && Array.isArray(guilds) && guilds.length) { + await Promise.all( + guilds.map(async (g: any) => { + try { + const check = await fetch( + `https://discord.com/api/guilds/${encodeURIComponent( + String(g.id) + )}`, + { headers: { Authorization: `Bot ${botToken}` } } + ); + g.botInGuild = check.ok; + } catch (e) { + g.botInGuild = undefined; + } + }) + ); + } + } catch (err) { + // ignore + } // If caller requested a fragment, render only the page template (no layout) if (fragment) { // Render the dashboard page and extract the inner #dashContent fragment diff --git a/src/server/views/partials/dashboard/dashboard_sidebar.ejs b/src/server/views/partials/dashboard/dashboard_sidebar.ejs index 4aaadd1..868296d 100644 --- a/src/server/views/partials/dashboard/dashboard_sidebar.ejs +++ b/src/server/views/partials/dashboard/dashboard_sidebar.ejs @@ -14,18 +14,32 @@ if(!btn) return; btn.addEventListener('click', async function(e){ e.preventDefault(); - const guildId = '<%= selectedGuild %>'; + const injected = '<%= selectedGuild || "" %>'; + let guildId = injected || ''; + if(!guildId && typeof location !== 'undefined'){ + try{ + const parts = location.pathname.split('/').filter(Boolean); + // expect /dashboard//... + if(parts.length >= 2 && parts[0] === 'dashboard') guildId = parts[1]; + }catch(e){ guildId = '' } + } if(!guildId) return; + + // visual feedback: disable while loading + btn.disabled = true; + btn.classList.add('opacity-50','pointer-events-none'); try{ const res = await fetch(`/api/dashboard/${encodeURIComponent(guildId)}/roles`, { method: 'GET', headers: { 'Accept': 'application/json' } }); - if(!res.ok) { - return; - } - const j = await res.json(); - if(j && Array.isArray(j.roles)){ - window.dispatchEvent(new CustomEvent('roles:loaded', { detail: { roles: j.roles } })); + if(res && res.ok){ + const j = await res.json(); + if(j && Array.isArray(j.roles)){ + window.dispatchEvent(new CustomEvent('roles:loaded', { detail: { roles: j.roles } })); + } } }catch(err){ /* ignore errors */ } + // restore + btn.disabled = false; + btn.classList.remove('opacity-50','pointer-events-none'); }); })(); diff --git a/src/server/views/partials/dashboard_nav.ejs b/src/server/views/partials/dashboard_nav.ejs index 8f28192..57d71cb 100644 --- a/src/server/views/partials/dashboard_nav.ejs +++ b/src/server/views/partials/dashboard_nav.ejs @@ -135,6 +135,39 @@ // close other menus first closeAllMenus(); openDropdown(btn, list); + // runtime-check: for items that were not marked as having the bot, try fetching roles + (async function refreshMissingBotFlags(){ + try{ + const items = Array.from(list.querySelectorAll('.guild-item')) || []; + for(const el of items){ + try{ + const botAttr = el.getAttribute('data-bot'); + if(botAttr === '1') continue; + const gid = el.getAttribute('data-id'); + if(!gid) continue; + const res = await fetch(`/api/dashboard/${encodeURIComponent(gid)}/roles`, { method: 'GET', headers: { 'Accept': 'application/json' } }); + if(res && res.ok){ + // update element to show the bot is present + el.setAttribute('data-bot','1'); + el.classList.remove('opacity-60'); + const infoSpan = el.querySelector('.text-xs'); + if(infoSpan) infoSpan.textContent = '(Bot)'; + const nameDiv = el.querySelector('.flex-1'); + if(nameDiv){ + // ensure (Bot) marker exists after name + let marker = nameDiv.querySelector('.bot-marker'); + if(!marker){ + marker = document.createElement('span'); + marker.className = 'ml-2 text-xs text-emerald-300 bot-marker'; + marker.textContent = '(Bot)'; + nameDiv.appendChild(marker); + } + } + } + }catch(e){ /* ignore per-item errors */ } + } + }catch(e){ /* ignore */ } + })(); } }); // Use event delegation on the list so clicks on children are handled reliably