feat: Add sus (translations missing)
This commit is contained in:
		@@ -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.",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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>
 | 
				
			||||||
@@ -274,21 +275,37 @@
 | 
				
			|||||||
<div id="modal-feedback" class="modal">
 | 
					<div id="modal-feedback" class="modal">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="modal-background"></div>
 | 
					    <div class="modal-background"></div>
 | 
				
			||||||
        <div class="modal-card">
 | 
					    <div class="modal-card">
 | 
				
			||||||
        <header class="modal-card-head">
 | 
					        <header class="modal-card-head">
 | 
				
			||||||
            <h2 data-i18n="feedback" class="modal-card-title">Feedback</h2>
 | 
					            <h2 data-i18n="feedback" class="modal-card-title">Feedback</h2>
 | 
				
			||||||
            <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">
 | 
				
			||||||
            <p>
 | 
					            <div class="section">
 | 
				
			||||||
                Wir freuen uns sehr, wenn du uns Feedback zu unserem Rattenrechner gibst!
 | 
					                <p>
 | 
				
			||||||
                Der einfachste Weg das zu tun ist per E-Mail an <a
 | 
					                    Wir freuen uns sehr, wenn du uns Feedback zu unserem Rattenrechner gibst!
 | 
				
			||||||
                    href="mailto:webmaster@vdrd.de">webmaster@vdrd.de</a>.
 | 
					                    Der einfachste Weg das zu tun ist per E-Mail an <a
 | 
				
			||||||
            </p>
 | 
					                        href="mailto:webmaster@vdrd.de">webmaster@vdrd.de</a>.
 | 
				
			||||||
            <p>
 | 
					                </p>
 | 
				
			||||||
                Der Code dieser Website ist <a href="https://codeberg.org/moanos/rettenrechner">öffentlich einsehbar.</a>
 | 
					                <p>
 | 
				
			||||||
                Gerne kannst du auch direkt dort <a href="https://codeberg.org/moanos/rettenrechner/issues">einen Issue</a> eröffnen!
 | 
					                    Der Code dieser Website ist <a href="https://codeberg.org/moanos/rettenrechner">öffentlich
 | 
				
			||||||
            </p>
 | 
					                    einsehbar.</a>
 | 
				
			||||||
 | 
					                    Gerne kannst du auch direkt dort <a href="https://codeberg.org/moanos/rettenrechner/issues">einen
 | 
				
			||||||
 | 
					                    Issue</a> eröffnen!
 | 
				
			||||||
 | 
					                </p>
 | 
				
			||||||
 | 
					            </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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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', () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 //
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
									
								
							
							
						
						
									
										107
									
								
								src/sus.js
									
									
									
									
									
										Normal 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");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
		Reference in New Issue
	
	Block a user