diff --git a/src/App.js b/src/App.js index 267aa05..7c8af8f 100644 --- a/src/App.js +++ b/src/App.js @@ -1,9 +1,9 @@ import React from "react"; import { Route, Routes } from "react-router-dom"; -import { GeistProvider, CssBaseline } from '@geist-ui/core' +import { GeistProvider, CssBaseline } from "@geist-ui/core"; import RouteTracker from "./core/log/RouteTracker"; -import { createStore } from 'zustand/vanilla' -import { persist, createJSONStorage } from 'zustand/middleware' +import { createStore } from "zustand/vanilla"; +import { persist, createJSONStorage } from "zustand/middleware"; import { PARTICIPANT_NUMBER } from "./core/Constants"; import { StudySite } from "./components/webpage_container/StudySite"; @@ -15,80 +15,90 @@ const TestInfoPage2 = React.lazy(() => import("./pages/TestInfoPage2")); const TestEndPage = React.lazy(() => import("./pages/TestEndPage")); const StartPage1 = React.lazy(() => import("./pages/study_site_1/StartPage1")); - export const sensorLogState = createStore( persist( () => ({ - sensorLog: {mouseLog: [], clickedElements: [], visitedSites: [], playedSonifications: []} + sensorLog: { + mouseLog: [], + clickedElements: [], + visitedSites: [], + playedSonifications: [], + }, }), { - name: 'sensor-storage', // name of the item in the storage (must be unique) + name: "sensor-storage", // name of the item in the storage (must be unique) storage: createJSONStorage(() => sessionStorage), // (optional) by default, 'localStorage' is used - }, - ), -) + } + ) +); -export const { getState, setState, subscribe, getInitialState } = sensorLogState; +export const { getState, setState, subscribe, getInitialState } = + sensorLogState; const latinSquare = [ - [1, 2, 3, 4, 5, 6], - [6, 5, 2, 3, 1, 4], - [3, 4, 5, 1, 6, 2], - [4, 6, 1, 2, 3, 5], + [1, 2, 3, 4, 5, 6], + [6, 5, 2, 3, 1, 4], + [3, 4, 5, 1, 6, 2], + [4, 6, 1, 2, 3, 5], [2, 3, 6, 5, 4, 1], - [5, 1, 4, 6, 2, 3] + [5, 1, 4, 6, 2, 3], ]; -const getLatinSquareIndex = function(participantNumber) { - return ((participantNumber - 1) % latinSquare.length); +const getLatinSquareIndex = function (participantNumber) { + return (participantNumber - 1) % latinSquare.length; }; -const findIndexOfOrderElement = function(el, order) { - for(var i = 0; i < order.length; i++) { - if(order[i] === el) { +const findIndexOfOrderElement = function (el, order) { + for (var i = 0; i < order.length; i++) { + if (order[i] === el) { return i; } } }; -const getLatinSquareOrder = function(participantNumber) { +const getLatinSquareOrder = function (participantNumber) { const latinSquareIndex = getLatinSquareIndex(participantNumber); const latinSquareElement = latinSquare[latinSquareIndex]; const originalOrder = [1, 2, 3, 4, 5, 6]; var latinSquareRedirectOrder = []; - latinSquareRedirectOrder.push(("in-between-" + latinSquareElement[0])); - - for(var originalOrderElement of originalOrder) { - const indexElement = findIndexOfOrderElement(originalOrderElement, latinSquareElement); - if(indexElement === originalOrder.length - 1) { + latinSquareRedirectOrder.push("in-between-" + latinSquareElement[0]); + + for (var originalOrderElement of originalOrder) { + const indexElement = findIndexOfOrderElement( + originalOrderElement, + latinSquareElement + ); + if (indexElement === originalOrder.length - 1) { latinSquareRedirectOrder.push("end"); continue; } - const nextOrderElement = latinSquareElement[(indexElement + 1)]; - const nextOrderElementIndex = findIndexOfOrderElement(nextOrderElement, latinSquareElement); + const nextOrderElement = latinSquareElement[indexElement + 1]; + const nextOrderElementIndex = findIndexOfOrderElement( + nextOrderElement, + latinSquareElement + ); const nextRedirctElement = latinSquareElement[nextOrderElementIndex]; - latinSquareRedirectOrder.push(("in-between-" + nextRedirctElement )); + latinSquareRedirectOrder.push("in-between-" + nextRedirctElement); } return latinSquareRedirectOrder; }; function App() { - - // TODO FIX... + // TODO FIX... /* There is an weird interaction/error with the lazy loading of the routers and the translation or any other component, that needs to be loaded in lazily... For now this works, but still, this is very hacky and I hate this... */ var wait = (ms) => { - const start = Date.now(); - let now = start; - while (now - start < ms) { - now = Date.now(); - } - } + const start = Date.now(); + let now = start; + while (now - start < ms) { + now = Date.now(); + } + }; wait(200); @@ -97,23 +107,128 @@ function App() { return ( - + - ...}>} /> - ...}>} /> - ...}>} /> - ...}>} /> - ...}>} /> - ...}>} /> - ...}>} /> - ...}>} /> - ...}>} /> - ...}>} /> - ...}>} /> - ...}>} /> - ...}>} /> - ...}>} /> - ...}>} /> + ...}> + + + } + /> + ...}> + + + } + /> + ...}> + + + } + /> + ...}> + + + } + /> + ...}> + + + } + /> + ...}> + + + } + /> + ...}> + + + } + /> + ...}> + + + } + /> + ...}> + + + } + /> + ...}> + + + } + /> + ...}> + + + } + /> + ...}> + + + } + /> + ...}> + + + } + /> + ...}> + + + } + /> + ...}> + + + } + /> diff --git a/src/App.test.js b/src/App.test.js index 1f03afe..9382b9a 100644 --- a/src/App.test.js +++ b/src/App.test.js @@ -1,7 +1,7 @@ -import { render, screen } from '@testing-library/react'; -import App from './App'; +import { render, screen } from "@testing-library/react"; +import App from "./App"; -test('renders learn react link', () => { +test("renders learn react link", () => { render(); const linkElement = screen.getByText(/learn react/i); expect(linkElement).toBeInTheDocument(); diff --git a/src/components/DownloadButton.jsx b/src/components/DownloadButton.jsx index d4b70ef..e94b15a 100644 --- a/src/components/DownloadButton.jsx +++ b/src/components/DownloadButton.jsx @@ -1,42 +1,41 @@ import React from "react"; import { getTranslation } from "../core/i18n/I18NHandler"; import { getSensorLog } from "../core/log/SensorLogger"; -import { Button } from '@geist-ui/core'; +import { Button } from "@geist-ui/core"; import { getUserID } from "./RandomIDComponent"; import { PARTICIPANT_NUMBER } from "../core/Constants"; function DownloadButton() { - const downloadFile = ({ data, fileName, fileType }) => { - const blob = new Blob([data], { type: fileType }); - const a = document.createElement('a'); - a.download = fileName; - a.href = window.URL.createObjectURL(blob); - const clickEvt = new MouseEvent('click', { - view: window, - bubbles: true, - cancelable: true, - }); - a.dispatchEvent(clickEvt); - a.remove(); - } - + const downloadFile = ({ data, fileName, fileType }) => { + const blob = new Blob([data], { type: fileType }); + const a = document.createElement("a"); + a.download = fileName; + a.href = window.URL.createObjectURL(blob); + const clickEvt = new MouseEvent("click", { + view: window, + bubbles: true, + cancelable: true, + }); + a.dispatchEvent(clickEvt); + a.remove(); + }; - const userData = { - participantId: getUserID(), - sensorLog: getSensorLog(), - participantNumber: PARTICIPANT_NUMBER - } + const userData = { + participantId: getUserID(), + sensorLog: getSensorLog(), + participantNumber: PARTICIPANT_NUMBER, + }; - const exportToJson = e => { - e.preventDefault(); - downloadFile({ - data: JSON.stringify(userData), - fileName: 'sensorData.json', - fileType: 'text/json', - }) - } + const exportToJson = (e) => { + e.preventDefault(); + downloadFile({ + data: JSON.stringify(userData), + fileName: "sensorData.json", + fileType: "text/json", + }); + }; - return (); + return ; } -export default DownloadButton; \ No newline at end of file +export default DownloadButton; diff --git a/src/components/InfoPageComponent.jsx b/src/components/InfoPageComponent.jsx index 634cc9a..3ad9af8 100644 --- a/src/components/InfoPageComponent.jsx +++ b/src/components/InfoPageComponent.jsx @@ -1,20 +1,26 @@ import React from "react"; import { getTranslation } from "../core/i18n/I18NHandler"; -import { Button } from '@geist-ui/core'; +import { Button } from "@geist-ui/core"; const redirectToPage = (redirectLoc) => { - window.location.href = "./" + redirectLoc; -} + window.location.href = "./" + redirectLoc; +}; -function InfoPageComponent({children, redirectLoc}) { - return ( -
- {children} -
- -
-
- ); +function InfoPageComponent({ children, redirectLoc }) { + return ( +
+ {children} +
+ +
+
+ ); } -export default InfoPageComponent; \ No newline at end of file +export default InfoPageComponent; diff --git a/src/components/RandomIDComponent.jsx b/src/components/RandomIDComponent.jsx index b23ff75..e7913d1 100644 --- a/src/components/RandomIDComponent.jsx +++ b/src/components/RandomIDComponent.jsx @@ -1,34 +1,39 @@ import React from "react"; -import { createStore } from 'zustand/vanilla' -import { persist, createJSONStorage } from 'zustand/middleware' +import { createStore } from "zustand/vanilla"; +import { persist, createJSONStorage } from "zustand/middleware"; import { getTranslation } from "../core/i18n/I18NHandler"; var randomId = 0; // State for saving participant ID globally. export const participantIdLogState = createStore( - persist( - () => ({ - participant_id: "" - }), - { - name: 'participant-id-storage', // name of the item in the storage (must be unique) - storage: createJSONStorage(() => sessionStorage), // (optional) by default, 'localStorage' is used - }, - ), + persist( + () => ({ + participant_id: "", + }), + { + name: "participant-id-storage", // name of the item in the storage (must be unique) + storage: createJSONStorage(() => sessionStorage), // (optional) by default, 'localStorage' is used + } ) - +); + const { getState, setState } = participantIdLogState; // Can only be called once. :) function RandomIDComponent() { - randomId = Math.floor(Math.random() * 89999) + 10000; - setState({ participant_id: "" + randomId }) - return (

Your ID:

{randomId}

); + randomId = Math.floor(Math.random() * 89999) + 10000; + setState({ participant_id: "" + randomId }); + return ( +
+

Your ID:

+

{randomId}

+
+ ); } export function getUserID() { - return getState().participant_id; + return getState().participant_id; } -export default RandomIDComponent; \ No newline at end of file +export default RandomIDComponent; diff --git a/src/components/questionnaire/QuestionComponent.jsx b/src/components/questionnaire/QuestionComponent.jsx index d855819..dd718f2 100644 --- a/src/components/questionnaire/QuestionComponent.jsx +++ b/src/components/questionnaire/QuestionComponent.jsx @@ -1,63 +1,80 @@ // QuestionComponent.js import React, { useEffect } from "react"; -import { Slider, Input, Radio, Checkbox, Link } from '@geist-ui/core'; +import { Slider, Input, Radio, Checkbox, Link } from "@geist-ui/core"; export default function QuestionComponent(props) { - const { questionData, onUpdateAnswerData } = props; + const { questionData, onUpdateAnswerData } = props; - useEffect(() => { - // Update questionData when component mounts or props change - questionData.sData({ "id": props.id, "answerValue": questionData.answerValue }); - }, [props.id, questionData.answerValue]); + useEffect(() => { + // Update questionData when component mounts or props change + questionData.sData({ id: props.id, answerValue: questionData.answerValue }); + }, [props.id, questionData.answerValue]); - // Define a function to handle answer data change - const handleAnswerChange = (val) => { - questionData.sAnswerData(val); - onUpdateAnswerData(questionData.gAnswerData()); // Update answerData in parent component - }; + // Define a function to handle answer data change + const handleAnswerChange = (val) => { + questionData.sAnswerData(val); + onUpdateAnswerData(questionData.gAnswerData()); // Update answerData in parent component + }; - // Determine and render answer element based on props - var element; - if (props.answerType === "slider") { - element = ( - - ); - } else if (props.answerType === "radio") { - const btnIndexes = Array.from({ length: props.maxElement }, (_, i) => i + 1); - element = ( - - {btnIndexes.map((x) => {x})} - - ); - } else if (props.answerType === "checkbox") { - const btnIndexes = Array.from({ length: props.maxElement }, (_, i) => i + 1); - element = ( - - {btnIndexes.map((x) => {x})} - - ); - } else { - element = ( - handleAnswerChange(e.target.value)} - clearable - /> - ); - } - - // Render the component - return ( -
-

