feat: Add sus (translations missing)

This commit is contained in:
moanos [he/him] 2025-04-17 18:24:37 +02:00
parent 17e1415136
commit d5a467aa55
7 changed files with 155 additions and 12 deletions

View File

@ -22,6 +22,8 @@
"source-code": "Quellcode", "source-code": "Quellcode",
"give-feedback": "Feedback geben", "give-feedback": "Feedback geben",
"feedback": "Feedback", "feedback": "Feedback",
"sus-title": "Bewerte den Rechner",
"submit": "Absenden",
"failed-base-area": "Die Mindestgrundfläche des Käfigs muss {{ MINIMUM_BASE_AREA }}m² (also z.B. 100x50cm) betragen.", "failed-base-area": "Die Mindestgrundfläche des Käfigs muss {{ MINIMUM_BASE_AREA }}m² (also z.B. 100x50cm) betragen.",
"failed-overall-area": "Die Gesamtfläche im Käfig ist zu klein.", "failed-overall-area": "Die Gesamtfläche im Käfig ist zu klein.",
"failed-fall-height": "Die mögliche Fallhöhe darf nicht mehr als {{ maximum_fall_height }}cm betragen.", "failed-fall-height": "Die mögliche Fallhöhe darf nicht mehr als {{ maximum_fall_height }}cm betragen.",

View File

@ -22,6 +22,8 @@
"source-code": "Source Code", "source-code": "Source Code",
"give-feedback": "Give Feedback", "give-feedback": "Give Feedback",
"feedback": "Feedback", "feedback": "Feedback",
"sus-title": "Rate the calculator",
"submit": "Submit",
"failed-base-area": "The base area of the cage must not be below {{ MINIMUM_BASE_AREA }}m².", "failed-base-area": "The base area of the cage must not be below {{ MINIMUM_BASE_AREA }}m².",
"failed-overall-area": "The overall area in the cage is to small.", "failed-overall-area": "The overall area in the cage is to small.",
"failed-fall-height": "The possible fall height between floors must not be above {{ maximum_fall_height }}cm.", "failed-fall-height": "The possible fall height between floors must not be above {{ maximum_fall_height }}cm.",

View File

@ -261,7 +261,8 @@
<li class="footer-link"><a href="https://codeberg.org/moanos/rettenrechner" data-i18n="source-code">Quellcode</a> <li class="footer-link"><a href="https://codeberg.org/moanos/rettenrechner" data-i18n="source-code">Quellcode</a>
</li> </li>
<li class="footer-link"> <li class="footer-link">
<a class="js-modal-trigger is-text is-link" data-target="modal-feedback" data-i18n="give-feedback"> <a class="js-modal-trigger is-text is-link" data-target="modal-feedback"
data-i18n="give-feedback">
Feedback geben Feedback geben
</a> </a>
</li> </li>
@ -280,16 +281,32 @@
<button class="delete" aria-label="close"></button> <button class="delete" aria-label="close"></button>
</header> </header>
<div class="modal-card-body"> <div class="modal-card-body">
<div class="section">
<p> <p>
Wir freuen uns sehr, wenn du uns Feedback zu unserem Rattenrechner gibst! Wir freuen uns sehr, wenn du uns Feedback zu unserem Rattenrechner gibst!
Der einfachste Weg das zu tun ist per E-Mail an <a Der einfachste Weg das zu tun ist per E-Mail an <a
href="mailto:webmaster@vdrd.de">webmaster@vdrd.de</a>. href="mailto:webmaster@vdrd.de">webmaster@vdrd.de</a>.
</p> </p>
<p> <p>
Der Code dieser Website ist <a href="https://codeberg.org/moanos/rettenrechner">öffentlich einsehbar.</a> Der Code dieser Website ist <a href="https://codeberg.org/moanos/rettenrechner">öffentlich
Gerne kannst du auch direkt dort <a href="https://codeberg.org/moanos/rettenrechner/issues">einen Issue</a> eröffnen! einsehbar.</a>
Gerne kannst du auch direkt dort <a href="https://codeberg.org/moanos/rettenrechner/issues">einen
Issue</a> eröffnen!
</p> </p>
</div> </div>
<div class="section">
<h1 class="title" data-i18n="sus-title">Bewerte den Rechner</h1>
<form id="sus-form">
<!--- Questions here --->
<div class="control" id="sus-control">
<button class="button is-primary" type="submit" data-i18n="submit">Absenden</button>
</div>
</form>
<div id="response-message" class="notification is-hidden"></div>
</div>
</div>
</div> </div>
</div> </div>

View File

