parent
0181865128
commit
391738c4e1
39 changed files with 2493 additions and 374 deletions
After Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 20 KiB |
@ -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 ( |
||||
<div |
||||
className={ |
||||
(fullHeight || showAll ? "fullHeight " : "") + |
||||
(collapse ? " collapse" : "") + |
||||
(showMonth ? " showMonth" : "") |
||||
} |
||||
> |
||||
<div className="calendar"> |
||||
<div |
||||
className={ |
||||
"header day-calendar-custom" + |
||||
(collapse && !showMonth ? "hide" : "") |
||||
} |
||||
> |
||||
<button |
||||
type="button" |
||||
className={"nav nav--prev"} |
||||
onClick={handlePrev} |
||||
> |
||||
<img |
||||
alt="ico_left_calender" |
||||
src="/assets/images/icon/ico_left_calender.png" |
||||
/> |
||||
</button> |
||||
<div className="datetime">{"Tháng " + dayObj.format("M/YYYY")}</div> |
||||
<button |
||||
type="button" |
||||
className={"nav nav--prev"} |
||||
onClick={handleNext} |
||||
> |
||||
<img |
||||
alt="ico_right_calender" |
||||
src="/assets/images/icon/ico_right_calender.png" |
||||
/> |
||||
</button> |
||||
</div> |
||||
<div className="week-container fix-nowap-row-calendar"> |
||||
{weekDays.map((d) => ( |
||||
<div |
||||
className={`${ |
||||
homePageTeacherCalendaSchedule |
||||
? "homePageTeacherCalendaSchedule" |
||||
: "" |
||||
} week-cell flex-1`}
|
||||
key={d} |
||||
> |
||||
{d} |
||||
</div> |
||||
))} |
||||
</div> |
||||
<div className="day-container"> |
||||
{showWeekDayOf1() && |
||||
range(weekDayOf1).map((i) => ( |
||||
<div className={"day-box"} key={i}> |
||||
<div |
||||
className={ |
||||
`${ |
||||
homePageTeacherCalendaSchedule |
||||
? "homePageTeacherCalendaSchedule" |
||||
: "" |
||||
} day-cell day-cell--faded` +
|
||||
renderClassHideCollapse( |
||||
dayObjOf1.subtract(weekDayOf1 - i, "day").date() + 1, |
||||
todayObj.month(), |
||||
todayObj.year() |
||||
) + |
||||
renderClass( |
||||
dayObjOf1.subtract(weekDayOf1 - i, "day").date() + 1, |
||||
todayObj.month(), |
||||
todayObj.year() |
||||
) |
||||
} |
||||
key={i} |
||||
> |
||||
{dayObjOf1.subtract(weekDayOf1 - i, "day").date()} |
||||
</div> |
||||
</div> |
||||
))} |
||||
|
||||
{range(daysInMonth).map((i) => ( |
||||
<div className={"day-box" + renderClassShot(i + 1)} key={i}> |
||||
<div |
||||
className={ |
||||
`${ |
||||
homePageTeacherCalendaSchedule |
||||
? "homePageTeacherCalendaSchedule" |
||||
: "" |
||||
} rel day-cell day-cell--in-month${ |
||||
i + 1 == todayObj.date() && |
||||
thisMonth == todayObj.month() && |
||||
thisYear == todayObj.year() |
||||
? " day-cell--today" |
||||
: "" |
||||
}${ |
||||
i + 1 == selectDate.day && |
||||
selectDate.month == thisMonth && |
||||
selectDate.year == thisYear |
||||
? " active" |
||||
: "" |
||||
}` +
|
||||
renderClass(i + 1, thisMonth + 1, thisYear) + |
||||
renderClassHideCollapse(i + 1, thisMonth + 1, thisYear) + |
||||
renderClassShot(i + 1) |
||||
} |
||||
key={i} |
||||
onClick={() => selectDay(thisYear, thisMonth, i + 1)} |
||||
> |
||||
{i + 1} |
||||
<img |
||||
alt="ico_check_calendar" |
||||
src="/assets/images/icon/ico_check_calendar.png" |
||||
className="img-check-calendar" |
||||
/> |
||||
<img |
||||
alt="ico_missing_calendar" |
||||
src="/assets/images/icon/ico_missing_calendar.png" |
||||
className="img-missing-calendar" |
||||
/> |
||||
<img |
||||
alt="ico_active_calendar_green" |
||||
src="/assets/images/icon/ico_green_circle.png" |
||||
className="img-active_dot-calendar" |
||||
/> |
||||
</div> |
||||
</div> |
||||
))} |
||||
|
||||
{range(6 - weekDayOfLast).map((i) => ( |
||||
<div className={"day-box"} key={i}> |
||||
<div |
||||
className={ |
||||
`${ |
||||
homePageTeacherCalendaSchedule |
||||
? "homePageTeacherCalendaSchedule" |
||||
: "" |
||||
} day-cell day-cell--faded` +
|
||||
renderClassHideCollapse( |
||||
dayObjOfLast.add(i + 1, "day").date(), |
||||
todayObj.month() + 2, |
||||
todayObj.year() |
||||
) + |
||||
renderClass( |
||||
dayObjOfLast.add(i + 1, "day").date(), |
||||
todayObj.month() + 2, |
||||
todayObj.year() |
||||
) |
||||
} |
||||
key={i} |
||||
> |
||||
{dayObjOfLast.add(i + 1, "day").date()} |
||||
</div> |
||||
</div> |
||||
))} |
||||
</div> |
||||
</div> |
||||
{collapse && ( |
||||
<div className="btn-collapse" onClick={() => showFullHeight()}> |
||||
{fullHeight ? ( |
||||
<img |
||||
src="/assets/images/student/ico_dropup_blue.png" |
||||
alt="ico_dropup_blue" |
||||
className="ico-calender-collapse" |
||||
/> |
||||
) : ( |
||||
<img |
||||
src="/assets/images/student/ico_dropdown_blue.png" |
||||
alt="ico_dropdown_blue" |
||||
className="ico-calender-collapse" |
||||
/> |
||||
)} |
||||
</div> |
||||
)} |
||||
</div> |
||||
); |
||||
} |
||||
|
||||
export { CalendaSchedule }; |
@ -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(<option key={i} >{i}</option>); |
||||
} |
||||
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 ( |
||||
<div className="select-gr"> |
||||
<select onChange={handleChange} name={'day'} value={parseInt(defaultValueDate)}> |
||||
{createElementsOption(1, (new Date(defaultValueYear, defaultValueMonth, 0)).getDate()) || 31} |
||||
</select> |
||||
<select onChange={handleChange} name={'month'} value={parseInt(defaultValueMonth)}> |
||||
{createElementsOption(1, 12)} |
||||
</select> |
||||
<select onChange={handleChange} name={'year'} value={parseInt(defaultValueYear)}> |
||||
{createElementsOption(2000, 2099)} |
||||
</select> |
||||
</div> |
||||
); |
||||
} |
||||
|
||||
export { PickDay }; |
@ -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 ( |
||||
<Fragment> |
||||
<DatePicker |
||||
minDate={minDate ? new Date() : {}} |
||||
onChangeRaw={(e) => 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} |
||||
/> |
||||
</Fragment> |
||||
); |
||||
} |
||||
|
||||
export { SelectDate }; |
@ -0,0 +1,3 @@ |
||||
export * from './CalendaSchedule'; |
||||
export * from './PickDay'; |
||||
export * from './SelectDate'; |
@ -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 |
||||
} |
||||
} |
@ -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 ( |
||||
<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 20 20"> |
||||
<path
|
||||
fill="#00bbb5"
|
||||
d="M5.673 0a.7.7 0 0 1 .7.7v1.309h7.517v-1.3a.7.7 0 0 1 1.4 0v1.3H18a2 2 0 0 1 2 1.999v13.993A2 2 0 0 1 18 20H2a2 2 0 0 1-2-1.999V4.008a2 2 0 0 1 2-1.999h2.973V.699a.7.7 0 0 1 .7-.699M1.4 7.742v10.259a.6.6 0 0 0 .6.6h16a.6.6 0 0 0 .6-.6V7.756zm5.267 6.877v1.666H5v-1.666zm4.166 0v1.666H9.167v-1.666zm4.167 0v1.666h-1.667v-1.666zm-8.333-3.977v1.666H5v-1.666zm4.166 0v1.666H9.167v-1.666zm4.167 0v1.666h-1.667v-1.666zM4.973 3.408H2a.6.6 0 0 0-.6.6v2.335l17.2.014V4.008a.6.6 0 0 0-.6-.6h-2.71v.929a.7.7 0 0 1-1.4 0v-.929H6.373v.92a.7.7 0 0 1-1.4 0z" |
||||
/> |
||||
</svg> |
||||
) |
||||
} |
||||
|
||||
return ( |
||||
<div className="box-chart-container"> |
||||
<div style={{borderBottom: '1px solid #c4c4c4', paddingBottom: '1.6rem', flex: 0.38, display: 'flex', flexDirection: 'column'}}> |
||||
{!!titleDoughnut && <p className='box-chart-title'>{titleDoughnut}</p>} |
||||
{!!subtitleDoughnut && <p className='box-chart-subtitle'>{subtitleDoughnut}</p>} |
||||
<div className='d-flex flex-1'> |
||||
<div className='doughnut-chart-content flex-1'> |
||||
<RDoughnutChart data={_dataDoughnut} /> |
||||
</div> |
||||
<div className='origin-vertical justify-content-center align-item-center flex-1'> |
||||
<p style={{fontSize: '1.8rem'}}>{dataDoughnut?.[0] + '/' + dataDoughnut?.[1]}</p> |
||||
<p style={{color: PRIMARY_COLOR, fontSize: '2.2rem', fontWeight: 800}}>{Math.round(dataDoughnut?.[0]/dataDoughnut?.[1] * 100) + '%'}</p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div className='d-flex' style={{marginTop: '1.2rem', flexDirection: 'column', flex: 0.62}}> |
||||
{!!titleLine && <p className='box-chart-title'>{titleLine}</p>} |
||||
{!!subTitleLine && <p className='box-chart-subtitle'>{subTitleLine}</p>} |
||||
<div className='flex-1' style={{padding: '1.6rem 0'}}> |
||||
<VerticalBarChart data={dataBarChart} labels={labelsBarChart}/> |
||||
</div> |
||||
</div> |
||||
<div className='d-flex justify-content-center align-item-center' style={{width: 140, alignSelf: 'center'}}> |
||||
{/* {renderArrowLeft()} |
||||
<span style={{padding: '0 2rem', fontSize: '1.8rem'}}>Tháng 11</span> |
||||
{renderArrowRight()} */} |
||||
<InputDate |
||||
maxDate={new Date()} |
||||
label={''} |
||||
styleContainer={{flex: 1}} |
||||
value={month} |
||||
setValue={changeMonth} |
||||
name="month" |
||||
renderLabelIcon={renderIconDate} |
||||
errorText={monthError} |
||||
errorAbsolute={true} |
||||
// placeholder={"Chọn ngày sinh"}
|
||||
popperPlacement='top' |
||||
typeErrText='underAbsolute' |
||||
isMonthPicker |
||||
/> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
@ -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 ( |
||||
<div className="box-chart-container" {...propsContainer}> |
||||
<p className='box-chart-subtitle'>{title}</p> |
||||
<div className='d-flex flex-1'> |
||||
<div className='doughnut-chart-content flex-1'><RDoughnutChart data={_data} /></div> |
||||
<div className='origin-vertical justify-content-center align-item-center flex-1'> |
||||
<p style={{fontSize: '1.8rem'}}>{data?.[0] + '/' + data?.[1]}</p> |
||||
<p style={{color: PRIMARY_COLOR, fontSize: '2.2rem', fontWeight: 800}}>{Math.round(data?.[0]/data?.[1] * 100) + '%'}</p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
@ -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 {} |
||||
} |
@ -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 <Chart
|
||||
type='doughnut'
|
||||
data={{ |
||||
labels: [], |
||||
datasets: [ |
||||
{ |
||||
label: '', |
||||
data, |
||||
backgroundColor: [ |
||||
PRIMARY_COLOR, '#01AEF0' |
||||
], |
||||
borderWidth: 0 |
||||
}, |
||||
], |
||||
}}
|
||||
options={{ |
||||
responsive: true, |
||||
maintainAspectRatio: false, |
||||
plugins: { |
||||
tooltip: { |
||||
enabled: false |
||||
} |
||||
} |
||||
}} |
||||
{...other}
|
||||
/>; |
||||
} |
@ -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 <Pie data={data} {...other} />; |
||||
} |
@ -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 <Bar options={options} data={{ |
||||
labels, |
||||
datasets: [ |
||||
{ |
||||
data, |
||||
backgroundColor: PRIMARY_COLOR, |
||||
barPercentage: 0.4, |
||||
}, |
||||
], |
||||
}} />; |
||||
} |
@ -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 ( |
||||
<div className="flex-1"> |
||||
<Header |
||||
icon={renderIconHome({ color: "#4D4D4D" })} |
||||
title={"Top 10 giáo viên tiêu biểu - Tỉnh Nam Định"} |
||||
/> |
||||
<div className="container-page-header container-page-sidebar"> |
||||
<div className="outstanding-teacher-container bg-outstanding-img"> |
||||
<div className="outstanding-teacher-left-side"> |
||||
<div className="outstanding-teacher-form-select"> |
||||
<RootSelect |
||||
data={LIST_SCHOOL_YEAR} |
||||
value={schoolYear} |
||||
setValue={setSchoolYear} |
||||
bgWhite |
||||
/> |
||||
<RootSelect |
||||
data={LIST_SEMESTER} |
||||
value={semester} |
||||
setValue={changeSemester} |
||||
bgWhite |
||||
/> |
||||
<RootSelect |
||||
data={getListMonthBySemester(semester.value)} |
||||
value={month} |
||||
setValue={setMonth} |
||||
bgWhite |
||||
/> |
||||
<PrimaryButton style={{ alignSelf: "center", marginTop: 8 }} onClick={handleFilter}> |
||||
Áp dụng |
||||
</PrimaryButton> |
||||
</div> |
||||
{!!firstTeacher && <div className="outstanding-teacher-best-container"> |
||||
<div className="outstanding-teacher-best-avatar-content"> |
||||
<div className="outstanding-teacher-best-avatar-box"> |
||||
<img className="outstanding-teacher-best-crown" src="/assets/imgs/crown_warning.png" /> |
||||
<img className="outstanding-teacher-best-avatar" src={configConstants.BASE_URL + firstTeacher?.avatar} /> |
||||
</div> |
||||
</div> |
||||
<div className="outstanding-teacher-best-info"> |
||||
<span className="outstanding-teacher-best-name">{firstTeacher?.teacher_name}</span> |
||||
<div className="flex flex-m" style={{gap: '1.6rem', width: '100%', marginTop: '1rem'}}> |
||||
<div className="flex-1 outstanding-teacher-best-address">{firstTeacher?.district_name}</div> |
||||
<div className="flex-1 outstanding-teacher-best-address">{firstTeacher?.school_name}</div> |
||||
</div> |
||||
<div className="outstanding-teacher-best-criteria"> |
||||
<div className="outstanding-teacher-criteria"> |
||||
<div className="outstanding-teacher-criteria-row"> |
||||
<p className="outstanding-teacher-criteria-title"> |
||||
Mức độ CĐS Sunday English |
||||
</p> |
||||
<RateStar rate={firstTeacher?.criteria_teacher?.criteria_level} /> |
||||
</div> |
||||
<div className="outstanding-teacher-criteria-row"> |
||||
<p className="outstanding-teacher-criteria-ratio"> |
||||
Tiêu chí giao bài |
||||
</p> |
||||
<RateStar rate={firstTeacher?.criteria_teacher?.assign_number_level} /> |
||||
</div> |
||||
<div className="outstanding-teacher-criteria-row"> |
||||
<p className="outstanding-teacher-criteria-ratio"> |
||||
Tiêu chí tỷ lệ học sinh làm bài |
||||
</p> |
||||
<RateStar rate={firstTeacher?.criteria_teacher?.student_done_per_level} /> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div>} |
||||
</div> |
||||
<div className="outstanding-teacher-right-side"> |
||||
<div className="outstanding-teacher-list-container outstanding-teacher-right-p-h scrollbar-custom"> |
||||
<div className="outstanding-teacher-list"> |
||||
{!isLoading && !listTeacher?.length && ( |
||||
<p style={{fontSize: '1.8rem', fontWeight: 700}}> |
||||
Không có giáo viên nào |
||||
</p> |
||||
)} |
||||
{listTeacher.map((item, index) => { |
||||
return ( |
||||
<div className="outstanding-teacher-item" key={index} onClick={() => handleClickTeacherItem(item)}> |
||||
{index === 0 && <img src="/assets/imgs/silver_medal.png" className="outstanding-teacher-silver-medal" />} |
||||
{index === 1 && <img src="/assets/imgs/copper_medal.png" className="outstanding-teacher-copper-medal" />} |
||||
<div className="outstanding-teacher-avatar"> |
||||
<img src={configConstants.BASE_URL + item?.avatar} /> |
||||
</div> |
||||
<div className="outstanding-teacher-detail"> |
||||
<div className="outstanding-teacher-info"> |
||||
<p className="outstanding-teacher-info-name"> |
||||
{(index + 2) + '. ' + item?.teacher_name} |
||||
</p> |
||||
<p className="outstanding-teacher-info-text"> |
||||
{item?.email} |
||||
</p> |
||||
<p className="outstanding-teacher-info-text"> |
||||
{item?.phone} |
||||
</p> |
||||
</div> |
||||
<div className="outstanding-teacher-criteria"> |
||||
<div className="outstanding-teacher-criteria-row"> |
||||
<p className="outstanding-teacher-criteria-title"> |
||||
Mức độ CĐS Sunday English |
||||
</p> |
||||
<RateStar rate={item?.criteria_teacher?.criteria_level} /> |
||||
</div> |
||||
<div className="outstanding-teacher-criteria-row"> |
||||
<p className="outstanding-teacher-criteria-ratio"> |
||||
Tiêu chí giao bài |
||||
</p> |
||||
<RateStar rate={item?.criteria_teacher?.assign_number_level} /> |
||||
</div> |
||||
<div className="outstanding-teacher-criteria-row"> |
||||
<p className="outstanding-teacher-criteria-ratio"> |
||||
Tiêu chí tỷ lệ học sinh làm bài |
||||
</p> |
||||
<RateStar rate={item?.criteria_teacher?.student_done_per_level} /> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
); |
||||
})} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
@ -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%; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
Loading…
Reference in new issue