// ===== Configuration ===== const API_BASE = ""; // ===== DOM Elements ===== const form = document.getElementById("researchForm"); const categoryInput = document.getElementById("productCategory"); const descriptionInput = document.getElementById("productDescription"); const submitBtn = document.getElementById("submitBtn"); const btnText = submitBtn.querySelector(".btn-text"); const btnLoader = submitBtn.querySelector(".btn-loader"); const errorBanner = document.getElementById("errorBanner"); const resultsDiv = document.getElementById("results"); const toggleBtns = document.querySelectorAll(".toggle-btn"); // Multi-select elements const multiselect = document.getElementById("audienceMultiselect"); const selectedContainer = document.getElementById("selectedAudiences"); const dropdown = document.getElementById("audienceDropdown"); const searchInput = document.getElementById("audienceSearch"); const optionsContainer = document.getElementById("audienceOptions"); let selectedMethod = "gpt"; let selectedAudiences = []; let allAudiences = []; // ===== Load Target Audiences ===== async function loadAudiences() { try { const res = await fetch(`${API_BASE}/api/target-audiences`); if (!res.ok) throw new Error("Failed to load audiences"); const data = await res.json(); allAudiences = data.audiences; renderOptions(); renderSelected(); } catch (err) { console.error("Could not load audiences:", err); selectedContainer.innerHTML = '⚠ Could not load — is the backend running?'; } } // ===== Multi-select Logic (UNCHANGED) ===== function renderOptions(filter = "") { const filterLower = filter.toLowerCase(); const filtered = allAudiences.filter((a) => a.toLowerCase().includes(filterLower) ); optionsContainer.innerHTML = filtered .map((a) => { const isSelected = selectedAudiences.includes(a); return `
${isSelected ? "✓" : ""} ${escapeHtml(a)}
`; }) .join(""); optionsContainer.querySelectorAll(".multiselect-option").forEach((opt) => { opt.addEventListener("click", () => { const val = opt.dataset.value; if (selectedAudiences.includes(val)) { selectedAudiences = selectedAudiences.filter((a) => a !== val); } else { selectedAudiences.push(val); } renderOptions(searchInput.value); renderSelected(); }); }); } function renderSelected() { if (selectedAudiences.length === 0) { selectedContainer.innerHTML = 'Select target audiences…'; return; } selectedContainer.innerHTML = selectedAudiences .map( (a) => ` ${escapeHtml(a)} × ` ) .join(""); selectedContainer.querySelectorAll(".multiselect-tag-remove").forEach((btn) => { btn.addEventListener("click", (e) => { e.stopPropagation(); const val = btn.dataset.value; selectedAudiences = selectedAudiences.filter((a) => a !== val); renderOptions(searchInput.value); renderSelected(); }); }); } selectedContainer.addEventListener("click", () => { dropdown.classList.toggle("hidden"); }); document.addEventListener("click", (e) => { if (!multiselect.contains(e.target)) { dropdown.classList.add("hidden"); } }); searchInput.addEventListener("input", () => { renderOptions(searchInput.value); }); dropdown.addEventListener("click", (e) => { e.stopPropagation(); }); // ===== Method Toggle ===== toggleBtns.forEach((btn) => { btn.addEventListener("click", () => { toggleBtns.forEach((b) => b.classList.remove("active")); btn.classList.add("active"); selectedMethod = btn.dataset.method; }); }); // ===== Form Submit ===== form.addEventListener("submit", async (e) => { e.preventDefault(); hideError(); hideResults(); const payload = { target_audience: selectedAudiences, product_category: categoryInput.value.trim(), product_description: descriptionInput.value.trim(), method: selectedMethod, }; if ( payload.target_audience.length === 0 || !payload.product_category || !payload.product_description ) { showError( "Please fill in all fields and select at least one target audience." ); return; } setLoading(true); try { const res = await fetch(`${API_BASE}/api/research`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); if (!res.ok) throw new Error("Server error"); const data = await res.json(); renderResults(data.results, selectedMethod); } catch (err) { showError(err.message || "Something went wrong."); } finally { setLoading(false); } }); // ===================================================== // ✅ NEW RESULTS (VERTICAL NESTED COLLAPSIBLE) // ===================================================== function renderResults(audienceResults, method) { const badge = method === "gpt" ? `GPT` : `Claude`; let html = `

Results

${badge}
`; audienceResults.forEach((group, groupIndex) => { html += `
👥

${escapeHtml(group.target_audience)}

`; group.output.forEach((item, idx) => { html += `
Trigger ${idx + 1}

${escapeHtml(item.phsychologyTriggers)}

Ad Angles

    ${item.angles.map((a) => `
  • ${escapeHtml(a)}
  • `).join("")}

Ad Concepts

    ${item.concepts.map((c) => `
  • ${escapeHtml(c)}
  • `).join("")}
`; }); html += `
`; }); html += `
`; resultsDiv.innerHTML = html; resultsDiv.classList.remove("hidden"); attachAccordionEvents(); } // ===== Accordion Logic ===== function attachAccordionEvents() { document.querySelectorAll(".audience-card-header").forEach((header) => { header.addEventListener("click", () => { const card = header.parentElement; card.classList.toggle("open"); }); }); document.querySelectorAll(".trigger-header").forEach((header) => { header.addEventListener("click", () => { const card = header.parentElement; // Close siblings const siblings = card.parentElement.querySelectorAll(".trigger-card"); siblings.forEach((s) => { if (s !== card) s.classList.remove("open"); }); card.classList.toggle("open"); }); }); } // ===== Helpers ===== function setLoading(isLoading) { submitBtn.disabled = isLoading; btnText.classList.toggle("hidden", isLoading); btnLoader.classList.toggle("hidden", !isLoading); } function showError(msg) { errorBanner.textContent = msg; errorBanner.classList.remove("hidden"); } function hideError() { errorBanner.classList.add("hidden"); } function hideResults() { resultsDiv.classList.add("hidden"); } function escapeHtml(str) { const div = document.createElement("div"); div.textContent = str; return div.innerHTML; } function escapeAttr(str) { return str.replace(/"/g, """).replace(/'/g, "'"); } loadAudiences();