Skip to content

Commit

Permalink
feat: Add character count to comment input of the feedback component (#…
Browse files Browse the repository at this point in the history
…423)

* Add character count to feedback control

* Refactor javascript

* Update feedback.js

* Update _BetaBanner.cshtml

* Update _Feedback.cshtml
  • Loading branch information
killij authored Feb 16, 2024
1 parent ce081fa commit 93b8665
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ private static bool IsModelValid(FeedbackModel model, out string pageId)
pageId = pageId.Trim('/');

if (pageId.Length > 512
|| model.Comments?.Length > 500
|| model.Comments?.Length > 400
|| !Regex.IsMatch(pageId, @"^[0-9a-z](\/?[0-9a-z\-])*\/?$", RegexOptions.Compiled, TimeSpan.FromSeconds(1)))
{
return false;
Expand Down
2 changes: 1 addition & 1 deletion Childrens-Social-Care-CPD/Views/Shared/_BetaBanner.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
BETA
</strong>
<span class="govuk-phase-banner__text">
This is a new service – your <a class="govuk-link" href="https://dferesearch.fra1.qualtrics.com/jfe/form/SV_bmcLDedq5wipeTA">feedback</a> will help us to improve it
This is a new service – your <a class="govuk-link" href="https://dferesearch.fra1.qualtrics.com/jfe/form/SV_bmcLDedq5wipeTA">feedback</a> will help us to improve it.
</span>
</p>
</div>
Expand Down
56 changes: 32 additions & 24 deletions Childrens-Social-Care-CPD/Views/Shared/_Feedback.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

@{
var contextModel = (ContextModel)ViewBag.ContextModel;
var commentsId = $"comments-{Guid.NewGuid()}";
}

<div class="govuk-grid-row">
<div class="govuk-grid-row" data-module="feedback-module">
<div class="govuk-grid-column-three-quarters">

@if (contextModel.FeedbackSubmitted)
Expand All @@ -27,37 +28,36 @@
return;
}

<details id="feedback-control" class="govuk-details" data-module="govuk-details">
<details class="govuk-details" data-module="govuk-details" data-module-id="feedbackDetail">
<summary class="govuk-details__summary">
<span class="govuk-details__summary-text">
Give feedback about this page
</span>
</summary>

@using (@Html.BeginForm("feedback", "Feedback", null, FormMethod.Post, true, new { id = "feedbackForm" }))
{
<input id="page" type="hidden" name="page" value="@contextModel.Id" />
<div id="controlsContainer">
<form action="feedback" method="post" data-module-id="feedbackForm" asp-antiforgery="true">
<input data-module-id="page" type="hidden" name="page" value="@contextModel.Id" />
<div data-module-id="controlsContainer">
<div class="govuk-details__text">
Use this form to provide feedback about this page. If you have more general feedback about this website, please use this <a href="https://dferesearch.fra1.qualtrics.com/jfe/form/SV_bmcLDedq5wipeTA">feedback form</a>.
</div>

<div class="govuk-details__text">
<div id="isUsefulQuestionGroup" class="govuk-form-group">
<div class="govuk-form-group" data-module-id="isUsefulQuestionGroup">
<fieldset class="govuk-fieldset">
<legend class="govuk-fieldset__legend">Did you find this page useful?</legend>
<p id="was-useful-error-message" class="govuk-error-message" style="display:none">
<p class="govuk-error-message" style="display:none" data-module-id="isUsefulErrorMessage">
<span class="govuk-visually-hidden">Error:</span> Please select yes or no
</p>
<div class="govuk-radios" data-module="govuk-radios">
<div class="govuk-radios__item">
<input class="govuk-radios__input" id="isUsefulYes" name="isUseful" type="radio" value="true">
<input class="govuk-radios__input" name="isUseful" type="radio" value="true" data-module-id="isUsefulYes">
<label class="govuk-label govuk-radios__label" for="isUsefulYes">
Yes
</label>
</div>
<div class="govuk-radios__item">
<input class="govuk-radios__input" id="isUsefulNo" name="isUseful" type="radio" value="false">
<input class="govuk-radios__input" name="isUseful" type="radio" value="false" data-module-id="isUsefulNo">
<label class="govuk-label govuk-radios__label" for="isUsefulNo">
No
</label>
Expand All @@ -66,31 +66,39 @@
</fieldset>
</div>

<div class="govuk-!-margin-top-4 feedback-container">
<label id="feedbackLabel" class="govuk-label" for="feebackText">
Tell us about your experience with this page (optional):
</label>
<textarea class="govuk-textarea" id="feebackText" name="comments" rows="5" maxlength="500"></textarea>
<div class="govuk-character-count" data-module="govuk-character-count" data-maxlength="400">
<div data-module-id="commentsFormGroup" class="govuk-form-group">
<label class="govuk-label" for="@commentsId">
Tell us about your experience with this page (optional):
</label>
<p data-module-id="commentsErrorMessage" class="govuk-error-message" style="display:none">
<span class="govuk-visually-hidden">Error:</span> Experience must be 400 characters or less
</p>
<textarea data-module-id="comments" class="govuk-textarea govuk-js-character-count" id="@commentsId" name="comments" rows="5" aria-describedby="@commentsId-info" maxlength="400"></textarea>
</div>
<div id="@commentsId-info" class="govuk-hint govuk-character-count__message">
You can enter up to 400 characters
</div>
</div>

<div class="govuk-button-group">
<button id="submitButton" class="govuk-button" data-module="govuk-button" type="submit">
Submit Feedback
</button>
<div class="govuk-button-group">
<button data-module-id="submitButton" class="govuk-button" data-module="govuk-button" type="submit">
Submit Feedback
</button>

<a id="cancelButton" class="govuk-link" href="#0" onclick="resetForm()" style="display: none">Cancel</a>
</div>
<a data-module-id="cancelLink" class="govuk-link" href="#0" style="display: none">Cancel</a>
</div>
</div>
</div>

<div id="thankYouMessage" class="govuk-details__text" style="display: none;">
<div data-module-id="thankYouMessage" class="govuk-details__text" style="display: none;">
Thank you for your feedback on this resource! If you have more general feedback about this website, please use this <a href="https://dferesearch.fra1.qualtrics.com/jfe/form/SV_bmcLDedq5wipeTA">feedback form</a>.
</div>
}
</form>
</details>
</div>
</div>

