[TestScreen]: add Question.tsx (this component is responsible for rendering individual questions)
This commit is contained in:
parent
58a76cd170
commit
972efe5e4c
|
@ -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`;
|
||||
|
|
|
@ -13,9 +13,6 @@ const QualificationNotFound = () => {
|
|||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
heading: {
|
||||
textAlignVertical: 'center',
|
||||
textAlign: 'center',
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -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>
|
||||
);
|
||||
})}
|
||||
|
|
|
@ -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;
|
||||
|
|
Reference in New Issue