{props.text}

- {element} - {props.referBack && ←} - → -
+ // Determine and render answer element based on props + var element; + if (props.answerType === "slider") { + element = ( + + ); + } else if (props.answerType === "radio") { + const btnIndexes = Array.from( + { length: props.maxElement }, + (_, i) => i + 1 + ); + element = ( + + {btnIndexes.map((x) => ( + + {x} + + ))} + + ); + } else if (props.answerType === "checkbox") { + const btnIndexes = Array.from( + { length: props.maxElement }, + (_, i) => i + 1 ); + element = ( + + {btnIndexes.map((x) => ( + + {x} + + ))} + + ); + } else { + element = ( + handleAnswerChange(e.target.value)} clearable /> + ); + } + + // Render the component + return ( +
+

{props.text}

+ {element} + {props.referBack && ( + + ← + + )} + + → + +
+ ); } diff --git a/src/components/questionnaire/QuestionData.jsx b/src/components/questionnaire/QuestionData.jsx index 2134ce5..824d51d 100644 --- a/src/components/questionnaire/QuestionData.jsx +++ b/src/components/questionnaire/QuestionData.jsx @@ -1,36 +1,36 @@ -import {useState} from "react"; +import { useState } from "react"; export function useQuestionData() { - const [data, setData] = useState({}); - - function setQuestionData(questionData) { - setData(questionData); - }; - - function getQuestionData() { - return data; - } - - function setAnswerValue(val) { - data.answerValue = val; - setData(data); - } - - function getAnswerValue() { - return data.answerValue; - } - - function reset() { - setData({}); - }; - - const inputProps = { - sData: setQuestionData, - gData: getQuestionData, - sAnswerData: setAnswerValue, - gAnswerData: getAnswerValue, - r: reset - }; - - return inputProps; -} \ No newline at end of file + const [data, setData] = useState({}); + + function setQuestionData(questionData) { + setData(questionData); + } + + function getQuestionData() { + return data; + } + + function setAnswerValue(val) { + data.answerValue = val; + setData(data); + } + + function getAnswerValue() { + return data.answerValue; + } + + function reset() { + setData({}); + } + + const inputProps = { + sData: setQuestionData, + gData: getQuestionData, + sAnswerData: setAnswerValue, + gAnswerData: getAnswerValue, + r: reset, + }; + + return inputProps; +} diff --git a/src/components/questionnaire/QuestionnaireData.jsx b/src/components/questionnaire/QuestionnaireData.jsx index 3f1c345..5001248 100644 --- a/src/components/questionnaire/QuestionnaireData.jsx +++ b/src/components/questionnaire/QuestionnaireData.jsx @@ -2,26 +2,32 @@ import { useState, useEffect } from "react"; import { useQuestionData } from "./QuestionData"; -export function useQuestionComponent(answerType, maxElement, text, referBack, referTo) { - const [answerData, setAnswerData] = useState(null); - const questionData = useQuestionData({}); +export function useQuestionComponent( + answerType, + maxElement, + text, + referBack, + referTo +) { + const [answerData, setAnswerData] = useState(null); + const questionData = useQuestionData({}); - useEffect(() => { - setAnswerData(questionData.gAnswerData()); - }, [questionData]); + useEffect(() => { + setAnswerData(questionData.gAnswerData()); + }, [questionData]); - const handleUpdateAnswerData = (data) => { - setAnswerData(data); - }; + const handleUpdateAnswerData = (data) => { + setAnswerData(data); + }; - return { - questionData, - answerData, - handleUpdateAnswerData, // Pass the function here - answerType, - maxElement, - text, - referBack, - referTo - }; + return { + questionData, + answerData, + handleUpdateAnswerData, // Pass the function here + answerType, + maxElement, + text, + referBack, + referTo, + }; } diff --git a/src/components/webpage_container/StudySite.jsx b/src/components/webpage_container/StudySite.jsx index 7284abd..73372ce 100644 --- a/src/components/webpage_container/StudySite.jsx +++ b/src/components/webpage_container/StudySite.jsx @@ -1,69 +1,68 @@ -import React, {useEffect} from "react"; +import React, { useEffect } from "react"; import h337 from "heatmap.js"; import { MOUSE_MODE, HEATMAP_MAX } from "../../core/Constants"; var stopInput = false; var heatmapInstance = h337.create({ - container: document.body, - radius: 20 + container: document.body, + radius: 20, }); -const visualiseMouseData = ((mouseData) => { - mouseData.max = mouseData.data.length + 1; - heatmapInstance.setData(mouseData); - document.getElementsByTagName("canvas")[0].style.opacity = 1; - stopInput = true; -}); +const visualiseMouseData = (mouseData) => { + mouseData.max = mouseData.data.length + 1; + heatmapInstance.setData(mouseData); + document.getElementsByTagName("canvas")[0].style.opacity = 1; + stopInput = true; +}; export function StudySite(props) { + useEffect(() => { + window.visualiseMouseData = visualiseMouseData; + heatmapInstance.setDataMax(HEATMAP_MAX); + var addData; + + if (MOUSE_MODE) { + const mouseDataFunc = function (ev) { + if (!stopInput) { + heatmapInstance.addData({ + x: ev.x, + y: ev.y, + value: 1, + }); + } + }; - useEffect(() => { - window.visualiseMouseData = visualiseMouseData; - heatmapInstance.setDataMax(HEATMAP_MAX); - var addData; - - if(MOUSE_MODE) { - const mouseDataFunc = function(ev) { - if(!stopInput) { - heatmapInstance.addData({ - x: ev.x, - y: ev.y, - value: 1, - }); - } - }; - - addData = mouseDataFunc; - } else { - const touchDataFunc = function(ev) { - if(!stopInput) { - heatmapInstance.addData({ - x: ev.layerX, - y: ev.layerY, - value: 1 - }); - } - }; - addData = touchDataFunc; - } - - if(MOUSE_MODE) { - document.body.addEventListener("mousemove", addData, false); - } else { - document.body.addEventListener("touchmove", addData, false); - document.body.addEventListener("touchstart", addData, false); - document.body.addEventListener("touchend", addData, false); - } + addData = mouseDataFunc; + } else { + const touchDataFunc = function (ev) { + if (!stopInput) { + heatmapInstance.addData({ + x: ev.layerX, + y: ev.layerY, + value: 1, + }); + } + }; + addData = touchDataFunc; + } - return () => { - delete window.visualiseMouseData; - }; - }); + if (MOUSE_MODE) { + document.body.addEventListener("mousemove", addData, false); + } else { + document.body.addEventListener("touchmove", addData, false); + document.body.addEventListener("touchstart", addData, false); + document.body.addEventListener("touchend", addData, false); + } - return (<>{props.children}); + return () => { + delete window.visualiseMouseData; + }; + }); + + return <>{props.children}; } export function getHeatmapData() { - return heatmapInstance.getData(); -} \ No newline at end of file + return heatmapInstance.getData(); +} diff --git a/src/components/webpage_container/WebpageBanner.jsx b/src/components/webpage_container/WebpageBanner.jsx index 7a769c8..147df4e 100644 --- a/src/components/webpage_container/WebpageBanner.jsx +++ b/src/components/webpage_container/WebpageBanner.jsx @@ -1,23 +1,24 @@ import { Component } from "react"; import { getTranslation } from "../../core/i18n/I18NHandler"; -import { Note } from '@geist-ui/core'; +import { Note } from "@geist-ui/core"; var bannerContent = ""; export default class WebpageBanner extends Component { - - constructor(props) { - super(props); - bannerContent = getTranslation(props.translationKey); - } + constructor(props) { + super(props); + bannerContent = getTranslation(props.translationKey); + } - setBannerContent(content) { - bannerContent = content; - } + setBannerContent(content) { + bannerContent = content; + } - render() { - return ( - {bannerContent} - ); - } -} \ No newline at end of file + render() { + return ( + + {bannerContent} + + ); + } +} diff --git a/src/core/audio/AudioHandler.jsx b/src/core/audio/AudioHandler.jsx index 92904cf..f23dccb 100644 --- a/src/core/audio/AudioHandler.jsx +++ b/src/core/audio/AudioHandler.jsx @@ -1,38 +1,33 @@ -import {Component} from 'react'; -import * as Tone from "tone"; -import { pushToSonificationLog } from '../log/SensorLogger'; +import { Component } from "react"; +import * as Tone from "tone"; +import { pushToSonificationLog } from "../log/SensorLogger"; export default class AudioHandler extends Component { - - playTabEarconSonification() { - - pushToSonificationLog("tab_earcon"); - } - - playTabModelSonification() { - - pushToSonificationLog("tab_model"); - } - - playDetailEarconSonification() { - - pushToSonificationLog("detail_earcon"); - } - - playDetailModelSonification() { - - pushToSonificationLog("detail_model"); - } - - setRotation(angle) { - Tone.Listener.forwardX.value = Math.sin(angle); - Tone.Listener.forwardY.value = 0; - Tone.Listener.forwardZ.value = -Math.cos(angle); - } - - setRotationRamp(panner, angle, rampTime) { - panner.positionX.rampTo(Math.sin(angle), rampTime); - panner.positionY.rampTo(0, rampTime); - panner.positionZ.rampTo(-Math.cos(angle), rampTime); - } -} \ No newline at end of file + playTabEarconSonification() { + pushToSonificationLog("tab_earcon"); + } + + playTabModelSonification() { + pushToSonificationLog("tab_model"); + } + + playDetailEarconSonification() { + pushToSonificationLog("detail_earcon"); + } + + playDetailModelSonification() { + pushToSonificationLog("detail_model"); + } + + setRotation(angle) { + Tone.Listener.forwardX.value = Math.sin(angle); + Tone.Listener.forwardY.value = 0; + Tone.Listener.forwardZ.value = -Math.cos(angle); + } + + setRotationRamp(panner, angle, rampTime) { + panner.positionX.rampTo(Math.sin(angle), rampTime); + panner.positionY.rampTo(0, rampTime); + panner.positionZ.rampTo(-Math.cos(angle), rampTime); + } +} diff --git a/src/core/audio/ChordHelper.jsx b/src/core/audio/ChordHelper.jsx index 2ae35be..4d93b26 100644 --- a/src/core/audio/ChordHelper.jsx +++ b/src/core/audio/ChordHelper.jsx @@ -1,26 +1,28 @@ import * as Tone from "tone"; export function buildChord(notes, octave) { - return notes.map(note => {return (note + octave);}) + return notes.map((note) => { + return note + octave; + }); } export function buildNote(note, octave) { - return (note + octave); + return note + octave; } export function generateChord(rootNote, chordType) { - // Define intervals for different chord types - const chordIntervals = { - 'major': [0, 4, 7], - 'minor': [0, 3, 7], - '7th': [0, 4, 7, 10], - 'diminished': [0, 3, 6], - 'augmented': [0, 4, 8], - 'sus2': [0, 2, 7], - 'sus4': [0, 5, 7] - }; + // Define intervals for different chord types + const chordIntervals = { + major: [0, 4, 7], + minor: [0, 3, 7], + "7th": [0, 4, 7, 10], + diminished: [0, 3, 6], + augmented: [0, 4, 8], + sus2: [0, 2, 7], + sus4: [0, 5, 7], + }; - const intervals = chordIntervals[chordType]; + const intervals = chordIntervals[chordType]; - return Tone.Frequency(rootNote).harmonize(intervals); -} \ No newline at end of file + return Tone.Frequency(rootNote).harmonize(intervals); +} diff --git a/src/core/i18n/I18NHandler.jsx b/src/core/i18n/I18NHandler.jsx index 0254bba..5f9a58e 100644 --- a/src/core/i18n/I18NHandler.jsx +++ b/src/core/i18n/I18NHandler.jsx @@ -1,5 +1,5 @@ import i18n from "./i18n"; export function getTranslation(translationKey) { - return i18n.t(translationKey); -} \ No newline at end of file + return i18n.t(translationKey); +} diff --git a/src/core/i18n/i18n.js b/src/core/i18n/i18n.js index abbb48a..afbef1e 100644 --- a/src/core/i18n/i18n.js +++ b/src/core/i18n/i18n.js @@ -1,7 +1,7 @@ import i18n from "i18next"; import { initReactI18next } from "react-i18next"; import Backend from "i18next-http-backend"; -import LanguageDetector from 'i18next-browser-languagedetector'; +import LanguageDetector from "i18next-browser-languagedetector"; i18n .use(Backend) @@ -10,10 +10,10 @@ i18n .init({ fallbackLng: "en", interpolation: { - escapeValue: false // react already safes from xss - } + escapeValue: false, // react already safes from xss + }, }); - i18n.changeLanguage('en'); // For now to control the language... Later on, not necessary... +i18n.changeLanguage("en"); // For now to control the language... Later on, not necessary... - export default i18n; \ No newline at end of file +export default i18n; diff --git a/src/core/log/RouteTracker.jsx b/src/core/log/RouteTracker.jsx index 4f545e5..e3a7e63 100644 --- a/src/core/log/RouteTracker.jsx +++ b/src/core/log/RouteTracker.jsx @@ -1,6 +1,6 @@ -import { useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; -import { pushToVisitLog } from './SensorLogger'; +import { useEffect } from "react"; +import { useLocation } from "react-router-dom"; +import { pushToVisitLog } from "./SensorLogger"; const RouteTracker = () => { const location = useLocation(); diff --git a/src/core/log/SensorLogger.jsx b/src/core/log/SensorLogger.jsx index 1141bbd..f481235 100644 --- a/src/core/log/SensorLogger.jsx +++ b/src/core/log/SensorLogger.jsx @@ -1,47 +1,57 @@ -import { getState, setState } from '../../App'; - - export function pushToMouseLog(logElement) { - const sensorLog = getState().sensorLog; - sensorLog.mouseLog.push(logElement); - setState({ sensorLog: sensorLog }); - } - - export function pushToClickLog(logElement) { - // Filter out dummy body objects - if(logElement.target.localName === "body") { - return; - } - - const sensorLog = getState().sensorLog; - sensorLog.clickedElements.push(logElement); - setState({ sensorLog: sensorLog }); - } - - export function pushToVisitLog(logElement) { - const sensorLog = getState().sensorLog; - - // Filter out double visit pushes... - const visitedSitesAmount = sensorLog.visitedSites.length; - if(visitedSitesAmount > 0) { - const lastVisitedElement = sensorLog.visitedSites[visitedSitesAmount - 1]; - if(lastVisitedElement.path === logElement.path && logElement.timestamp - lastVisitedElement.timestamp < 500) { - return; - } - sensorLog.visitedSites.push(logElement); - setState({ sensorLog: sensorLog }); - } +import { getState, setState } from "../../App"; + +export function pushToMouseLog(logElement) { + const sensorLog = getState().sensorLog; + sensorLog.mouseLog.push(logElement); + setState({ sensorLog: sensorLog }); +} + +export function pushToClickLog(logElement) { + // Filter out dummy body objects + if (logElement.target.localName === "body") { + return; + } + + const sensorLog = getState().sensorLog; + sensorLog.clickedElements.push(logElement); + setState({ sensorLog: sensorLog }); +} + +export function pushToVisitLog(logElement) { + const sensorLog = getState().sensorLog; + + // Filter out double visit pushes... + const visitedSitesAmount = sensorLog.visitedSites.length; + if (visitedSitesAmount > 0) { + const lastVisitedElement = sensorLog.visitedSites[visitedSitesAmount - 1]; + if ( + lastVisitedElement.path === logElement.path && + logElement.timestamp - lastVisitedElement.timestamp < 500 + ) { + return; } - - export function pushToSonificationLog(logElement) { - const sensorLog = getState().sensorLog; - sensorLog.playedSonifications.push(logElement); - setState({ sensorLog: sensorLog }); - } - - export function getSensorLog() { - return getState().sensorLog; - } - - export function resetSensorLog() { - setState({ sensorLog: {mouseLog: [], clickedElements: [], visitedSites: [], playedSonifications: []}}); - } \ No newline at end of file + sensorLog.visitedSites.push(logElement); + setState({ sensorLog: sensorLog }); + } +} + +export function pushToSonificationLog(logElement) { + const sensorLog = getState().sensorLog; + sensorLog.playedSonifications.push(logElement); + setState({ sensorLog: sensorLog }); +} + +export function getSensorLog() { + return getState().sensorLog; +} + +export function resetSensorLog() { + setState({ + sensorLog: { + mouseLog: [], + clickedElements: [], + visitedSites: [], + playedSonifications: [], + }, + }); +} diff --git a/src/index.js b/src/index.js index 3c9757f..a103ffa 100644 --- a/src/index.js +++ b/src/index.js @@ -1,23 +1,22 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; +import React from "react"; +import ReactDOM from "react-dom/client"; +import "./index.css"; +import App from "./App"; +import reportWebVitals from "./reportWebVitals"; import { BrowserRouter } from "react-router-dom"; import "./core/i18n/i18n"; -import { pushToClickLog } from './core/log/SensorLogger'; +import { pushToClickLog } from "./core/log/SensorLogger"; -document.onclick = function(event) { +document.onclick = function (event) { pushToClickLog(event); }; -const root = ReactDOM.createRoot(document.getElementById('root')); +const root = ReactDOM.createRoot(document.getElementById("root")); root.render( - - - - + + + ); diff --git a/src/interfaces/DataComponent.jsx b/src/interfaces/DataComponent.jsx index 4ae563a..2578884 100644 --- a/src/interfaces/DataComponent.jsx +++ b/src/interfaces/DataComponent.jsx @@ -1,14 +1,14 @@ import ResetableComponent from "./ResetableComponent.jsx"; export default class DataComponent extends ResetableComponent { + constructor(componentId) { + super(); + this.compId = componentId; + } - constructor(componentId) { - super(); - this.compId = componentId; - } + exportData() {} - exportData() {} - - getId() { return this.compId; } - -} \ No newline at end of file + getId() { + return this.compId; + } +} diff --git a/src/interfaces/ResetableComponent.jsx b/src/interfaces/ResetableComponent.jsx index 9405557..8f2577b 100644 --- a/src/interfaces/ResetableComponent.jsx +++ b/src/interfaces/ResetableComponent.jsx @@ -1,7 +1,5 @@ -import React from 'react'; +import React from "react"; export default class ResetableComponent extends React.Component { - - reset() {} - -} \ No newline at end of file + reset() {} +} diff --git a/src/pages/NoPageFound.jsx b/src/pages/NoPageFound.jsx index 728d384..b8b9530 100644 --- a/src/pages/NoPageFound.jsx +++ b/src/pages/NoPageFound.jsx @@ -1,8 +1,7 @@ import React from "react"; export default class NoPageFound extends React.Component { - - render() { - return (

No Page Found

); - } -} \ No newline at end of file + render() { + return

No Page Found

; + } +} diff --git a/src/pages/TestEndPage.jsx b/src/pages/TestEndPage.jsx index 77d50a3..e86728e 100644 --- a/src/pages/TestEndPage.jsx +++ b/src/pages/TestEndPage.jsx @@ -2,10 +2,12 @@ import React from "react"; import DownloadButton from "../components/DownloadButton"; function TestInfoPage() { - return (
-

Thank you for participating! ❤️

- -
); + return ( +
+

Thank you for participating! ❤️

+ +
+ ); } -export default TestInfoPage; \ No newline at end of file +export default TestInfoPage; diff --git a/src/pages/TestInfoPage.jsx b/src/pages/TestInfoPage.jsx index d88050b..483cd81 100644 --- a/src/pages/TestInfoPage.jsx +++ b/src/pages/TestInfoPage.jsx @@ -2,11 +2,23 @@ import React from "react"; import InfoPageComponent from "../components/InfoPageComponent"; import RandomIDComponent from "../components/RandomIDComponent"; -function TestInfoPage({redirectLoc}) { - return ( -

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

- -
); +function TestInfoPage({ redirectLoc }) { + return ( + +

+ Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy + eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam + voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet + clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit + amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam + nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, + sed diam voluptua. At vero eos et accusam et justo duo dolores et ea + rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem + ipsum dolor sit amet. +

+ +
+ ); } -export default TestInfoPage; \ No newline at end of file +export default TestInfoPage; diff --git a/src/pages/TestInfoPage2.jsx b/src/pages/TestInfoPage2.jsx index 0f5e135..0f3c6b6 100644 --- a/src/pages/TestInfoPage2.jsx +++ b/src/pages/TestInfoPage2.jsx @@ -1,10 +1,22 @@ import React from "react"; import InfoPageComponent from "../components/InfoPageComponent"; -function TestInfoPage2({redirectLoc}) { - return ( -

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

-
); +function TestInfoPage2({ redirectLoc }) { + return ( + +

+ Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy + eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam + voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet + clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit + amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam + nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, + sed diam voluptua. At vero eos et accusam et justo duo dolores et ea + rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem + ipsum dolor sit amet. +

+
+ ); } -export default TestInfoPage2; \ No newline at end of file +export default TestInfoPage2; diff --git a/src/pages/TestPage.jsx b/src/pages/TestPage.jsx index 1983142..9a06327 100644 --- a/src/pages/TestPage.jsx +++ b/src/pages/TestPage.jsx @@ -1,17 +1,31 @@ import React from "react"; import { getTranslation } from "../core/i18n/I18NHandler"; import WebpageBanner from "../components/webpage_container/WebpageBanner"; -import { StudySite, getHeatmapData } from "../components/webpage_container/StudySite"; +import { + StudySite, + getHeatmapData, +} from "../components/webpage_container/StudySite"; import { pushToMouseLog, getSensorLog } from "../core/log/SensorLogger"; -import { Button } from '@geist-ui/core'; +import { Button } from "@geist-ui/core"; - -function TestPage({redirectLoc}) { - var clickFunction = function() { - pushToMouseLog(getHeatmapData()); - window.location.href = "./" + redirectLoc; - }; - return (

{clickFunction()}}>{getTranslation("hello_world")}

); +function TestPage({ redirectLoc }) { + var clickFunction = function () { + pushToMouseLog(getHeatmapData()); + window.location.href = "./" + redirectLoc; + }; + return ( + + +

{ + clickFunction(); + }} + > + {getTranslation("hello_world")} +

+ +
+ ); } -export default TestPage; \ No newline at end of file +export default TestPage; diff --git a/src/pages/TestPage2.jsx b/src/pages/TestPage2.jsx index 7b76ca7..44ace4c 100644 --- a/src/pages/TestPage2.jsx +++ b/src/pages/TestPage2.jsx @@ -1,16 +1,31 @@ import React from "react"; import { getTranslation } from "../core/i18n/I18NHandler"; import WebpageBanner from "../components/webpage_container/WebpageBanner"; -import { StudySite, getHeatmapData } from "../components/webpage_container/StudySite"; +import { + StudySite, + getHeatmapData, +} from "../components/webpage_container/StudySite"; import { pushToMouseLog } from "../core/log/SensorLogger"; -import { Button } from '@geist-ui/core'; +import { Button } from "@geist-ui/core"; -function TestPage2({redirectLoc}) { - var clickFunction = function() { - pushToMouseLog(getHeatmapData()); - window.location.href = "./" + redirectLoc; - }; - return (

{getTranslation("hello_world")}

); +function TestPage2({ redirectLoc }) { + var clickFunction = function () { + pushToMouseLog(getHeatmapData()); + window.location.href = "./" + redirectLoc; + }; + return ( + + +

{getTranslation("hello_world")}

+ +
+ ); } -export default TestPage2; \ No newline at end of file +export default TestPage2; diff --git a/src/pages/TestQuestionnaire.jsx b/src/pages/TestQuestionnaire.jsx index 55e3d8f..0185862 100644 --- a/src/pages/TestQuestionnaire.jsx +++ b/src/pages/TestQuestionnaire.jsx @@ -1,22 +1,36 @@ import React from "react"; -import { useParams } from 'react-router-dom'; +import { useParams } from "react-router-dom"; import QuestionComponent from "../components/questionnaire/QuestionComponent"; import { useQuestionComponent } from "../components/questionnaire/QuestionnaireData"; - export default function TestQuestionnaire() { - const { id } = useParams() + const { id } = useParams(); - const q1Props = useQuestionComponent("checkbox", 4, "Lorem Ipsum", "/info", "./q2"); - const q2Props = useQuestionComponent("slider", 8, "Lorem Ipsum Ye", "./q1", "/info"); + const q1Props = useQuestionComponent( + "checkbox", + 4, + "Lorem Ipsum", + "/info", + "./q2" + ); + const q2Props = useQuestionComponent( + "slider", + 8, + "Lorem Ipsum Ye", + "./q1", + "/info" + ); - const questionProperties = {"q1": q1Props, "q2": q2Props}; - const questionProperty = questionProperties[id]; + const questionProperties = { q1: q1Props, q2: q2Props }; + const questionProperty = questionProperties[id]; - return ( -
- -

Current Answer Data: {JSON.stringify(questionProperty.answerData)}

-
- ); + return ( +
+ +

Current Answer Data: {JSON.stringify(questionProperty.answerData)}

+
+ ); } diff --git a/src/pages/study_site_1/StartPage1.jsx b/src/pages/study_site_1/StartPage1.jsx index 3000c9c..07f1d1a 100644 --- a/src/pages/study_site_1/StartPage1.jsx +++ b/src/pages/study_site_1/StartPage1.jsx @@ -1,81 +1,155 @@ import React from "react"; import { getTranslation } from "../../core/i18n/I18NHandler"; import WebpageBanner from "../../components/webpage_container/WebpageBanner"; -import { StudySite, getHeatmapData } from "../../components/webpage_container/StudySite"; +import { + StudySite, + getHeatmapData, +} from "../../components/webpage_container/StudySite"; import { pushToMouseLog, getSensorLog } from "../../core/log/SensorLogger"; import { Collapse, Text, Spacer } from "@geist-ui/core"; //import {logo} from "/public/images/budget_bird_logo.png"; -function StartPage1({redirectLoc}) { - var saveMouseLog = function() { - pushToMouseLog(getHeatmapData()); - //window.location.href = "./" + redirectLoc; - }; +function StartPage1({ redirectLoc }) { + var saveMouseLog = function () { + pushToMouseLog(getHeatmapData()); + //window.location.href = "./" + redirectLoc; + }; - // TODO THINK IF I WANT TO JUST USE AN OVERLAY FOR OTHER DUMMY LINKS, WHICH ARENT CORRECT??? - // IS THAT OKAY??? + // TODO THINK IF I WANT TO JUST USE AN OVERLAY FOR OTHER DUMMY LINKS, WHICH ARENT CORRECT??? + // IS THAT OKAY??? - return ( - - - BudgetBird Airlines Logo - -

Frequently Asked Questions

- - - - You can change your flight bookings providing the fare conditions of your ticket permit this. - You can find out whether your ticket can be rebooked and whether there is a fee for this on your booking confirmation, or contact your travel agency or the Service Centre. - Alternatively, you can also rebook your flight details under My Bookings. - - - It is not possible to make a retroactive name change for a booking. Lufthansa shall provide the transport service to the passenger named in the ticket only. - The BudgetBird Service Team will be happy to help you if you require further information. - - - The maximum weight limit for your flight can be checked - - The maximum size per piece of baggage is 158 cm (width X + height Y + depth Z). - - Larger, heavier or additional bags are carried as excess baggage. You can find the prices in our baggage calculator. - - - Since BudgetBird Airlines offers no flights outside the European Union the European Air Passenger Rights will apply. - - - You can change your flight bookings provided that the fare conditions of your ticket permit this. -You can find out whether your ticket can be rebooked and whether there is a fee for this on your booking confirmation, or contact your travel agency or the Service Centre. -Alternatively, you can also make a change to your flight details in the My Bookings section. Depending on the alternative flight you choose, there may be surcharges on a higher fare. The amount of the surcharge depends on the availability of the selected booking class and will be communicated to you during the rebooking process. - - - In principle, the refund is paid using the same method that you originally used to pay for the ticket, in other words, if you paid for your ticket by credit card, the refund will be credited to the same credit card account. - - - To make a reservation, please contact us in the following way: - Contact Details: - +31 99 999 9999 - Monday - Sunday open for 24 hours. - (Standard phone charges apply.) - reservation.budgetbird@example.com - - - When your ticket has not been used, the ticket price including all taxes and fees will be refunded to the original method of payment. -If you have already used one or more segments of the journey, the unused portion of the fare value, taxes and fees will be calculated and the ticket refunded accordingly on a pro rata basis. - - - Depending on your concern, you can contact Customer Support in the following ways: - - - - For every 100 kilometers travelled on any flight with BudgetBird Airlines, you will gain one BudgetBird Mile. These BudgetBird Miles can be used within the BudgetBird Miles Store, in exchange for goodies, discounts or free BudgetBird flight tickets. - - -
); + return ( + + + + BudgetBird Airlines Logo + +

Frequently Asked Questions

+ + + + + You can change your flight bookings providing the fare conditions of + your ticket permit this. You can find out whether your ticket can be + rebooked and whether there is a fee for this on your booking + confirmation, or contact your travel agency or the Service Centre. + Alternatively, you can also rebook your flight details under{" "} + My Bookings. + + + + + It is not possible to make a retroactive name change for a booking. + Lufthansa shall provide the transport service to the passenger named + in the ticket only. The BudgetBird Service Team will be happy to + help you if you require further information. + + + + The maximum weight limit for your flight can be checked + + The maximum size per piece of baggage is 158 cm (width X + height Y + + depth Z). + + + Larger, heavier or additional bags are carried as excess baggage. + You can find the prices in our baggage calculator. + + + + + Since BudgetBird Airlines offers no flights outside the European + Union the{" "} + + European Air Passenger Rights + {" "} + will apply. + + + + + You can change your flight bookings provided that the fare + conditions of your ticket permit this. You can find out whether your + ticket can be rebooked and whether there is a fee for this on your + booking confirmation, or contact your travel agency or the Service + Centre. Alternatively, you can also make a change to your flight + details in the My Bookings section. Depending on + the alternative flight you choose, there may be surcharges on a + higher fare. The amount of the surcharge depends on the availability + of the selected booking class and will be communicated to you during + the rebooking process. + + + + + In principle, the refund is paid using the same method that you + originally used to pay for the ticket, in other words, if you paid + for your ticket by credit card, the refund will be credited to the + same credit card account. + + + + + To make a reservation, please contact us in the following way:{" "} + + Contact Details: + + +31 99 999 9999 + Monday - Sunday open for 24 hours. + (Standard phone charges apply.) + + + + reservation.budgetbird@example.com + + + + + + When your ticket has not been used, the ticket price including all + taxes and fees will be refunded to the original method of payment. + If you have already used one or more segments of the journey, the + unused portion of the fare value, taxes and fees will be calculated + and the ticket refunded accordingly on a pro rata basis. + + + + + Depending on your concern, you can contact Customer Support in the + following ways: + + + + + + For every 100 kilometers travelled on any flight with BudgetBird + Airlines, you will gain one BudgetBird Mile. These BudgetBird Miles + can be used within the BudgetBird Miles Store, in exchange for + goodies, discounts or free BudgetBird flight tickets. + + + +
+ ); } -export default StartPage1; \ No newline at end of file +export default StartPage1;