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} + ico_check_calendar + ico_missing_calendar + ico_active_calendar_green +
+
+ ))} + + {range(6 - weekDayOfLast).map((i) => ( +
+
+ {dayObjOfLast.add(i + 1, "day").date()} +
+
+ ))} +
+
+ {collapse && ( +
showFullHeight()}> + {fullHeight ? ( + ico_dropup_blue + ) : ( + ico_dropdown_blue + )} +
+ )} +
+ ); +} + +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(); + } + 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 ( +
+ + + +
+ ); +} + +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 +
+ + + + + Áp dụ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 ( +
+
+
+
+
+
+ + + + + Áp dụng + +
+ {!!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)); // } };