diff --git a/package.json b/package.json
index f4ab379..f65156d 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"axios": "^0.21.1",
- "chart.js": "^2.9.4",
+ "chart.js": "^3.6.0",
"chartjs-plugin-datalabels": "1.0.0",
"classnames": "^2.3.1",
"date-fns": "^2.22.1",
@@ -19,13 +19,14 @@
"jquery": "^3.6.0",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
+ "moment": "^2.30.1",
"moment-duration-format": "2.2.2",
"node-sass": "9.0.0",
"qs": "^6.9.6",
"query-string": "^7.1.1",
"react": "^17.0.1",
"react-apple-login": "^1.1.3",
- "react-chartjs-2": "^2.11.1",
+ "react-chartjs-2": "^4.0.0",
"react-datepicker": "^4.1.1",
"react-dom": "^17.0.1",
"react-facebook-login": "^4.1.1",
diff --git a/public/assets/css/all.css b/public/assets/css/all.css
index 3bc18ef..1cc8b62 100644
--- a/public/assets/css/all.css
+++ b/public/assets/css/all.css
@@ -88,6 +88,7 @@
--primary-color: #00CC83;
--second-color: #FF9F00;
--button-bg-color: #FF9F00;
+ --text-color: #4D4D4D;
--height-header: 64px;
--width-sidebar: 78px;
}
@@ -96,9 +97,10 @@ html {
font-size: 62.5%;
}
-@media screen and (max-height: 700px) {
+@media screen and (max-height: 800px) {
:root {
- --height-header: 54px
+ --height-header: 42px;
+ --width-sidebar: 68px;
}
html {
@@ -1139,6 +1141,30 @@ a:hover {
background-size: cover;
}
+.bg-sub-main-green-img {
+ width: 100%;
+ height: 100%;
+ background-image: url("./../imgs/bg/bg_sub_main_green.png");
+ background-position: bottom;
+ background-repeat: no-repeat;
+ -webkit-background-size: cover;
+ -moz-background-size: cover;
+ -o-background-size: cover;
+ background-size: cover;
+}
+
+.bg-outstanding-img {
+ width: 100%;
+ height: 100%;
+ background-image: url("./../imgs/bg/bg_outstanding.png");
+ background-position: bottom;
+ background-repeat: no-repeat;
+ -webkit-background-size: cover;
+ -moz-background-size: cover;
+ -o-background-size: cover;
+ background-size: cover;
+}
+
.bg-main-color {
background-image: linear-gradient(to top, #fafffd, #e1fef0);
}
@@ -8491,12 +8517,41 @@ p.text-center.f-18 {
.react-datepicker__month-text--keyboard-selected,
.react-datepicker__quarter-text--keyboard-selected,
.react-datepicker__year-text--keyboard-selected {
- border-radius: 50% !important;
+ border-radius: 8px !important;
background-image: linear-gradient(to right, #00e1a0, #00b9b7);
border: none;
color: #fff !important;
}
+.react-datepicker__month .react-datepicker__month-text:hover, .react-datepicker__month .react-datepicker__quarter-text:hover {
+ border-radius: 8px !important;
+ border: none !important;
+}
+
+.react-datepicker__month .react-datepicker__month-text, .react-datepicker__month .react-datepicker__quarter-text {
+ width: auto !important;
+}
+
+.react-datepicker__current-month, .react-datepicker-time__header, .react-datepicker-year-header {
+ font-size: 1.6rem !important;
+}
+
+.react-datepicker__navigation {
+ top: .8rem !important;
+}
+
+.react-datepicker__month {
+ width: 180px !important;
+}
+
+.react-datepicker__month-wrapper {
+ display: flex !important;
+}
+
+.react-datepicker__day--today, .react-datepicker__month-text--today, .react-datepicker__quarter-text--today, .react-datepicker__year-text--today {
+ border-radius: 8px !important;
+}
+
.react-datepicker__day--keyboard-selected {
border-radius: 0;
background-color: #fff !important;
@@ -11243,3 +11298,7 @@ strong {
align-items: center;
gap: 2.4rem;
}
+
+.gap-16 {
+ gap: 16px
+}
\ No newline at end of file
diff --git a/public/assets/imgs/bg/bg_outstanding.png b/public/assets/imgs/bg/bg_outstanding.png
new file mode 100644
index 0000000..eec06a9
Binary files /dev/null and b/public/assets/imgs/bg/bg_outstanding.png differ
diff --git a/public/assets/imgs/bg/bg_sub_main_green.png b/public/assets/imgs/bg/bg_sub_main_green.png
new file mode 100644
index 0000000..3f47369
Binary files /dev/null and b/public/assets/imgs/bg/bg_sub_main_green.png differ
diff --git a/public/assets/imgs/copper_medal.png b/public/assets/imgs/copper_medal.png
new file mode 100644
index 0000000..98fde64
Binary files /dev/null and b/public/assets/imgs/copper_medal.png differ
diff --git a/public/assets/imgs/crown_warning.png b/public/assets/imgs/crown_warning.png
new file mode 100644
index 0000000..9a07218
Binary files /dev/null and b/public/assets/imgs/crown_warning.png differ
diff --git a/public/assets/imgs/silver_medal.png b/public/assets/imgs/silver_medal.png
new file mode 100644
index 0000000..08e1079
Binary files /dev/null and b/public/assets/imgs/silver_medal.png differ
diff --git a/src/App.js b/src/App.js
index fee6532..7bd4291 100644
--- a/src/App.js
+++ b/src/App.js
@@ -9,7 +9,7 @@ import {
import { alertActions } from "./_actions";
import { history } from "./_helpers";
import Login from "./_screens/login";
-import { PATH, USER_ROLE } from "./_constants";
+import { PATH, USER_ROLE, USER_TYPE } from "./_constants";
import HomePage from "./_screens/home";
import ForgetPassword from "./_screens/forget-password";
import TeacherHome from "./_screens/home/teacher";
@@ -21,6 +21,7 @@ import DetailGrade from "./_screens/home/detail-grade";
import DetailRoomEducation from "./_screens/home/detail-room-education";
import EducationDepartmentHome from "./_screens/home/education-department";
import { Alert } from "./_components/Alert";
+import OutstandingTeacher from "./_screens/home/outstanding-teacher";
function App() {
const dispatch = useDispatch();
@@ -83,7 +84,7 @@ function App() {
/>
+
diff --git a/src/_components/Auth/InputDate/index.js b/src/_components/Auth/InputDate/index.js
index 038798e..b90bfba 100644
--- a/src/_components/Auth/InputDate/index.js
+++ b/src/_components/Auth/InputDate/index.js
@@ -3,85 +3,113 @@ import React, { useRef, useState } from "react";
// import { SelectDate } from "../../Calendar";
import "./index.scss";
import DatePicker, { registerLocale } from "react-datepicker";
+import "react-datepicker/dist/react-datepicker.css";
import vi from "date-fns/locale/vi";
import { isEmpty } from "lodash";
-registerLocale("vi", vi);
+const months = [
+ "Tháng 1",
+ "Tháng 2",
+ "Tháng 3",
+ "Tháng 4",
+ "Tháng 5",
+ "Tháng 6",
+ "Tháng 7",
+ "Tháng 8",
+ "Tháng 9",
+ "Tháng 10",
+ "Tháng 11",
+ "Tháng 12",
+];
+const days = ["CN", "T2", "T3", "T4", "T5", "T6", "T7"];
+
+registerLocale("vi", {
+ ...vi,
+ options: { ...vi.options, weekStartsOn: 1 },
+ localize: {
+ month: (n) => months[n],
+ day: (n) => days[n],
+ },
+});
const InputDate = (props) => {
- const $inputRef = useRef(null);
- const [isFocus, setIsFocus] = useState(false);
+ const $inputRef = useRef(null);
+ const [isFocus, setIsFocus] = useState(false);
- /**
- * changeValue: input change value
- * @param e event
- */
- const changeValue = (date) => {
- if (props.isWarning) {
- props.setIsWarning && props.setIsWarning("");
- }
- props.setValue(date);
- };
+ /**
+ * changeValue: input change value
+ * @param e event
+ */
+ const changeValue = (date) => {
+ if (props.isWarning) {
+ props.setIsWarning && props.setIsWarning("");
+ }
+ props.setValue(date);
+ };
- return (
-
- {props.errorText ? (
-
- {props.errorText}
-
- ) : null}
-
-
- {props.renderLabelIcon ? props.renderLabelIcon() : null}
+ return (
+
+ {props.errorText && props?.typeErrText != "underAbsolute" ? (
+
+ {props.errorText}
+
+ ) : null}
+
+
{props.renderLabelIcon ? props.renderLabelIcon() : null}
+
changeValue(date)}
+ // showMonthDropdown
+ showYearDropdown
+ showMonthYearPicker={!!props?.isMonthPicker}
+ showFullMonthYearPicker={!!props?.isMonthPicker}
+ fixedHeight
+ dropdownMode="select"
+ dateFormat={!!props?.isMonthPicker ? "MM/yyyy" : "P"}
+ locale="vi"
+ placeholderText={!isEmpty(props?.placeholder) ? `${props?.placeholder}`: !!props?.isMonthPicker ? 'MM/YYYY' : `DD/MM/YYYY`}
+ name={props.name}
+ popperPlacement={props?.popperPlacement ? props.popperPlacement : "bottom"}
+ // popperModifiers={[
+ // {
+ // name: "flip",
+ // options: {
+ // fallbackPlacements: ["bottom"],
+ // },
+ // },
+ // ]}
+ onKeyDown={(e) => {
+ e.preventDefault();
+ }}
+ readOnly={props?.readOnly}
+ />
+
+ {props.errorText && props?.typeErrText == "underAbsolute" ? (
+
+ {props.errorText}
+
+ ) : null}
-
changeValue(date)}
- showMonthDropdown
- showYearDropdown
- fixedHeight
- dropdownMode="select"
- dateFormat="P"
- locale="vi"
- placeholderText={
- !isEmpty(props?.placeholder)
- ? `${props?.placeholder}`
- : `DD/MM/YYYY`
- }
- name={props.name}
- popperPlacement="bottom"
- popperModifiers={[
- {
- name: "flip",
- options: {
- fallbackPlacements: ["bottom"],
- },
- },
- ]}
- onKeyDown={(e) => {
- e.preventDefault();
- }}
- />
-
-
- );
+ );
};
export default InputDate;
diff --git a/src/_components/Auth/InputDate/index.scss b/src/_components/Auth/InputDate/index.scss
index 2aa0f21..d45f4f8 100644
--- a/src/_components/Auth/InputDate/index.scss
+++ b/src/_components/Auth/InputDate/index.scss
@@ -25,23 +25,19 @@ $border-color: #4a4848;
.input_date_base {
display: flex;
align-items: center;
- height: 65px;
+ height: 40px;
padding: 0px 22px;
border: 1px solid $border-color;
border-radius: 10px;
- margin-bottom: 22px;
+ // margin-bottom: 22px;
- @media screen and (max-width: 768px) {
- height: 44px;
-
- svg {
- width: 18px;
- }
+ svg {
+ width: 18px;
}
.icon_label {
width: 31px;
- margin-right: 26px;
+ // margin-right: 26px;
flex: none;
@include screen_mobile {
@@ -100,4 +96,4 @@ $border-color: #4a4848;
color: #8e9298;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/_components/Calendar/CalendaSchedule.js b/src/_components/Calendar/CalendaSchedule.js
new file mode 100644
index 0000000..70b6539
--- /dev/null
+++ b/src/_components/Calendar/CalendaSchedule.js
@@ -0,0 +1,494 @@
+import React, { useCallback, useEffect, useState } from "react";
+import dayjs from "dayjs";
+import range from "lodash-es/range";
+import { scheduleActions } from "./../../_actions";
+import moment from "moment";
+import "./style.scss";
+import { useSelector, useDispatch } from "react-redux";
+import { useParams } from "react-router-dom";
+import { scheduleConstants } from "../../_constants";
+import { isEmpty } from "lodash";
+
+const weekDays = ["T2", "T3", "T4", "T5", "T6", "T7", "CN"];
+
+const todayObj = dayjs();
+
+function CalendaSchedule(props) {
+ const dispatch = useDispatch();
+ const schedules = useSelector((state) => state.schedules);
+ const status = schedules.status;
+ const date = new Date();
+ let {
+ changeDateCalendaSchedule,
+ collapse,
+ showAll,
+ showMonth,
+ role,
+ student_id,
+ hideEvent,
+ class_id,
+ homePageTeacherCalendaSchedule,
+ } = props;
+
+ role = role || "teacher";
+ const [fullHeight, setFullHeight] = useState(false);
+ const [dayObj, setDayObj] = useState(
+ dayjs(
+ date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate()
+ )
+ );
+ const thisYearSelected = schedules.selectDate
+ ? parseInt(moment(schedules.selectDate)?.format("YYYY"))
+ : dayObj.year();
+ const thisMonthSelected = schedules.selectDate
+ ? parseInt(moment(schedules.selectDate)?.format("MM") - 1)
+ : dayObj.month();
+ const thisDateSelected = schedules.selectDate
+ ? parseInt(moment(schedules.selectDate)?.format("DD"))
+ : dayObj.date();
+ const thisWeekSelected = weekCount(
+ thisYearSelected,
+ thisMonthSelected,
+ thisDateSelected
+ );
+
+ const thisYear = dayObj.year();
+ const thisMonth = dayObj.month();
+ const thisDate = dayObj.date();
+
+ const thisWeek = weekCount(thisYear, thisMonth, thisDate);
+ const daysInMonth = dayObj.daysInMonth();
+
+ const dayObjOf1 = dayjs(`${thisYear}-${thisMonth + 1}-1`);
+ let weekDayOf1 = dayObjOf1.day() - 1;
+
+ if (weekDayOf1 < 0) {
+ weekDayOf1 = 6;
+ }
+ const dayObjOfLast = dayjs(`${thisYear}-${thisMonth + 1}-${daysInMonth}`);
+ let weekDayOfLast = dayObjOfLast.day() - 1;
+ if (weekDayOfLast < 0) {
+ weekDayOfLast = 6;
+ }
+
+ const handlePrev = () => {
+ let dayObjTmp = dayObj.subtract(1, "month");
+ dispatch(
+ scheduleActions.getStatus(
+ dayObjTmp.month() + 1,
+ dayObjTmp.year(),
+ role,
+ student_id,
+ class_id
+ )
+ );
+ setDayObj(dayObjTmp);
+ };
+ const handleNext = () => {
+ let dayObjTmp = dayObj.add(1, "month");
+ dispatch(
+ scheduleActions.getStatus(
+ dayObjTmp.month() + 1,
+ dayObjTmp.year(),
+ role,
+ student_id,
+ class_id
+ )
+ );
+ setDayObj(dayObjTmp);
+ };
+
+ const [selectDate, setSelectDate] = useState({
+ year: schedules.dateSelectedCalendar
+ ? parseInt(moment(schedules.dateSelectedCalendar).format("YYYY"))
+ : localStorage.getItem("date_selected")
+ ? parseInt(
+ moment(JSON.parse(localStorage.getItem("date_selected"))).format(
+ "YYYY"
+ )
+ )
+ : thisYear,
+ month: schedules.dateSelectedCalendar
+ ? parseInt(
+ parseInt(moment(schedules.dateSelectedCalendar).format("MM")) - 1
+ )
+ : localStorage.getItem("date_selected")
+ ? parseInt(
+ parseInt(
+ moment(JSON.parse(localStorage.getItem("date_selected"))).format(
+ "MM"
+ )
+ ) - 1
+ )
+ : thisMonth,
+ day: schedules.dateSelectedCalendar
+ ? parseInt(moment(schedules.dateSelectedCalendar).format("DD"))
+ : localStorage.getItem("date_selected")
+ ? parseInt(
+ moment(JSON.parse(localStorage.getItem("date_selected"))).format("DD")
+ )
+ : todayObj.date(),
+ });
+
+ function selectDay(year, month, day) {
+ localStorage.setItem(
+ "date_selected",
+ JSON.stringify(`${year}-${parseInt(month) + 1}-${day}`)
+ );
+ setSelectDate({
+ year,
+ month,
+ day,
+ });
+ dispatch({
+ type: scheduleConstants.SET_DATE_SELECTED_CALENDAR,
+ time: `${year}-${parseInt(month) + 1}-${day}`,
+ });
+ changeDateCalendaSchedule({
+ year,
+ month,
+ day,
+ });
+ }
+
+ useEffect(() => {
+ let currentDate = new Date();
+ dispatch(
+ scheduleActions.getStatus(
+ parseInt(currentDate.getMonth()) + 1,
+ currentDate.getFullYear(),
+ role,
+ student_id,
+ class_id
+ )
+ );
+
+ return () => {
+ dispatch({
+ type: scheduleConstants.GET_STATUS,
+ data: {
+ in_complete: [],
+ complete: [],
+ has_log: [],
+ },
+ });
+ };
+ }, []);
+
+ const renderClass = useCallback(
+ (day, month, year) => {
+ if (hideEvent) {
+ return "";
+ }
+ let date = year + "-" + parseInt(month) + "-" + day;
+
+ if (status.in_complete.indexOf(moment(date).format("YYYY-MM-DD")) != -1) {
+ return " missing";
+ } else if (
+ status.complete.indexOf(moment(date).format("YYYY-MM-DD")) != -1
+ ) {
+ return " complete";
+ } else if (
+ status?.has_log?.length > 0 &&
+ status.has_log?.indexOf(moment(date).format("YYYY-MM-DD")) != -1
+ ) {
+ return " active_date";
+ } else {
+ return "";
+ }
+ },
+ [status]
+ );
+
+ function showFullHeight() {
+ setFullHeight(!fullHeight);
+ }
+
+ function renderClassHideCollapse(day, month, year) {
+ let dateFormat =
+ selectDate.year +
+ "-" +
+ (parseInt(selectDate.month) + 1) +
+ "-" +
+ selectDate.day;
+
+ let dateWeekToday = moment(dateFormat);
+ let dowDateWeekToday = parseInt(dateWeekToday.day()) + 1;
+ let listDateShowCollapse = [moment(dateFormat).format("YYYY-MM-DD")];
+ if (dowDateWeekToday == 2) {
+ for (let i = 1; i <= 6; i++) {
+ listDateShowCollapse.push(
+ moment(dateFormat, "YYYY-MM-DD").add("days", i).format("YYYY-MM-DD")
+ );
+ }
+ } else if (dowDateWeekToday == 1) {
+ for (let i = 1; i <= 6; i++) {
+ listDateShowCollapse.push(
+ moment(dateFormat, "YYYY-MM-DD")
+ .subtract("days", i)
+ .format("YYYY-MM-DD")
+ );
+ }
+ } else {
+ for (let i = 2; i < dowDateWeekToday; i++) {
+ listDateShowCollapse.push(
+ moment(dateFormat, "YYYY-MM-DD")
+ .subtract("days", i - 1)
+ .format("YYYY-MM-DD")
+ );
+ }
+ for (let i = 1; i <= 8 - dowDateWeekToday; i++) {
+ listDateShowCollapse.push(
+ moment(dateFormat, "YYYY-MM-DD").add("days", i).format("YYYY-MM-DD")
+ );
+ }
+ }
+
+ let date = year + "-" + month + "-" + day;
+ if (listDateShowCollapse.indexOf(moment(date).format("YYYY-MM-DD")) == -1) {
+ // return ' hide_collapse';
+ } else {
+ // return '';
+ }
+ return "";
+ }
+
+ function dequyWeek(days, week, total) {
+ days = parseInt(days) + 7;
+ week++;
+ if (total > days) {
+ return dequyWeek(days, week, total);
+ } else {
+ return week;
+ }
+ }
+
+ function weekCount(year, month_number, total) {
+ var firstOfMonth = new Date(year, month_number, 1);
+ let week = 1;
+ let days = firstOfMonth.getDay() == 0 ? 1 : 8 - firstOfMonth.getDay();
+ if (total > days) {
+ week = dequyWeek(days, week, total);
+ }
+ return week;
+ }
+
+ const renderClassShot = (date) => {
+ if (fullHeight || !collapse) {
+ return "";
+ } else {
+ let className = "";
+ if (
+ thisMonthSelected == dayObj.month() &&
+ thisYearSelected == dayObj.year()
+ ) {
+ let week = weekCount(thisYearSelected, thisMonthSelected, date);
+ className = " hide-date-custom";
+ if (thisWeekSelected == week) {
+ className = "";
+ }
+ }
+ return className;
+ }
+ };
+
+ const showWeekDayOf1 = () => {
+ if (fullHeight || !collapse) {
+ return true;
+ } else {
+ let isHide = true;
+ if (
+ thisMonthSelected == dayObj.month() &&
+ thisYearSelected == dayObj.year()
+ ) {
+ var firstOfMonth = new Date(thisYear, thisMonth, 1);
+ if (
+ (firstOfMonth.getDay() == 1 && thisWeekSelected == 1) ||
+ thisWeekSelected != 1
+ ) {
+ isHide = false;
+ }
+ }
+ // console.log('isHide ====', isHide)
+ return isHide;
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
{"Tháng " + dayObj.format("M/YYYY")}
+
+
+
+
+
+ {weekDays.map((d) => (
+
+ {d}
+
+ ))}
+
+
+ {showWeekDayOf1() &&
+ range(weekDayOf1).map((i) => (
+
+
+ {dayObjOf1.subtract(weekDayOf1 - i, "day").date()}
+
+
+ ))}
+
+ {range(daysInMonth).map((i) => (
+
+
selectDay(thisYear, thisMonth, i + 1)}
+ >
+ {i + 1}
+
+
+
+
+
+ ))}
+
+ {range(6 - weekDayOfLast).map((i) => (
+
+
+ {dayObjOfLast.add(i + 1, "day").date()}
+
+
+ ))}
+
+
+ {collapse && (
+
showFullHeight()}>
+ {fullHeight ? (
+
+ ) : (
+
+ )}
+
+ )}
+
+ );
+}
+
+export { CalendaSchedule };
diff --git a/src/_components/Calendar/PickDay.js b/src/_components/Calendar/PickDay.js
new file mode 100644
index 0000000..366aaa4
--- /dev/null
+++ b/src/_components/Calendar/PickDay.js
@@ -0,0 +1,68 @@
+import React, { useState } from 'react';
+import { isEmpty } from 'lodash';
+
+function PickDay(props) {
+ let { time, handleChangeDate, name_time } = props;
+ const [inputs, setInputs] = useState({
+ day: !isEmpty(time) ? time.substr(0, 2) : new Date().getDate(),
+ month: !isEmpty(time) ? time.substr(3, 2) : new Date().getMonth() + 1,
+ year: !isEmpty(time) ? time.substr(6, 4) : new Date().getFullYear(),
+ });
+
+ function createElementsOption(start, end) {
+ var elements = [];
+ for (let i = start; i <= end; i++) {
+ elements.push(
{i} );
+ }
+ return elements;
+ }
+
+ let defaultValueDate = new Date().getDate();
+ let defaultValueMonth = new Date().getMonth() + 1;
+ let defaultValueYear = new Date().getFullYear();
+ if (!isEmpty(time)) {
+ defaultValueDate = time.substr(0, 2);
+ defaultValueMonth = time.substr(3, 2)
+ defaultValueYear = time.substr(6, 4)
+ }
+
+ function handleChange(e) {
+ try{
+ const { name, value } = e.target;
+ let day = defaultValueDate;
+ let month = defaultValueMonth;
+ let year = defaultValueYear;
+ if(_.isEqual(name, 'day')){
+ day = value;
+ }else if(_.isEqual(name, 'month')){
+ month = value;
+ if ((new Date(defaultValueYear, month, 0)).getDate() < (new Date(defaultValueYear, defaultValueMonth, 0)).getDate() && day > (new Date(defaultValueYear, month, 0)).getDate()){
+ day = (new Date(defaultValueYear, month, 0)).getDate()
+ }
+ }else if(_.isEqual(name, 'year')){
+ year = value;
+ }
+ handleChangeDate({
+ [name_time]: year + '-' + month + '-' + day,
+ })
+ }catch(e){
+ console.log('handleChange', e)
+ }
+ }
+
+ return (
+
+
+ {createElementsOption(1, (new Date(defaultValueYear, defaultValueMonth, 0)).getDate()) || 31}
+
+
+ {createElementsOption(1, 12)}
+
+
+ {createElementsOption(2000, 2099)}
+
+
+ );
+}
+
+export { PickDay };
\ No newline at end of file
diff --git a/src/_components/Calendar/SelectDate.js b/src/_components/Calendar/SelectDate.js
new file mode 100644
index 0000000..824e879
--- /dev/null
+++ b/src/_components/Calendar/SelectDate.js
@@ -0,0 +1,67 @@
+import React, { Fragment, useEffect, useRef } from "react";
+// import DatePicker from "react-datepicker";
+import "react-datepicker/dist/react-datepicker.css";
+import DatePicker, { registerLocale } from "react-datepicker";
+import es from "date-fns/locale/es";
+
+const months = [
+ "Tháng 1 / ",
+ "Tháng 2 / ",
+ "Tháng 3 / ",
+ "Tháng 4 / ",
+ "Tháng 5 / ",
+ "Tháng 6 / ",
+ "Tháng 7 / ",
+ "Tháng 8 / ",
+ "Tháng 9 / ",
+ "Tháng 10 / ",
+ "Tháng 11 / ",
+ "Tháng 12 / ",
+];
+const days = ["CN", "T2", "T3", "T4", "T5", "T6", "T7"];
+
+registerLocale("es", {
+ ...es,
+ options: { ...es.options, weekStartsOn: 1 },
+ localize: {
+ month: (n) => months[n],
+ day: (n) => days[n],
+ },
+});
+
+function SelectDate(props) {
+ const { id, name, selected, onChange, dateFormat, disableMouseFocus, minDate } = props;
+ const showTimeSelect = props.showTimeSelect || false;
+ const showTimeSelectOnly = props.showTimeSelectOnly || false;
+ const dateRef = useRef(null);
+
+ useEffect(() => {
+ let isFirefox = window.navigator.userAgent.indexOf("Firefox") != -1;
+ if (dateRef.current && disableMouseFocus && !isFirefox) {
+ dateRef.current?.input?.setAttribute("disabled", true);
+ }
+ }, [dateRef, disableMouseFocus]);
+
+ return (
+
+ e.preventDefault()}
+ showTimeSelect={showTimeSelect}
+ showTimeSelectOnly={showTimeSelectOnly}
+ // timeFormat="HH:mm"
+ locale="es"
+ id={id}
+ timeIntervals={props?.timeIntervals || 15}
+ dateFormat={dateFormat}
+ name={name}
+ selected={selected}
+ placeholderText="DD/MM/YYYY"
+ onChange={(time) => onChange(time)}
+ ref={dateRef}
+ />
+
+ );
+}
+
+export { SelectDate };
diff --git a/src/_components/Calendar/index.js b/src/_components/Calendar/index.js
new file mode 100644
index 0000000..e154a3d
--- /dev/null
+++ b/src/_components/Calendar/index.js
@@ -0,0 +1,3 @@
+export * from './CalendaSchedule';
+export * from './PickDay';
+export * from './SelectDate';
\ No newline at end of file
diff --git a/src/_components/Calendar/style.scss b/src/_components/Calendar/style.scss
new file mode 100644
index 0000000..1557e9d
--- /dev/null
+++ b/src/_components/Calendar/style.scss
@@ -0,0 +1,203 @@
+@import url('https://fonts.googleapis.com/css?family=Manjari:400,700&display=swap');
+
+body {
+ font-family: Manjari, sans-serif;
+ font-size: 14px;
+}
+
+.calendar {
+ width: 350px;
+ margin: 0 auto;
+ box-shadow: 0 2px 4px 0 rgba(21, 27, 38, .15);
+ border-radius: 6px;
+}
+
+.header {
+ display: flex;
+ align-items: center;
+ padding: 12px 12px 0 12px;
+ border-radius: 6px 6px 0 0;
+ background-color: #fff;
+ color: #fff;
+ border-top-left-radius: 20px;
+ border-top-right-radius: 20px;
+}
+
+.nav {
+ border: 1px solid #fff;
+ border-radius: 25px;
+ outline: 0;
+ background-color: transparent;
+ cursor: pointer;
+}
+
+.datetime {
+ margin: 0 auto;
+ font-size: 18px;
+ font-weight: bold;
+ color: #00B9B7;
+}
+
+.week-container,
+.day-container {
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.week-cell{
+ font-family: 'Myriadpro-SemiBold';
+}
+.week-cell,
+.day-cell {
+ flex: 0 0 calc(100% / 7 - 10px);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 40px;
+ width: 40px;
+ cursor: pointer;
+ margin: 5px;
+}
+
+.day-cell.active{
+ background: #fff;
+ border: 2px solid #00A79D!important;
+ border-radius: 25px!important;
+ color: #404041!important;
+}
+
+.img-check-calendar{
+ display: none;
+ position: absolute;
+ top: 0;
+ right: -4px;
+}
+
+.day-cell.complete .img-check-calendar{
+ display: block;
+
+}
+
+
+.img-missing-calendar{
+ display: none;
+ position: absolute;
+ top: 9px;
+ right: 1px;
+}
+
+.day-cell.missing .img-missing-calendar{
+ display: block;
+}
+.day-cell.complete .img-missing-calendar{
+ display: none;
+}
+.day-cell.active_date .img-missing-calendar{
+ display: none;
+}
+.day-cell.today .img-missing-calendar{
+ display: none;
+}
+
+.img-active_dot-calendar{
+ display: none;
+ position: absolute;
+ top: 0px;
+ right: -5px;
+}
+
+.day-cell.missing .img-active_dot-calendar{
+ display: none;
+}
+.day-cell.complete .img-active_dot-calendar{
+ display: none;
+}
+.day-cell.active_date .img-active_dot-calendar{
+ display: block;
+}
+.day-cell.today .img-active_dot-calendar{
+ display: none;
+}
+
+.day-cell.today{
+ border: none!important;
+}
+
+.day-cell {
+ &--faded {
+ opacity: .4;
+ }
+
+ &--today {
+ border-radius: 25px;
+ background-image: linear-gradient(to right, #00e1a0 , #00b9b7)!important;
+ color: #fff!important;
+ border: none;
+ }
+}
+.lichngay-teacher .week-cell,.lichngay-teacher .day-cell {
+ flex-basis: calc(100% / 7 - 36px);
+ margin: 5px 0px;
+}
+.hide_collapse{
+ display : none;
+}
+.fullHeight .hide_collapse{
+ display : flex;
+}
+@media screen and (max-height: 800px) {
+ .img-check-calendar {
+ top: -4px;
+ right: -2px;
+ }
+ .box-40-40.lichngay-teacher .day-cell {
+ flex-basis: calc(100% / 7 - 24px);
+ margin: 5px 0px;
+ }
+ .hide_collapse {
+ display: none;
+ }
+}
+@media screen and (max-height: 700px) {
+ .calendar {
+ // width: 258px;
+ margin: 0 auto;
+ box-shadow: 2px 3px 4px 0 rgba(21, 27, 38, .15);
+ border-radius: 6px;
+ }
+ .week-cell,
+ .day-cell {
+ font-size: 14px;
+ flex: 0 0 calc(100% / 7 - 10px);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+ margin: 5px 0px;
+ }
+ .day-cell.missing .img-missing-calendar {
+ display: block;
+ width: 7px;
+ }
+ .img-missing-calendar {
+ display: none;
+ position: absolute;
+ top: 2px;
+ right: -3px;
+ }
+ .img-check-calendar {
+ top: -4px;
+ right: -4px;
+ }
+ .box-40-40.lichngay-teacher .day-cell {
+ flex-basis: calc(100% / 7 - 27px);
+ margin: 5px 0px;
+ }
+ .hide_collapse {
+ display: none;
+ }
+
+ .homePageTeacherCalendaSchedule {
+ margin: 0 !important
+ }
+}
\ No newline at end of file
diff --git a/src/_components/Header/header.style.scss b/src/_components/Header/header.style.scss
index f80f8e5..83c039f 100644
--- a/src/_components/Header/header.style.scss
+++ b/src/_components/Header/header.style.scss
@@ -36,6 +36,11 @@
box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 3px,
rgba(0, 0, 0, 0.24) 0px 1px 2px;
border-radius: 50%;
+
+ @media screen and (max-height: 800px) {
+ width: 32px;
+ height: 32px;
+ }
}
}
-}
+}
\ No newline at end of file
diff --git a/src/_components/RootSelect/index.js b/src/_components/RootSelect/index.js
index 3e16ab0..f0014be 100644
--- a/src/_components/RootSelect/index.js
+++ b/src/_components/RootSelect/index.js
@@ -9,6 +9,8 @@ export default function RootSelect({
setValue,
className,
isLoading = false,
+ bgWhite = false,
+ ...other
}) {
const ref = useRef(null);
const [isOpen, setIsOpen] = useState(false);
@@ -66,8 +68,9 @@ export default function RootSelect({
return (
{isLoading ? (
diff --git a/src/_components/RootSelect/rootSelect.style.scss b/src/_components/RootSelect/rootSelect.style.scss
index d7bd7b9..0239ac9 100644
--- a/src/_components/RootSelect/rootSelect.style.scss
+++ b/src/_components/RootSelect/rootSelect.style.scss
@@ -22,7 +22,7 @@
.item-selected-label {
color: #fff;
- font-size: 2rem;
+ font-size: 1.6rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -71,3 +71,15 @@
}
}
}
+
+.box-select.box-select-bg-white {
+ background-color: #fff;
+
+ .item-selected-label {
+ color: var(--text-color);
+ }
+
+ svg {
+ color: var(--text-color);
+ }
+}
\ No newline at end of file
diff --git a/src/_components/Router/RouteRedirectToAdmin.js b/src/_components/Router/RouteRedirectToAdmin.js
index a46c6ab..65d7514 100644
--- a/src/_components/Router/RouteRedirectToAdmin.js
+++ b/src/_components/Router/RouteRedirectToAdmin.js
@@ -18,7 +18,7 @@ export const RouteRedirectToAdmin = ({
return (
diff --git a/src/_components/Router/RouteRedirectToLogin.js b/src/_components/Router/RouteRedirectToLogin.js
index 50f5a0e..13c9720 100644
--- a/src/_components/Router/RouteRedirectToLogin.js
+++ b/src/_components/Router/RouteRedirectToLogin.js
@@ -27,11 +27,11 @@ export const RouteRedirectToLogin = ({
/>
);
}
- if (!!prefix?.length && !prefix?.includes(rest?.authentication?.user?.role)) {
+ if (!!prefix?.length && !prefix?.includes(rest?.authentication?.user?.role) && !prefix?.includes(rest?.authentication?.user?.type)) {
return (
diff --git a/src/_components/Sidebar/sidebar.style.scss b/src/_components/Sidebar/sidebar.style.scss
index 2cc74a8..a392663 100644
--- a/src/_components/Sidebar/sidebar.style.scss
+++ b/src/_components/Sidebar/sidebar.style.scss
@@ -14,6 +14,10 @@
justify-content: center;
align-items: center;
+ @media screen and (max-height: 800px) {
+ width: 60px;
+ }
+
.sidebar-logo-img {
width: 100%;
height: 100%;
@@ -43,4 +47,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/src/_components/boxChart/BoxDoughnutBarChart.js b/src/_components/boxChart/BoxDoughnutBarChart.js
new file mode 100644
index 0000000..afdbb54
--- /dev/null
+++ b/src/_components/boxChart/BoxDoughnutBarChart.js
@@ -0,0 +1,76 @@
+import { Subtitles } from '@material-ui/icons'
+import { PRIMARY_COLOR } from '../../_constants/common'
+import RDoughnutChart from '../chart/RDoughnutChart'
+import './boxChart.scss'
+import { VerticalBarChart } from '../chart/VerticalBarChart'
+import { useState } from 'react'
+import InputDate from '../Auth/InputDate'
+
+export default function BoxDoughnutBarChart({dataDoughnut = [], dataBarChart = [], labelsBarChart = [], dateBarChat, onSetDateBarChart, titleDoughnut, subtitleDoughnut, titleLine, subTitleLine}) {
+ const [month, setMonth] = useState(dateBarChat)
+ const [monthError, setMonthError] = useState('')
+
+ const changeMonth = (date) => {
+ setMonth(date)
+ !!onSetDateBarChart && onSetDateBarChart(date)
+ }
+
+ const _dataDoughnut = (dataDoughnut?.[0] / dataDoughnut?.[1] === 1 || dataDoughnut?.[0] > dataDoughnut?.[1]) ? [dataDoughnut?.[0]] : [dataDoughnut?.[0], dataDoughnut?.[1] - dataDoughnut?.[0]]
+
+
+ const renderIconDate = () => {
+ return (
+
+
+
+ )
+ }
+
+ return (
+
+
+ {!!titleDoughnut &&
{titleDoughnut}
}
+ {!!subtitleDoughnut &&
{subtitleDoughnut}
}
+
+
+
+
+
+
{dataDoughnut?.[0] + '/' + dataDoughnut?.[1]}
+
{Math.round(dataDoughnut?.[0]/dataDoughnut?.[1] * 100) + '%'}
+
+
+
+
+ {!!titleLine &&
{titleLine}
}
+ {!!subTitleLine &&
{subTitleLine}
}
+
+
+
+
+
+ {/* {renderArrowLeft()}
+ Tháng 11
+ {renderArrowRight()} */}
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/_components/boxChart/BoxDoughnutChar.js b/src/_components/boxChart/BoxDoughnutChar.js
new file mode 100644
index 0000000..0ff1760
--- /dev/null
+++ b/src/_components/boxChart/BoxDoughnutChar.js
@@ -0,0 +1,19 @@
+import { PRIMARY_COLOR } from '../../_constants/common'
+import RDoughnutChart from '../chart/RDoughnutChart'
+import './boxChart.scss'
+
+export default function BoxDoughnutChart({data = [], title, propsContainer}) {
+ const _data = (data?.[0] / data?.[1] === 1 || data?.[0] > data?.[1]) ? [data?.[0]] : [data?.[0], data?.[1] - data?.[0]]
+ return (
+
+
{title}
+
+
+
+
{data?.[0] + '/' + data?.[1]}
+
{Math.round(data?.[0]/data?.[1] * 100) + '%'}
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/_components/boxChart/boxChart.scss b/src/_components/boxChart/boxChart.scss
new file mode 100644
index 0000000..cbe3ceb
--- /dev/null
+++ b/src/_components/boxChart/boxChart.scss
@@ -0,0 +1,23 @@
+.box-chart-container {
+ padding: 1.6rem;
+ border-radius: 8px;
+ box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
+ background-color: #fff;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+
+ .box-chart-title {
+ font-size: 2rem;
+ font-weight: 700;
+ color: var(--primary-color);
+ padding-bottom: 0.5rem;
+ }
+
+ .box-chart-subtitle {
+ font-size: 1.8rem;
+ font-weight: 700;
+ }
+
+ .doughnut-chart-content {}
+}
\ No newline at end of file
diff --git a/src/_components/chart/RDoughnutChart.js b/src/_components/chart/RDoughnutChart.js
new file mode 100644
index 0000000..00b5752
--- /dev/null
+++ b/src/_components/chart/RDoughnutChart.js
@@ -0,0 +1,67 @@
+import React from 'react';
+import { Chart } from 'react-chartjs-2';
+import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js';
+import { PRIMARY_COLOR } from '../../_constants/common';
+
+ChartJS.register(ArcElement, Tooltip, Legend);
+
+
+// const data = {
+// labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
+// datasets: [
+// {
+// label: '# of Votes',
+// data: [12, 19, 3, 5, 2, 3],
+// backgroundColor: [
+// 'rgba(255, 99, 132, 0.2)',
+// 'rgba(54, 162, 235, 0.2)',
+// 'rgba(255, 206, 86, 0.2)',
+// 'rgba(75, 192, 192, 0.2)',
+// 'rgba(153, 102, 255, 0.2)',
+// 'rgba(255, 159, 64, 0.2)',
+// ],
+// borderColor: [
+// 'rgba(255, 99, 132, 1)',
+// 'rgba(54, 162, 235, 1)',
+// 'rgba(255, 206, 86, 1)',
+// 'rgba(75, 192, 192, 1)',
+// 'rgba(153, 102, 255, 1)',
+// 'rgba(255, 159, 64, 1)',
+// ],
+// borderWidth: 1,
+// },
+// ],
+// };
+
+export default function RDoughnutChart({data = [], ...other}) {
+ if (!data?.length) {
+ return null
+ }
+
+ return
;
+}
diff --git a/src/_components/chart/RPieChart.js b/src/_components/chart/RPieChart.js
new file mode 100644
index 0000000..ceeae3b
--- /dev/null
+++ b/src/_components/chart/RPieChart.js
@@ -0,0 +1,36 @@
+import React from 'react';
+import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js';
+import { Pie } from 'react-chartjs-2';
+
+ChartJS.register(ArcElement, Tooltip, Legend);
+
+// const data = {
+// labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
+// datasets: [
+// {
+// label: '# of Votes',
+// data: [12, 19, 3, 5, 2, 3],
+// backgroundColor: [
+// 'rgba(255, 99, 132, 0.2)',
+// 'rgba(54, 162, 235, 0.2)',
+// 'rgba(255, 206, 86, 0.2)',
+// 'rgba(75, 192, 192, 0.2)',
+// 'rgba(153, 102, 255, 0.2)',
+// 'rgba(255, 159, 64, 0.2)',
+// ],
+// borderColor: [
+// 'rgba(255, 99, 132, 1)',
+// 'rgba(54, 162, 235, 1)',
+// 'rgba(255, 206, 86, 1)',
+// 'rgba(75, 192, 192, 1)',
+// 'rgba(153, 102, 255, 1)',
+// 'rgba(255, 159, 64, 1)',
+// ],
+// borderWidth: 1,
+// },
+// ],
+// };
+
+export default function RPieChart({data, ...other}) {
+ return
;
+}
diff --git a/src/_components/chart/VerticalBarChart.js b/src/_components/chart/VerticalBarChart.js
new file mode 100644
index 0000000..bf2dabb
--- /dev/null
+++ b/src/_components/chart/VerticalBarChart.js
@@ -0,0 +1,83 @@
+import React from 'react';
+import {
+ Chart as ChartJS,
+ CategoryScale,
+ LinearScale,
+ BarElement,
+ Title,
+ Tooltip,
+ Legend,
+} from 'chart.js';
+import { Bar } from 'react-chartjs-2';
+import { PRIMARY_COLOR } from '../../_constants/common';
+
+ChartJS.register(
+ CategoryScale,
+ LinearScale,
+ BarElement,
+ Title,
+ Tooltip,
+ Legend
+);
+
+export function VerticalBarChart({data = [], labels = []}) {
+ if (!data?.length) {
+ return null
+ }
+ let maxValue = 0;
+ data?.map(item => {
+ if (item > maxValue) {
+ maxValue = item;
+ }
+ })
+
+ const options = {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ legend: {
+ display: false
+ },
+ datalabels: {
+ anchor: 'end', // Position of the labels (start, end, center, etc.)
+ align: 'end', // Alignment of the labels (start, end, center, etc.)
+ color: 'blue', // Color of the labels
+ font: {
+ weight: 'bold',
+ },
+ formatter: function (value, context) {
+ return value; // Display the actual data value
+ }
+ }
+ },
+ scales: {
+ y: {
+ max: maxValue < 5 ? 5 : maxValue < 20 ? maxValue + 5 : maxValue + 10,
+ ticks: {
+ callback: function(value) {if (value % 1 === 0) {return value;}},
+ stepSize: 1,
+ precision: 0,
+ }
+ },
+ yAxes: [{
+ ticks: {
+ beginAtZero: true,
+ callback: function(value) {if (value % 1 === 0) {return value;}},
+ stepSize: 1,
+ precision: 0,
+ }
+ }]
+ },
+ };
+
+ return
;
+}
diff --git a/src/_constants/common.js b/src/_constants/common.js
index 4899743..f2b9115 100644
--- a/src/_constants/common.js
+++ b/src/_constants/common.js
@@ -174,4 +174,6 @@ export const DEFAULT_SETTING_CRITERIA = {
target2: 90,
enable: false,
},
- }
\ No newline at end of file
+ }
+
+export const PRIMARY_COLOR = '#00CC83'
\ No newline at end of file
diff --git a/src/_constants/path.js b/src/_constants/path.js
index 70ecdc0..141f03f 100644
--- a/src/_constants/path.js
+++ b/src/_constants/path.js
@@ -11,6 +11,7 @@ export const PATH = {
detailGrade: "/home/detail-grade/:schoolId/:gradeId",
detailRoomEducation: "/home/detail-room-education/:idRoom",
educationDepartment: "/home/education-department",
+ outstandingTeacherByEducation: '/home/education-department/outstanding-teacher/:id'
},
criteria: {
root: "/criteria",
diff --git a/src/_constants/user.js b/src/_constants/user.js
index 7fbbefa..5f82d02 100644
--- a/src/_constants/user.js
+++ b/src/_constants/user.js
@@ -3,3 +3,32 @@ export const USER_ROLE = {
ADMIN: "supper_admin",
HEADMASTER: "organization_admin"
};
+
+export const USER_TYPE = {
+ PROVINCE: 'province',
+ DISTRICT: 'district',
+ SCHOOLMASTER: 'schoolmaster'
+}
+
+export const USER_TYPE_ROLE = {
+ admin: {
+ role: USER_ROLE.ADMIN,
+ type: null
+ },
+ PROVINCE: {
+ role: USER_ROLE.HEADMASTER,
+ type: USER_TYPE.PROVINCE
+ },
+ DISTRICT: {
+ role: USER_ROLE.HEADMASTER,
+ type: USER_TYPE.DISTRICT
+ },
+ headMaster: {
+ role: USER_ROLE.HEADMASTER,
+ type: USER_TYPE.SCHOOLMASTER
+ },
+ teacher: {
+ role: USER_ROLE.TEACHER,
+ type: null
+ }
+}
\ No newline at end of file
diff --git a/src/_helpers/utils.js b/src/_helpers/utils.js
index a777c85..11e41ac 100644
--- a/src/_helpers/utils.js
+++ b/src/_helpers/utils.js
@@ -1,4 +1,4 @@
-import { PATH, USER_ROLE } from "../_constants";
+import { PATH, USER_ROLE, USER_TYPE } from "../_constants";
import XLSX from "sheetjs-style";
import { listAlphabet } from "../_constants/common";
@@ -29,14 +29,23 @@ export const convertSkillVN = (skill) => {
}
};
-export const routeHome = (role) => {
- switch (role) {
+export const routeHome = (user) => {
+ switch (user?.role) {
case USER_ROLE.TEACHER:
return PATH.home.teacher;
case USER_ROLE.ADMIN:
return PATH.home.admin;
case USER_ROLE.HEADMASTER:
- return PATH.home.headmaster
+ switch (user?.type) {
+ case USER_TYPE.PROVINCE:
+ return PATH.home.educationDepartment;
+ case USER_TYPE.DISTRICT:
+ return replacePathParams(PATH.home.detailRoomEducation, {idRoom: user?.organization_id});
+ case USER_TYPE.SCHOOLMASTER:
+ return PATH.home.headmaster;
+ default:
+ return "";
+ }
default:
return "";
}
diff --git a/src/_screens/criteria/criteria-manage/criteriaManage.style.scss b/src/_screens/criteria/criteria-manage/criteriaManage.style.scss
index 12695c1..fae1dd5 100644
--- a/src/_screens/criteria/criteria-manage/criteriaManage.style.scss
+++ b/src/_screens/criteria/criteria-manage/criteriaManage.style.scss
@@ -148,4 +148,4 @@
gap: 24px;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/_screens/home/detail-room-education/detailRoomEducation.style.scss b/src/_screens/home/detail-room-education/detailRoomEducation.style.scss
index 8a2e025..70af0c4 100644
--- a/src/_screens/home/detail-room-education/detailRoomEducation.style.scss
+++ b/src/_screens/home/detail-room-education/detailRoomEducation.style.scss
@@ -1,144 +1,159 @@
@import "/src/_styles/mixin";
.detail-room-education-container {
- padding: 24px 0 48px;
display: flex;
- flex-direction: column;
- overflow: auto;
- .detail-room-education-action {
+ .detail-room-education-left-side {
+ width: 40%;
+ border-right: 1px solid #c7c7c7;
display: flex;
- gap: 16px;
- justify-content: space-between;
- align-items: center;
- padding: 0 24px 0 20rem;
+ flex-direction: column;
+ padding: 16px 0;
- .detail-room-education-note {
+ .detail-room-education-statistic-container {
flex: 1;
- text-align: center;
- font-weight: 700;
- font-size: 2.2rem;
+ max-height: 95%;
+ padding: 0 2rem 2rem;
+ display: flex;
+ flex-direction: column;
}
}
- .detail-room-education-list-container {
- padding: 4rem 24rem 0;
+ .detail-room-education-right-side {
flex: 1;
display: flex;
flex-direction: column;
- overflow: hidden;
+ padding-right: 8px;
+ background-color: #fff;
- .detail-room-education-list-school {
- // margin-top: 16px;
- padding-bottom: 16px;
- padding-right: 24px;
- margin-right: -24px;
- flex: 1;
- gap: 20px;
+ .detail-room-education-right-p-h {
+ padding-right: 32px;
+ }
+
+ .detail-room-education-list-container {
+ padding: 2rem 0;
display: flex;
flex-direction: column;
+ height: 100%;
- @include screen_pc_sm {
- gap: 16px;
- }
-
- .detail-room-education-item-school {
- padding: 8px;
- border: 1px solid #e5e5e5;
- border-radius: 6px;
- display: flex;
- gap: 16px;
- background-color: #fff;
+ .detail-room-education-list {
flex: 1;
+ gap: 20px;
+ display: flex;
+ flex-direction: column;
+ padding-bottom: 16px;
+ padding-left: 32px;
- &:hover {
- opacity: 0.8;
- cursor: pointer;
- }
-
- .detail-room-education-avatar-school {
- width: 88px;
- height: 88px;
- border-radius: 5px;
- box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px,
- rgba(60, 64, 67, 0.15) 0px 2px 6px 2px;
-
- @include screen_pc_sm {
- height: 70px;
- width: 70px;
- }
-
- img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- border-radius: 5px;
- }
+ @include screen_pc_sm {
+ gap: 16px;
}
- .detail-room-education-detail-school {
- display: flex;
- flex: 1;
- justify-content: space-between;
- gap: 24px;
-
- .detail-room-education-info-school {
- display: flex;
- align-items: center;
-
- .criteria-info-school-name {
- font-size: 2rem;
- font-weight: 700;
- color: var(--primary-color);
- }
-
- .criteria-info-school-text {
- font-size: 1.8rem;
- }
+ .detail-room-education-item {
+ padding: 8px;
+ border: 1.25px solid var(--primary-color);
+ border-radius: 4px;
+ background-color: #fff;
+ transition: all 0.5s linear;
+ box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
+
+ &:hover {
+ opacity: 0.8;
+ cursor: pointer;
}
- .detail-room-education-criteria-class {
+ .detail-room-education-item-content {
display: flex;
- flex-direction: column;
+ gap: 16px;
+
+ .detail-room-education-avatar {
+ width: 88px;
+ height: 88px;
+ border-radius: 5px;
+ box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px,
+ rgba(60, 64, 67, 0.15) 0px 2px 6px 2px;
+
+ @include screen_pc_sm {
+ height: 70px;
+ width: 70px;
+ }
- .criteria-class-title {
- font-size: 2rem;
- font-weight: 700;
- color: var(--primary-color);
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ border-radius: 5px;
+ }
}
- .criteria-class-row {
+ .detail-room-education-detail {
display: flex;
+ flex: 1;
justify-content: space-between;
- gap: 8px;
+ gap: 24px;
- .criteria-class-title {
- font-size: 2rem;
- font-weight: 700;
- }
+ .detail-room-education-info {
+ display: flex;
+ flex-direction: column;
- .criteria-class-criteria {
- font-size: 1.8rem;
- font-weight: 400;
- position: relative;
- padding-left: 12px;
-
- &::before {
- content: "";
- display: block;
- position: absolute;
- left: 0;
- top: 12px;
- width: 5px;
- height: 5px;
- background-color: var(--primary-color);
- border-radius: 50%;
+ .detail-room-education-info-name {
+ font-size: 2rem;
+ font-weight: 700;
+ color: var(--primary-color);
}
+
}
}
}
+
+ .detail-room-education-info-text {
+ font-size: 1.8rem;
+ }
}
}
}
}
-}
+
+
+
+ .detail-room-education-criteria {
+ display: flex;
+ flex-direction: column;
+
+ .detail-room-education-criteria-title {
+ font-size: 2rem;
+ font-weight: 700;
+ color: var(--primary-color);
+ }
+
+ .detail-room-education-criteria-row {
+ display: flex;
+ justify-content: space-between;
+ gap: 8px;
+
+ .criteria-teacher-title {
+ font-size: 2rem;
+ font-weight: 700;
+ }
+
+ .detail-room-education-criteria-ratio {
+ font-size: 1.8rem;
+ font-weight: 400;
+ position: relative;
+ padding-left: 12px;
+
+ &::before {
+ content: "";
+ display: block;
+ position: absolute;
+ left: 0;
+ top: 12px;
+ width: 5px;
+ height: 5px;
+ background-color: var(--primary-color);
+ border-radius: 50%;
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/_screens/home/detail-room-education/index.js b/src/_screens/home/detail-room-education/index.js
index 59926c2..0fabe4f 100644
--- a/src/_screens/home/detail-room-education/index.js
+++ b/src/_screens/home/detail-room-education/index.js
@@ -1,11 +1,222 @@
-import { useState } from "react";
+import { useEffect, useState } from "react";
import Header from "../../../_components/Header";
import { renderIconHome } from "../../../_components/renderIcon";
-import PrimaryButton from "../../../_components/Button/PrimaryButton";
-import "./detailRoomEducation.style.scss";
import RateStar from "../../../_components/RateStar";
+import { defaultMonthYearSemester, getListMonthBySemester, LIST_SCHOOL_YEAR, LIST_SEMESTER, PRIMARY_COLOR } from "../../../_constants/common";
+import { configConstants, PATH } from "../../../_constants";
+import RootSelect from "../../../_components/RootSelect";
+import PrimaryButton from "../../../_components/Button/PrimaryButton";
+import { useSelector } from "react-redux";
+import './detailRoomEducation.style.scss'
+import BoxDoughnutChart from "../../../_components/boxChart/BoxDoughnutChar";
+import BoxDoughnutBarChart from "../../../_components/boxChart/BoxDoughnutBarChart";
+import { apiCaller, history } from "../../../_helpers";
+import { replacePathParams } from "../../../_helpers/utils";
+import $ from "jquery";
+import { useParams } from "react-router-dom";
export default function DetailRoomEducation() {
+ const {idRoom} = useParams()
+ const grade = useSelector((state) => state.grade);
+ const authentication = useSelector((state) => state.authentication);
+ const [dateStudentChart, setDateStudentChart] = useState(new Date())
+ const [dateTeacherChart, setDateTeacherChart] = useState(new Date())
+ const [data, setData] = useState()
+ const [dataStudentChart, setDataStudentChart] = useState([])
+ const [dataTeacherChart, setDataTeacherChart] = useState([])
+ const [schoolYear, setSchoolYear] = useState(
+ grade?.filterGrade?.schoolYear,
+ );
+ const [semester, setSemester] = useState(grade?.filterGrade?.semester);
+ const [month, setMonth] = useState(grade?.filterGrade?.month);
+ const [listOrganization, setListOrganization] = useState([]);
+ const [isLoadingListOrganization, setIsLoadingListOrganization] = useState(false);
+ const [isLoadingStatisticCircle, setIsLoadingStatisticCircle] = useState(false);
+ const [isLoadingStudentChart, setIsLoadingStudentChart] = useState(false);
+ const [isLoadingTeacherChart, setIsLoadingTeacherChart] = useState(false);
+
+ const getListOrganization = async () => {
+ try {
+ setIsLoadingListOrganization(true);
+ const endPoint = `/report/api_report/getListOrganizationFromDistrictOrganization?organization_id=${
+ idRoom
+ }${
+ !!schoolYear?.value ? `&year=${schoolYear?.value}` : ""
+ }${
+ !!semester?.value ? `&semester=${semester?.value}` : ""
+ }${
+ !!month?.value ? `&month=${month?.value}` : ""
+ }`;
+ const res = await apiCaller(
+ endPoint,
+ "GET",
+ {},
+ null,
+ true,
+ configConstants.API_URL_SETEST,
+ false
+ )
+ if (res?.status) {
+ const endPointStatistic = `/report/api_report/getOrganizationStatisticsByOrganizationId?organization_id=${
+ idRoom
+ }&is_no_cache=1${
+ !!schoolYear?.value ? `&year=${schoolYear?.value}` : ""
+ }${
+ !!semester?.value ? `&semester=${semester?.value}` : ""
+ }${
+ !!month?.value ? `&month=${month?.value}` : ""
+ }`;
+ apiCaller(
+ endPointStatistic,
+ "GET",
+ {},
+ null,
+ true,
+ configConstants.API_URL_SETEST,
+ false
+ )
+ .then(resStatistic => {
+ if (resStatistic?.status) {
+ const listData = res?.data?.map(item => {
+ const statistic = resStatistic?.data?.find(statisticItem => statisticItem?.organization_id === item?.organization_id);
+ return {
+ ...item,
+ ...statistic
+ }
+ })
+ setListOrganization(listData)
+ } else {
+ setListOrganization(res?.data);
+ }
+ setIsLoadingListOrganization(false);
+ }).catch(e => {
+ setListOrganization(res?.data);
+ setIsLoadingListOrganization(false);
+ })
+ } else {
+ setIsLoadingListOrganization(false);
+ }
+ } catch (err) {
+ setIsLoadingListOrganization(false)
+ console.log(err)
+ }
+ }
+
+ const getDataStatisticCircle = async () => {
+ try {
+ setIsLoadingStatisticCircle(true);
+ const res = await apiCaller(
+ "/report/api_report/statisticalInfoOrganization?organization_id=" + idRoom,
+ "GET",
+ {},
+ null,
+ true,
+ configConstants.API_URL_SETEST,
+ false
+ )
+ if (res?.status) {
+ setData(res?.data)
+ }
+ setIsLoadingStatisticCircle(false);
+ } catch (e) {
+ setIsLoadingStatisticCircle(false);
+ }
+ }
+
+ const getDataStudentChart = async () => {
+ try {
+ setIsLoadingStudentChart(true);
+ const endPoint = '/report/api_report/homeworkChartInfo?organization_id=' + idRoom +
+ '&month='+ (dateStudentChart.getMonth() + 1) + '&year=' + dateStudentChart.getFullYear()
+
+ const res = await apiCaller(
+ endPoint,
+ "GET",
+ {},
+ null,
+ true,
+ configConstants.API_URL_SETEST,
+ false
+ )
+ if (res?.status) {
+ setDataStudentChart(res?.data)
+ }
+ setIsLoadingStudentChart(false);
+ } catch (e) {
+ setIsLoadingStudentChart(false);
+ }
+ }
+
+ const getDataTeacherChart = async () => {
+ try {
+ setIsLoadingTeacherChart(true);
+ const endPoint = '/report/api_report/assignmentChartInfo?organization_id=' + idRoom +
+ '&month='+ (dateTeacherChart.getMonth() + 1) + '&year=' + dateTeacherChart.getFullYear()
+
+ const res = await apiCaller(
+ endPoint,
+ "GET",
+ {},
+ null,
+ true,
+ configConstants.API_URL_SETEST,
+ false
+ )
+ if (res?.status) {
+ setDataTeacherChart(res?.data)
+ }
+ setIsLoadingTeacherChart(false)
+ } catch (e) {
+ setIsLoadingTeacherChart(false);
+ }
+ }
+
+ const changeSemester = (item) => {
+ setSemester(item);
+ setMonth(getListMonthBySemester(item?.value)?.[0]);
+ };
+
+ const handleFilter = () => {
+ getListOrganization();
+ };
+
+ const goToOutstandingTeacher = () => {
+ history.push(replacePathParams(PATH.home.outstandingTeacherByEducation, {id: idRoom}))
+ }
+
+ const goToDetailSchool = (item) => {
+ history.push(replacePathParams(PATH.home.detailSchool, {schoolId: item?.organization_id}) +
+ "?school_name=" +
+ encodeURIComponent(item?.organization_name));
+ }
+
+ useEffect(() => {
+ getDataStatisticCircle()
+ getListOrganization()
+ }, [])
+
+ useEffect(() => {
+ getDataStudentChart()
+ }, [dateStudentChart])
+
+ useEffect(() => {
+ getDataTeacherChart()
+ }, [dateTeacherChart])
+
+ useEffect(() => {
+ if (isLoadingListOrganization || isLoadingStatisticCircle || isLoadingStudentChart || isLoadingTeacherChart) {
+ $(".loading").removeClass("hide");
+ } else {
+ $(".loading").addClass("hide");
+ }
+ }, [isLoadingListOrganization, isLoadingStatisticCircle, isLoadingStudentChart, isLoadingTeacherChart])
+
+ const renderIconButton = () => {
+ return (
+
+ )
+ }
+
return (
-
-
-
- Vui lòng chọn 1 trường trong danh sách sau
-
-
Xuất excel
-
-
-
- {Array(12)
- .fill(0)
- .map((item, index) => {
- return (
-
handleSelectItem(item)}
- >
-
-
-
-
-
-
- Trường THCS Giao An
-
-
-
-
-
- Mức độ CĐS Sunday English
-
-
-
-
-
- Tiêu chí giao bài
-
-
+
+
+
+
+
+
+
+
+
+ Number(item?.total_teacher_assignment))}
+ labelsBarChart={dataTeacherChart?.map(item => item?.label)}
+ dataDoughnut={[data?.teacher_join, data?.total_teacher]}
+ titleDoughnut={'Giáo viên'}
+ subtitleDoughnut={'Số giáo viên đã tham gia'}
+ subTitleLine={"Số giáo viên giao bài trong tuần"}
+ />
+ Number(item?.total_student_learn))}
+ labelsBarChart={dataStudentChart?.map(item => item?.label)}
+ dataDoughnut={[data?.student_join, data?.total_student]}
+ titleDoughnut={'Học sinh'}
+ subtitleDoughnut={'Số học sinh đã tham gia'}
+ subTitleLine={"Số học sinh làm bài trong tuần"}
+ />
+
+
+
+
+ Top 10 giáo viên tiêu biểu
+ {renderIconButton()}
+
+
+
+
+
+
+
Danh sách trường
+
+
+ {!isLoadingListOrganization && !listOrganization?.length && (
+
+ Không có trường nào
+
+ )}
+ {listOrganization.map((item, index) => {
+ return (
+
goToDetailSchool(item)}>
+
+
+
-
-
- Tiêu chí tỷ lệ học sinh làm bài
-
-
+
+
+
+ {item?.organization_name}
+
+
+ {'Giáo viên tham gia: ' + (item?.total_join_teacher || 0) + '/' + (item?.total_real_teacher || 0)}
+
+
+ {'Học sinh tham gia: ' + (item?.total_join_student || 0) + '/' + (item?.total_real_student || 0)}
+
+
+
+
+
+ Mức độ CĐS Sunday English
+
+
+
+
+
+ Tiêu chí giao bài
+
+
+
+
+
+ Tiêu chí tỷ lệ học sinh làm bài
+
+
+
+
+
+ Số lượng active:{' '}
+ {item?.total_active_teacher || 0}
+ {' '}giáo viên |{' '}
+ {item?.total_active_student || 0}
+ {' '}học sinh
+
-
- );
- })}
+ );
+ })}
+
- );
-}
+ )
+}
\ No newline at end of file
diff --git a/src/_screens/home/education-department/educationDepartmentHome.style.scss b/src/_screens/home/education-department/educationDepartmentHome.style.scss
index 994bdd1..0cac2d4 100644
--- a/src/_screens/home/education-department/educationDepartmentHome.style.scss
+++ b/src/_screens/home/education-department/educationDepartmentHome.style.scss
@@ -1,109 +1,87 @@
@import "/src/_styles/mixin";
.education-department-home-container {
- overflow: auto;
display: flex;
- flex-direction: column;
+ overflow: hidden;
- .education-department-home-banner {
- width: 100%;
- height: 30%;
- background-image: url("../../../_assets/banner_education_department.png");
- background-position: bottom;
- background-repeat: no-repeat;
- -webkit-background-size: cover;
- -moz-background-size: cover;
- -o-background-size: cover;
- background-size: cover;
- display: flex;
- justify-content: center;
- align-items: flex-end;
-
- @include screen_pc_sm {
- height: 35%;
- }
-
- .input_text_base_container {
- width: unset;
- }
-
- .education-department-home-search {
- background-color: #fff;
- border-radius: 40px;
- margin-bottom: 16px;
- height: 46px;
- width: 392px;
+ .education-department-statistic-container {
+ flex: 0.7;
+ height: calc(100vh - var(--height-header));
+ padding: 2rem;
- @include screen_pc_sm {
- height: 36px;
- }
- }
- }
-
- .education-department-home-note {
- font-size: 2.2rem;
- font-weight: 700;
- text-align: center;
- margin-top: 24px;
-
- @include screen_pc_sm {
- margin-top: 16px;
+ .education-department-statistic-col {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
}
}
.education-department-home-list-container {
- flex: 1;
+ flex: 0.3;
+ height: calc(100vh - var(--height-header));
+ overflow: hidden;
+ padding: 2rem 0;
display: flex;
flex-direction: column;
- overflow: hidden;
- padding: 0 10% 2.4rem;
+ background-color: #fff;
- .education-department-home-list-room {
+ .education-department-home-note {
+ font-size: 2rem;
+ font-weight: 700;
+ padding-left: 3.2rem;
+ padding-bottom: 1.2rem;
+ }
+
+ .education-department-home-list-content {
flex: 1;
- margin-top: 12px;
display: flex;
- flex-wrap: wrap;
- justify-content: center;
- // align-items: center;
- column-gap: 40px;
- row-gap: 2.4rem;
+ flex-direction: column;
+ padding: 0 3.2rem;
- .education-department-home-item-room {
- max-width: 544px;
- min-width: 444px;
- height: fit-content;
- border-radius: 10px;
- border: 1px solid var(--primary-color);
- padding: 0.8rem 16px;
+ .education-department-home-list-room {
+ flex: 1;
display: flex;
- align-items: center;
- gap: 12px;
- background-color: #fff;
-
- &:hover {
- opacity: 0.8;
- cursor: pointer;
- }
+ flex-wrap: wrap;
+ flex-direction: column;
+ gap: 1.6rem;
- .education-department-home-item-img {
- width: 4.2rem;
- height: 4.2rem;
- border-radius: 50%;
- background-color: var(--second-color);
+ .education-department-home-item-room {
+ width: 100%;
+ height: fit-content;
+ border-radius: 10px;
+ border: 1px solid var(--primary-color);
+ padding: 0.8rem 16px;
display: flex;
align-items: center;
- justify-content: center;
+ gap: 12px;
+ background-color: #fff;
- svg {
- height: 2.8rem;
- width: 2.8rem;
+ &:hover {
+ opacity: 0.8;
+ cursor: pointer;
}
- }
- .education-department-home-item-text {
- font-size: 2rem;
+ .education-department-home-item-img {
+ width: 4.2rem;
+ height: 4.2rem;
+ border-radius: 50%;
+ background-color: var(--second-color);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ svg {
+ height: 2.8rem;
+ width: 2.8rem;
+ }
+ }
+
+ .education-department-home-item-text {
+ font-size: 1.6rem;
+ }
}
}
}
}
-}
+}
\ No newline at end of file
diff --git a/src/_screens/home/education-department/index.js b/src/_screens/home/education-department/index.js
index a38b64a..419c656 100644
--- a/src/_screens/home/education-department/index.js
+++ b/src/_screens/home/education-department/index.js
@@ -1,4 +1,4 @@
-import { useState } from "react";
+import { useEffect, useState } from "react";
import InputText from "../../../_components/Auth/InputText";
import Header from "../../../_components/Header";
import {
@@ -6,9 +6,91 @@ import {
renderIconSearchInput,
} from "../../../_components/renderIcon";
import "./educationDepartmentHome.style.scss";
+import { PRIMARY_COLOR } from "../../../_constants/common";
+import RDoughnutChart from "../../../_components/chart/RDoughnutChart";
+import BoxDoughnutChart from "../../../_components/boxChart/BoxDoughnutChar";
+import BoxDoughnutBarChart from "../../../_components/boxChart/BoxDoughnutBarChart";
+import PrimaryButton from "../../../_components/Button/PrimaryButton";
+import { apiCaller, history } from "../../../_helpers";
+import { PATH } from "../../../_constants";
+import { replacePathParams } from "../../../_helpers/utils";
+import { useSelector } from "react-redux";
export default function EducationDepartmentHome() {
- const [searchText, setSearchText] = useState("");
+ const authentication = useSelector((state) => state.authentication);
+ const [dateStudentChart, setDateStudentChart] = useState(new Date())
+ const [dateTeacherChart, setDateTeacherChart] = useState(new Date())
+ const [data, setData] = useState()
+ const [dataStudentChart, setDataStudentChart] = useState([])
+ const [dataTeacherChart, setDataTeacherChart] = useState([])
+ const [listOrganization, setListOrganization] = useState([])
+
+ const getDataOrganization = async () => {
+ try {
+ const res = await apiCaller("/report/api_report/listChildOrganization?organization_id=" + authentication?.user?.organization_id, "GET")
+ if (res?.status) {
+ setListOrganization(res?.data)
+ }
+ } catch (e) {
+
+ }
+ }
+
+ const getDataStatisticCircle = async () => {
+ try {
+ const res = await apiCaller("/report/api_report/statisticalInfoOrganization?organization_id=" + authentication?.user?.organization_id, "GET")
+ if (res?.status) {
+ setData(res?.data)
+ }
+ } catch (e) {
+
+ }
+ }
+
+ const getDataStudentChart = async () => {
+ try {
+ const endPoint = '/report/api_report/homeworkChartInfo?organization_id=' + authentication?.user?.organization_id +
+ '&month='+ (dateStudentChart.getMonth() + 1) + '&year=' + dateStudentChart.getFullYear()
+
+ const res = await apiCaller(endPoint, "GET")
+ if (res?.status) {
+ setDataStudentChart(res?.data)
+ }
+ } catch (e) { }
+ }
+
+ const getDataTeacherChart = async () => {
+ try {
+ const endPoint = '/report/api_report/assignmentChartInfo?organization_id=' + authentication?.user?.organization_id +
+ '&month='+ (dateTeacherChart.getMonth() + 1) + '&year=' + dateTeacherChart.getFullYear()
+
+ const res = await apiCaller(endPoint, "GET")
+ if (res?.status) {
+ setDataTeacherChart(res?.data)
+ }
+ } catch (e) { }
+ }
+
+ const goToOutstandingTeacher = () => {
+ history.push(replacePathParams(PATH.home.outstandingTeacherByEducation, {id: authentication?.user?.organization_id}))
+ }
+
+ const goToDetailRoomEducation = (item) => {
+ history.push(replacePathParams(PATH.home.detailRoomEducation, {idRoom: item?.id}))
+ }
+
+ useEffect(() => {
+ getDataOrganization()
+ getDataStatisticCircle()
+ }, [])
+
+ useEffect(() => {
+ getDataStudentChart()
+ }, [dateStudentChart])
+
+ useEffect(() => {
+ getDataTeacherChart()
+ }, [dateTeacherChart])
const renderIconBook = () => {
return (
@@ -27,6 +109,12 @@ export default function EducationDepartmentHome() {
);
};
+ const renderIconButton = () => {
+ return (
+
+ )
+ }
+
return (
-
-
-
+
+
+ {!!data &&
+
+
+
+
+
+
+ Number(item?.total_teacher_assignment))}
+ labelsBarChart={dataTeacherChart?.map(item => item?.label)}
+ dataDoughnut={[data?.teacher_join, data?.total_teacher]}
+ titleDoughnut={'Giáo viên'}
+ subtitleDoughnut={'Số giáo viên đã tham gia'}
+ subTitleLine={"Số giáo viên giao bài trong tuần"}
+ />
+
+
+ Number(item?.total_student_learn))}
+ labelsBarChart={dataStudentChart?.map(item => item?.label)}
+ dataDoughnut={[data?.student_join, data?.total_student]}
+ titleDoughnut={'Học sinh'}
+ subtitleDoughnut={'Số học sinh đã tham gia'}
+ subTitleLine={"Số học sinh làm bài trong tuần"}
+ />
+
+
}
+
+
+ Top 10 giáo viên tiêu biểu
+ {renderIconButton()}
+
+
-
- Vui lòng chọn Phòng Giáo Dục trong danh sách sau
-
-
- {Array(12)
- .fill(0)
- .map((item, index) => (
-
-
- {renderIconBook()}
+
+ Danh sách phòng giáo dục
+
+
+
+ {listOrganization.map((item, index) => (
+
goToDetailRoomEducation(item)}
+ >
+
+ {renderIconBook()}
+
+
+ {item?.name}
+
-
- Phòng giáo dục huyện Giao Thủy
-
-
- ))}
+ ))}
+
diff --git a/src/_screens/home/outstanding-teacher/index.js b/src/_screens/home/outstanding-teacher/index.js
new file mode 100644
index 0000000..cdb335e
--- /dev/null
+++ b/src/_screens/home/outstanding-teacher/index.js
@@ -0,0 +1,187 @@
+import { useEffect, useState } from "react";
+import Header from "../../../_components/Header";
+import { renderIconHome } from "../../../_components/renderIcon";
+import RateStar from "../../../_components/RateStar";
+import { defaultMonthYearSemester, getListMonthBySemester, LIST_SCHOOL_YEAR, LIST_SEMESTER } from "../../../_constants/common";
+import { configConstants } from "../../../_constants";
+import RootSelect from "../../../_components/RootSelect";
+import PrimaryButton from "../../../_components/Button/PrimaryButton";
+import { useSelector } from "react-redux";
+import './outstandingTeacher.style.scss'
+import { apiCaller } from "../../../_helpers";
+import { useParams } from "react-router-dom";
+
+export default function OutstandingTeacher() {
+
+ const {id} = useParams()
+ const authentication = useSelector((state) => state.authentication);
+ const grade = useSelector((state) => state.grade);
+ const [schoolYear, setSchoolYear] = useState(
+ grade?.filterGrade?.schoolYear,
+ );
+ const [semester, setSemester] = useState(grade?.filterGrade?.semester);
+ const [month, setMonth] = useState(grade?.filterGrade?.month);
+ const [firstTeacher, setFirstTeacher] = useState();
+ const [listTeacher, setListTeacher] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const getData = async () => {
+ setIsLoading(true)
+ try {
+ const endPoint = `/report/api_report/outStandingTeachers?organization_id=${id}&year=${schoolYear?.value}${!!semester?.value ? `&semester=${semester?.value}` : ""}${!!month?.value ? `&month=${month?.value}` : ""}`
+ const res = await apiCaller(endPoint, "GET")
+ if (res.status) {
+ const firstTeacher = res?.data?.[0];
+ const listTeacher = res?.data?.slice(1);
+ setFirstTeacher(firstTeacher);
+ setListTeacher(listTeacher);
+ setIsLoading(false)
+ }
+ } catch (err) {
+ setIsLoading(false)
+ }
+ }
+
+ const changeSemester = (item) => {
+ setSemester(item);
+ setMonth(getListMonthBySemester(item?.value)?.[0]);
+ };
+
+ const handleFilter = () => {
+ getData();
+ };
+
+ useEffect(() => {
+ getData()
+ }, [])
+
+ return (
+
+
+
+
+
+
+ {!!firstTeacher &&
+
+
+
+
+
+
+
+
{firstTeacher?.teacher_name}
+
+
{firstTeacher?.district_name}
+
{firstTeacher?.school_name}
+
+
+
+
+
+ Mức độ CĐS Sunday English
+
+
+
+
+
+ Tiêu chí giao bài
+
+
+
+
+
+ Tiêu chí tỷ lệ học sinh làm bài
+
+
+
+
+
+
+
}
+
+
+
+
+ {!isLoading && !listTeacher?.length && (
+
+ Không có giáo viên nào
+
+ )}
+ {listTeacher.map((item, index) => {
+ return (
+
handleClickTeacherItem(item)}>
+ {index === 0 &&
}
+ {index === 1 &&
}
+
+
+
+
+
+
+ {(index + 2) + '. ' + item?.teacher_name}
+
+
+ {item?.email}
+
+
+ {item?.phone}
+
+
+
+
+
+ Mức độ CĐS Sunday English
+
+
+
+
+
+ Tiêu chí giao bài
+
+
+
+
+
+ Tiêu chí tỷ lệ học sinh làm bài
+
+
+
+
+
+
+ );
+ })}
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/_screens/home/outstanding-teacher/outstandingTeacher.style.scss b/src/_screens/home/outstanding-teacher/outstandingTeacher.style.scss
new file mode 100644
index 0000000..8bcf2d2
--- /dev/null
+++ b/src/_screens/home/outstanding-teacher/outstandingTeacher.style.scss
@@ -0,0 +1,243 @@
+@import "/src/_styles/mixin";
+
+.outstanding-teacher-container {
+ display: flex;
+ padding: 24px 0 48px;
+ // overflow: hidden;
+
+ @include screen_pc_sm {
+ padding: 16px 0;
+ }
+
+ .outstanding-teacher-left-side {
+ width: 30%;
+ border-right: 1px solid #4d4d4d;
+ display: flex;
+ flex-direction: column;
+
+ .outstanding-teacher-form-select {
+ padding: 0 32px;
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ }
+
+ .outstanding-teacher-best-container {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ padding: 0 32px;
+ margin-top: 3.2rem;
+
+ @include screen_pc_sm {
+ margin-top: 2rem;
+
+ }
+
+ .outstanding-teacher-best-avatar-content {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ .outstanding-teacher-best-avatar-box {
+ height: 90%;
+ aspect-ratio: 1;
+ padding: 0.8rem;
+ border-radius: 50%;
+ border: 1px solid #fff;
+ position: relative;
+
+ .outstanding-teacher-best-crown {
+ position: absolute;
+ top: -30%;
+ left: -16%;
+ height: 70%;
+ width: 70%;
+ }
+
+ .outstanding-teacher-best-avatar {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ border-radius: 50%;
+ box-shadow: rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px;
+ }
+ }
+
+ }
+
+ .outstanding-teacher-best-info {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ .outstanding-teacher-best-name {
+ color: #fff;
+ font-size: 2.4rem;
+ font-weight: 700;
+ align-self: center;
+ }
+
+ .outstanding-teacher-best-address {
+ padding: .4rem;
+ border-radius: 2.4rem;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: rgba(17, 17, 17, 0.3);
+ color: #fff;
+ }
+
+ .outstanding-teacher-best-criteria {
+ background-color: #fff;
+ width: 100%;
+ padding: 1.6rem;
+ border-radius: .8rem;
+ margin-top: 1.6rem;
+ }
+ }
+ }
+ }
+
+ .outstanding-teacher-right-side {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ padding-right: 8px;
+
+ .outstanding-teacher-right-p-h {
+ padding-right: 32px;
+ }
+
+ .outstanding-teacher-list-container {
+
+ .outstanding-teacher-list {
+ flex: 1;
+ gap: 20px;
+ display: flex;
+ flex-direction: column;
+ margin-top: 16px;
+ padding-bottom: 16px;
+ padding-left: 32px;
+
+ @include screen_pc_sm {
+ gap: 16px;
+ }
+
+ .outstanding-teacher-item {
+ padding: 8px;
+ border: 1.25px solid #e5e5e5;
+ border-radius: 4px;
+ display: flex;
+ gap: 16px;
+ background-color: #fff;
+ transition: all 0.5s linear;
+ position: relative;
+
+ &:hover {
+ opacity: 0.8;
+ cursor: pointer;
+ }
+
+ .outstanding-teacher-silver-medal,
+ .outstanding-teacher-copper-medal {
+ width: 3.2rem;
+ height: 4.9rem;
+ object-fit: cover;
+ position: absolute;
+ top: -1rem;
+ left: -1.6rem;
+ }
+
+ .outstanding-teacher-avatar {
+ width: 88px;
+ height: 88px;
+ border-radius: 5px;
+ box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px,
+ rgba(60, 64, 67, 0.15) 0px 2px 6px 2px;
+
+ @include screen_pc_sm {
+ height: 70px;
+ width: 70px;
+ }
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ border-radius: 5px;
+ }
+ }
+
+ .outstanding-teacher-detail {
+ display: flex;
+ flex: 1;
+ justify-content: space-between;
+ gap: 24px;
+
+ .outstanding-teacher-info {
+ display: flex;
+ flex-direction: column;
+
+ .outstanding-teacher-info-name {
+ font-size: 2rem;
+ font-weight: 700;
+ color: var(--primary-color);
+ }
+
+ .outstanding-teacher-info-text {
+ font-size: 1.8rem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+
+ .outstanding-teacher-criteria {
+ display: flex;
+ flex-direction: column;
+
+ .outstanding-teacher-criteria-title {
+ font-size: 2rem;
+ font-weight: 700;
+ color: var(--primary-color);
+ }
+
+ .outstanding-teacher-criteria-row {
+ display: flex;
+ justify-content: space-between;
+ gap: 8px;
+
+ .criteria-teacher-title {
+ font-size: 2rem;
+ font-weight: 700;
+ }
+
+ .outstanding-teacher-criteria-ratio {
+ font-size: 1.8rem;
+ font-weight: 400;
+ position: relative;
+ padding-left: 12px;
+
+ &::before {
+ content: "";
+ display: block;
+ position: absolute;
+ left: 0;
+ top: 12px;
+ width: 5px;
+ height: 5px;
+ background-color: var(--primary-color);
+ border-radius: 50%;
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/_screens/login/index.js b/src/_screens/login/index.js
index 2583af4..ab9d51d 100644
--- a/src/_screens/login/index.js
+++ b/src/_screens/login/index.js
@@ -96,7 +96,7 @@ export default function Login() {
},
});
// if (user?.user_role === USER_ROLE.TEACHER) {
- history.push(routeHome(user?.role));
+ history.push(routeHome(user));
// }
};