forked from HoangLaoTa/gk_se_web_report
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, |
||||||
|
}, |
||||||
|
], |
||||||
|
}} />; |
||||||
|
} |
@ -1,144 +1,159 @@ |
|||||||
@import "/src/_styles/mixin"; |
@import "/src/_styles/mixin"; |
||||||
|
|
||||||
.detail-room-education-container { |
.detail-room-education-container { |
||||||
padding: 24px 0 48px; |
|
||||||
display: flex; |
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; |
display: flex; |
||||||
gap: 16px; |
flex-direction: column; |
||||||
justify-content: space-between; |
padding: 16px 0; |
||||||
align-items: center; |
|
||||||
padding: 0 24px 0 20rem; |
|
||||||
|
|
||||||
.detail-room-education-note { |
.detail-room-education-statistic-container { |
||||||
flex: 1; |
flex: 1; |
||||||
text-align: center; |
max-height: 95%; |
||||||
font-weight: 700; |
padding: 0 2rem 2rem; |
||||||
font-size: 2.2rem; |
display: flex; |
||||||
|
flex-direction: column; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
.detail-room-education-list-container { |
.detail-room-education-right-side { |
||||||
padding: 4rem 24rem 0; |
|
||||||
flex: 1; |
flex: 1; |
||||||
display: flex; |
display: flex; |
||||||
flex-direction: column; |
flex-direction: column; |
||||||
overflow: hidden; |
padding-right: 8px; |
||||||
|
background-color: #fff; |
||||||
|
|
||||||
.detail-room-education-list-school { |
.detail-room-education-right-p-h { |
||||||
// margin-top: 16px; |
padding-right: 32px; |
||||||
padding-bottom: 16px; |
} |
||||||
padding-right: 24px; |
|
||||||
margin-right: -24px; |
.detail-room-education-list-container { |
||||||
flex: 1; |
padding: 2rem 0; |
||||||
gap: 20px; |
|
||||||
display: flex; |
display: flex; |
||||||
flex-direction: column; |
flex-direction: column; |
||||||
|
height: 100%; |
||||||
|
|
||||||
@include screen_pc_sm { |
.detail-room-education-list { |
||||||
gap: 16px; |
|
||||||
} |
|
||||||
|
|
||||||
.detail-room-education-item-school { |
|
||||||
padding: 8px; |
|
||||||
border: 1px solid #e5e5e5; |
|
||||||
border-radius: 6px; |
|
||||||
display: flex; |
|
||||||
gap: 16px; |
|
||||||
background-color: #fff; |
|
||||||
flex: 1; |
flex: 1; |
||||||
|
gap: 20px; |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
padding-bottom: 16px; |
||||||
|
padding-left: 32px; |
||||||
|
|
||||||
&:hover { |
@include screen_pc_sm { |
||||||
opacity: 0.8; |
gap: 16px; |
||||||
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; |
|
||||||
} |
|
||||||
} |
} |
||||||
|
|
||||||
.detail-room-education-detail-school { |
.detail-room-education-item { |
||||||
display: flex; |
padding: 8px; |
||||||
flex: 1; |
border: 1.25px solid var(--primary-color); |
||||||
justify-content: space-between; |
border-radius: 4px; |
||||||
gap: 24px; |
background-color: #fff; |
||||||
|
transition: all 0.5s linear; |
||||||
.detail-room-education-info-school { |
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px; |
||||||
display: flex; |
|
||||||
align-items: center; |
&:hover { |
||||||
|
opacity: 0.8; |
||||||
.criteria-info-school-name { |
cursor: pointer; |
||||||
font-size: 2rem; |
|
||||||
font-weight: 700; |
|
||||||
color: var(--primary-color); |
|
||||||
} |
|
||||||
|
|
||||||
.criteria-info-school-text { |
|
||||||
font-size: 1.8rem; |
|
||||||
} |
|
||||||
} |
} |
||||||
|
|
||||||
.detail-room-education-criteria-class { |
.detail-room-education-item-content { |
||||||
display: flex; |
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 { |
img { |
||||||
font-size: 2rem; |
width: 100%; |
||||||
font-weight: 700; |
height: 100%; |
||||||
color: var(--primary-color); |
object-fit: cover; |
||||||
|
border-radius: 5px; |
||||||
|
} |
||||||
} |
} |
||||||
|
|
||||||
.criteria-class-row { |
.detail-room-education-detail { |
||||||
display: flex; |
display: flex; |
||||||
|
flex: 1; |
||||||
justify-content: space-between; |
justify-content: space-between; |
||||||
gap: 8px; |
gap: 24px; |
||||||
|
|
||||||
.criteria-class-title { |
.detail-room-education-info { |
||||||
font-size: 2rem; |
display: flex; |
||||||
font-weight: 700; |
flex-direction: column; |
||||||
} |
|
||||||
|
|
||||||
.criteria-class-criteria { |
.detail-room-education-info-name { |
||||||
font-size: 1.8rem; |
font-size: 2rem; |
||||||
font-weight: 400; |
font-weight: 700; |
||||||
position: relative; |
color: var(--primary-color); |
||||||
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-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%; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
} |
} |
@ -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