@ -30,7 +30,7 @@ document.addEventListener('DOMContentLoaded', () => {
}); });
// Add a click event on various child elements to close the parent modal // Add a click event on various child elements to close the parent modal
(document.querySelectorAll('.modal-background, .modal-close, .delete, .button') || []).forEach(($close) => { (document.querySelectorAll('.modal-background, .modal-close, .delete') || []).forEach(($close) => {
const $target = $close.closest('.modal'); const $target = $close.closest('.modal');
$close.addEventListener('click', () => { $close.addEventListener('click', () => {

View File

@ -8,6 +8,7 @@ import '@fortawesome/fontawesome-free/js/brands';
import './feedback.js'; import './feedback.js';
import './main.scss'; import './main.scss';
import {send} from './telemetry'; import {send} from './telemetry';
import './sus.js';
///////////////// /////////////////
// TRANSLATION // // TRANSLATION //

View File

@ -148,3 +148,17 @@ Reused from Notfellchen
.tooltip:not(.top) .tooltiptext::before { .tooltip:not(.top) .tooltiptext::before {
top: auto; top: auto;
} }
// SUS Slider
.sus-slider {
width: 100%;
}
.slider-labels {
display: flex;
justify-content: space-between;
font-size: 0.9rem;
margin-top: 0.25rem;
}

107
src/sus.js Normal file
View File

@ -0,0 +1,107 @@
const scaleQuestions = [
"sus-question-easy-to-use", // I thought CageCalc is easy to use
"sus-question-like-to-use-frequently", // I would like to use CageCalc frequently
"sus-question-unnecessarily-complex", // I find CageCalc unnecessarily complex
"sus-question-need-support-of-technical-person", // I think that I need the support of a technical person to be able to use CageCalc
"sus-question-well-integrated", // I found various functions in CageCalc were well integrated
"sus-question-inconsistency", // I thought there was too much inconsistency in CageCalc
"sus-question-learn-quickly", // I would imagine that most people would learn to use CageCalc very quickly
"sus-question-cumbersome", // I found CageCalc very cumbersome to use
"sus-question-confident", // I felt very confident using CageCalc
"sus-question-need-to-learn" // I needed to learn a lot of things before I could get going with CageCalc
];
const freetextQuestions = [
"question-whats-missing", // Welche Funktion fehlt dir?
"question-pain-points", // Was muss aus deiner Sicht an XX geändert werden?
"question-other-feedback" // Was willst du uns mitgeben?
]
function prepareQuestionnaire() {
const form = document.getElementById("sus-form");
scaleQuestions.forEach((key, index) => {
const field = document.createElement("div");
field.className = "field";
field.id = key;
field.innerHTML = `
<label class="label" data-i18n="${key}"></label>
<p class="control">
<input class="sus-slider" type="range" min="1" max="5" step="1" name=${key} required>
<div class="slider-labels">
<span data-i18n="strongly-disagree">Strongly Disagree</span>
<span data-i18n="disagree">Disagree</span>
<span data-i18n="neutral">Neutral</span>
<span data-i18n="agree">Agree</span>
<span data-i18n="strongly-agree">Strongly Agree</span>
</div>
</p>
`;
form.insertBefore(field, form.querySelector('#sus-control'));
});
freetextQuestions.forEach((key, index) => {
const field = document.createElement("div");
field.classList.add("field");
field.id = key;
field.innerHTML = `
<label class="label" data-i18n="${key}"></label>
<p class="control">
<input class="input" type="text" name=${key}/>
</p>
`
form.insertBefore(field, form.querySelector('#sus-control'));
})
return form;
}
window.addEventListener('DOMContentLoaded', () => {
let form = prepareQuestionnaire();
form.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(form);
const jsonData = {};
for (let [key, value] of formData.entries()) {
console.log(key, value);
if (key.startsWith("sws-question")) {
jsonData[key] = parseInt(value, 10);
} else {
jsonData[key] = value;
}
}
try {
const response = await fetch("https://storandom.hyteck.de/submit", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(jsonData)
});
const messageDiv = document.getElementById("response-message");
if (response.ok) {
messageDiv.className = "notification is-success";
messageDiv.setAttribute("data-i18n", "submit-success");
messageDiv.textContent = "Survey submitted successfully!";
} else {
messageDiv.className = "notification is-danger";
messageDiv.setAttribute("data-i18n", "submit-error");
messageDiv.textContent = "There was an error submitting the survey.";
}
messageDiv.classList.remove("is-hidden");
} catch (error) {
const messageDiv = document.getElementById("response-message");
messageDiv.className = "notification is-danger";
messageDiv.removeAttribute("data-i18n"); // For dynamic error message
messageDiv.textContent = "Network error: " + error.message;
messageDiv.classList.remove("is-hidden");
}
});
});