Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[162] Build UI - Eval Form Step 2 - Evaluation Criteria Add/Remove Criteria #219

Merged
merged 31 commits into from
Nov 1, 2024
Merged
Changes from 7 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
64b9841
162 Initial eval criteria commit for eval form
cpreisinger Oct 18, 2024
16ed9dc
162 Initial temp styling for eval criteria
cpreisinger Oct 18, 2024
13c836e
Merge branch 'dev' of github.com:GSA/Challenge_platform into 162/eval…
cpreisinger Oct 18, 2024
9ade174
164 Add support for binary scale to eval criteria
cpreisinger Oct 22, 2024
765ae15
165 Add support for rating scale to eval criteria
cpreisinger Oct 22, 2024
a22b0e8
165 Fix bug with new criteria option labels
cpreisinger Oct 22, 2024
d77a3cc
165 Option label bug with form validation error
cpreisinger Oct 22, 2024
38d8f2c
165 Fix bug with rating options on new criteria
cpreisinger Oct 22, 2024
2af7b30
61 Accordion titles and collapse validity check
cpreisinger Oct 28, 2024
e55b445
Merge branch 'dev' of github.com:GSA/Challenge_platform into 162/eval…
cpreisinger Oct 28, 2024
ef80db5
Merge branch '165/evaluation-criteria-rating-scale' into 162/eval-for…
cpreisinger Oct 28, 2024
c23e016
61 Fix rspec failure with criteria option labels
cpreisinger Oct 28, 2024
eea695f
162 Initial eval criteria stimulus port
cpreisinger Oct 29, 2024
85725f6
Merge branch 'dev' of github.com:GSA/Challenge_platform into 162/eval…
cpreisinger Oct 29, 2024
db83008
update yarn.lock
stepchud Oct 29, 2024
3394377
61 Update dependency versions
cpreisinger Oct 29, 2024
1f1716f
Merge branch '162/eval-form-evaluation-criteria' of github.com:GSA/Ch…
cpreisinger Oct 29, 2024
027e1c4
set node-version for circleci
stepchud Oct 29, 2024
d3fb1be
61 Make eval criteria respect eval form disabled
cpreisinger Oct 29, 2024
7a7307f
61 Simplify eval criteria js for code climate1
cpreisinger Oct 29, 2024
9e04a71
61 Styling and add max length for eval criteria
cpreisinger Oct 30, 2024
a8afc05
61 Styled add another criteria button
cpreisinger Oct 30, 2024
2ac908c
61 Temp darker accordion styling for criteria
cpreisinger Oct 30, 2024
9d0f5b5
Merge branch 'dev' into 162/eval-form-evaluation-criteria
stepchud Oct 30, 2024
a631c66
Update .circleci/config.yml
stepchud Oct 30, 2024
a2e5321
revert structure.sql
stepchud Oct 30, 2024
ac91b8e
61 Remove unsued targets and code readability
cpreisinger Oct 31, 2024
6e2e07a
Merge branch '162/eval-form-evaluation-criteria' of github.com:GSA/Ch…
cpreisinger Oct 31, 2024
cfeb931
Merge branch 'dev' of github.com:GSA/Challenge_platform into 162/eval…
cpreisinger Oct 31, 2024
2d05253
61 Add the confirmation screen for eval form save
cpreisinger Oct 31, 2024
aba2de0
grammar
stepchud Oct 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions app/controllers/evaluation_forms_controller.rb
Original file line number Diff line number Diff line change
@@ -77,9 +77,10 @@ def evaluation_form_params
permitted = params.require(:evaluation_form).
permit(:title, :instructions, :phase_id, :status, :comments_required,
:weighted_scoring, :publication_date, :closing_date, :challenge_id,
evaluation_criteria_attributes: %i[
id title description points_or_weight scoring_type
option_range_start option_range_end option_labels _destroy
evaluation_criteria_attributes: [
:id, :title, :description, :points_or_weight, :scoring_type,
:option_range_start, :option_range_end, :_destroy,
{ option_labels: {} }
])
closing_date = parse_closing_date(permitted[:closing_date])
closing_date ? permitted.merge({ closing_date: }) : permitted
210 changes: 194 additions & 16 deletions app/javascript/evaluation_criteria.js
Original file line number Diff line number Diff line change
@@ -14,7 +14,6 @@ document.addEventListener("DOMContentLoaded", function () {
if (criteriaList) {
criteriaList.addEventListener("click", function (event) {
if (event.target.classList.contains("delete-criteria-button")) {
let criteriaList = document.getElementById("criteria-list");
let criteriaRow = event.target.closest(".criteria-row");

// Don't count hidden criteria rows marked for deletion
@@ -41,27 +40,44 @@ document.addEventListener("DOMContentLoaded", function () {
newCriteria.style.display = "block";
newCriteria.removeAttribute("id");

newCriteria.querySelectorAll("input, textarea").forEach(function (input) {
let id = input.getAttribute("id");
let name = input.getAttribute("name");
let accordionButton = newCriteria.querySelector(".usa-accordion__button");
let accordionContent = newCriteria.querySelector(".usa-accordion__content");

// TODO: Remove condition when adding other scoring types
if (input.type !== "radio") {
input.disabled = false;
}
let accordionId = accordionContent
.getAttribute("id")
.replace("NEW_CRITERIA", criteriaCounter);

if (id) {
let newId = id.replace("NEW_CRITERIA", criteriaCounter);
input.setAttribute("id", newId);
}
accordionButton.setAttribute("aria-controls", accordionId);
accordionContent.setAttribute("id", accordionId);

if (name) {
let newName = name.replace("NEW_CRITERIA", criteriaCounter);
input.setAttribute("name", newName);
}
newCriteria.querySelectorAll("label").forEach(function (label) {
let oldFor = label.getAttribute("for");
let newFor = oldFor.replace("NEW_CRITERIA", criteriaCounter);
label.setAttribute("for", newFor);
});

newCriteria
.querySelectorAll("input, textarea, select")
.forEach(function (input) {
let id = input.getAttribute("id");
let name = input.getAttribute("name");

input.disabled = false;

if (id) {
let newId = id.replace("NEW_CRITERIA", criteriaCounter);
input.setAttribute("id", newId);
}

if (name) {
let newName = name.replace("NEW_CRITERIA", criteriaCounter);
input.setAttribute("name", newName);
}
});

document.getElementById("criteria-list").appendChild(newCriteria);

updateCriteriaRowTitles();
}

function destroyCriteriaRow(criteriaRow) {
@@ -86,5 +102,167 @@ document.addEventListener("DOMContentLoaded", function () {
// Otherwise remove row entirely
criteriaRow.remove();
}

updateCriteriaRowTitles();
}

function updateCriteriaRowTitles() {
let visibleCriteriaRows = Array.from(criteriaList.children).filter(
(row) => row.style.display !== "none"
);

visibleCriteriaRows.forEach(function (row, index) {
// Find the span with the class 'criteria-number' inside this row
let span = row.querySelector(".criteria-number");
if (span) {
// Update the inner text of the span with the new index
span.innerHTML = index + 1;
}
});
}

// Toggle Binary/Rating Scale Options
if (criteriaList) {
criteriaList.addEventListener("click", function (event) {
if (event.target.classList.contains("scoring-type-radio")) {
let criteriaRow = event.target.closest(".criteria-row");
toggleScoringTypeOptions(criteriaRow);
}
});
}

function toggleScoringTypeOptions(criteriaRow) {
let selectedScoringType = criteriaRow.querySelector(
".scoring-type-radio:checked"
);
let scaleOptions = criteriaRow.querySelector(".criteria-scale-options");
let binaryOptions = criteriaRow.querySelector(".criteria-binary-options");
let ratingOptions = criteriaRow.querySelector(".criteria-rating-options");

if (selectedScoringType.value == "binary") {
scaleOptions.style.display = "block";
binaryOptions.style.display = "block";
ratingOptions.style.display = "none";

binaryOptions.querySelectorAll("input, select").forEach(function (input) {
input.disabled = false;
});
ratingOptions.querySelectorAll("input, select").forEach(function (input) {
input.disabled = true;
});

toggleOptionLabels(criteriaRow, 0, 1);
} else if (selectedScoringType.value == "rating") {
scaleOptions.style.display = "block";
binaryOptions.style.display = "none";
ratingOptions.style.display = "block";

binaryOptions.querySelectorAll("input, select").forEach(function (input) {
input.disabled = true;
});
ratingOptions.querySelectorAll("input, select").forEach(function (input) {
input.disabled = false;
});

let optionRangeStart = criteriaRow.querySelector(
".option-range-select.option-range-start"
).value;
let optionRangeEnd = criteriaRow.querySelector(
".option-range-select.option-range-end"
).value;

toggleOptionLabels(criteriaRow, optionRangeStart, optionRangeEnd);
} else if (selectedScoringType.value == "numeric") {
scaleOptions.style.display = "none";
binaryOptions.style.display = "none";
ratingOptions.style.display = "none";

binaryOptions.querySelectorAll("input, select").forEach(function (input) {
input.disabled = true;
});
ratingOptions.querySelectorAll("input, select").forEach(function (input) {
input.disabled = true;
});

let criteriaOptionLabelRows = criteriaRow.querySelectorAll(
".criteria-option-label-row input"
);
criteriaOptionLabelRows.forEach(function (input) {
input.disabled = true;
});
}
}

// Toggle Binary/Rating Scale Options
if (criteriaList) {
criteriaList.addEventListener("change", function (event) {
if (event.target.classList.contains("option-range-select")) {
let criteriaRow = event.target.closest(".criteria-row");

let optionRangeStart = criteriaRow.querySelector(
".option-range-select.option-range-start"
).value;
let optionRangeEnd = criteriaRow.querySelector(
".option-range-select.option-range-end"
).value;

toggleOptionLabels(criteriaRow, optionRangeStart, optionRangeEnd);
}
});
}

function toggleOptionLabels(criteriaRow, optionRangeStart, optionRangeEnd) {
let criteriaOptionLabelRows = criteriaRow.querySelectorAll(
".criteria-option-label-row"
);

criteriaOptionLabelRows.forEach(function (row, index) {
row.querySelectorAll("input").forEach(function (input) {
if (index < optionRangeStart || index > optionRangeEnd) {
row.style.display = "none";
input.disabled = true;
} else {
row.style.display = "flex";
input.disabled = false;
}
});
});
}

// Accordion Buttons
if (criteriaList) {
criteriaList.addEventListener("click", function (event) {
let accordionButton = event.target.closest(".usa-accordion__button");

if (accordionButton) {
const sectionId = accordionButton.getAttribute("aria-controls");

if (
!accordionButton.getAttribute("aria-expanded") ||
accordionButton.getAttribute("aria-expanded") === "true"
) {
const isValid = validateAccordionSection(sectionId);
if (!isValid) {
event.preventDefault();
event.stopPropagation();
}
}
}
});
}

function validateAccordionSection(sectionId) {
const section = document.getElementById(sectionId);
const requiredFields = section.querySelectorAll("[required]");

for (let field of requiredFields) {
if (!field.checkValidity()) {
if (!field.reportValidity()) {
return false;
}
}
}

return true;
}
});
2 changes: 1 addition & 1 deletion app/models/evaluation_criterion.rb
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ class EvaluationCriterion < ApplicationRecord
enum :scoring_type, { numeric: 0, rating: 1, binary: 2 }
attribute :option_range_start, :integer
attribute :option_range_end, :integer
attribute :option_labels, :json, default: -> { [] }
attribute :option_labels, :json, default: -> { {} }
attribute :evaluation_form_id, :integer

# Validations
Loading