-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented create or edit answer component (#1119)
* Implemented create or edit answer component * Fixed code smell * Moved typy to types * Fixed comments * Changed name component
- Loading branch information
Showing
13 changed files
with
480 additions
and
9 deletions.
There are no files selected for viewing
23 changes: 23 additions & 0 deletions
23
src/components/question-editor/QuestionEditor.constants.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline' | ||
import NotesIcon from '@mui/icons-material/Notes' | ||
import RuleIcon from '@mui/icons-material/Rule' | ||
|
||
import { SizeEnum } from '~/types' | ||
|
||
export const sortQuestions = [ | ||
{ | ||
icon: <CheckCircleOutlineIcon fontSize={SizeEnum.Small} />, | ||
title: 'questionPage.questionType.multipleChoice', | ||
value: 'multipleChoice' | ||
}, | ||
{ | ||
icon: <NotesIcon fontSize={SizeEnum.Small} />, | ||
title: 'questionPage.questionType.openAnswer', | ||
value: 'openAnswer' | ||
}, | ||
{ | ||
icon: <RuleIcon fontSize={SizeEnum.Small} />, | ||
title: 'questionPage.questionType.oneAnswer', | ||
value: 'oneAnswer' | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { commonShadow } from '~/styles/app-theme/custom-shadows' | ||
|
||
export const styles = { | ||
root: { | ||
display: 'flex', | ||
padding: '16px 24px', | ||
flexDirection: 'column', | ||
alignItems: 'flex-start', | ||
borderRadius: '6px', | ||
boxShadow: commonShadow | ||
}, | ||
questionHeader: { | ||
width: '100%', | ||
display: 'flex', | ||
justifyContent: 'space-between' | ||
}, | ||
group: { | ||
width: '100%' | ||
}, | ||
options: { | ||
display: 'flex', | ||
alignItems: 'center', | ||
gap: '16px' | ||
}, | ||
divider: { | ||
alignSelf: 'stretch', | ||
mb: '24px' | ||
}, | ||
inputItem: { | ||
color: 'basic.black', | ||
width: '100%', | ||
mb: '8px', | ||
'.MuiFormControlLabel-label': { | ||
width: '100%' | ||
} | ||
}, | ||
answer: { | ||
width: '100%', | ||
display: 'flex', | ||
justifyContent: 'space-between', | ||
alignItems: 'center' | ||
}, | ||
iconWrapper: { | ||
display: 'flex', | ||
padding: '8px', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
borderRadius: '4px', | ||
backgroundColor: 'basic.grey' | ||
}, | ||
selectContainer: { | ||
'.MuiOutlinedInput-notchedOutline': { border: 0 } | ||
}, | ||
addRadio: (isEmptyAnswer: boolean) => ({ | ||
display: 'flex', | ||
alignItems: 'center', | ||
color: 'primary.600', | ||
cursor: isEmptyAnswer ? 'auto' : 'pointer', | ||
'& label': { | ||
mr: '8px' | ||
} | ||
}), | ||
addIcon: (isEmptyAnswer: boolean) => ({ | ||
color: isEmptyAnswer ? 'primary.300' : 'primary.700' | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
import { ChangeEvent, MouseEvent, useState } from 'react' | ||
import { useTranslation } from 'react-i18next' | ||
import Box from '@mui/material/Box' | ||
import Divider from '@mui/material/Divider' | ||
import IconButton from '@mui/material/IconButton' | ||
import DeleteIcon from '@mui/icons-material/Delete' | ||
import CloseIcon from '@mui/icons-material/Close' | ||
import AddIcon from '@mui/icons-material/Add' | ||
import Checkbox from '@mui/material/Checkbox' | ||
import FormControlLabel from '@mui/material/FormControlLabel' | ||
import FormGroup from '@mui/material/FormGroup' | ||
import InputBase from '@mui/material/InputBase' | ||
import Radio from '@mui/material/Radio' | ||
import RadioGroup from '@mui/material/RadioGroup' | ||
|
||
import AppTextField from '~/components/app-text-field/AppTextField' | ||
import AppSelect from '~/components/app-select/AppSelect' | ||
|
||
import { styles } from '~/components/question-editor/QuestionEditor.styles' | ||
import { sortQuestions } from '~/components/question-editor/QuestionEditor.constants' | ||
import { Answer, SizeEnum, TextFieldVariantEnum } from '~/types' | ||
|
||
const QuestionEditor = () => { | ||
const [questionType, setQuestionType] = useState(sortQuestions[0]) | ||
const [question, setQuestion] = useState<string>('') | ||
const [answers, setAnswers] = useState<Answer[]>([]) | ||
const [answer, setAnswer] = useState<string>('') | ||
|
||
const { t } = useTranslation() | ||
|
||
const isMultipleChoice = questionType.value === sortQuestions[0].value | ||
const isOpenAnswer = questionType.value === sortQuestions[1].value | ||
const isSingleChoice = questionType.value === sortQuestions[2].value | ||
const isEmptyAnswer = answers[answers.length - 1]?.text === '' | ||
|
||
const setTypeValue = (value: string) => { | ||
const questionOption = sortQuestions.find((item) => item.value === value) | ||
|
||
setQuestionType(questionOption ?? sortQuestions[0]) | ||
} | ||
|
||
const handleQuestion = (event: ChangeEvent<HTMLInputElement>) => { | ||
setQuestion(event.target.value) | ||
} | ||
|
||
const sortOptions = sortQuestions.map(({ icon, title, value }) => ({ | ||
title: t(title), | ||
value, | ||
icon | ||
})) | ||
|
||
const handleOptionChange = (index: number, checked: boolean) => { | ||
const updatedAnswers = [...answers] | ||
|
||
if (isMultipleChoice) { | ||
updatedAnswers[index].isCorrect = checked | ||
} else if (isSingleChoice) { | ||
updatedAnswers.forEach((answer, i) => { | ||
answer.isCorrect = i === index | ||
}) | ||
} | ||
|
||
setAnswers(updatedAnswers) | ||
} | ||
|
||
const onChangeInput = ( | ||
event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>, | ||
index: number | ||
) => { | ||
const currentValue = event.target.value | ||
setAnswers((prevAnswers) => { | ||
const updatedAnswers = [...prevAnswers] | ||
updatedAnswers[index] = { | ||
...updatedAnswers[index], | ||
text: currentValue | ||
} | ||
return updatedAnswers | ||
}) | ||
} | ||
|
||
const addNewOneAnswer = (event: MouseEvent<HTMLInputElement>) => { | ||
event.preventDefault() | ||
if (!isEmptyAnswer) { | ||
setAnswers((prev) => [ | ||
...prev, | ||
{ | ||
id: answers.length, | ||
text: '', | ||
isCorrect: false | ||
} | ||
]) | ||
} | ||
} | ||
|
||
const deleteRadioButton = (id: number) => { | ||
const updatedAnswers = answers.filter((item) => item.id !== id) | ||
setAnswers(updatedAnswers) | ||
} | ||
|
||
const handleTypeChange = (value: string) => { | ||
setAnswers((prevAnswers) => | ||
prevAnswers.map((answer) => ({ ...answer, isCorrect: false })) | ||
) | ||
setTypeValue(value) | ||
} | ||
|
||
const handleAnswer = (event: ChangeEvent<HTMLInputElement>) => | ||
setAnswer(event.target.value) | ||
|
||
const options = answers.map((item) => ( | ||
<Box key={item.id} sx={styles.answer}> | ||
<FormControlLabel | ||
checked={item.isCorrect} | ||
control={isMultipleChoice ? <Checkbox /> : <Radio />} | ||
label={ | ||
<InputBase | ||
fullWidth | ||
onChange={(e) => onChangeInput(e, item.id)} | ||
placeholder={t('questionPage.writeYourAnswer')} | ||
value={item.text} | ||
/> | ||
} | ||
onChange={(_, checked) => handleOptionChange(item.id, checked)} | ||
sx={styles.inputItem} | ||
value={item.id} | ||
/> | ||
<IconButton onClick={() => deleteRadioButton(item.id)}> | ||
<CloseIcon fontSize={SizeEnum.Small} /> | ||
</IconButton> | ||
</Box> | ||
)) | ||
|
||
return ( | ||
<Box sx={styles.root}> | ||
<Box sx={styles.questionHeader}> | ||
<Box sx={styles.options}> | ||
<Box sx={styles.iconWrapper}>{questionType.icon}</Box> | ||
<AppSelect | ||
fields={sortOptions} | ||
setValue={handleTypeChange} | ||
sx={styles.selectContainer} | ||
value={questionType.value} | ||
/> | ||
</Box> | ||
|
||
<IconButton> | ||
<DeleteIcon /> | ||
</IconButton> | ||
</Box> | ||
|
||
<Divider sx={styles.divider} /> | ||
|
||
<AppTextField | ||
fullWidth | ||
label={t('questionPage.question')} | ||
onChange={handleQuestion} | ||
value={question} | ||
variant={TextFieldVariantEnum.Outlined} | ||
/> | ||
|
||
{isMultipleChoice && <FormGroup sx={styles.group}>{options}</FormGroup>} | ||
|
||
{isSingleChoice && <RadioGroup sx={styles.group}>{options}</RadioGroup>} | ||
|
||
{!isOpenAnswer && ( | ||
<Box onClick={addNewOneAnswer} sx={styles.addRadio(isEmptyAnswer)}> | ||
<FormControlLabel | ||
checked={false} | ||
control={isMultipleChoice ? <Checkbox /> : <Radio />} | ||
disabled={isEmptyAnswer} | ||
label={t('questionPage.addNewOne')} | ||
value={0} | ||
/> | ||
<AddIcon | ||
fontSize={SizeEnum.Small} | ||
sx={styles.addIcon(isEmptyAnswer)} | ||
/> | ||
</Box> | ||
)} | ||
|
||
{isOpenAnswer && ( | ||
<AppTextField | ||
fullWidth | ||
label={t('questionPage.answer')} | ||
onChange={handleAnswer} | ||
value={answer} | ||
variant={TextFieldVariantEnum.Outlined} | ||
/> | ||
)} | ||
</Box> | ||
) | ||
} | ||
|
||
export default QuestionEditor |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"question": "Question", | ||
"answer": "Answer", | ||
"questionType": { | ||
"multipleChoice": "Multiple Choice", | ||
"openAnswer": "Open Answer", | ||
"oneAnswer": "One Answer" | ||
}, | ||
"addNewOne": "Add new one", | ||
"writeYourAnswer": "Write your answer" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"question": "Питання", | ||
"answer": "Відповідь", | ||
"questionType": { | ||
"multipleChoice": "Множинний вибір", | ||
"openAnswer": "Відкрита відповідь", | ||
"oneAnswer": "Одна відповідь" | ||
}, | ||
"addNewOne": "Добавити ще одне питання", | ||
"writeYourAnswer": "Напишіть свою відповідь" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export interface Answer { | ||
id: number | ||
text: string | ||
isCorrect: boolean | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from '~/types/questions/interfaces/questions.interface' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.