Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented question component #1129

Merged
merged 25 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions src/components/question/Question.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import palette from '~/styles/app-theme/app.pallete'
import { TypographyVariantEnum } from '~/types'

const actionIconWrapper = {
display: 'flex',
alignItems: 'center'
}

const actionIcon = {
fontSize: '18px',
mr: '10px'
}

export const styles = {
root: {
width: '60%',
background: 'basic.white',
borderRadius: '6px',
p: '24px'
},
header: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
},
iconTitleDescription: {
container: { display: 'flex', columnGap: '16px', alignItems: 'center' },
icon: {
svg: { width: '16px', height: '16px', color: 'primary.600' }
},
titleWithDescription: {
wrapper: { display: 'flex', flexDirection: 'column', rowGap: '3px' },
title: {
typography: TypographyVariantEnum.Subtitle2,
color: 'primary.900'
},
description: {
typography: TypographyVariantEnum.Caption,
color: 'primary.400'
}
}
},
iconWrapper: {
backgroundColor: 'basic.grey',
borderRadius: '4px',
p: '8px'
},
categoryChip: {
backgroundColor: 'inherit',
border: `2px solid ${palette.basic.turquoiseDark}`,
borderRadius: '50px',
'& .MuiChip-label': { p: '0px 8px' },
my: '12px'
},
categoryChipLabel: {
typography: TypographyVariantEnum.Caption,
fontWeight: 500,
color: 'basic.turquoiseDark'
},
questionBody: {
my: '24px'
},
questionText: {
typography: TypographyVariantEnum.MidTitle
},
answers: {
display: 'flex',
flexDirection: 'column'
},
answer: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
},
moreIcon: {
fontSize: '20px'
},
dragIconWrapper: {
display: 'flex',
justifyContent: 'center'
},
dragIcon: {
fontSize: '30px',
transform: 'rotate(90deg)',
color: 'primary.400',
cursor: 'pointer'
},
editIconWrapper: actionIconWrapper,
deleteIconWrapper: { ...actionIconWrapper, color: 'error.700' },
editIcon: actionIcon,
deleteIcon: {
...actionIcon,
color: 'error.700'
},
checkIcon: { color: 'basic.orientalHerbs' }
}
124 changes: 124 additions & 0 deletions src/components/question/Question.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { MenuItem } from '@mui/material'
import Box from '@mui/material/Box'
import Divider from '@mui/material/Divider'
import Typography from '@mui/material/Typography'
import FormControlLabel from '@mui/material/FormControlLabel'
import Checkbox from '@mui/material/Checkbox'
import CheckIcon from '@mui/icons-material/Check'
import appPallete from '~/styles/app-theme/app.pallete'
import DragIndicatorIcon from '@mui/icons-material/DragIndicator'
import IconButton from '@mui/material/IconButton'
import MoreVertIcon from '@mui/icons-material/MoreVert'
import EditIcon from '@mui/icons-material/Edit'
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline'
import LibraryAddCheckOutlinedIcon from '@mui/icons-material/LibraryAddCheckOutlined'

import useMenu from '~/hooks/use-menu'
import IconTitleDescription from '~/components/icon-title-description/IconTitleDescription'
import AppChip from '~/components/app-chip/AppChip'

import { ColorEnum, Answer, TableActionFunc, QuestionCategory } from '~/types'
import { styles } from '~/components/question/Question.styles'

interface QuestionProps {
title: string
answers: Answer[]
text: string
category: QuestionCategory
id: string
}

const Question: FC<QuestionProps> = ({
title,
answers,
text,
category,
id
}) => {
const { t } = useTranslation()
const { openMenu, renderMenu, closeMenu } = useMenu()

const onAction = async (actionFunc: TableActionFunc) => {
closeMenu()
await actionFunc(id)
}
const rowActions = [
{
label: (
<Box sx={styles.editIconWrapper}>
<EditIcon sx={styles.editIcon} />
{` ${t('common.edit')}`}
</Box>
),
func: (id: string) => {
console.log('Edit', id)
}
},
{
label: (
<Box sx={styles.deleteIconWrapper}>
<DeleteOutlineIcon color='primary' sx={styles.deleteIcon} />
{` ${t('common.delete')}`}
</Box>
),
func: (id: string) => {
console.log('Delete', id)
}
}
]
const menuItems = rowActions.map(({ label, func }) => (
<MenuItem key={label} onClick={() => void onAction(func)}>
{label}
</MenuItem>
))

const answersList = answers.map((answer, i) => (
<Box key={answer.text} sx={styles.answer}>
<FormControlLabel
checked={i == 1}
control={<Checkbox />}
label={answer.text}
/>

{answer.isCorrect && (
<CheckIcon sx={{ color: appPallete.basic.orientalHerbs }} />
Tolik170 marked this conversation as resolved.
Show resolved Hide resolved
)}
</Box>
))

return (
<Box sx={styles.root}>
<Box sx={styles.dragIconWrapper}>
<DragIndicatorIcon sx={styles.dragIcon} />
</Box>
<Box sx={styles.header}>
<IconTitleDescription
icon={
<Box sx={styles.iconWrapper}>
<LibraryAddCheckOutlinedIcon />
</Box>
}
sx={styles.iconTitleDescription}
title={title}
/>
<IconButton onClick={openMenu}>
<MoreVertIcon color={ColorEnum.Primary} sx={styles.moreIcon} />
</IconButton>
{renderMenu(menuItems)}
</Box>
<AppChip labelSx={styles.categoryChipLabel} sx={styles.categoryChip}>
{category.name}
</AppChip>

<Divider />
<Box sx={styles.questionBody}>
<Typography sx={styles.questionText}>{text}</Typography>
<Box sx={styles.answers}>{answersList}</Box>
</Box>
</Box>
)
}

export default Question
4 changes: 4 additions & 0 deletions src/types/common/enums/common.enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,7 @@ export enum OverlapEnum {
Circular = 'circular',
Rectangular = 'rectangular'
}

export enum ColorEnum {
Primary = 'primary'
}
6 changes: 5 additions & 1 deletion src/types/questions/interfaces/questions.interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CommonEntityFields, UserResponse } from '~/types'
export interface Answer {
id: number
id: string
text: string
isCorrect: boolean
}
Expand All @@ -10,3 +10,7 @@ export interface Question extends CommonEntityFields {
items: Omit<Answer, 'id'>[]
author: Pick<UserResponse, '_id'>
}
export interface QuestionCategory {
name: string
_id: string
}
42 changes: 42 additions & 0 deletions tests/unit/components/question/Question.spec.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { screen, render } from '@testing-library/react'
import Question from '~/components/question/Question'

const mockedQuestion = {
title: 'Philosophy',
answers: [
{
id: '1',
text: 'Buddha Shakyamuni',
isCorrect: true
},
{
id: '2',
text: 'Jordan Belfort',
isCorrect: false
}
],
text: 'Who created buddhism?',
category: {
_id: 'some-text-id-123',
name: 'Philosophy'
},
id: '1'
}

describe('Question', () => {
beforeEach(() => {
render(<Question {...mockedQuestion} />)
})

it('render question text', () => {
const questionText = screen.getByText(mockedQuestion.text)

expect(questionText).toBeInTheDocument()
})

it('render question category', () => {
const category = screen.getByText(mockedQuestion.category.name)

expect(category).toBeInTheDocument()
})
})
Loading