Skip to content

Commit

Permalink
implemented questions table (#1124)
Browse files Browse the repository at this point in the history
* implemented questions table

* fixed comment and added description for title field

* fix lint
  • Loading branch information
Tolik170 authored Sep 12, 2023
1 parent 3fcbe03 commit 450dab4
Show file tree
Hide file tree
Showing 19 changed files with 355 additions and 47 deletions.
3 changes: 3 additions & 0 deletions src/constants/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ export const URLs = {
get: '/attachments',
patch: '/attachments',
delete: '/attachments'
},
questions: {
get: '/questions'
}
},
messages: {
Expand Down
9 changes: 9 additions & 0 deletions src/constants/translations/en/my-resources-page.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,14 @@
"confirmDeletionTitle":"Do you confirm quiz deletion?",
"successDeletion":"Quiz was deleted successfully"
},
"questions": {
"addBtn": "New question",
"title": "Title",
"category": "Category",
"updated": "Last updates",
"emptyItems": "You have no questions yet",
"confirmDeletionTitle":"Do you confirm question deletion?",
"successDeletion":"Question was deleted successfully"
},
"confirmDeletionMessage":"This action is permanent and will remove all related content. Please review your decision before proceeding."
}
9 changes: 9 additions & 0 deletions src/constants/translations/ua/my-resources-page.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,14 @@
"confirmDeletionTitle":"Ви підтверджуєте видалення тесту?",
"successDeletion":"Тест було успішно видалено"
},
"questions": {
"addBtn": "Нове запитання",
"title": "Заголовок",
"category": "Категорія",
"updated": "Останнє оновлення",
"emptyItems": "У вас ще немає запитань",
"confirmDeletionTitle":"Ви підтверджуєте видалення запитання?",
"successDeletion":"Запитання було успішно видалено"
},
"confirmDeletionMessage":"Ця дія є остаточною, та призведе до видалення всього пов’язаного вмісту. Перш ніж продовжити, перегляньте своє рішення."
}
5 changes: 3 additions & 2 deletions src/containers/my-quizzes/QuizzesContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { ajustColumns, getScreenBasedLimit } from '~/utils/helper-functions'

