Browse Source

feat: Added basic version of second study site.

master
Denis Thiessen 5 months ago
parent
commit
38fffa5b7c
  1. 28
      package-lock.json
  2. 2
      package.json
  3. 3
      public/locales/de/translation.json
  4. 3
      public/locales/en/translation.json
  5. 12
      src/App.js
  6. 107
      src/components/ScrollableTab.jsx
  7. 102
      src/pages/study_site_2/StartPage2.jsx
  8. 103
      src/pages/study_site_2/TourOperators.jsx

28
package-lock.json

@ -9,6 +9,7 @@
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@geist-ui/core": "^2.3.8", "@geist-ui/core": "^2.3.8",
"@geist-ui/icons": "^1.0.2",
"@testing-library/jest-dom": "^5.17.0", "@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
@ -21,6 +22,7 @@
"react-i18next": "^14.1.1", "react-i18next": "^14.1.1",
"react-router-dom": "^6.23.0", "react-router-dom": "^6.23.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-tabs-scrollable": "^2.0.6",
"web-vitals": "^2.1.4", "web-vitals": "^2.1.4",
"zustand": "^4.5.2" "zustand": "^4.5.2"
} }
@ -2404,6 +2406,15 @@
"react-dom": ">=16.9.0" "react-dom": ">=16.9.0"
} }
}, },
"node_modules/@geist-ui/icons": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@geist-ui/icons/-/icons-1.0.2.tgz",
"integrity": "sha512-Npfa0NW6fQ31qw/+iMPWbs1hAcJ/3FqBjSLYgEfITDqy/3TJFpFKeVyK04AC/hTmYTsdNruVYczqPNcham5FOQ==",
"peerDependencies": {
"@geist-ui/core": ">=1.0.0",
"react": ">=16.13.0"
}
},
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
"version": "0.11.14", "version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@ -8844,11 +8855,6 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/fs": {
"version": "0.0.1-security",
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
"integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w=="
},
"node_modules/fs-extra": { "node_modules/fs-extra": {
"version": "10.1.0", "version": "10.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
@ -15343,6 +15349,18 @@
} }
} }
}, },
"node_modules/react-tabs-scrollable": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/react-tabs-scrollable/-/react-tabs-scrollable-2.0.6.tgz",
"integrity": "sha512-b1uwkqF1UVgP4EgqqDkv6Xp38sqMcuQvr+H/seYVQGxNhQjqnVpuck8T/mRio4oB+1PB7Xpaa0gibesB7Q7LfQ==",
"funding": {
"url": "https://www.buymeacoffee.com/Mooder"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/read-cache": { "node_modules/read-cache": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",

2
package.json

@ -4,6 +4,7 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@geist-ui/core": "^2.3.8", "@geist-ui/core": "^2.3.8",
"@geist-ui/icons": "^1.0.2",
"@testing-library/jest-dom": "^5.17.0", "@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
@ -16,6 +17,7 @@
"react-i18next": "^14.1.1", "react-i18next": "^14.1.1",
"react-router-dom": "^6.23.0", "react-router-dom": "^6.23.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-tabs-scrollable": "^2.0.6",
"web-vitals": "^2.1.4", "web-vitals": "^2.1.4",
"zustand": "^4.5.2" "zustand": "^4.5.2"
}, },

3
public/locales/de/translation.json

@ -2,5 +2,6 @@
"hello_world": "Hallo Welt", "hello_world": "Hallo Welt",
"download": "Download", "download": "Download",
"continue": "Fortfahren", "continue": "Fortfahren",
"task_1_info": "Ihr Flug wurde storniert und Sie möchten nun den Kunden-Support kontaktieren für eine Rückerstattung."
"task_1_info": "Ihr Flug wurde storniert und Sie möchten nun den Kunden-Support kontaktieren für eine Rückerstattung.",
"task_2_info": "Finde heraus, wie viel eine Buchung mit 'Misguided Getaways' kostet."
} }

3
public/locales/en/translation.json

@ -2,5 +2,6 @@
"hello_world": "Hello World", "hello_world": "Hello World",
"download": "Download", "download": "Download",
"continue": "Continue", "continue": "Continue",
"task_1_info": "Your flight was cancelled and you want to contact customer support to get a refund."
"task_1_info": "Your flight was cancelled and you want to contact customer support to get a refund.",
"task_2_info": "Find out how much a booking with the 'Misguided Getaways' tour operator costs."
} }

12
src/App.js