@{
Html.RequireScriptUrl("~/javascript/feedback.js");
Html.RequireScriptUrl("~/javascript/components/feedback.js");
}
121 changes: 121 additions & 0 deletions Childrens-Social-Care-CPD/wwwroot/javascript/components/feedback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
class FeedbackControl {
#root
#isUsefulYesRadioButton
#isUsefulNoRadioButton
#pageInput
#feedbackForm
#cancelLink
#isUsefulQuestionGroup
#commentsInput
#commentsFormGroup

constructor(root) {
this.#root = root
}

init = () => {
this.#feedbackForm = this.#root.querySelector("[data-module-id=feedbackForm]")
this.#cancelLink = this.#root.querySelector("[data-module-id=cancelLink]")
this.#isUsefulYesRadioButton = this.#root.querySelector("[data-module-id=isUsefulYes]")
this.#isUsefulNoRadioButton = this.#root.querySelector("[data-module-id=isUsefulNo]")
this.#isUsefulQuestionGroup = this.#root.querySelector("[data-module-id=isUsefulQuestionGroup]")
this.#pageInput = this.#root.querySelector("[data-module-id=page]")
this.#commentsInput = this.#root.querySelector("[data-module-id=comments]")
this.#commentsFormGroup = this.#root.querySelector("[data-module-id=commentsFormGroup]")

// Initialise the event handlers
this.#feedbackForm.addEventListener("submit", this.#handleFormSubmit)
this.#feedbackForm.addEventListener("reset", this.#handleFormReset)
this.#cancelLink.addEventListener("click", this.#resetForm)

this.#show(this.#cancelLink)
}

#show = element => element.style.display = "block"
#hide = element => element.style.display = "none"

#handleFormSubmit = (event) => {
event.preventDefault()

if (this.#validateForm()) {
const data = {
Page: this.#pageInput.value,
IsUseful: this.#isUsefulYesRadioButton.checked,
Comments: this.#commentsInput.value,
}
this.#submitFeedback(data)
this.#root.querySelector("[data-module-id=submitButton]").disabled = true
this.#hide(this.#root.querySelector("[data-module-id=controlsContainer]"))
this.#show(this.#root.querySelector("[data-module-id=thankYouMessage]"))
}
}

#handleFormReset = () => {
// Close the detail
this.#root.querySelector("[data-module-id=feedbackDetail]").removeAttribute("open")

// Hide the error messages
this.#isUsefulQuestionGroup.classList.remove("govuk-form-group--error")
this.#commentsFormGroup.classList.remove("govuk-form-group--error")
this.#hide(this.#root.querySelector("[data-module-id=isUsefulErrorMessage]"))
this.#hide(this.#root.querySelector("[data-module-id=commentsErrorMessage]"))

// Executes after the form has been reset - resets the character count component
setTimeout((() => this.#commentsInput.dispatchEvent(new KeyboardEvent("keyup"))), 1);
}

#resetForm = (event) => {
event.preventDefault()
this.#feedbackForm.reset()
}

#submitFeedback = async (data) => {
try {
await fetch("/api/feedback", {
method: "POST",
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
RequestVerificationToken: this.#root.querySelector("[name=__RequestVerificationToken]").value
},
redirect: "error",
referrerPolicy: "same-origin",
body: JSON.stringify(data),
});
} catch (e) {
console.error(e)
}
}

#validateForm = () => {
let isValid = true
if (this.#isUsefulYesRadioButton.checked === false && this.#isUsefulNoRadioButton.checked === false) {
isValid = false
this.#isUsefulQuestionGroup.classList.add("govuk-form-group--error")
this.#show(this.#root.querySelector("[data-module-id=isUsefulErrorMessage]"))
} else {
this.#isUsefulQuestionGroup.classList.remove("govuk-form-group--error")
this.#hide(this.#root.querySelector("[data-module-id=isUsefulErrorMessage]"))
}

if (this.#commentsInput.value.length > 400) {
isValid = false
this.#commentsFormGroup.classList.add("govuk-form-group--error")
this.#show(this.#root.querySelector("[data-module-id=commentsErrorMessage]"))
} else {
this.#commentsFormGroup.classList.remove("govuk-form-group--error")
this.#hide(this.#root.querySelector("[data-module-id=commentsErrorMessage]"))
}

return isValid
}
}

document.addEventListener("DOMContentLoaded", () => {
const controls = document.querySelectorAll("[data-module=feedback-module]")
controls.forEach(control => {
new FeedbackControl(control).init()
})
})
72 changes: 0 additions & 72 deletions Childrens-Social-Care-CPD/wwwroot/javascript/feedback.js

This file was deleted.

0 comments on commit 93b8665

Please sign in to comment.