import { h, render, Component } from 'preact'; // eslint-disable-line no-unused-vars // content and config: import content from '../content/module.json'; import config from '../config'; // services and helper: import api from '../utilities/api'; import { fixedDigits } from '../utilities/formatter'; // screens and items: import TitleScreen from './TitleScreen.jsx'; import FinalScreen from './FinalScreen.jsx'; import QuestionScreen from './QuestionScreen.jsx'; /** * titlescreen, questionscreen (repeat), finalscreen */ export default class App extends Component { // construct and initialize functions constructor (props) { super(props); // for example: (1400 - 200) / 3 -> 400 points per section const diff = (config.numberOfPoints.first - config.numberOfPoints.last) / 3; // for example: 1400, 1000, 600, 200 this.numberOfPoints = [ parseInt(config.numberOfPoints.first, 10), parseInt(config.numberOfPoints.first - diff, 10), parseInt(config.numberOfPoints.last + diff, 10), parseInt(config.numberOfPoints.last, 10) ]; this.state = { route: 'titlescreen', // current screen isFetching: false, // currently performing XHR? userId: null, // current user id for posting token: null, // current access token mode: 'intro', // current mode: init || intro || question || score currentQuestion: 0, // current question number currentAnswerIndex: null, // index in question pair of the currently set answer currentAnswerCorrect: false, // is the currently set question the correct one? currentNumberOfPoints: this.numberOfPoints[0], // current number of points nextNumberOfPoints: this.numberOfPoints[1], // next number of points currentAmount: config.highlightedAmount, // curent amount of points to be highlighted voteRatios: null // get votes from other users }; if (window.location.hash) this.state.route = window.location.hash.replace('#', ''); // context binding this.navigate = this.navigate.bind(this); this.toNextQuestion = this.toNextQuestion.bind(this); this.setAnswer = this.setAnswer.bind(this); this.getUserVotes = this.getUserVotes.bind(this); this.reset = this.reset.bind(this); this.setup = this.setup.bind(this); this.endUserSession = this.endUserSession.bind(this); } // to next question toNextQuestion () { // intro screen, introduce bubbles :P if (this.state.mode === 'intro') { this.setState({ // currentQuestion: null, mode: 'init', route: 'question' }); } else if (this.state.currentQuestion === 0 && this.state.mode === 'init') { // is first question? this.setState({ currentAmount: 0, mode: 'question', route: 'question' }); } else if (this.state.currentQuestion === 3 && this.state.mode === 'score') { // is last question? go to final screen this.setState({ route: 'finalscreen', mode: 'intro', currentNumberOfPoints: this.numberOfPoints[0], currentAmount: config.highlightedAmount, currentQuestion: 0, currentAnswerIndex: null, currentAnswerCorrect: false, nextNumberOfPoints: this.numberOfPoints[1], voteRatios: null }); } else if (this.state.voteRatios && this.state.mode === 'question') { // go to score screen this.setState({ route: 'question', mode: 'score' }); } else { // go to next question this.setState({ route: 'question', mode: 'question', currentQuestion: this.state.currentQuestion + 1, currentAnswerIndex: null, currentNumberOfPoints: this.numberOfPoints[this.state.currentQuestion + 1], nextNumberOfPoints: this.numberOfPoints[this.state.currentQuestion + 2], currentAmount: 0, voteRatios: null }); } } // set and check answer setAnswer (index, isCorrect) { if (this.state.currentAnswerIndex === null) { // check answer this.setState({ currentAnswerIndex: index, currentAnswerCorrect: isCorrect, mode: 'question' }); // submit answer if (!this.props.isOffline) { // only send answer for current question const payload = { userId: this.state.userId }; payload[`answerQ${this.state.currentQuestion + 1}`] = this.state.currentAnswerIndex + 1; api.post(config.api.create, payload, this.state.token).then(() => this.getUserVotes()); } else { this.getUserVotes(); } } } // get user votes from api getUserVotes () { if (!this.props.isOffline) { api.get(config.api.proportions, { question: this.state.currentQuestion + 1 }).then( json => this.setState({ voteRatios: [ json.anteile.richtig, json.anteile.falsch ] }) ); } else { this.setState({ voteRatios: [] }); } } // initial setup setup () { if (!this.props.isOffline) { this.setState({ isFetching: true }); api.getToken().then(accessToken => { this.setState({ token: accessToken }); // create user api.createUser(accessToken) .then(user => { this.setState({ userId: user.userId, isFetching: false }); this.jumpTo(); }); }); } } // shortcut: jump to specific screen using `#{something}` jumpTo () { if (window.location.hash) { const hashInfo = window.location.hash.replace('#', '').split('_'); this.setState({ route: 'question', mode: hashInfo[0], currentAmount: 0, currentAnswerCorrect: null, currentAnswerIndex: null, currentNumberOfPoints: 1000, currentQuestion: parseInt(hashInfo[1], 10), nextNumberOfPoints: 200, voteRatios: null }); } } // set navigation state navigate (route) { this.setState({ route }); } // finish user session endUserSession () { api.endSession(this.state.userId, this.state.token); } // reset everything to restart the module reset () { this.setState({ route: 'titlescreen' }); this.setup(); } // LIFECYLCE componentWillMount () { this.setup(); } // RENDER render () { let outputContent; // get header content const total = fixedDigits(config.numberQuestions, 2); const index = this.state.currentQuestion + 1; // 0-indexed const headerState = `${fixedDigits(index, 2)}/${total}`; switch (this.state.route) { case 'question': outputContent = ; break; case 'finalscreen': outputContent = ; break; case 'titlescreen': default: outputContent = ; break; } return outputContent; } }