diff --git a/package-lock.json b/package-lock.json
index 44323b9b56..edccc70095 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,6 +22,7 @@
"@tinymce/tinymce-react": "^5.1.1",
"allotment": "^1.19.3",
"axios": "^1.6.0",
+ "chart.js": "^4.4.4",
"date-fns": "^2.30.0",
"dompurify": "^3.1.1",
"emoji-mart": "^5.5.2",
@@ -29,6 +30,7 @@
"normalize.css": "^8.0.1",
"nuka-carousel": "^8.0.1",
"react": "^18.2.0",
+ "react-chartjs-2": "^5.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^15.0.0",
"react-player": "^2.16.0",
@@ -3733,6 +3735,11 @@
"resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz",
"integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA=="
},
+ "node_modules/@kurkle/color": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
+ "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
+ },
"node_modules/@mdx-js/mdx": {
"version": "1.6.22",
"resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz",
@@ -15449,6 +15456,17 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/chart.js": {
+ "version": "4.4.4",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.4.tgz",
+ "integrity": "sha512-emICKGBABnxhMjUjlYRR12PmOXhJ2eJjEHL2/dZlWjxRAZT1D8xplLFq5M0tMQK8ja+wBS/tuVEJB5C6r7VxJA==",
+ "dependencies": {
+ "@kurkle/color": "^0.3.0"
+ },
+ "engines": {
+ "pnpm": ">=8"
+ }
+ },
"node_modules/check-error": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
@@ -25976,6 +25994,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-chartjs-2": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz",
+ "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==",
+ "peerDependencies": {
+ "chart.js": "^4.1.1",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/react-docgen": {
"version": "5.4.3",
"resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz",
diff --git a/package.json b/package.json
index 29853df26f..16fb8cb489 100644
--- a/package.json
+++ b/package.json
@@ -12,11 +12,12 @@
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.16",
"@mui/material": "^5.14.16",
- "@reduxjs/toolkit": "^2.2.7",
"@mui/x-date-pickers": "^5.0.20",
+ "@reduxjs/toolkit": "^2.2.7",
"@tinymce/tinymce-react": "^5.1.1",
"allotment": "^1.19.3",
"axios": "^1.6.0",
+ "chart.js": "^4.4.4",
"date-fns": "^2.30.0",
"dompurify": "^3.1.1",
"emoji-mart": "^5.5.2",
@@ -24,6 +25,7 @@
"normalize.css": "^8.0.1",
"nuka-carousel": "^8.0.1",
"react": "^18.2.0",
+ "react-chartjs-2": "^5.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^15.0.0",
"react-player": "^2.16.0",
diff --git a/src/components/students-in-categories/StudentsInCategories.styles.ts b/src/components/students-in-categories/StudentsInCategories.styles.ts
new file mode 100644
index 0000000000..7cb57b79e7
--- /dev/null
+++ b/src/components/students-in-categories/StudentsInCategories.styles.ts
@@ -0,0 +1,126 @@
+import { TypographyVariantEnum } from '~/types'
+
+export const styles = {
+ cardContainer: {
+ width: '100%',
+ maxWidth: '460px',
+ minHeight: '400px',
+ borderRadius: '8px',
+ border: '1px',
+ borderColor: 'basic.lightGrey',
+ backgroundColor: 'basic.white',
+ p: { xs: '20px 41px 40px', sm: '20px 41px 68px' },
+ boxSizing: 'border-box',
+ mt: '75px'
+ },
+
+ cardTitle: {
+ typography: TypographyVariantEnum.H5,
+ color: 'basic.darkGray',
+ mb: '5px'
+ },
+
+ cardSubTitle: {
+ typography: TypographyVariantEnum.Body2,
+ color: 'basic.blueGray',
+ mb: '15px'
+ },
+
+ select: {
+ height: '40px',
+ border: '1px solid',
+ borderColor: 'basic.gray',
+ '& .MuiSelect-select': {
+ p: '8px 10px'
+ }
+ },
+
+ selectedValue: {
+ display: 'flex',
+ gap: 1
+ },
+
+ selectAndButtonContainer: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ mb: 'auto',
+ flexWrap: 'wrap',
+ gap: '8px'
+ },
+
+ clearAllButton: {
+ height: '40px',
+ ml: 'auto',
+ typography: TypographyVariantEnum.Body1,
+ color: 'basic.darkGray'
+ },
+
+ chartAndLegendContainer: {
+ display: 'flex',
+ flexDirection: { xs: 'column', sm: 'row' },
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ mt: '30px',
+ gap: '15px'
+ },
+
+ legendContainer: {
+ width: '146px',
+ display: 'flex',
+ flexDirection: 'column',
+ gap: '20px'
+ },
+
+ legendRow: {
+ display: 'flex',
+ alignItems: 'center'
+ },
+
+ legendBoxIcon: (color: string) => ({
+ width: '12px',
+ height: '12px',
+ backgroundColor: color,
+ mr: 1,
+ borderRadius: '50%'
+ }),
+
+ percentage: {
+ ml: 'auto',
+ typography: TypographyVariantEnum.Overline,
+ color: 'basic.black'
+ },
+
+ totalStudents: {
+ typography: TypographyVariantEnum.H5,
+ color: 'basic.darkGray'
+ },
+
+ allStudents: {
+ typography: TypographyVariantEnum.Subtitle2,
+ color: 'basic.darkGray',
+ textAlign: 'center'
+ },
+
+ category: {
+ typography: TypographyVariantEnum.Overline,
+ color: 'basic.black',
+ textTransform: 'uppercase'
+ },
+
+ diagramContainer: {
+ width: '170px',
+ height: '170px',
+ position: 'relative'
+ },
+
+ diagramInnerText: {
+ position: 'absolute',
+ top: '50%',
+ left: '50%',
+ transform: 'translate(-50%, -50%)',
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center'
+ }
+}
diff --git a/src/components/students-in-categories/StudentsInCategories.tsx b/src/components/students-in-categories/StudentsInCategories.tsx
new file mode 100644
index 0000000000..dacc1a0a69
--- /dev/null
+++ b/src/components/students-in-categories/StudentsInCategories.tsx
@@ -0,0 +1,98 @@
+import { Box, Button, MenuItem, Select, Typography } from '@mui/material'
+import { styles } from './StudentsInCategories.styles'
+import SchoolIcon from '@mui/icons-material/School'
+import EventIcon from '@mui/icons-material/Event'
+import StudentsInCatgoriesChart from './StudentsInCategoriesChart'
+import { useTranslation } from 'react-i18next'
+
+const currencies = [
+ {
+ value: 'USD',
+ label: '$'
+ },
+ {
+ value: 'EUR',
+ label: '€'
+ },
+ {
+ value: 'BTC',
+ label: '฿'
+ },
+ {
+ value: 'JPY',
+ label: '¥'
+ }
+]
+
+const years = [
+ {
+ value: '2021'
+ },
+
+ {
+ value: '2022'
+ },
+
+ {
+ value: '2023'
+ },
+
+ {
+ value: '2024'
+ }
+]
+
+function StudentsInCatgories() {
+ const { t } = useTranslation()
+ return (
+
+
+ {t('tutorHomePage.studentsInCategories.title')}
+
+
+ {t('tutorHomePage.studentsInCategories.subTitle')}
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default StudentsInCatgories
diff --git a/src/components/students-in-categories/StudentsInCategoriesChart.tsx b/src/components/students-in-categories/StudentsInCategoriesChart.tsx
new file mode 100644
index 0000000000..6d196cc24a
--- /dev/null
+++ b/src/components/students-in-categories/StudentsInCategoriesChart.tsx
@@ -0,0 +1,70 @@
+import { Doughnut } from 'react-chartjs-2'
+import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'
+import { Box, Typography } from '@mui/material'
+import { styles } from './StudentsInCategories.styles'
+import { useTranslation } from 'react-i18next'
+
+ChartJS.register(ArcElement, Tooltip, Legend)
+
+const categories = [
+ { label: 'Languages', value: 75, color: '#79B260' },
+ { label: 'Mathematics', value: 12, color: '#FFD166' },
+ { label: 'History', value: 8, color: '#EF476F' },
+ { label: 'Other (+3)', value: 5, color: '#6C757D' }
+]
+
+const data = {
+ labels: categories.map((category) => category.label),
+ datasets: [
+ {
+ data: categories.map((category) => category.value),
+ backgroundColor: categories.map((category) => category.color),
+ hoverBackgroundColor: categories.map((category) => category.color),
+ borderWidth: 1,
+ cutout: '70%',
+ rotation: 180
+ }
+ ]
+}
+
+const options = {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ legend: {
+ display: false
+ },
+ tooltip: {
+ enabled: true
+ }
+ }
+}
+
+const StudentsInCategoriesChart = () => {
+ const { t } = useTranslation()
+ return (
+
+
+
+
+ 24
+
+ {t('tutorHomePage.studentsInCategories.allStudents')}
+
+
+
+
+
+ {categories.map((category, index) => (
+
+
+ {category.label}
+ {category.value}%
+
+ ))}
+
+
+ )
+}
+
+export default StudentsInCategoriesChart
diff --git a/src/constants/translations/en/tutor-home-page.json b/src/constants/translations/en/tutor-home-page.json
index 73e6d586e0..eaad238d64 100644
--- a/src/constants/translations/en/tutor-home-page.json
+++ b/src/constants/translations/en/tutor-home-page.json
@@ -13,5 +13,15 @@
"title": "Popular Categories",
"description": "Explore tutoring categories you're passionate about.",
"viewMore": "View more"
+ },
+ "studentsInCategories": {
+ "title": "Students in Your Categories",
+ "subTitle": "Statistics of your students quantity during the last time.",
+ "resetButton": "Clear all",
+ "select": {
+ "category": "Category",
+ "year": "Year"
+ },
+ "allStudents": "All students"
}
}
diff --git a/src/constants/translations/uk/tutor-home-page.json b/src/constants/translations/uk/tutor-home-page.json
index 315a09e973..c43f9c1ea3 100644
--- a/src/constants/translations/uk/tutor-home-page.json
+++ b/src/constants/translations/uk/tutor-home-page.json
@@ -13,5 +13,15 @@
"title": "Популярні категорії",
"description": "Досліджуйте категорії репетиторства, які вас цікавлять.",
"viewMore": "Дивитися більше"
+ },
+ "studentsInCategories": {
+ "title": "Студенти по Ваших категоріях",
+ "subTitle": "Статистика кількості Ваших студентів протягом останнього часу",
+ "resetButton": "Очистити",
+ "select": {
+ "category": "Категорія",
+ "year": "Рік"
+ },
+ "allStudents": "Всі студенти"
}
}
diff --git a/src/pages/tutor-home/TutorHome.tsx b/src/pages/tutor-home/TutorHome.tsx
index e9bbc4e331..0e1e1db314 100644
--- a/src/pages/tutor-home/TutorHome.tsx
+++ b/src/pages/tutor-home/TutorHome.tsx
@@ -15,6 +15,7 @@ import { translationKey } from '~/components/find-block/find-student-constants'
import Calendar from '~/components/calendar/Calendar'
import TutorSchedule from '~/components/tutor-schedule/TutorSchedule'
import { Box } from '@mui/material'
+import StudentsInCatgories from '~/components/students-in-categories/StudentsInCategories'
const TutorHome = () => {
const { t } = useTranslation()
@@ -39,6 +40,7 @@ const TutorHome = () => {
+