const QuizzesContainer = () => {
const { setAlert } = useSnackBarContext()
const { page } = usePagination()
const { page, handleChangePage } = usePagination()
const sortOptions = useSort({ initialSort })
const searchTitle = useRef<string>('')
const breakpoints = useBreakpoints()
Expand Down Expand Up @@ -85,7 +85,8 @@ const QuizzesContainer = () => {
itemsPerPage,
actions: { onEdit: () => null },
resource: ResourcesTabsEnum.Quizzes,
sort: sortOptions
sort: sortOptions,
pagination: { page, onChange: handleChangePage }
}

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import useBreakpoints from '~/hooks/use-breakpoints'
import useAxios from '~/hooks/use-axios'
import usePagination from '~/hooks/table/use-pagination'
import AddDocuments from '~/containers/add-documents/AddDocuments'
import { attachmentService } from '~/services/attachment-service'

import { defaultResponses, snackbarVariants } from '~/constants'
import {
Expand All @@ -38,7 +37,7 @@ const AttachmentsContainer = () => {
const { t } = useTranslation()
const { setAlert } = useSnackBarContext()
const breakpoints = useBreakpoints()
const { page } = usePagination()
const { page, handleChangePage } = usePagination()
const sortOptions = useSort({ initialSort })
const searchFileName = useRef<string>('')
const [selectedItemId, setSelectedItemId] = useState<string>('')
Expand Down Expand Up @@ -107,7 +106,7 @@ const AttachmentsContainer = () => {
})

const createAttachments = useCallback(
(data?: FormData) => attachmentService.createAttachments(data),
(data?: FormData) => ResourceService.createAttachments(data),
[]
)

Expand Down Expand Up @@ -151,6 +150,7 @@ const AttachmentsContainer = () => {
actions: { onEdit },
resource: ResourcesTabsEnum.Attachments,
sort: sortOptions,
pagination: { page, onChange: handleChangePage },
sx: styles.table
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
const LessonsContainer = () => {
const { setAlert } = useSnackBarContext()
const navigate = useNavigate()
const { page } = usePagination()
const { page, handleChangePage } = usePagination()
const sortOptions = useSort({ initialSort })
const searchTitle = useRef<string>('')
const breakpoints = useBreakpoints()
Expand Down Expand Up @@ -95,7 +95,8 @@ const LessonsContainer = () => {
itemsPerPage,
actions: { onEdit },
resource: ResourcesTabsEnum.Lessons,
sort: sortOptions
sort: sortOptions,
pagination: { page, onChange: handleChangePage }
}

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useTranslation } from 'react-i18next'
import { AxiosResponse } from 'axios'
import { PaginationProps } from '@mui/material'

import { useSnackBarContext } from '~/context/snackbar-context'
import useAxios from '~/hooks/use-axios'
import useConfirm from '~/hooks/use-confirm'
import usePagination from '~/hooks/table/use-pagination'
import AppPagination from '~/components/app-pagination/AppPagination'
import EnhancedTable, {
EnhancedTableProps
Expand All @@ -21,6 +21,7 @@ interface MyResourcesTableInterface<T>
data: ResourcesTableData<T>
actions: { onEdit: (id: string) => void }
services: { deleteService: (id?: string) => Promise<AxiosResponse> }
pagination: PaginationProps
}

const MyResourcesTable = <T extends TableItem>({
Expand All @@ -29,13 +30,17 @@ const MyResourcesTable = <T extends TableItem>({
data,
actions,
services,
pagination,
...props
}: MyResourcesTableInterface<T>) => {
const { t } = useTranslation()
const { setAlert } = useSnackBarContext()
const { page, handleChangePage } = usePagination()
const { openDialog } = useConfirm()

const { page, onChange } = pagination
const { response, getData } = data
const { onEdit } = actions

const onDeleteError = (error: ErrorResponse) => {
setAlert({
severity: snackbarVariants.error,
Expand All @@ -61,7 +66,7 @@ const MyResourcesTable = <T extends TableItem>({
const handleDelete = async (id: string, isConfirmed: boolean) => {
if (isConfirmed) {
await deleteItem(id)
if (!error) await data.getData()
if (!error) await getData()
}
}

Expand All @@ -76,7 +81,7 @@ const MyResourcesTable = <T extends TableItem>({
const rowActions = [
{
label: t('common.edit'),
func: actions.onEdit
func: onEdit
},
{
label: t('common.delete'),
Expand All @@ -87,16 +92,16 @@ const MyResourcesTable = <T extends TableItem>({
return (
<>
<EnhancedTable<T>
data={{ items: data.response.items }}
data={{ items: response.items }}
emptyTableKey={`myResourcesPage.${resource}.emptyItems`}
rowActions={rowActions}
sx={roundedBorderTable}
{...props}
/>
<AppPagination
onChange={handleChangePage}
onChange={onChange}
page={page}
pageCount={Math.ceil(data.response.count / itemsPerPage)}
pageCount={Math.ceil(response.count / itemsPerPage)}
/>
</>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'
import Typography from '@mui/material/Typography'
import Box from '@mui/material/Box'

import IconTitleDescription from '~/components/icon-title-description/IconTitleDescription'
import AppChip from '~/components/app-chip/AppChip'

import { Question, RemoveColumnRules, SortEnum, TableColumn } from '~/types'
import { getFormattedDate } from '~/utils/helper-functions'
import { styles } from '~/containers/my-resources/questions-container/QuestionsContainer.styles'

export const columns: TableColumn<Question>[] = [
{
label: 'myResourcesPage.questions.title',
field: 'title',
calculatedCellValue: (item: Question) => {
return (
<IconTitleDescription
description={'Which word is the antonym of "benevolent"?'}
icon={
<Box sx={styles.iconWrapper}>
<CheckCircleOutlineIcon />
</Box>
}
sx={styles.iconTitleDescription}
title={item.title}
/>
)
}
},
{
label: 'myResourcesPage.questions.category',
calculatedCellValue: () => (
<AppChip labelSx={styles.categoryChipLabel} sx={styles.categoryChip}>
{'Vocabulary Building'}
</AppChip>
)
},
{
label: 'myResourcesPage.questions.updated',
field: 'updatedAt',
calculatedCellValue: (item: Question) => (
<Typography sx={styles.date}>
{getFormattedDate({ date: item.updatedAt })}
</Typography>
)
}
]

export const removeColumnRules: RemoveColumnRules<Question> = {
tablet: ['myOffersPage.tableHeaders.updated']
}

export const initialSort = { order: SortEnum.Desc, orderBy: 'updatedAt' }

export const itemsLoadLimit = {
default: 10,
tablet: 8,
mobile: 6
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import palette from '~/styles/app-theme/app.pallete'
import { TypographyVariantEnum } from '~/types'

export const styles = {
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: {
display: 'flex',
alignItems: 'center',
backgroundColor: 'basic.grey',
borderRadius: '4px',
p: '8px'
},
categoryChip: {
backgroundColor: 'inherit',
border: `2px solid ${palette.basic.turquoiseDark}`,
borderRadius: '50px',
'& .MuiChip-label': { p: '0px 8px' }
},
categoryChipLabel: {
typography: TypographyVariantEnum.Caption,
fontWeight: 500,
color: 'basic.turquoiseDark'
},
date: {
color: 'primary.400',
typography: TypographyVariantEnum.Caption
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,98 @@
import { useCallback, useRef } from 'react'
import Box from '@mui/material/Box'

import { useSnackBarContext } from '~/context/snackbar-context'
import { ResourceService } from '~/services/resource-service'
import AddResourceWithInput from '~/containers/my-resources/add-resource-with-input/AddResourceWithInput'
import MyResourcesTable from '~/containers/my-resources/my-resources-table/MyResourcesTable'
import Loader from '~/components/loader/Loader'
import useSort from '~/hooks/table/use-sort'
import useBreakpoints from '~/hooks/use-breakpoints'
import useAxios from '~/hooks/use-axios'

import { defaultResponses, snackbarVariants } from '~/constants'
import {
columns,
initialSort,
itemsLoadLimit,
removeColumnRules
} from '~/containers/my-resources/questions-container/QuestionsContainer.constants'
import {
ItemsWithCount,
GetResourcesParams,
ErrorResponse,
ResourcesTabsEnum,
Question
} from '~/types'
import { ajustColumns, getScreenBasedLimit } from '~/utils/helper-functions'

const QuestionsContainer = () => {
const { setAlert } = useSnackBarContext()
const sortOptions = useSort({ initialSort })
const searchTitle = useRef<string>('')
const breakpoints = useBreakpoints()

const { sort } = sortOptions
const itemsPerPage = getScreenBasedLimit(breakpoints, itemsLoadLimit)
const columnsToShow = ajustColumns<Question>(
breakpoints,
columns,
removeColumnRules
)

const onResponseError = useCallback(
(error: ErrorResponse) => {
setAlert({
severity: snackbarVariants.error,
message: error ? `errors.${error.code}` : ''
})
},
[setAlert]
)

const getQuestions = useCallback(
() =>
ResourceService.getQuestions({
limit: itemsPerPage,
sort,
title: searchTitle.current
}),
[itemsPerPage, sort]
)

const { response, loading, fetchData } = useAxios<
ItemsWithCount<Question>,
GetResourcesParams
>({
service: getQuestions,
defaultResponse: defaultResponses.itemsWithCount,
onResponseError
})

const props = {
columns: columnsToShow,
data: { response, getData: fetchData },
services: { deleteService: () => null },
itemsPerPage,
actions: { onEdit: () => null },
resource: ResourcesTabsEnum.Questions,
sort: sortOptions,
pagination: { page: 1, onChange: () => null }
}

return (
<Box>
<h3>Questions</h3>
<AddResourceWithInput
btnText={'myResourcesPage.questions.addBtn'}
fetchData={fetchData}
link={'#'}
searchRef={searchTitle}
/>
{loading ? (
<Loader pageLoad size={50} />
) : (
<MyResourcesTable<Question> {...props} />
)}
</Box>
)
}
Expand Down
Loading

0 comments on commit 450dab4

Please sign in to comment.