-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathindex.js
More file actions
112 lines (98 loc) · 3.67 KB
/
index.js
File metadata and controls
112 lines (98 loc) · 3.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import './style';
import { Component } from 'preact';
import snarkdown from 'snarkdown';
import Intro from './components/Intro';
import Drawer from './components/Drawer';
import QuestionHeader from './components/QuestionHeader';
import LoadingActivity from './components/LoadingActivity';
export default class App extends Component {
state = {
questions: [],
questionsUpdatedAt: null,
questionId: location.hash ? parseInt(location.hash.split('#')[1]) : null,
revealAnswer: false,
userAnswers: []
}
loadQuestions() {
fetch('./assets/questions.json')
.then(res => res.json())
.then(questions => this.setState({
questions: questions.data,
questionsUpdatedAt: questions.updatedAt
}));
}
componentDidMount() {
this.loadQuestions();
window.addEventListener('hashchange', () => this.locationHashChanged(), false);
}
locationHashChanged() {
const { questionId } = this.state;
const newQuestionId = parseInt(location.hash.split('#')[1]);
if (newQuestionId === questionId) return;
this.showQuestion(newQuestionId);
window.scrollTo({ top: 0 });
}
getQuestion(id) {
const { questions } = this.state;
return questions.find(question => question.id === id);
}
showQuestion(id) {
const question = this.getQuestion(id);
if (question) {
this.setState({ questionId: id, revealAnswer: false });
location.hash = id;
}
}
updateUserChoice = ({ questionId, choiceId }) => {
const { userAnswers } = this.state;
const newAnswer = { questionId, choiceId };
const index = userAnswers.findIndex(({ questionId }) => questionId === questionId);
if (index === -1) {
userAnswers.push(newAnswer);
} else {
userAnswers[index] = newAnswer;
}
this.setState({ userAnswers });
}
revealAnswer = choiceId => {
if (this.state.revealAnswer) return;
this.setState({ revealAnswer: true });
}
render({}, { questions, questionsUpdatedAt, questionId, userAnswers, revealAnswer }) {
const totalQuestions = questions.length;
const question = this.getQuestion(questionId);
const userAnswer = userAnswers.find(answer => answer.questionId === questionId);
if (!questionId) return <div><Intro /><Drawer updatedAt={questionsUpdatedAt} /></div>;
if (!question) return <div class="app-shell"><LoadingActivity /></div>;
return (
<div class="app-shell">
<Drawer updatedAt={questionsUpdatedAt} />
<main>
<QuestionHeader question={question} />
<div class="Box">
{question.code ? <pre class="Box-header" dangerouslySetInnerHTML={{__html: question.code}} /> : null}
<ul>
{question.choices.map((choice, choiceId) => (
<li
class="Box-row Box-row--hover-gray"
dangerouslySetInnerHTML={{__html: snarkdown(choice)}}
data-selected={userAnswer && userAnswer.choiceId === choiceId}
onClick={() => {
this.updateUserChoice({questionId, choiceId});
this.revealAnswer();
}}
/>
))}
</ul>
{revealAnswer && <div class="Box-row" dangerouslySetInnerHTML={{__html: snarkdown(question.answer)}} />}
</div>
<div class="Pagination">
<a href={`/#${questionId - 1}`} class="Button Button--purple" rel="prev" disabled={questionId === 1}>Prev</a>
<small><i>{questionId} of {totalQuestions}</i></small>
<a href={`/#${questionId + 1}`} class="Button Button--purple" rel="next" disabled={questionId === totalQuestions}>Next</a>
</div>
</main>
</div>
);
}
}