Nessun oggetto della modifica
Nessun oggetto della modifica
Riga 1: Riga 1:
// ============================================
/* dashboard.js — Masticationpedia (colla UI) */
// 🔧 CommonDashboard.js – versione SOLO server-proxy (no API key lato client)
// ---------- Utilità ----------
// Pulito e coerente con "Gestione Progetti" (filesystem reale)
const $ = sel => document.querySelector(sel);
// ============================================
const $$ = sel => Array.from(document.querySelectorAll(sel));


// ────────────────────────────────────────────
function logActivity(msg) {
// 🧭 UTILITÀ GENERALI
   const box = $('#activityLogContent');
// ────────────────────────────────────────────
   if (!box) return;
window.toggleDashboardBox = function (id) {
   const now = new Date();
   const box = document.getElementById(id);
   const hh = now.toTimeString().slice(0,8);
  if (box) box.style.display = box.style.display === "block" ? "none" : "block";
   const line = `[${hh}] ${msg}`;
};
   const pre = document.createElement('div');
 
   pre.textContent = line;
// Mini-log visuale in pagina
  box.prepend(pre);
window.logActivity = function (messaggio) {
}
  const contenitore = document.getElementById("activityLogContent") || document.getElementById("activityLog");
   if (!contenitore) return;
   const ora = new Date().toLocaleTimeString("it-IT");
   const entry = document.createElement("div");
   entry.innerHTML = `<span style="color:gray;">[${ora}]</span> ${messaggio}`;
  contenitore.prepend(entry);
};
window.clearActivityLog = function () {
   const contenitore = document.getElementById("activityLogContent");
   if (contenitore) {
    contenitore.innerHTML = "<em>Registro svuotato.</em><br>";
    logActivity("🧹 Log svuotato manualmente.");
  }
};


// Log persistente lato server (Basic Auth inclusa)
async function postJSON(url, body) {
function dashLog(msg, lvl='INFO', mod='Dashboard', act='') {
   const r = await fetch(url, {
   const body = new URLSearchParams({ m: msg, lvl, mod, act });
  return fetch('/dashboard/api/log.php', {
     method: 'POST',
     method: 'POST',
     headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
     headers: {'Content-Type':'application/json'},
     body,
     body: JSON.stringify(body || {})
    credentials: 'include'
   });
   }).catch(e => console.error('dashLog fail:', e));
  // alcuni endpoint tornano text; gestisco entrambe
  const txt = await r.text();
  try { return JSON.parse(txt); } catch { return {ok:false, raw:txt}; }
}
}
function logInfo (m, extra={}) { return dashLog(m, 'INFO',    extra.mod||'Dashboard', extra.act||''); }
function logWarn (m, extra={}) { return dashLog(m, 'WARNING', extra.mod||'Dashboard', extra.act||''); }
function logError(m, extra={}) { return dashLog(m, 'ERROR',  extra.mod||'Dashboard', extra.act||''); }


// ────────────────────────────────────────────
// ---------- Toggle sezioni ----------
/* ⚙️ CONNESSIONE API (via proxy server) */
window.toggleDashboardBox = function(id){
// ────────────────────────────────────────────
  // chiudi tutte
window.testAPIConnection = async function () {
  ['api-settings','project-status','chatgpt-plus','test-tools','activity-log'].forEach(i=>{
  const prompt = (document.getElementById("test-prompt")?.value || "").trim();
    const el = document.getElementById(i);
   const output = document.getElementById("api-result");
    if (el) el.style.display = 'none';
   const model  = document.getElementById("model-select")?.value || "gpt-4o-2024-05-13";
   });
 
  // apri quella scelta
   if (!prompt) { output.innerText = "⚠️ Inserisci un prompt di test."; return; }
   const box = document.getElementById(id);
 
   if (box) box.style.display = 'block';
  output.innerText = "⏳ Contatto il proxy sul server...";
};
  logActivity(`🚀 Test API via proxy – Modello: <strong>${model}</strong>`);


// ---------- Clear log server ----------
window.clearServerLog = async function(){
   try {
   try {
     const res = await fetch("/dashboard/api/openai_project_gpt.php", {
     const r = await fetch('/dashboard/api/log_clear.php', {cache:'no-store'});
      method: "POST",
     const j = await r.json();
      headers: { "Content-Type": "application/json" },
     if (j.ok) {
      credentials: "include",
       alert('Log svuotato ');
      body: JSON.stringify({ prompt, model })
       logActivity('🧹 Log server svuotato');
    });
     const data = await res.json();
 
     if (data.status === "ok" && data.result) {
       output.innerText = "Risposta: " + data.result;
       logActivity(`✅ Proxy OK – Modello: <strong>${model}</strong>`);
     } else {
     } else {
       output.innerText = "❌ Errore: " + (data.error || "Risposta vuota");
       alert('Errore svuota log: ' + (j.error||''));
       logActivity(`❌ Errore proxy: ${data.error || "risposta vuota"}`);
       logActivity('❌ Errore svuota log');
     }
     }
   } catch (e) {
   } catch(e) {
     output.innerText = "🚫 Errore di rete: " + e.message;
     alert('Errore rete: ' + e.message);
    logActivity(`❌ Errore rete: ${e.message}`);
   }
   }
};
};


