From efcecfe905b9de488909a424cbaa1da900d2c2ca Mon Sep 17 00:00:00 2001 From: Lunix-420 Date: Fri, 15 Nov 2024 01:08:33 +0100 Subject: [PATCH 1/3] fix: Still working on this --- .../static/js/skills/fetchSecondarySkills.js | 129 ++++++++------- .../static/js/skills/skillSelector.js | 156 +++++++++++++++--- .../templates/fragments/core/_metadata.html | 2 +- 3 files changed, 203 insertions(+), 84 deletions(-) diff --git a/src/main/resources/static/js/skills/fetchSecondarySkills.js b/src/main/resources/static/js/skills/fetchSecondarySkills.js index e1c47bb..3ecea74 100644 --- a/src/main/resources/static/js/skills/fetchSecondarySkills.js +++ b/src/main/resources/static/js/skills/fetchSecondarySkills.js @@ -77,16 +77,12 @@ function updateSecondarySkillsDropdown(secondarySkills, selectElement) { } selectElement.appendChild( - createOption("Select a secondary skill", true, true) + createOption("Bitte eine Fähigkeit auswählen", true, true) ); - secondarySkills.forEach((skill) => { - selectElement.appendChild( - createOption(skill.description, false, false, skill.ssid) - ); - }); - selectElement.disabled = false; + + initSkillSelector(secondarySkills); } /** @@ -107,6 +103,15 @@ function initializeSkillsDropdowns() { async function fetchSecondarySkills() { const primarySkillSelect = document.getElementById("primarySkill"); + + // If there is more than one selector delete all except the first one + const skillSelectors = document.querySelectorAll(".skill-selector"); + if (skillSelectors.length > 1) { + for (let i = 1; i < skillSelectors.length; i++) { + skillSelectors[i].remove(); + } + } + const secondarySkillSelect = document.getElementById("secondarySkill"); const selectedPrimarySkillId = primarySkillSelect.value; @@ -122,64 +127,64 @@ async function fetchSecondarySkills() { secondarySkillSelect.innerHTML = ""; secondarySkillSelect.appendChild(createOption("Loading...", true, true)); - try { - const response = await fetch( - `/api/secondary-skill/from-primary-skill?psid=${selectedPrimarySkillId}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Accept: "application/json", - }, - } - ); - - if (!response.ok) { - const errorMessage = `Server returned ${response.status}: ${response.statusText}`; - throw new Error(errorMessage); + // try { + const response = await fetch( + `/api/secondary-skill/from-primary-skill?psid=${selectedPrimarySkillId}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, } + ); - const responseText = await response.text(); - console.log("Response Text:", responseText); - - let secondarySkills; - try { - secondarySkills = JSON.parse(responseText); - } catch (jsonError) { - throw new Error(`Failed to parse JSON: ${jsonError.message}`); - } - - updateSecondarySkillsDropdown(secondarySkills, secondarySkillSelect); - } catch (error) { - console.error("Error fetching secondary skills:", error); - secondarySkillSelect.innerHTML = ""; - secondarySkillSelect.appendChild( - createOption("Error loading secondary skills", true, true) - ); - secondarySkillSelect.disabled = true; - - let userMessage = ""; - if (error.name === "TypeError" && !window.navigator.onLine) { - userMessage = - "No internet connection. Please check your network and try again."; - } else if (error.message.includes("Server returned 404")) { - userMessage = - "The selected primary skill was not found. Please refresh and try again."; - } else if (error.message.includes("Server returned 500")) { - userMessage = "Server error occurred. Please try again in a few minutes."; - } else if (error.message.includes("Server returned 403")) { - userMessage = - "You don't have permission to access these skills. Please contact support."; - } else { - userMessage = `Failed to load secondary skills: ${error.message}`; - } - showTemporaryMessage( - userMessage, - "error", - 5000, - secondarySkillSelect.parentNode - ); + if (!response.ok) { + const errorMessage = `Server returned ${response.status}: ${response.statusText}`; + throw new Error(errorMessage); } + + const responseText = await response.text(); + console.log("Response Text:", responseText); + + let secondarySkills; + try { + secondarySkills = JSON.parse(responseText); + } catch (jsonError) { + throw new Error(`Failed to parse JSON: ${jsonError.message}`); + } + + updateSecondarySkillsDropdown(secondarySkills, secondarySkillSelect); + // } catch (error) { + // console.error("Error fetching secondary skills:", error); + // secondarySkillSelect.innerHTML = ""; + // secondarySkillSelect.appendChild( + // createOption("Error loading secondary skills", true, true) + // ); + // secondarySkillSelect.disabled = true; + + // let userMessage = ""; + // if (error.name === "TypeError" && !window.navigator.onLine) { + // userMessage = + // "No internet connection. Please check your network and try again."; + // } else if (error.message.includes("Server returned 404")) { + // userMessage = + // "The selected primary skill was not found. Please refresh and try again."; + // } else if (error.message.includes("Server returned 500")) { + // userMessage = "Server error occurred. Please try again in a few minutes."; + // } else if (error.message.includes("Server returned 403")) { + // userMessage = + // "You don't have permission to access these skills. Please contact support."; + // } else { + // userMessage = `Failed to load secondary skills: ${error.message}`; + // } + // showTemporaryMessage( + // userMessage, + // "error", + // 5000, + // secondarySkillSelect.parentNode + // ); + // } } document.addEventListener("DOMContentLoaded", initializeSkillsDropdowns); diff --git a/src/main/resources/static/js/skills/skillSelector.js b/src/main/resources/static/js/skills/skillSelector.js index 33bc2f1..493cec1 100644 --- a/src/main/resources/static/js/skills/skillSelector.js +++ b/src/main/resources/static/js/skills/skillSelector.js @@ -1,38 +1,141 @@ -function handleSecondarySkillSelection(selectElement) { - const skillCreator = document.querySelector("#skillCreator"); - const newSkillSelector = selectElement.closest(".row").cloneNode(true); - const selectedOptions = Array.from( - document.querySelectorAll("#skillCreator select[name='ssid']") - ).map((select) => select.value); +/** + * Creates an option element for a select dropdown + */ +var secondarySkillsList = {}; - // Filter out already selected options - const secondarySkillSelect = - newSkillSelector.querySelector("#secondarySkill"); - const options = Array.from(secondarySkillSelect.options); - options.forEach((option) => { - if (selectedOptions.includes(option.value)) { - option.remove(); +//==================================================================================== +/** + * Initializes the skill selector with the available secondary skills + * @param {SecondarySkill[]} secondarySkills - Array of secondary skills from the API + */ +function initSkillSelector(secondarySkills) { + secondarySkillsList = secondarySkills; + rebuildOptions(); +} + +//==================================================================================== +/** + * Populates the secondary skills dropdowns with the available options + * and updates the options based on the selected values in the other dropdowns + */ +function rebuildOptions() { + // Get all secondary skill dropdowns + const secondarySkillSelects = document.querySelectorAll("#secondarySkill"); + + // Make a list with all options that are currently selected + const selectedOptions = []; + secondarySkillSelects.forEach((select) => { + selectedOptions.push(select.value); + }); + + // Make a list with all options that are not selected + const availableOptions = []; + secondarySkillsList.forEach((skill) => { + if (!selectedOptions.includes(skill.ssid.toString())) { + availableOptions.push(skill); } }); - // Check if there are any options left to select - if (secondarySkillSelect.options.length <= 1) { - return; // Exit if no options left + // Iterate over all secondary skill dropdowns + secondarySkillSelects.forEach((select) => { + // Save the current selected value + const selectedValue = select.value; + const selectedElement = select.querySelector( + `option[value="${selectedValue}"]` + ); + + // Clear the dropdown + select.innerHTML = ""; + + // Add selectedElement back to the dropdown + select.appendChild(selectedElement); + + // Add all other options + availableOptions.forEach((skill) => { + select.appendChild( + createOption(skill.description, false, false, skill.ssid) + ); + }); + }); +} + +//==================================================================================== +/** + * Handles the selection of a secondary skill in a dropdown + * @param {HTMLSelectElement} selectElement - The secondary skill dropdown + */ +function handleSecondarySkillSelection(selectElement) { + const skillCreator = document.querySelector("#skillCreator"); + const skillSelectors = document.querySelectorAll(".skill-selector"); + + // Check if all existing selectors have an option selected + const allSelected = Array.from(skillSelectors).every((selector) => { + const secondarySkillSelect = selector.querySelector("#secondarySkill"); + return secondarySkillSelect.value; + }); + + // Test if we can have more selectors + if (!allSelected || skillSelectors.length >= secondarySkillsList.length) { + rebuildOptions(); + updateRemoveButtonsVisibility(); + return; } - newSkillSelector.querySelector("#secondarySkill").value = ""; + // Add a new skill selector + addSkillSelector(selectElement); +} + +//==================================================================================== +/* + * Creates an option element for a select dropdown + */ +function addSkillSelector() { + // Clone the first skill selector + const newSkillSelector = document + .querySelector(".skill-selector") + .cloneNode(true); + + // Clear the selected value and set the default level newSkillSelector.querySelector("#level").value = "1"; - newSkillSelector.querySelector(".btn-default").disabled = true; + newSkillSelector.querySelector(".btn-default").style.display = "none"; + + // Clear the secondary skill dropdown and set it to the default value + const secondarySkillSelect = + newSkillSelector.querySelector("#secondarySkill"); + secondarySkillSelect.innerHTML = ""; + secondarySkillSelect.appendChild( + createOption("Bitte eine Fähigkeit auswählen", true, true) + ); + const skillSelectorList = document.querySelector("#skillSelectorList"); skillSelectorList.appendChild(newSkillSelector); + // Delete the existing options and set it to the default value + rebuildOptions(); + + // Update the visibility of the "Entfernen" buttons + updateRemoveButtonsVisibility(); + + // Append the new skill selector to the container + const container = document.querySelector(".skill-selectors"); + container.appendChild(newSkillSelector); + // Initialize star rating components for the new skill selector initializeStarRatingComponents(); - // Update the visibility of the "Entfernen" buttons - updateRemoveButtonsVisibility(); + // Add event listener to the new "Entfernen" button + newSkillSelector + .querySelector(".btn-default") + .addEventListener("click", function (event) { + event.preventDefault(); + handleRemoveSkillButtonClick(this); + }); } +//==================================================================================== +/** + * Updates the visibility of the "Entfernen" buttons based on the number of skill selectors + */ function updateRemoveButtonsVisibility() { const skillSelectors = document.querySelectorAll(".skill-selector"); const removeButtons = document.querySelectorAll(".btn-default"); @@ -56,12 +159,23 @@ function updateRemoveButtonsVisibility() { } } +//==================================================================================== +/** + * Handles the removal of a skill selector + * @param {HTMLButtonElement} button - The "Entfernen" button that was clicked + */ function handleRemoveSkillButtonClick(button) { const skillSelector = button.closest(".skill-selector"); skillSelector.remove(); - updateRemoveButtonsVisibility(); + + // If there is no slector with an empty value left we need to add one + addSkillSelector(); } +//==================================================================================== +/** + * Creates an option element for a select dropdown + */ document.addEventListener("DOMContentLoaded", function () { // Initialize star rating components on page load initializeStarRatingComponents(); diff --git a/src/main/resources/templates/fragments/core/_metadata.html b/src/main/resources/templates/fragments/core/_metadata.html index 0c4b39a..ede1cb5 100644 --- a/src/main/resources/templates/fragments/core/_metadata.html +++ b/src/main/resources/templates/fragments/core/_metadata.html @@ -3,7 +3,7 @@ - + UPch Date: Fri, 15 Nov 2024 01:11:33 +0100 Subject: [PATCH 2/3] fix: UPch --- src/main/resources/templates/fragments/core/_metadata.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/templates/fragments/core/_metadata.html b/src/main/resources/templates/fragments/core/_metadata.html index ede1cb5..0c4b39a 100644 --- a/src/main/resources/templates/fragments/core/_metadata.html +++ b/src/main/resources/templates/fragments/core/_metadata.html @@ -3,7 +3,7 @@ - UPch + Date: Fri, 15 Nov 2024 01:38:03 +0100 Subject: [PATCH 3/3] fix: Multi skill add works now --- .../static/js/skills/skillSelector.js | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/main/resources/static/js/skills/skillSelector.js b/src/main/resources/static/js/skills/skillSelector.js index 493cec1..247f65b 100644 --- a/src/main/resources/static/js/skills/skillSelector.js +++ b/src/main/resources/static/js/skills/skillSelector.js @@ -113,16 +113,6 @@ function addSkillSelector() { // Delete the existing options and set it to the default value rebuildOptions(); - // Update the visibility of the "Entfernen" buttons - updateRemoveButtonsVisibility(); - - // Append the new skill selector to the container - const container = document.querySelector(".skill-selectors"); - container.appendChild(newSkillSelector); - - // Initialize star rating components for the new skill selector - initializeStarRatingComponents(); - // Add event listener to the new "Entfernen" button newSkillSelector .querySelector(".btn-default") @@ -130,6 +120,15 @@ function addSkillSelector() { event.preventDefault(); handleRemoveSkillButtonClick(this); }); + + // Append the new skill selector to the container + skillSelectorList.appendChild(newSkillSelector); + + // Initialize star rating components for the new skill selector + initializeStarRatingComponents(); + + // Update the visibility of the "Entfernen" buttons + updateRemoveButtonsVisibility(); } //==================================================================================== @@ -140,17 +139,13 @@ function updateRemoveButtonsVisibility() { const skillSelectors = document.querySelectorAll(".skill-selector"); const removeButtons = document.querySelectorAll(".btn-default"); - // Show "Entfernen" buttons only if there are at least two skill selectors if (skillSelectors.length > 1) { removeButtons.forEach((button) => { const selectElement = button .closest(".skill-selector") - .querySelector("#secondarySkill"); - if (selectElement.value) { - button.style.display = "inline-block"; - } else { - button.style.display = "none"; - } + ?.querySelector("#secondarySkill"); + button.style.display = + selectElement && selectElement.value ? "inline-block" : "none"; }); } else { removeButtons.forEach((button) => { @@ -169,7 +164,13 @@ function handleRemoveSkillButtonClick(button) { skillSelector.remove(); // If there is no slector with an empty value left we need to add one - addSkillSelector(); + if ( + document.querySelectorAll("#secondarySkill option[value='']").length === 0 + ) { + addSkillSelector(); + } else { + rebuildOptions(); + } } //====================================================================================