[TestScreen]: add Question.tsx (this component is responsible for rendering individual questions)

This commit is contained in:
Dawid Wysokiński 2021-04-10 09:14:55 +02:00
parent 58a76cd170
commit 972efe5e4c
6 changed files with 179 additions and 13 deletions

View File

@ -1,3 +1,7 @@
export const CDN_URI = __DEV__
? 'http://localhost:9000/'
: 'https://cdn.zdamegzaminzawodowy.pl';
export const IMAGE_RESIZING_SERVICE = `${
__DEV__ ? 'http://localhost:3000' : 'https://zdamegzaminzawodowy.pl'
}/_next/image`;

View File

@ -13,9 +13,6 @@ const QualificationNotFound = () => {
};
const styles = StyleSheet.create({
wrapper: {
flexGrow: 1,
},
heading: {
textAlignVertical: 'center',
textAlign: 'center',

View File

@ -0,0 +1,53 @@
import React, { useState, Fragment } from 'react';
import buildURL from 'utils/buildURL';
import {
Image,
StyleSheet,
useWindowDimensions,
ImageProps as RNImageProps,
} from 'react-native';
import { H3 } from 'native-base';
export interface ImageProps extends Pick<RNImageProps, 'style'> {
path: string;
}
const MyImage = ({ path, style }: ImageProps) => {
const [loading, setLoading] = useState(true);
const height = useWindowDimensions().height;
const imageHeight = height / 3;
return (
<Fragment>
{loading && (
<H3 style={[{ minHeight: imageHeight }, styles.heading]}>
Ładowanie obrazka...
</H3>
)}
<Image
source={{ uri: buildURL('cdnimg', path) }}
style={[
{ height: imageHeight, display: loading ? 'none' : undefined },
styles.image,
style,
]}
resizeMode="contain"
onLoadEnd={() => setLoading(false)}
/>
</Fragment>
);
};
const styles = StyleSheet.create({
image: {
width: '100%',
flex: 1,
},
heading: {
textAlign: 'center',
textAlignVertical: 'center',
},
});
export default MyImage;

View File

@ -0,0 +1,84 @@
import React from 'react';
import { Question as QuestionT, Answer } from 'libs/graphql';
import { StyleSheet } from 'react-native';
import { Button, H1, Text } from 'native-base';
import Content from '../Content/Content';
import Image from './Image';
export interface QuestionProps {
question: QuestionT;
reviewMode: boolean;
selectedAnswer: Answer;
selectAnswer: (a: Answer) => void;
}
const ANSWERS = Object.values(Answer);
const Question = ({
question,
selectedAnswer,
reviewMode,
selectAnswer,
}: QuestionProps) => {
return (
<Content>
{question.from && <Text note>{question.from}</Text>}
<H1 style={styles.mb}>{question.content}</H1>
{question.image ? (
<Image
path={question.image + '?' + new Date(question.updatedAt).getTime()}
style={styles.mb}
/>
) : null}
{ANSWERS.map((answer, index) => {
const upper = answer.toUpperCase();
const image = question[
`answer${upper}Image` as keyof QuestionT
] as string;
const answerContent = question[
`answer${upper}` as keyof QuestionT
] as string;
const isCorrect = answer === question.correctAnswer;
const isSelected = selectedAnswer === answer;
return (
<Button
key={answer}
style={[
index + 1 === ANSWERS.length ? undefined : styles.mb,
styles.button,
]}
success={reviewMode && isCorrect}
danger={reviewMode && isSelected && !isCorrect}
bordered={reviewMode ? !isSelected && !isCorrect : !isSelected}
full
vertical
onPress={() => selectAnswer(answer)}
>
<Text style={styles.answerContent} uppercase={false}>
{upper}. {answerContent}
</Text>
{image ? <Image path={image} style={styles.answerImage} /> : null}
</Button>
);
})}
</Content>
);
};
const styles = StyleSheet.create({
mb: {
marginBottom: 15,
},
button: {
height: 'auto',
},
answerContent: {
alignSelf: 'flex-start',
},
answerImage: {
marginTop: 5,
},
});
export default Question;

View File

@ -1,13 +1,31 @@
import React, { useRef } from 'react';
import { Question } from 'libs/graphql';
import { ScrollableTab, Tab, Tabs, Text } from 'native-base';
import React, { useRef, useState } from 'react';
import { Question as QuestionT, Answer } from 'libs/graphql';
import { ScrollableTab, Tab, Tabs } from 'native-base';
import Question from './Question';
export interface TestProps {
questions: Question[];
questions: QuestionT[];
}
const Test = ({ questions }: TestProps) => {
const startedAt = useRef(new Date()).current;
const startedAtRef = useRef(new Date());
const endedAtRef = useRef(new Date());
const [reviewMode, setReviewMode] = useState(false);
const [selectedAnswers, setSelectedAnswers] = useState<Answer[]>(
new Array(questions.length).fill(''),
);
const createSelectAnswerHandler = (index: number) => (answer: Answer) => {
if (reviewMode) {
return;
}
setSelectedAnswers(answers =>
answers.map((otherAnswer, index2) =>
index === index2 ? answer : otherAnswer,
),
);
};
return (
<Tabs
@ -19,7 +37,12 @@ const Test = ({ questions }: TestProps) => {
{questions.map((question, index) => {
return (
<Tab key={question.id} heading={`Pytanie ${index + 1}`}>
<Text>Pytanie</Text>
<Question
question={question}
reviewMode={reviewMode}
selectedAnswer={selectedAnswers[index]}
selectAnswer={createSelectAnswerHandler(index)}
/>
</Tab>
);
})}

View File

@ -1,11 +1,16 @@
import { CDN_URI } from 'config/cdn';
import { CDN_URI, IMAGE_RESIZING_SERVICE } from 'config/cdn';
const buildURL = (type: 'cdn', str: string): string => {
const buildURL = (type: 'cdn' | 'cdnimg', path: string): string => {
switch (type) {
case 'cdn':
return CDN_URI + str;
return CDN_URI + path;
case 'cdnimg':
return (
IMAGE_RESIZING_SERVICE +
`?url=${CDN_URI + encodeURIComponent(path)}&w=640&q=75`
);
}
return str;
return path;
};
export default buildURL;