diff --git a/static/script.js b/static/script.js index 28dbbeb..bbc8250 100644 --- a/static/script.js +++ b/static/script.js @@ -453,6 +453,58 @@ updateProfileWidgets(); return valid; } + + // ---------------------------------------------------------- + // Form submission and API call + // ---------------------------------------------------------- + + form.addEventListener("submit", function (evt) { + evt.preventDefault(); + clearAllErrors(); + + if (skillsTextInput.value.trim()) { + addSkill(skillsTextInput.value); + skillsTextInput.value = ""; + hideSuggestions(); + } + + if (!validateForm()) return; + + setLoadingState(true); + + requestAnimationFrame(function () { + var payload = { + skills: skillsHidden.value.trim() || skillsTextInput.value.trim(), + level: document.getElementById("level").value, + interest: document.getElementById("interest").value, + time: document.getElementById("time").value + }; + + fetch("/api/recommend", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(payload) + }) + .then(function (res) { return res.json(); }) + .then(function (data) { + setLoadingState(false); + if (data.error) { + var generalErr = document.getElementById("form-error-general"); + if (generalErr) generalErr.textContent = data.error; + return; + } + renderResults(data.projects || [], data.message); + }) + .catch(function (err) { + setLoadingState(false); + var generalErr = document.getElementById("form-error-general"); + if (generalErr) generalErr.textContent = "Something went wrong. Please try again."; + console.error("API request failed:", err); + }); + }); +}); + + // Manages the loading state of the form and results section(whats visible or not) function setLoadingState(isLoading) { submitBtn.disabled = isLoading; submitBtn.setAttribute("aria-busy", isLoading ? "true" : "false"); @@ -474,6 +526,35 @@ updateProfileWidgets(); return text.length > maxLength ? text.slice(0, maxLength) + "..." : text; } + // ---------------------------------------------------------- + // Render result cards + // ---------------------------------------------------------- + + //takes the array of projects from the api and draws them on the page as cards + //if array is empty it shows the "no results" message instead + function renderResults(projects, message) { + resultsSection.style.display = "block"; + resultsLoadingEl.style.display = "none"; + // Clear out any cards from a previous search before showing new ones + resultsGrid.innerHTML = ""; + + if (!projects || projects.length === 0) { + resultsGrid.style.display = "none"; + resultsEmptyEl.style.display = "block"; + if (message && emptyMessageEl) emptyMessageEl.textContent = message; + resultsSection.scrollIntoView({ behavior: "smooth" }); + return; +} + + resultsEmptyEl.style.display = "none"; + resultsGrid.style.display = "grid"; + + //build a card for each project and add it to the grid + projects.forEach(function (project) { + resultsGrid.appendChild(buildProjectCard(project)); + }); + + resultsSection.scrollIntoView({ behavior: "smooth" }); function createTag(text, type) { var span = document.createElement("span"); span.className = "project-tag project-tag--" + normalize(type).replace(/[^a-z0-9_-]/g, "-");