userIdc2024 commited on
Commit
bb80b30
·
verified ·
1 Parent(s): 165b4b3

Update frontend/script.js

Browse files
Files changed (1) hide show
  1. frontend/script.js +125 -14
frontend/script.js CHANGED
@@ -3,7 +3,6 @@ const API_BASE = "";
3
 
4
  // ===== DOM Elements =====
5
  const form = document.getElementById("researchForm");
6
- const audienceSelect = document.getElementById("targetAudience");
7
  const categoryInput = document.getElementById("productCategory");
8
  const descriptionInput = document.getElementById("productDescription");
9
  const submitBtn = document.getElementById("submitBtn");
@@ -13,7 +12,16 @@ const errorBanner = document.getElementById("errorBanner");
13
  const resultsDiv = document.getElementById("results");
14
  const toggleBtns = document.querySelectorAll(".toggle-btn");
15
 
 
 
 
 
 
 
 
16
  let selectedMethod = "gpt";
 
 
17
 
18
  // ===== Load Target Audiences =====
19
  async function loadAudiences() {
@@ -21,20 +29,119 @@ async function loadAudiences() {
21
  const res = await fetch(`${API_BASE}/api/target-audiences`);
22
  if (!res.ok) throw new Error("Failed to load audiences");
23
  const data = await res.json();
24
-
25
- audienceSelect.innerHTML = '<option value="" disabled selected>Select target audience</option>';
26
- data.audiences.forEach((audience) => {
27
- const opt = document.createElement("option");
28
- opt.value = audience;
29
- opt.textContent = audience;
30
- audienceSelect.appendChild(opt);
31
- });
32
  } catch (err) {
33
  console.error("Could not load audiences:", err);
34
- audienceSelect.innerHTML = '<option value="" disabled selected>⚠ Could not load — is the backend running?</option>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  }
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  // ===== Method Toggle =====
39
  toggleBtns.forEach((btn) => {
40
  btn.addEventListener("click", () => {
@@ -51,14 +158,14 @@ form.addEventListener("submit", async (e) => {
51
  hideResults();
52
 
53
  const payload = {
54
- target_audience: audienceSelect.value,
55
  product_category: categoryInput.value.trim(),
56
  product_description: descriptionInput.value.trim(),
57
  method: selectedMethod,
58
  };
59
 
60
- if (!payload.target_audience || !payload.product_category || !payload.product_description) {
61
- showError("Please fill in all fields.");
62
  return;
63
  }
64
 
@@ -101,7 +208,7 @@ function renderResults(triggers, method) {
101
  triggers.forEach((item, idx) => {
102
  html += `
103
  <div class="trigger-card">
104
- <span class="trigger-label">PsychologicalTrigger ${idx + 1}</span>
105
  <h3 class="trigger-name">${escapeHtml(item.phsychologyTriggers)}</h3>
106
 
107
  <div class="trigger-section">
@@ -152,5 +259,9 @@ function escapeHtml(str) {
152
  return div.innerHTML;
153
  }
154
 
 
 
 
 
155
  // ===== Init =====
156
  loadAudiences();
 
3
 
4
  // ===== DOM Elements =====
5
  const form = document.getElementById("researchForm");
 
6
  const categoryInput = document.getElementById("productCategory");
7
  const descriptionInput = document.getElementById("productDescription");
8
  const submitBtn = document.getElementById("submitBtn");
 
12
  const resultsDiv = document.getElementById("results");
13
  const toggleBtns = document.querySelectorAll(".toggle-btn");
14
 
15
+ // Multi-select elements
16
+ const multiselect = document.getElementById("audienceMultiselect");
17
+ const selectedContainer = document.getElementById("selectedAudiences");
18
+ const dropdown = document.getElementById("audienceDropdown");
19
+ const searchInput = document.getElementById("audienceSearch");
20
+ const optionsContainer = document.getElementById("audienceOptions");
21
+
22
  let selectedMethod = "gpt";
23
+ let selectedAudiences = [];
24
+ let allAudiences = [];
25
 
26
  // ===== Load Target Audiences =====
27
  async function loadAudiences() {
 
29
  const res = await fetch(`${API_BASE}/api/target-audiences`);
30
  if (!res.ok) throw new Error("Failed to load audiences");
31
  const data = await res.json();
32
+ allAudiences = data.audiences;
33
+ renderOptions();
34
+ renderSelected();
 
 
 
 
 
35
  } catch (err) {
36
  console.error("Could not load audiences:", err);
37
+ selectedContainer.innerHTML = '<span class="multiselect-placeholder">⚠ Could not load — is the backend running?</span>';
38
+ }
39
+ }
40
+
41
+ // ===== Multi-select: Render Options =====
42
+ function renderOptions(filter = "") {
43
+ const filterLower = filter.toLowerCase();
44
+ const filtered = allAudiences.filter((a) =>
45
+ a.toLowerCase().includes(filterLower)
46
+ );
47
+
48
+ optionsContainer.innerHTML = filtered
49
+ .map((a) => {
50
+ const isSelected = selectedAudiences.includes(a);
51
+ return `
52
+ <div class="multiselect-option ${isSelected ? "selected" : ""}" data-value="${escapeAttr(a)}">
53
+ <span class="check">${isSelected ? "✓" : ""}</span>
54
+ <span>${escapeHtml(a)}</span>
55
+ </div>
56
+ `;
57
+ })
58
+ .join("");
59
+
60
+ // Attach click listeners
61
+ optionsContainer.querySelectorAll(".multiselect-option").forEach((opt) => {
62
+ opt.addEventListener("click", () => {
63
+ const val = opt.dataset.value;
64
+ if (selectedAudiences.includes(val)) {
65
+ selectedAudiences = selectedAudiences.filter((a) => a !== val);
66
+ } else {
67
+ selectedAudiences.push(val);
68
+ }
69
+ renderOptions(searchInput.value);
70
+ renderSelected();
71
+ });
72
+ });
73
+ }
74
+
75
+ // ===== Multi-select: Render Selected Tags =====
76
+ function renderSelected() {
77
+ if (selectedAudiences.length === 0) {
78
+ selectedContainer.innerHTML = '<span class="multiselect-placeholder">Select target audiences…</span>';
79
+ return;
80
+ }
81
+
82
+ selectedContainer.innerHTML = selectedAudiences
83
+ .map(
84
+ (a) => `
85
+ <span class="multiselect-tag">
86
+ ${escapeHtml(a)}
87
+ <span class="multiselect-tag-remove" data-value="${escapeAttr(a)}">×</span>
88
+ </span>
89
+ `
90
+ )
91
+ .join("");
92
+
93
+ // Attach remove listeners
94
+ selectedContainer.querySelectorAll(".multiselect-tag-remove").forEach((btn) => {
95
+ btn.addEventListener("click", (e) => {
96
+ e.stopPropagation();
97
+ const val = btn.dataset.value;
98
+ selectedAudiences = selectedAudiences.filter((a) => a !== val);
99
+ renderOptions(searchInput.value);
100
+ renderSelected();
101
+ });
102
+ });
103
+ }
104
+
105
+ // ===== Multi-select: Toggle Dropdown =====
106
+ selectedContainer.addEventListener("click", () => {
107
+ const isOpen = !dropdown.classList.contains("hidden");
108
+ if (isOpen) {
109
+ closeDropdown();
110
+ } else {
111
+ openDropdown();
112
  }
113
+ });
114
+
115
+ function openDropdown() {
116
+ dropdown.classList.remove("hidden");
117
+ selectedContainer.classList.add("active");
118
+ searchInput.value = "";
119
+ renderOptions();
120
+ searchInput.focus();
121
+ }
122
+
123
+ function closeDropdown() {
124
+ dropdown.classList.add("hidden");
125
+ selectedContainer.classList.remove("active");
126
  }
127
 
128
+ // Close on click outside
129
+ document.addEventListener("click", (e) => {
130
+ if (!multiselect.contains(e.target)) {
131
+ closeDropdown();
132
+ }
133
+ });
134
+
135
+ // Search filter
136
+ searchInput.addEventListener("input", () => {
137
+ renderOptions(searchInput.value);
138
+ });
139
+
140
+ // Prevent dropdown close when clicking inside it
141
+ dropdown.addEventListener("click", (e) => {
142
+ e.stopPropagation();
143
+ });
144
+
145
  // ===== Method Toggle =====
146
  toggleBtns.forEach((btn) => {
147
  btn.addEventListener("click", () => {
 
158
  hideResults();
159
 
160
  const payload = {
161
+ target_audience: selectedAudiences,
162
  product_category: categoryInput.value.trim(),
163
  product_description: descriptionInput.value.trim(),
164
  method: selectedMethod,
165
  };
166
 
167
+ if (payload.target_audience.length === 0 || !payload.product_category || !payload.product_description) {
168
+ showError("Please fill in all fields and select at least one target audience.");
169
  return;
170
  }
171
 
 
208
  triggers.forEach((item, idx) => {
209
  html += `
210
  <div class="trigger-card">
211
+ <span class="trigger-label">Trigger ${idx + 1}</span>
212
  <h3 class="trigger-name">${escapeHtml(item.phsychologyTriggers)}</h3>
213
 
214
  <div class="trigger-section">
 
259
  return div.innerHTML;
260
  }
261
 
262
+ function escapeAttr(str) {
263
+ return str.replace(/"/g, "&quot;").replace(/'/g, "&#39;");
264
+ }
265
+
266
  // ===== Init =====
267
  loadAudiences();