// ────────────────────────────────────────────
// ---------- Test API OpenAI ----------
/* 🧠 ANALISI PROGETTO (render pulito in card) */
window.testAPIConnection = async function(){
// ────────────────────────────────────────────
  const model  = ($('#model-select')?.value || 'gpt-4o-2024-05-13').trim();
  const prompt = ($('#test-prompt')?.value || 'Dimmi una curiosità sulla mandibola').trim();


// Renderer stile ChatGPT per #gptResponse
  logActivity(`🚀 Test API via proxy — Modello: ${model}`);
function renderGpt(text) {
   const res = await postJSON('/dashboard/api/openai_project_gpt.php', {model, prompt});
   const box = document.getElementById('gptResponse');
   if (res.status === 'ok' && res.result) {
   if (!box) return;
     logActivity(`✅ Proxy OK — Modello: ${model}`);
  if (!text) { box.innerHTML = '<em style="opacity:.7">Nessuna risposta</em>'; return; }
     const out = $('#gptResponse');
 
    if (out) out.textContent = res.result;
  let html = (text || '').replace(/\r\n/g, '\n')
   } else {
     .replace(/^\s*#{3}\s?(.*)$/gm, '<h3 style="font-size:18px;margin:14px 0 6px;">$1</h3>')
     logActivity(`❌ Proxy errore: ${(res.error||res.raw||'sconosciuto')}`);
    .replace(/^\s*#{2}\s?(.*)$/gm, '<h2 style="font-size:20px;margin:16px 0 8px;">$1</h2>')
    alert('Errore API: ' + (res.error||res.raw||''));
     .replace(/^\s*#\s?(.*)$/gm,  '<h1 style="font-size:22px;margin:18px 0 10px;">$1</h1>')
   }
    .replace(/^\s*-\s+(.*)$/gm,  '<li>$1</li>');
};
  html = html.replace(/(?:<li>.*<\/li>\n?)+/gs, m => `<ul style="margin:8px 0 14px 22px;">${m}</ul>`);
   html = html.split('\n').map(line => {
     if (/^<h\d|^<ul|^<li|^<\/ul>/.test(line)) return line;
    if (line.trim()==='') return '';
    return `<p style="margin:8px 0;">${line}</p>`;
  }).join('');
  box.innerHTML = html;
}
 
// Costruisce prompt dal form
// Costruisce prompt *disciplinato* e sempre in ITALIANO
function buildPromptForGPT() {
  const title      = (document.getElementById('newProjectTitle')?.value || '').trim();
  const notes      = (document.getElementById('newProjectNotes')?.value || '').trim();
  const goal        = (document.getElementById('p_goal')?.value || '').trim();
  const audience    = (document.getElementById('p_audience')?.value || '').trim();
   const deliverable = (document.getElementById('p_deliverable')?.value || '').trim();
  const constraints = (document.getElementById('p_constraints')?.value || '').trim();


  // 🔒 Non far partire l’analisi senza un minimo di contesto
// ---------- Analizza progetto (Stato Progetti) ----------
   const haveMinContext = goal || deliverable || notes || title;
function buildPromptForGPT(){
   if (!haveMinContext) {
   const goal        = ($('#p_goal')?.value||'').trim();
    throw new Error("Aggiungi almeno uno tra: Titolo, Note, Obiettivo o Output atteso.");
  const audience    = ($('#p_audience')?.value||'').trim();
  }
  const deliverable = ($('#p_deliverable')?.value||'').trim();
   const constraints = ($('#p_constraints')?.value||'').trim();


  // Prompt con regole anti-fuffa (📌 lingua fissa: ITALIANO)
   const parts = [];
   const parts = [];
   parts.push("Rispondi esclusivamente in ITALIANO. Sei un project designer senior.");
   parts.push('Sei un project manager ed editor senior. Rispondi in ITALIANO. Fornisci un piano chiaro e operativo.');
   parts.push("Scrivi in modo operativo, conciso e senza preamboli inutili.");
   if (goal)        parts.push('\n# Obiettivo\n' + goal);
   parts.push("Se mancano dati, aggiungi una sezione 'Dati mancanti' senza inventare.");
  if (audience)    parts.push('\n# Pubblico\n' + audience);
   parts.push("Tono pratico. Usa al massimo 12 bullet in totale.");
   if (deliverable) parts.push('\n# Output atteso\n' + deliverable);
   parts.push("");
   if (constraints) parts.push('\n# Vincoli\n' + constraints);
   parts.push(`
# Formato output richiesto
- Sommario introduttivo
- Punti di forza e rischi
- Piano step-by-step (milestones)
- File/Config necessari dal server (ELENCO puntuale dei file da leggere)
- Risorse & Budget hint
- Metriche di successo`);


  if (title)      parts.push("📌 Titolo: " + title);
   return parts.join('\n');
  if (notes)      parts.push("📝 Note: " + notes);
  if (goal)        parts.push("🎯 Obiettivo: " + goal);
  if (audience)    parts.push("👥 Pubblico: " + audience);
  if (deliverable) parts.push("📦 Output atteso: " + deliverable);
  if (constraints) parts.push("⏱️ Vincoli: " + constraints);
 
   return parts.join("\n");
}
}


 
window.runProjectAnalysis = async function(){
// Bottone "Analizza con GPT" (via proxy server). Se vuoi la chiamata reale, basta usare questo handler.
   const btn = $('#btnAnalyze');
window.analyzeProjectWithGPT = async function () {
   if (!btn) return;
   const btn   = document.getElementById('btnAnalyze');
   btn.disabled = true; btn.textContent = 'Analizzo…';
   const model = document.getElementById("model-select")?.value || "gpt-4o-2024-05-13";
   const prompt = buildPromptForGPT();
 
  btn && (btn.disabled = true, btn.textContent = 'Analizzo…');
  logActivity('🤖 Analisi GPT via proxy…');
 
   try {
   try {
     const res = await fetch("/dashboard/api/openai_project_gpt.php", {
    const prompt = buildPromptForGPT();
      method: "POST",
    const model  = ($('#model-select')?.value || 'gpt-4o-2024-05-13').trim();
      headers: { "Content-Type": "application/json" },
     const res = await postJSON('/dashboard/api/openai_project_gpt.php', {model, prompt});
      credentials: "include",
     if (res.status === 'ok' && res.result) {
      body: JSON.stringify({ prompt, model })
       const out = $('#gptResponse');
    });
       if (out) out.textContent = res.result;
    const data = await res.json();
       logActivity('🧠 Analisi GPT completata');
 
     if (data.status === "ok" && data.result) {
       renderGpt(data.result);
       logActivity('✅ Analisi GPT completata');
       logInfo('GPT analysis done', { mod:'GPT', act:'analyze' });
     } else {
     } else {
       renderGpt('❌ Errore GPT: ' + (data.error || 'Risposta vuota'));
       const msg = res.error || res.raw || 'Errore sconosciuto';
       logError('GPT analysis failed', { mod:'GPT', act:'analyze' });
       logActivity('❌ Analisi GPT fallita: ' + msg);
      alert('Errore analisi: ' + msg);
     }
     }
   } catch (err) {
   } catch(e){
     renderGpt('Errore di rete: ' + err.message);
     alert('Errore rete: ' + e.message);
    logError('GPT network error', { mod:'GPT', act:'analyze' });
   } finally {
   } finally {
     btn && (btn.disabled = false, btn.textContent = 'Analizza con GPT');
     btn.disabled = false; btn.textContent = 'Analizza con GPT';
   }
   }
};
};


// ────────────────────────────────────────────
// ---------- Progetti (crea + lista) ----------
/* 📁 PROMPT / FILE (utility esistenti) */
async function refreshProjects(){
// ────────────────────────────────────────────
   const list = $('#projectsList');
window.loadPrompt = function () {
   if (!list) return;
  fetch("/dashboard/api/read_file.php?projectName=global&subfolder=&filename=prompt.txt", {
   list.innerHTML = '<em>Carico…</em>';
    credentials: "include"
  })
  .then(r => r.json())
  .then(data => {
    if (data.status === "ok") {
      const el = document.getElementById("promptArea");
      if (el) el.value = data.content;
      logActivity("📥 Caricato prompt.txt nella textarea.");
    } else {
      alert("Errore: " + data.error);
      logActivity("❌ Errore nel caricamento: " + data.error);
    }
  })
  .catch(e => {
    alert("Errore nel caricamento: " + e);
    logActivity("❌ Errore nel caricamento di prompt.txt.");
  });
};
 
window.savePrompt = function () {
  const content = document.getElementById("promptArea")?.value || "";
  fetch("/dashboard/api/write_prompt.php", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    credentials: "include",
    body: "text=" + encodeURIComponent(content)
  })
  .then(r => { if (!r.ok) throw new Error("Errore nel salvataggio"); return r.text(); })
  .then(() => { logActivity("💾 Salvato prompt.txt dal form."); alert("Prompt salvato con successo."); })
  .catch(e => { alert("Errore nel salvataggio: " + e); logActivity("❌ Errore nel salvataggio di prompt.txt."); });
};
 
// Salva / Carica files per GPT
window.salvaFileDaTextarea = function () {
  const content  = document.getElementById("gpt-response-area")?.value || "";
  const filename = document.getElementById("gpt-filename")?.value.trim();
  const subfolder= document.getElementById("gpt-subfolder")?.value || "";
  const project  = document.getElementById("newProjectTitle")?.value.trim() || "SSO_LinkedIn";
  if (!filename || !content) { alert("Nome file o contenuto mancante."); return; }
 
  fetch("/dashboard/api/write_file.php", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    credentials: "include",
    body: JSON.stringify({ projectName: project, subfolder, filename, content })
  })
  .then(r => r.json())
  .then(data => {
    if (data.status === "ok") {
      logActivity(`💾 Salvato <strong>${filename}</strong> in progetto <strong>${project}</strong>.`);
      alert("File salvato: " + (data.path || filename));
    } else {
      alert("Errore: " + data.error);
      logActivity(`❌ Errore salvataggio ${filename}: ${data.error}`);
    }
  })
  .catch(e => { alert("Errore durante il salvataggio."); console.error(e); });
};
 
window.caricaFileGPT = function () {
  const filename = document.getElementById("gpt-filename")?.value.trim();
  const subfolder= document.getElementById("gpt-subfolder")?.value || "";
  const project  = document.getElementById("newProjectTitle")?.value.trim() || "SSO_LinkedIn";
  if (!filename) { alert("Inserisci il nome del file da caricare."); return; }
 
  fetch(`/dashboard/api/read_file.php?projectName=${encodeURIComponent(project)}&subfolder=${encodeURIComponent(subfolder)}&filename=${encodeURIComponent(filename)}`, { credentials: "include" })
  .then(r => r.json())
  .then(data => {
    if (data.status === "ok") {
      const ta = document.getElementById("gpt-response-area");
      if (ta) ta.value = data.content;
      logActivity(`📂 Caricato <strong>${filename}</strong> da progetto <strong>${project}</strong>.`);
    } else {
      alert("Errore: " + data.error);
      logActivity(`❌ Errore nel caricamento di ${filename}: ${data.error}`);
    }
  })
  .catch(e => { alert("Errore durante il caricamento del file."); console.error(e); });
};
 
// ────────────────────────────────────────────
/* 🧪 STRUMENTI DI TEST */
// ────────────────────────────────────────────
window.runTestCode = function () {
   const ta = document.getElementById('codeArea');
   if (!ta) { alert('Area di test non trovata (#codeArea).'); return; }
   const src = ta.value || '';
  try { return new Function(src)(); }
  catch (e) { alert('Errore nel codice:\n' + e.message); }
};
 
// ────────────────────────────────────────────
/* =======================
* 📂 GESTIONE PROGETTI (REALE)
* ======================= */
// ────────────────────────────────────────────
const API = {
  list:  '/dashboard/api/project_list.php',
  create: '/dashboard/api/project_create.php',
  del:    '/dashboard/api/project_delete.php',
  backup: '/dashboard/api/project_backup.php'
};
 
let currentProject = null;
 
// Carica lista
async function loadAllProjects() {
   try {
   try {
     const r = await fetch(API.list, { credentials:'include', cache:'no-store' });
     const r = await fetch('/dashboard/api/project_list.php', {cache:'no-store'});
     const txt = await r.text();
     const j = await r.json();
     let j; try { j = JSON.parse(txt); } catch { throw new Error('Risposta non-JSON dalla lista progetti'); }
     if (!j.ok || !Array.isArray(j.projects)) { list.textContent = 'Nessun progetto.'; return; }
     if (!j.ok) throw new Error(j.error || 'Lista progetti fallita');
    if (!j.projects.length) { list.textContent = 'Nessun progetto.'; return; }
     renderProjects(j.projects || []);
    list.innerHTML = j.projects.map(name => `
  } catch (e) {
      <li style="display:flex;gap:8px;align-items:center;margin:4px 0;">
    console.error('project_list error:', e);
        <code>${name}</code>
     alert('Errore nel caricamento dei progetti: ' + e.message);
        <button data-open="${name}">Apri</button>
        <button data-zip="${name}">ZIP</button>
        <button data-del="${name}" title="Sposta nel cestino">🗑️</button>
      </li>
    `).join('');
     list.querySelectorAll('[data-open]').forEach(b=>{
      b.addEventListener('click', ()=>selectProject(b.getAttribute('data-open')));
     });
    list.querySelectorAll('[data-zip]').forEach(b=>{
      b.addEventListener('click', ()=>zipProject(b.getAttribute('data-zip')));
    });
    list.querySelectorAll('[data-del]').forEach(b=>{
      b.addEventListener('click', ()=>deleteProject(b.getAttribute('data-del')));
     });
  } catch(e) {
    list.textContent = 'Errore lista: ' + e.message;
   }
   }
}
}


// Disegna lista
async function selectProject(name){
function renderProjects(projects) {
   // eventuale endpoint select (se esiste). Per ora solo log.
   const ul = document.getElementById('projectsList');
   logActivity('📂 Project selezionato: ' + name);
  if (!ul) return;
  ul.innerHTML = '';
 
  if (!projects.length) {
    ul.innerHTML = '<li style="color:#777;">Nessun progetto trovato.</li>';
    return;
   }
 
  projects.forEach(p => {
    const li = document.createElement('li');
    li.style.display = 'flex';
    li.style.alignItems = 'center';
    li.style.gap = '8px';
    li.style.margin = '6px 0';
 
    const label = document.createElement('span');
    label.textContent = p.name;
    label.style.fontWeight = (p.name === currentProject ? '700' : '500');
 
    const btnOpen = document.createElement('button');
    btnOpen.textContent = 'Apri';
    btnOpen.onclick = () => { selectProject(p.name); };
 
    const btnZip = document.createElement('button');
    btnZip.textContent = 'ZIP';
    btnZip.title = 'Crea backup zip';
    btnZip.onclick = () => backupProject(p.name);
 
    const btnDel = document.createElement('button');
    btnDel.textContent = '🗑️';
    btnDel.title = 'Sposta nel cestino (soft delete)';
    btnDel.onclick = () => deleteProject(p.name);
 
    li.append(label, btnOpen, btnZip, btnDel);
    ul.appendChild(li);
  });
}
}


function selectProject(name) {
async function zipProject(name){
  currentProject = name;
  logInfo('Project selected', { mod:'Progetti', act:'select' });
  loadAllProjects();
}
 
// Crea
let __creating = false;
 
async function createProject() {
  if (__creating) return;                // evita doppio invio
  const input = document.getElementById('newProjectName');
  const raw  = (input?.value || '').trim();
  if (!raw) { alert('Inserisci un nome progetto'); return; }
 
  // 1) normalizza: sostituisci spazi con underscore
  const name = raw.replace(/\s+/g, '_');
 
  // 2) valida: solo A-Z a-z 0-9 _ -
  if (!/^[A-Za-z0-9_-]+$/.test(name)) {
    alert('Nome non valido. Usa solo A–Z, a–z, 0–9, _ e - (niente accenti/simboli).');
    return;
  }
 
  __creating = true;
  const btn = document.getElementById('btnCreateProject');
  if (btn) { btn.disabled = true; btn.textContent = 'Creo…'; }
 
   try {
   try {
     const r = await fetch('/dashboard/api/project_create.php', {
     const j = await postJSON('/dashboard/api/project_backup.php', { name });
      method: 'POST',
     if (j.ok) { alert('ZIP creato: ' + (j.zip||'')); logActivity('🗜️ Backup creato: ' + (j.zip||'')); }
      credentials: 'include',
     else { alert('Errore ZIP: ' + (j.error||'')); }
      headers: { 'Content-Type':'application/x-www-form-urlencoded' },
   } catch(e){ alert('Errore: ' + e.message); }
      body: new URLSearchParams({ name })
    });
 
    let j;
     try { j = await r.json(); } catch { throw new Error('Risposta non-JSON dal server'); }
 
    if (!j.ok) {
      if (r.status === 409) throw new Error('Questo progetto esiste già.');
      if (r.status === 401) throw new Error('Non sei autenticato (Basic Auth). Apri /dashboard/api/project_list.php, inserisci user/pass e riprova.');
      if (j.error)          throw new Error(j.error);
      throw new Error('Creazione fallita.');
    }
 
     logInfo('Project created', { mod:'Progetti', act:'create' });
    input.value = '';
    await loadAllProjects();
    selectProject(name);
   } catch (e) {
    console.error(e);
    logError('Project create failed', { mod:'Progetti', act:'create' });
    alert('Errore creazione: ' + e.message);
  } finally {
    __creating = false;
    if (btn) { btn.disabled = false; btn.textContent = 'Crea progetto'; }
  }
}
}


 
async function deleteProject(name){
// Elimina (soft)
   if (!confirm('Spostare nel cestino "'+name+'"?')) return;
async function deleteProject(name) {
   if (!confirm(`Sicuro di spostare "${name}" nel cestino?`)) return;
   try {
   try {
     const r = await fetch(API.del, {
     const j = await postJSON('/dashboard/api/project_delete.php', { name });
      method:'POST',
     if (j.ok) { logActivity('🗑️ Progetto spostato nel cestino'); refreshProjects(); }
      credentials:'include',
     else { alert('Errore delete: ' + (j.error||'')); }
      headers:{'Content-Type':'application/x-www-form-urlencoded'},
   } catch(e){ alert('Errore: ' + e.message); }
      body: new URLSearchParams({ name })
    });
    const j = await r.json();
     if (!j.ok) throw new Error(j.error || 'delete failed');
     logWarn('Project moved to trash', { mod:'Progetti', act:'delete' });
    if (currentProject === name) currentProject = null;
    await loadAllProjects();
   } catch (e) {
    console.error(e);
    logError('Project delete failed', { mod:'Progetti', act:'delete' });
    alert('Errore eliminazione: ' + e.message);
  }
}
}


// Backup
async function createProject(){
async function backupProject(name) {
  const inp = $('#newProjectName');
  const name = (inp?.value||'').trim();
  if (!name) { alert('Inserisci un nome progetto'); return; }
   try {
   try {
     const r = await fetch(API.backup, {
     const j = await postJSON('/dashboard/api/project_create.php', { name });
      method:'POST',
     if (j.ok) {
      credentials:'include',
      logActivity('✅ Progetto creato: ' + name);
      headers:{'Content-Type':'application/x-www-form-urlencoded'},
      inp.value = '';
      body: new URLSearchParams({ name })
      refreshProjects();
    });
     } else {
    const j = await r.json();
      alert('Errore creazione: ' + (j.error||''));
     if (!j.ok) throw new Error(j.error || 'backup failed');
     }
     logInfo('Project zipped', { mod:'Progetti', act:'backup' });
   } catch(e) {
     alert(`Backup creato: ${j.zip}`);
     alert('Errore rete: ' + e.message);
   } catch (e) {
    console.error(e);
    logError('Project backup failed', { mod:'Progetti', act:'backup' });
     alert('Errore backup: ' + e.message);
   }
   }
}
}


// Bind UI
// ---------- Carica in OpenAI (stub clic pulsante in alto) ----------
document.addEventListener('DOMContentLoaded', () => {
window.uploadToOpenAI = function(){
   const btnCreate = document.getElementById('btnCreateProject');
   alert('Funzione "Carica in OpenAI" in preparazione.');
  if (btnCreate) btnCreate.addEventListener('click', createProject);
};


  const analyzeBtn = document.getElementById('btnAnalyze');
// ---------- Bind all ----------
   if (analyzeBtn) analyzeBtn.addEventListener('click', window.analyzeProjectWithGPT);
document.addEventListener('DOMContentLoaded', ()=>{
 
  // bottoni/azioni principali già definiti in HTML
   loadAllProjects(); // subito all’avvio
   $('#btnAnalyze') && $('#btnAnalyze').addEventListener('click', window.runProjectAnalysis);
  $('#btnCreateProject') && $('#btnCreateProject').addEventListener('click', createProject);
   refreshProjects();
});
});
// ────────────────────────────────────────────
// FINE FILE
// ────────────────────────────────────────────

Versione delle 18:03, 23 set 2025

/* dashboard.js — Masticationpedia (colla UI) */
// ---------- Utilità ----------
const $ = sel => document.querySelector(sel);
const $$ = sel => Array.from(document.querySelectorAll(sel));

function logActivity(msg) {
  const box = $('#activityLogContent');
  if (!box) return;
  const now = new Date();
  const hh = now.toTimeString().slice(0,8);
  const line = `[${hh}] ${msg}`;
  const pre = document.createElement('div');
  pre.textContent = line;
  box.prepend(pre);
}

async function postJSON(url, body) {
  const r = await fetch(url, {
    method: 'POST',
    headers: {'Content-Type':'application/json'},
    body: JSON.stringify(body || {})
  });
  // alcuni endpoint tornano text; gestisco entrambe
  const txt = await r.text();
  try { return JSON.parse(txt); } catch { return {ok:false, raw:txt}; }
}

// ---------- Toggle sezioni ----------
window.toggleDashboardBox = function(id){
  // chiudi tutte
  ['api-settings','project-status','chatgpt-plus','test-tools','activity-log'].forEach(i=>{
    const el = document.getElementById(i);
    if (el) el.style.display = 'none';
  });
  // apri quella scelta
  const box = document.getElementById(id);
  if (box) box.style.display = 'block';
};

// ---------- Clear log server ----------
window.clearServerLog = async function(){
  try {
    const r = await fetch('/dashboard/api/log_clear.php', {cache:'no-store'});
    const j = await r.json();
    if (j.ok) {
      alert('Log svuotato ✅');
      logActivity('🧹 Log server svuotato');
    } else {
      alert('Errore svuota log: ' + (j.error||''));
      logActivity('❌ Errore svuota log');
    }
  } catch(e) {
    alert('Errore rete: ' + e.message);
  }
};

// ---------- Test API OpenAI ----------
window.testAPIConnection = async function(){
  const model  = ($('#model-select')?.value || 'gpt-4o-2024-05-13').trim();
  const prompt = ($('#test-prompt')?.value || 'Dimmi una curiosità sulla mandibola').trim();

  logActivity(`🚀 Test API via proxy — Modello: ${model}`);
  const res = await postJSON('/dashboard/api/openai_project_gpt.php', {model, prompt});
  if (res.status === 'ok' && res.result) {
    logActivity(`✅ Proxy OK — Modello: ${model}`);
    const out = $('#gptResponse');
    if (out) out.textContent = res.result;
  } else {
    logActivity(`❌ Proxy errore: ${(res.error||res.raw||'sconosciuto')}`);
    alert('Errore API: ' + (res.error||res.raw||''));
  }
};

// ---------- Analizza progetto (Stato Progetti) ----------
function buildPromptForGPT(){
  const goal        = ($('#p_goal')?.value||'').trim();
  const audience    = ($('#p_audience')?.value||'').trim();
  const deliverable = ($('#p_deliverable')?.value||'').trim();
  const constraints = ($('#p_constraints')?.value||'').trim();

  const parts = [];
  parts.push('Sei un project manager ed editor senior. Rispondi in ITALIANO. Fornisci un piano chiaro e operativo.');
  if (goal)        parts.push('\n# Obiettivo\n' + goal);
  if (audience)    parts.push('\n# Pubblico\n' + audience);
  if (deliverable) parts.push('\n# Output atteso\n' + deliverable);
  if (constraints) parts.push('\n# Vincoli\n' + constraints);
  parts.push(`
# Formato output richiesto
- Sommario introduttivo
- Punti di forza e rischi
- Piano step-by-step (milestones)
- File/Config necessari dal server (ELENCO puntuale dei file da leggere)
- Risorse & Budget hint
- Metriche di successo`);

  return parts.join('\n');
}

window.runProjectAnalysis = async function(){
  const btn = $('#btnAnalyze');
  if (!btn) return;
  btn.disabled = true; btn.textContent = 'Analizzo…';
  try {
    const prompt = buildPromptForGPT();
    const model  = ($('#model-select')?.value || 'gpt-4o-2024-05-13').trim();
    const res = await postJSON('/dashboard/api/openai_project_gpt.php', {model, prompt});
    if (res.status === 'ok' && res.result) {
      const out = $('#gptResponse');
      if (out) out.textContent = res.result;
      logActivity('🧠 Analisi GPT completata');
    } else {
      const msg = res.error || res.raw || 'Errore sconosciuto';
      logActivity('❌ Analisi GPT fallita: ' + msg);
      alert('Errore analisi: ' + msg);
    }
  } catch(e){
    alert('Errore rete: ' + e.message);
  } finally {
    btn.disabled = false; btn.textContent = 'Analizza con GPT';
  }
};

// ---------- Progetti (crea + lista) ----------
async function refreshProjects(){
  const list = $('#projectsList');
  if (!list) return;
  list.innerHTML = '<em>Carico…</em>';
  try {
    const r = await fetch('/dashboard/api/project_list.php', {cache:'no-store'});
    const j = await r.json();
    if (!j.ok || !Array.isArray(j.projects)) { list.textContent = 'Nessun progetto.'; return; }
    if (!j.projects.length) { list.textContent = 'Nessun progetto.'; return; }
    list.innerHTML = j.projects.map(name => `
      <li style="display:flex;gap:8px;align-items:center;margin:4px 0;">
        <code>${name}</code>
        <button data-open="${name}">Apri</button>
        <button data-zip="${name}">ZIP</button>
        <button data-del="${name}" title="Sposta nel cestino">🗑️</button>
      </li>
    `).join('');
    list.querySelectorAll('[data-open]').forEach(b=>{
      b.addEventListener('click', ()=>selectProject(b.getAttribute('data-open')));
    });
    list.querySelectorAll('[data-zip]').forEach(b=>{
      b.addEventListener('click', ()=>zipProject(b.getAttribute('data-zip')));
    });
    list.querySelectorAll('[data-del]').forEach(b=>{
      b.addEventListener('click', ()=>deleteProject(b.getAttribute('data-del')));
    });
  } catch(e) {
    list.textContent = 'Errore lista: ' + e.message;
  }
}

async function selectProject(name){
  // eventuale endpoint select (se esiste). Per ora solo log.
  logActivity('📂 Project selezionato: ' + name);
}

async function zipProject(name){
  try {
    const j = await postJSON('/dashboard/api/project_backup.php', { name });
    if (j.ok) { alert('ZIP creato: ' + (j.zip||'')); logActivity('🗜️ Backup creato: ' + (j.zip||'')); }
    else { alert('Errore ZIP: ' + (j.error||'')); }
  } catch(e){ alert('Errore: ' + e.message); }
}

async function deleteProject(name){
  if (!confirm('Spostare nel cestino "'+name+'"?')) return;
  try {
    const j = await postJSON('/dashboard/api/project_delete.php', { name });
    if (j.ok) { logActivity('🗑️ Progetto spostato nel cestino'); refreshProjects(); }
    else { alert('Errore delete: ' + (j.error||'')); }
  } catch(e){ alert('Errore: ' + e.message); }
}

async function createProject(){
  const inp = $('#newProjectName');
  const name = (inp?.value||'').trim();
  if (!name) { alert('Inserisci un nome progetto'); return; }
  try {
    const j = await postJSON('/dashboard/api/project_create.php', { name });
    if (j.ok) {
      logActivity('✅ Progetto creato: ' + name);
      inp.value = '';
      refreshProjects();
    } else {
      alert('Errore creazione: ' + (j.error||''));
    }
  } catch(e) {
    alert('Errore rete: ' + e.message);
  }
}

// ---------- Carica in OpenAI (stub clic pulsante in alto) ----------
window.uploadToOpenAI = function(){
  alert('Funzione "Carica in OpenAI" in preparazione.');
};

// ---------- Bind all ----------
document.addEventListener('DOMContentLoaded', ()=>{
  // bottoni/azioni principali già definiti in HTML
  $('#btnAnalyze') && $('#btnAnalyze').addEventListener('click', window.runProjectAnalysis);
  $('#btnCreateProject') && $('#btnCreateProject').addEventListener('click', createProject);
  refreshProjects();
});