|
1 | 1 | import React, { useEffect, useState } from "react";
|
2 |
| -import { Flex, Text, CircularProgress, CircularProgressLabel, Progress, Card, Th, TableContainer, Table } from "@chakra-ui/react"; |
| 2 | +import { |
| 3 | + Flex, |
| 4 | + Text, |
| 5 | + CircularProgress, |
| 6 | + CircularProgressLabel, |
| 7 | + Progress, |
| 8 | + Card, |
| 9 | + Th, |
| 10 | + TableContainer, |
| 11 | + Table, |
| 12 | + ProgressProps, |
| 13 | + Box, |
| 14 | + CardHeader, |
| 15 | + Heading, |
| 16 | + HStack, |
| 17 | + Stat, |
| 18 | + StatLabel, |
| 19 | + StatNumber, |
| 20 | + StatHelpText, |
| 21 | + Center, |
| 22 | + VStack, |
| 23 | +} from "@chakra-ui/react"; |
3 | 24 | import { fetchAllQuestions } from "../../api/questions";
|
4 | 25 | import { Question } from "../../models/Question.model";
|
5 | 26 | import { useProfile } from "../../contexts/profileContext";
|
| 27 | +import { |
| 28 | + diffRanges, |
| 29 | + mapRangeToDifficulty, |
| 30 | +} from "../../helper/DifficultyFilterHelper"; |
6 | 31 |
|
| 32 | +type info = { |
| 33 | + name: string; |
| 34 | + percentage: number; |
| 35 | + solved: number; |
| 36 | + total: number; |
| 37 | + scheme?: string; |
| 38 | +}; |
7 | 39 |
|
8 | 40 | const ProgressBar = () => {
|
9 |
| - |
10 | 41 | const { solvedQuestions } = useProfile();
|
11 | 42 |
|
12 |
| - const [easyCount, setEasyCount] = useState(0); |
13 |
| - const [mediumCount, setMediumCount] = useState(0); |
14 |
| - const [hardCount, setHardCount] = useState(0); |
15 |
| - const [totalSolved, setTotalSolved] = useState(0); |
16 |
| - const [totalEasy, setTotalEasy] = useState(0); |
17 |
| - const [totalMedium, setTotalMedium] = useState(0); |
18 |
| - const [totalHard, setTotalHard] = useState(0); |
19 |
| - const [totalQuestions, setTotalQuestions] = useState(0); |
20 |
| - const [easyPercentage, setEasyPercentage] = useState(0); |
21 |
| - const [mediumPercentage, setMediumPercentage] = useState(0); |
22 |
| - const [hardPercentage, setHardPercentage] = useState(0); |
23 |
| - const [totalPercentage, setTotalPercentage] = useState(0); |
| 43 | + const [datas, setDatas] = useState<info[]>([]); |
24 | 44 |
|
25 | 45 | useEffect(() => {
|
26 |
| - async function fetchAndCategorizeQuestions() { |
| 46 | + (async () => { |
27 | 47 | try {
|
28 | 48 | const allQuestions: Question[] = await fetchAllQuestions();
|
29 | 49 |
|
30 |
| - // Categorize questions into easy, medium, and hard |
31 |
| - const easyQuestions = allQuestions.filter((question) => question.difficulty >= 0 && question.difficulty < 3.5).length; |
32 |
| - const mediumQuestions = allQuestions.filter((question) => question.difficulty >= 3.5 && question.difficulty < 7).length; |
33 |
| - const hardQuestions = allQuestions.filter((question) => question.difficulty >= 7 && question.difficulty <= 10).length; |
34 |
| - |
35 |
| - const userEasyQuestions = solvedQuestions.filter((question) => question.difficulty >= 0 && question.difficulty < 3.5).length; |
36 |
| - const userMediumQuestions = solvedQuestions.filter((question) => question.difficulty >= 3.5 && question.difficulty < 7).length; |
37 |
| - const userHardQuestions = solvedQuestions.filter((question) => question.difficulty >= 7 && question.difficulty <= 10).length; |
38 |
| - |
39 |
| - setTotalEasy(easyQuestions); |
40 |
| - setTotalMedium(mediumQuestions); |
41 |
| - setTotalHard(hardQuestions); |
42 |
| - setTotalQuestions(easyQuestions + mediumQuestions + hardQuestions); |
43 |
| - setEasyCount(userEasyQuestions); |
44 |
| - setMediumCount(userMediumQuestions); |
45 |
| - setHardCount(userHardQuestions); |
46 |
| - setTotalSolved(userEasyQuestions + userMediumQuestions + userHardQuestions); |
47 |
| - |
48 |
| - // Calculate percentages here |
49 |
| - const easyPercentage = (userEasyQuestions / easyQuestions) * 100; |
50 |
| - const mediumPercentage = (userMediumQuestions / mediumQuestions) * 100; |
51 |
| - const hardPercentage = (userHardQuestions / hardQuestions) * 100; |
52 |
| - const totalPercentage = (totalSolved / totalQuestions) * 100; |
53 |
| - |
54 |
| - // Set state for percentages |
55 |
| - setEasyPercentage(easyPercentage); |
56 |
| - setMediumPercentage(mediumPercentage); |
57 |
| - setHardPercentage(hardPercentage); |
58 |
| - setTotalPercentage(totalPercentage); |
59 |
| - |
60 |
| - // Hard coded values for testing |
61 |
| - // setTotalEasy(10); |
62 |
| - // setTotalMedium(10); |
63 |
| - // setTotalHard(10); |
64 |
| - // setTotalQuestions(30); |
65 |
| - // setEasyCount(8); |
66 |
| - // setMediumCount(7); |
67 |
| - // setHardCount(3); |
68 |
| - // setTotalSolved(18); |
69 |
| - // setEasyPercentage(80); |
70 |
| - // setMediumPercentage(70); |
71 |
| - // setHardPercentage(30); |
72 |
| - // setTotalPercentage(60); |
| 50 | + const res: info[] = diffRanges.map((dr) => { |
| 51 | + const diff = dr.difficulty; |
| 52 | + const total = |
| 53 | + dr.difficulty !== "All" |
| 54 | + ? allQuestions.filter( |
| 55 | + (qn) => mapRangeToDifficulty(qn.difficulty) === diff |
| 56 | + ).length |
| 57 | + : allQuestions.length; |
| 58 | + const solved = |
| 59 | + dr.difficulty !== "All" |
| 60 | + ? new Set( |
| 61 | + solvedQuestions |
| 62 | + .filter( |
| 63 | + (qn) => |
| 64 | + qn.solved && |
| 65 | + mapRangeToDifficulty(qn.difficulty) === diff |
| 66 | + ) |
| 67 | + .map((q) => q._id) |
| 68 | + ).size |
| 69 | + : new Set( |
| 70 | + solvedQuestions.filter((qn) => qn.solved).map((q) => q._id) |
| 71 | + ).size; |
| 72 | + return { |
| 73 | + name: diff, |
| 74 | + percentage: total |
| 75 | + ? Math.round((solved / total) * 10000) / 100 |
| 76 | + : 0.0, |
| 77 | + solved, |
| 78 | + total, |
| 79 | + scheme: dr.scheme, |
| 80 | + }; |
| 81 | + }); |
| 82 | + setDatas(res); |
73 | 83 | } catch (error) {
|
74 | 84 | console.error(error);
|
75 | 85 | }
|
76 |
| - } |
77 |
| - |
78 |
| - fetchAndCategorizeQuestions(); |
| 86 | + })(); |
79 | 87 | }, [solvedQuestions]);
|
80 |
| - |
| 88 | + console.log(solvedQuestions); |
81 | 89 | return (
|
82 | 90 | <>
|
83 |
| - <TableContainer width="100%"> |
84 |
| - <Table |
85 |
| - variant="striped" |
86 |
| - backgroundColor={"white"} |
87 |
| - size="md" |
88 |
| - boxShadow="md" |
89 |
| - transition="box-shadow 0.2s" |
90 |
| - _hover={{ |
91 |
| - boxShadow: "xl", |
92 |
| - }} |
93 |
| - width="100%" |
94 |
| - sx={{ tableLayout: "fixed" }} |
95 |
| - > |
96 |
| - |
97 |
| - <Th colSpan={4}> |
98 |
| - Solved Problems |
99 |
| - </Th> |
100 |
| - </Table> |
101 |
| - </TableContainer> |
102 | 91 | <Card>
|
103 |
| - <Flex direction="column" p={10}> |
104 |
| - <Flex width="100%" direction="row" align="center"> |
105 |
| - <CircularProgress size="180px" value={totalPercentage} color="yellow.400"> |
106 |
| - <CircularProgressLabel fontSize="18px">{totalSolved} solved</CircularProgressLabel> |
107 |
| - </CircularProgress> |
108 |
| - <Flex width="100%" direction="column" align="left" textAlign="left" ml={6}> |
109 |
| - <Flex justify="space between" align="center" mb={2}> |
110 |
| - <Text fontSize="sm">Easy</Text> |
111 |
| - <Text fontSize="sm" color="gray.500"> |
112 |
| - {easyCount}/{totalEasy} |
113 |
| - </Text> |
114 |
| - </Flex> |
115 |
| - <Progress value={easyPercentage} colorScheme="green" mb={2} /> |
116 |
| - <Flex justify="space between" align="center" mb={2}> |
117 |
| - <Text fontSize="sm">Medium</Text> |
118 |
| - <Text fontSize="sm" color="gray.500"> |
119 |
| - {mediumCount}/{totalMedium} |
120 |
| - </Text> |
121 |
| - </Flex> |
122 |
| - <Progress value={mediumPercentage} colorScheme="yellow" mb={2} /> |
123 |
| - <Flex justify="space between" align="center" mb={2}> |
124 |
| - <Text fontSize="sm">Hard</Text> |
125 |
| - <Text fontSize="sm" color="gray.500"> |
126 |
| - {hardCount}/{totalHard} |
127 |
| - </Text> |
128 |
| - </Flex> |
129 |
| - <Progress value={hardPercentage} colorScheme="red" mb={2} /> |
130 |
| - </Flex> |
131 |
| - </Flex> |
132 |
| - </Flex> |
| 92 | + <CardHeader> |
| 93 | + <Heading size="md">Solved Problems</Heading> |
| 94 | + </CardHeader> |
| 95 | + <HStack gap={3} margin={4}> |
| 96 | + {datas |
| 97 | + .filter((d) => d.name === "All") |
| 98 | + .map((d) => ( |
| 99 | + <CircularProgress |
| 100 | + size="200px" |
| 101 | + value={d.percentage} |
| 102 | + color="yellow.400" |
| 103 | + key="All" |
| 104 | + thickness={5} |
| 105 | + > |
| 106 | + <CircularProgressLabel fontSize="15px"> |
| 107 | + <Stat textShadow="md"> |
| 108 | + <StatLabel>Total Solved</StatLabel> |
| 109 | + <StatNumber> |
| 110 | + {d.solved}/{d.total} |
| 111 | + </StatNumber> |
| 112 | + <StatHelpText>{d.percentage}%</StatHelpText> |
| 113 | + </Stat> |
| 114 | + </CircularProgressLabel> |
| 115 | + </CircularProgress> |
| 116 | + ))} |
| 117 | + <VStack width="100%" align="left" textAlign="left" gap={2}> |
| 118 | + {datas |
| 119 | + .filter((d) => d.name !== "All") |
| 120 | + .map((d) => ( |
| 121 | + <HStack alignContent="center"> |
| 122 | + <Stat textShadow="md" size="xs"> |
| 123 | + <StatLabel>{d.name}</StatLabel> |
| 124 | + <StatNumber> |
| 125 | + {d.solved}/{d.total} |
| 126 | + </StatNumber> |
| 127 | + </Stat> |
| 128 | + <Progress |
| 129 | + size="lg" |
| 130 | + width="100%" |
| 131 | + value={d.percentage} |
| 132 | + colorScheme={d.scheme} |
| 133 | + marginLeft={4} |
| 134 | + /> |
| 135 | + </HStack> |
| 136 | + ))} |
| 137 | + </VStack> |
| 138 | + </HStack> |
133 | 139 | </Card>
|
134 | 140 | </>
|
135 | 141 | );
|
|
0 commit comments