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

WIP: Add feature of leaderboard search and sort and multiple correct to the application #55

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
14 changes: 12 additions & 2 deletions src/modules/checkQuiz/api/generateLeaderboard.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow code structure, patch get requests will not come here

Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,29 @@ import axiosInstance from './axiosInstance'
export const GenerateLeaderboard = async ({
quizId,
sectionIndex = null,
searchQuery = null,
}: {
quizId: string
sectionIndex: number | null
searchQuery: string | null
}) => {
try {
if (sectionIndex === null) {
if (sectionIndex === null && searchQuery === null) {
const res = await axiosInstance.patch(`/checkQuiz/leaderboard/${quizId}`)
return res.data
} else {
} else if (sectionIndex !== null && searchQuery === null) {
const res = await axiosInstance.patch(
`/checkQuiz/generateSectionLeaderboard/${quizId}/${sectionIndex}`,
)
return res.data
} else if (sectionIndex === null && searchQuery !== null) {
const res = await axiosInstance.patch(`/checkQuiz/leaderboard/${quizId}?search=${searchQuery}`)
return res.data
} else {
const res = await axiosInstance.patch(
`/checkQuiz/generateSectionLeaderboard/${quizId}/${sectionIndex}?search=${searchQuery}`,
)
return res.data
}
} catch (e: any) {
if (axios.isAxiosError(e)) {
Expand Down
12 changes: 9 additions & 3 deletions src/modules/checkQuiz/api/getDashboard.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import axios from 'axios'
import axiosInstance from './axiosInstance'

export const getDashboard = async (quizId: string, sectionIndex: number | null = null) => {
export const getDashboard = async (quizId: string, sectionIndex: number | null = null, searchQuery: string | null = null) => {
try {
if (sectionIndex === null) {
if (sectionIndex === null && searchQuery === null) {
const res = await axiosInstance.get(`/checkQuiz/dashboard/${quizId}`)
return res.data
} else {
} else if (sectionIndex !== null && searchQuery === null) {
const res = await axiosInstance.get(`/checkQuiz/sectionLeaderboard/${quizId}/${sectionIndex}`)
return res.data
} else if (sectionIndex === null && searchQuery !== null) {
const res = await axiosInstance.get(`/checkQuiz/dashboard/${quizId}?search=${searchQuery}`)
return res.data
} else {
const res = await axiosInstance.get(`/checkQuiz/sectionLeaderboard/${quizId}/${sectionIndex}?search=${searchQuery}`)
return res.data
}
} catch (e: unknown) {
if (axios.isAxiosError(e)) {
Expand Down
6 changes: 3 additions & 3 deletions src/modules/checkQuiz/api/useDashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { useQuery, useMutation } from '@tanstack/react-query'
import axiosInstance from './axiosInstance'
import { getDashboard } from './getDashboard'

export const useFetchDashboard = (quizId: string, sectionIndex: number | null = null) => {
export const useFetchDashboard = (quizId: string, sectionIndex: number | null = null, searchQuery: string | null = null) => {
const query = useQuery({
queryKey: ['fetchDashboard', quizId, sectionIndex],
queryFn: () => getDashboard(quizId, sectionIndex),
queryKey: ['fetchDashboard', quizId, sectionIndex, searchQuery],
queryFn: () => getDashboard(quizId, sectionIndex, searchQuery),
})
return query
}
122 changes: 82 additions & 40 deletions src/modules/checkQuiz/components/Filters.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the purpose of handleAddClick function?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to find a better way than window.location.reload()?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put this setdebounced function in hooks folder

Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React, { useEffect, useState } from 'react'
import { Select } from 'chakra-react-select'
import { Button, HStack, Input, Select as SelectChakra, Text } from '@chakra-ui/react'
import { Button, HStack, Input, IconButton, Select as SelectChakra, Text } from '@chakra-ui/react'
import { useLeaderboard } from '@checkQuiz/api/useLeaderboard'
import AutocheckModal from './Modals/Autocheck'
import useCheckQuizStore from '@checkQuiz/store/checkQuizStore'
import { Section } from '@checkQuiz/types'
import { useFetchDashboard } from '@checkQuiz/api/useDashboard'
import { getDashboard } from '@checkQuiz/api/getDashboard'
import { AddIcon } from '@chakra-ui/icons';

interface FiltersProps {
question?: boolean
Expand All @@ -28,8 +27,24 @@ const Filters: React.FC<FiltersProps> = ({
state.leaderboard,
state.setLeaderboard,
])
const [searchQuery, setSearchQuery] = useState('')
const [debouncedSearchQuery, setDebouncedSearchQuery] = useState(searchQuery)

const { data, isFetched, refetch } = useFetchDashboard(quizId, sectionIndex)
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchQuery(e.target.value.toLocaleLowerCase())
}

useEffect(() => {
const handler = setTimeout(() => {
setDebouncedSearchQuery(searchQuery);
}, 300);

return () => {
clearTimeout(handler);
};
}, [searchQuery]);

const { data, isFetched, refetch } = useFetchDashboard(quizId, sectionIndex, debouncedSearchQuery)

useEffect(() => {
if (isFetched && data) {
Expand All @@ -47,6 +62,7 @@ const Filters: React.FC<FiltersProps> = ({
}
}, [sectionIndex, isFetched, data])


useEffect(() => {
if (sections) {
let totalAutocheckQuestionsCount = 0
Expand All @@ -59,25 +75,26 @@ const Filters: React.FC<FiltersProps> = ({
})
setTotalAutocheckQuestions(totalAutocheckQuestionsCount)
}
}, [sections])
}, [sections, searchQuery])

const { mutate: generateLeaderboard } = useLeaderboard()
const {
data: sectionData,
isFetched: sectionDataIsFetched,
refetch: sectionDataRefetch,
} = useFetchDashboard(quizId, sectionIndex)
} = useFetchDashboard(quizId, sectionIndex, debouncedSearchQuery)

const handleLeaderboard = (sectionIndex: number | null) => {
generateLeaderboard(
{ quizId, sectionIndex },
{ quizId, sectionIndex, searchQuery: debouncedSearchQuery }, // Correct property name
{
onSuccess: () => {
window.location.reload()
console.log('Leaderboard generated successfully')
},
},
)
}


// TODO: fetch assignees from athena
const [availableAssignees] = useState([
Expand All @@ -101,6 +118,10 @@ const Filters: React.FC<FiltersProps> = ({
}
}

const handleAddClick = () => {
console.log('Add button clicked');
};

useEffect(() => {
sectionDataRefetch()
}, [sectionIndex])
Expand All @@ -111,42 +132,62 @@ const Filters: React.FC<FiltersProps> = ({
<HStack spacing={4} alignItems='center' width='full'>
{question && (
<>
<Text fontSize='0.875rem' color='#939393'>
Assigned to:
</Text>
<Select
styles={{
option: (provided, state) => ({
...provided,
padding: '0.75rem',
fontSize: '0.875rem',
fontWeight: '600',
borderRadius: '0.25rem',
}),
}}
value={assignees}
options={availableAssignees}
isMulti
placeholder='Assignees'
onChange={handleAssigneesChange}
/>
</>
<Input
maxWidth='20rem'
placeholder='Search or add assignee'
variant='outline'
borderColor='grey'
borderRadius='0.25rem'
fontSize='0.875rem'
fontWeight='600'
color='grey'
value={searchQuery}
onChange={handleSearchChange}
_placeholder={{ color: 'grey' }}
/>
<IconButton
aria-label="Add"
icon={<AddIcon />}
onClick={handleAddClick}
size="sm"
bgColor="brand"
color="white"
borderRadius="0.25rem"
/>
</>
)}

{participants && (
<>
<Input
maxWidth='20rem'
placeholder='Search'
variant='outline'
borderColor='#939393'
borderRadius='0.25rem'
fontSize='0.875rem'
fontWeight='600'
color='#939393'
_placeholder={{ color: '#939393' }}
/>
</>
<Input
maxWidth='20rem'
placeholder='Search'
variant='outline'
borderColor='grey'
borderRadius='0.25rem'
fontSize='0.875rem'
fontWeight='600'
color='grey'
value={searchQuery}
onChange={handleSearchChange}
_placeholder={{ color: 'grey' }}
/>
<Text fontSize='0.875rem' color='grey'>
Sort by
</Text>
<SelectChakra
width='12rem'
placeholder='None'
color='grey'
onChange={handleSectionChange}
>
{sections.map((section, index) => (
<option value={index} key={section.name}>
{section.name}
</option>
))}
</SelectChakra>
</>
)}
</HStack>
{participants && (
Expand All @@ -159,6 +200,7 @@ const Filters: React.FC<FiltersProps> = ({
fontWeight='400'
onClick={() => {
handleLeaderboard(sectionIndex)
window.location.reload()
}}
>
Generate Leaderboard
Expand Down
2 changes: 1 addition & 1 deletion src/modules/checkQuiz/components/Leaderboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,4 @@ const Leaderboard = () => {
)
}

export default Leaderboard
export default Leaderboard
2 changes: 1 addition & 1 deletion src/modules/checkQuiz/components/TabViewDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ const TabViewDashboard = () => {
)
}

export default TabViewDashboard
export default TabViewDashboard
29 changes: 19 additions & 10 deletions src/modules/createQuiz/forms/QuestionDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
Text,
VStack,
} from '@chakra-ui/react'
import select from 'react-select'
import { useEffect, useState } from 'react'
import CustomRichTextEditor from '@common/components/CustomRichTextEditor'
import { QuestionType, Option } from '../../types'
Expand All @@ -36,7 +37,7 @@ const QuestionDetails = () => {
const [marks, setMarks] = useState<number>(0)
const [autoCheck, setAutoCheck] = useState<boolean>(false)
const [options, setOptions] = useState<Option[]>([])
const [answer, setAnswer] = useState<string>('')
const [answer, setAnswer] = useState<string[]>([]);

const { sections, currentSectionIdx, currentQuestionIdx } = useSectionStore((state) => state)
const activeSection = sections[currentSectionIdx ?? 0]
Expand All @@ -61,7 +62,7 @@ const QuestionDetails = () => {
setMarks(data?.question.maxMarks ?? 0)
setAutoCheck(data?.question?.autoCheck ?? false)
setOptions(data?.question?.options ?? [])
setAnswer(data?.question?.correctAnswer ?? '')
setAnswer(Array.isArray(data.question?.correctAnswer) ? data.question.correctAnswer : [data.question?.correctAnswer ?? '']);
}
const handleEdit = (id: string, newLabel: string) => {
setOptions((prevOptions) =>
Expand Down Expand Up @@ -98,7 +99,7 @@ const QuestionDetails = () => {
setAutoCheck(data.question?.autoCheck)
setOptions(data.question?.options)
setNotes(data.question?.checkerNotes)
setAnswer(data.question?.correctAnswer)
setAnswer(Array.isArray(data.question?.correctAnswer) ? data.question.correctAnswer : [data.question?.correctAnswer ?? '']);
}
}, [isFetched, isLoading, data])

Expand Down Expand Up @@ -210,13 +211,21 @@ const QuestionDetails = () => {
<Text color='accentBlack' fontSize='sm'>
Answer:
</Text>
<Select w={48} value={answer} onChange={(e) => setAnswer(e.target.value)}>
{options?.map((option) => (
<option key={option.id} value={option.id}>
{option.id}
</option>
))}
</Select>
<select
value={answer}
onChange={(e) => {
const selectedOptions = Array.from(e.target.selectedOptions, option => option.value);
setAnswer(selectedOptions);
}}
multiple
style={{ width: '100%' }}
>
{options?.map((option) => (
<option key={option.id} value={option.id}>
{option.id}
</option>
))}
</select>
</HStack>
</>
)}
Expand Down
Loading