@ -14,6 +14,8 @@ const TestInfoPage = React.lazy(() => import("./pages/TestInfoPage"));
const TestInfoPage2 = React.lazy(() => import("./pages/TestInfoPage2")); const TestInfoPage2 = React.lazy(() => import("./pages/TestInfoPage2"));
const TestEndPage = React.lazy(() => import("./pages/TestEndPage")); const TestEndPage = React.lazy(() => import("./pages/TestEndPage"));
const StartPage1 = React.lazy(() => import("./pages/study_site_1/StartPage1")); const StartPage1 = React.lazy(() => import("./pages/study_site_1/StartPage1"));
const StartPage2 = React.lazy(() => import("./pages/study_site_2/StartPage2"));
const TourOperators = React.lazy(() => import("./pages/study_site_2/TourOperators"));
export const sensorLogState = createStore( export const sensorLogState = createStore(
persist( persist(
@ -145,7 +147,7 @@ function App() {
path="/study-page-2" path="/study-page-2"
element={ element={
<React.Suspense fallback={<>...</>}> <React.Suspense fallback={<>...</>}>
<TestPage redirectLoc={latinSquareOrder[2]} />
<StartPage2 redirectLoc={latinSquareOrder[2]} />
</React.Suspense> </React.Suspense>
} }
/> />
@ -221,6 +223,14 @@ function App() {
</React.Suspense> </React.Suspense>
} }
/> />
<Route
path="/tour_operators"
element={
<React.Suspense fallback={<>...</>}>
<TourOperators />
</React.Suspense>
}
/>
<Route <Route
path="*" path="*"
element={ element={

107
src/components/ScrollableTab.jsx

@ -0,0 +1,107 @@
import React from "react";
import { Tabs, Tab } from "react-tabs-scrollable";
import "react-tabs-scrollable/dist/rts.css";
var amountTabs = 0;
var reachedEndValue = false;
var rightSideEnd = true;
var endElement = amountTabs;
export default class ScrollableTab extends React.Component {
//extends AudioPlayer {
constructor(props) {
super(props);
this.state = {
activeTab: 1,
};
}
// define a onClick function to bind the value on tab click
onTabClick(e, index) {
this.setState({ activeTab: index });
}
onHoverElement() {}
onHoverTab(key) {
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
const panVal = rightSideEnd
? clamp(3 * ((-1 / amountTabs) * key + 1) - 2, -1, 1)
: clamp(2 * ((-1 / amountTabs) * -1 * key + 1) - 4, -1, 1); // ((-1 / amountTabs) * key + 1);
console.log(panVal);
const frequencyVal = rightSideEnd
? Math.round((key / amountTabs) * key + 6)
: Math.round(((key - amountTabs) / amountTabs) * (key - amountTabs) + 6);
var endValueVisible = this.isVisible(document.getElementById(endElement));
if (endValueVisible) {
reachedEndValue = true;
}
if (reachedEndValue && endValueVisible) {
//this.playChordEndSound();
if (rightSideEnd) {
endElement = 1;
rightSideEnd = false;
} else {
endElement = amountTabs;
rightSideEnd = true;
}
} else if (!endValueVisible) {
//this.playChordSound(panVal, frequencyVal);
//this.playPitchSound(panVal, 200 + 10*key);
}
}
// didReachEnd is bad... That is why, I have my own function... :)
// This sets it to "visible", if at least some part is visible... But maybe I want to have a percentage-based thing...
// If whole viewport is necessary, this makes it also bad, since a scroll all the way is required...
// Not really necessary, since the user already "knows", that this is the end...
isVisible(el) {
var rect = el.getBoundingClientRect();
return (
rect.bottom > 0 &&
rect.right > 0 &&
rect.left < (window.innerWidth || document.documentElement.clientWidth) &&
rect.top < (window.innerHeight || document.documentElement.clientHeight)
);
}
render() {
//var keys = Array.from({ length: amountTabs }, (_, i) => i + 1);
// onFocus as an additional thingy?
var tabId = 0;
amountTabs = this.props.children.length;
endElement = amountTabs;
var tabs = this.props.children.map((k) => {
tabId += 1;
return (
<Tab
id={tabId}
onTouchStart={() => this.onHoverTab(k)}
onMouseOver={() => this.onHoverTab(k)}
key={tabId}
>
{k.props.children}
</Tab>
);
});
const tabsStyle = {};//{position: "fixed", bottom: "0"};
return (
<div style={tabsStyle}>
<Tabs
onMouseOver={() => this.onHoverElement()}
activeTab={this.state.activeTab}
onTabClick={(e, index) => this.onTabClick(e, index)}
>
{tabs}
</Tabs>
</div>
);
}
}

102
src/pages/study_site_2/StartPage2.jsx

@ -0,0 +1,102 @@
import React from "react";
import { getTranslation } from "../../core/i18n/I18NHandler";
import WebpageBanner from "../../components/webpage_container/WebpageBanner";
import { Tab } from "react-tabs-scrollable";
import {
StudySite,
getHeatmapData,
} from "../../components/webpage_container/StudySite";
import { pushToMouseLog, getSensorLog } from "../../core/log/SensorLogger";
import { Collapse, Text, Spacer } from "@geist-ui/core";
import ScrollableTab from "../../components/ScrollableTab";
import {
Emoji,
Home,
HelpCircle,
Map,
MapPin,
Star,
Flag,
Key,
User,
ArrowUpRight,
} from "@geist-ui/icons";
function StartPage2({ 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???
return (
<StudySite>
<WebpageBanner translationKey="task_2_info" />
<Spacer h={2} />
<img
src="/images/budget_bird_logo.png"
width="150px"
alt="BudgetBird Airlines Logo"
/>
<Spacer h={1} />
<h4>Hotel Le Laboratoire</h4>
<Spacer h={2} />
<ScrollableTab>
<Tab>
<Flag viewBox="0 -8 24 32" size={18}/>
<Spacer inline w={.35} />
Features
</Tab>
<Tab>
<Home viewBox="0 -8 24 32" size={18}/>
<Spacer inline w={.35} />
Facilities
</Tab>
<Tab>
<MapPin viewBox="0 -8 24 32" size={18}/>
<Spacer inline w={.35} />
Location
</Tab>
<Tab>
<ArrowUpRight viewBox="0 -8 24 32" size={18}/>
<Spacer inline w={.35} />
Flights
</Tab>
<Tab>
<Key viewBox="0 -8 24 32" size={18}/>
<Spacer inline w={.35} />
Rooms
</Tab>
<Tab>
<Emoji viewBox="0 -8 24 32" size={18}/>
<Spacer inline w={.35} />
Catering
</Tab>
<Tab>
<User viewBox="0 -8 24 32" size={18}/>
<Spacer inline w={.35} />
Tour Operators
</Tab>
<Tab>
<Map viewBox="0 -8 24 32" size={18}/>
<Spacer inline w={.35} />
Map
</Tab>
<Tab>
<Star viewBox="0 -8 24 32" size={18}/>
<Spacer inline w={.35} />
Ratings
</Tab>
<Tab>
<HelpCircle viewBox="0 -8 24 32" size={18}/>
<Spacer inline w={.35} />
Useful Information
</Tab>
</ScrollableTab>
</StudySite>
);
}
export default StartPage2;

103
src/pages/study_site_2/TourOperators.jsx

@ -0,0 +1,103 @@
import React from "react";
import { getTranslation } from "../../core/i18n/I18NHandler";
import WebpageBanner from "../../components/webpage_container/WebpageBanner";
import { Tab } from "react-tabs-scrollable";
import {
StudySite,
getHeatmapData,
} from "../../components/webpage_container/StudySite";
import { pushToMouseLog, getSensorLog } from "../../core/log/SensorLogger";
import { Divider, Text, Spacer, Card } from "@geist-ui/core";
import ScrollableTab from "../../components/ScrollableTab";
import {
Emoji,
Home,
HelpCircle,
Map,
MapPin,
Star,
Flag,
Key,
User,
ArrowUpRight,
} from "@geist-ui/icons";
function TourOperators({ 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???
return (
<StudySite>
<WebpageBanner translationKey="task_2_info" />
<Spacer h={2} />
<img
src="/images/budget_bird_logo.png"
width="150px"
alt="BudgetBird Airlines Logo"
/>
<Spacer h={1} />
<h4>Hotel Le Laboratoire</h4>
<Spacer h={2} />
<Card>
<Card.Content>
<Text b my={0}>
Haphazard Holidays
</Text>
</Card.Content>
<Divider h="1px" my={0} />
<Card.Content>
<Text>
Ever thought, how the best experiences in life happen, when you just stumble upon them? That is the goal with Haphazard Holidays.
</Text>
<ul>
<li><a href="">Prices</a></li>
<li><a href="mailto:haphazard.holidays@example.com">Contact</a></li>
</ul>
</Card.Content>
</Card>
<Card>
<Card.Content>
<Text b my={0}>
Misguided Getaways
</Text>
</Card.Content>
<Divider h="1px" my={0} />
<Card.Content>
<Text>
We at Misguided Getaways are specialized in hotels and tours, not captured by conventional tour operators to "mis"guide you into your perfect vacation.
</Text>
<ul>
<li><a href="">Prices</a></li>
<li><a href="mailto:misguided.getaways@example.com">Contact</a></li>
</ul>
</Card.Content>
</Card>
<Card>
<Card.Content>
<Text b my={0}>
Lost & Found Excursions
</Text>
</Card.Content>
<Divider h="1px" my={0} />
<Card.Content>
<Text>
Here at Lost & Found Excursions try to capture the same feeling, when you find something precious again by chance but we don't let luck decide upon your perfect holiday or trip.
</Text>
<Text>
<ul>
<li><a href="">Prices</a></li>
<li><a href="mailto:l_f_excursions@example.com">Contact</a></li>
</ul>
</Text>
</Card.Content>
</Card>
</StudySite>
);
}
export default TourOperators;
Loading…
Cancel
Save