From c1d0b7ce410de0b178d245a99c339220b63d903f Mon Sep 17 00:00:00 2001 From: Quy_FE Date: Thu, 24 Apr 2025 17:22:46 +0700 Subject: [PATCH 1/9] =?UTF-8?q?Feat=20:=20s=E1=BB=ADa=20t=C3=AAn=20c?= =?UTF-8?q?=E1=BB=A7a=20hi=E1=BB=87u=20tr=C6=B0=E1=BB=9Fng?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/_components/Header/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/_components/Header/index.js b/src/_components/Header/index.js index 43db49e..f95383f 100644 --- a/src/_components/Header/index.js +++ b/src/_components/Header/index.js @@ -7,7 +7,9 @@ export default function Header({ icon, title, subtitles = [] }) { const { fullname, organization_name, role } = authentication?.user || {}; const hasFullName = fullname || organization_name; - const fullName = role === "organization_admin" ? `Hiệu trưởng ${hasFullName}` : fullname; + const fullName = role === "organization_admin" + ? `${organization_name && !organization_name.toLowerCase().includes('giáo dục') ? 'Hiệu trưởng ' : ''}${hasFullName}` + : fullname; return (
From d8cb4ae59bcacc38082029cda2723778ae97b60a Mon Sep 17 00:00:00 2001 From: Quy_FE Date: Fri, 25 Apr 2025 10:42:27 +0700 Subject: [PATCH 2/9] =?UTF-8?q?Feat=20:=20fix=20l=E1=BB=97i=20ch=E1=BB=8Dn?= =?UTF-8?q?=20h=E1=BB=8Dc=20k=E1=BB=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/_screens/criteria/criteria-manage/index.js | 8 ++++++++ src/_screens/home/admin/index.js | 5 +++-- src/_screens/home/detail-grade/index.js | 1 - src/_screens/home/headmaster/index.js | 1 - 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/_screens/criteria/criteria-manage/index.js b/src/_screens/criteria/criteria-manage/index.js index dc5a8b7..0890e14 100644 --- a/src/_screens/criteria/criteria-manage/index.js +++ b/src/_screens/criteria/criteria-manage/index.js @@ -40,6 +40,7 @@ export default function CriteriaManage() { const [limitOnline] = useState(10); const [offsetOnline, setOffsetOnline] = useState(0); const [isEndOnlineClasses, setIsEndOnlineClasses] = useState(false); + const [isCheckAll,setIsCheckAll] = useState(false) const listRef = useRef(null); const dispatch = useDispatch(); const changeProvince = (item) => { @@ -64,6 +65,12 @@ export default function CriteriaManage() { }); } }; + useEffect(() => { + if(isCheckAll){ + handleSelectAll() + } + }, [listData]) + const handleSelectAll = () => { if (listData?.every((item) => listIdSelected?.includes(item?.school_id))) { @@ -80,6 +87,7 @@ export default function CriteriaManage() { newListIdSelected.push(item?.school_id); }); setListIdSelected(newListIdSelected); + setIsCheckAll(true) }; const handleSelectItem = (item) => { diff --git a/src/_screens/home/admin/index.js b/src/_screens/home/admin/index.js index 92126f7..7cf5caf 100644 --- a/src/_screens/home/admin/index.js +++ b/src/_screens/home/admin/index.js @@ -232,7 +232,8 @@ export default function AdminHome() { if (savedState) { const state = JSON.parse(savedState); setSearchTextSchool(state.searchTextSchool); - setProvinceSelect(state.provinceSelect); + // setProvinceSelect(state.provinceSelect); + changeProvince(state.provinceSelect) setDistrictSelect(state.districtSelect); setendPointSave(state.endPointSave) if(state.endPointSave){ @@ -288,7 +289,7 @@ export default function AdminHome() { queryParams.length ? `&${queryParams.join("&")}` : "" }`; const res = await apiCaller(endPoint, "GET"); - if(!res.data){ + if(!res?.data){ setIsEndOnlineClasses(true); } else { concatListSide = res?.data; diff --git a/src/_screens/home/detail-grade/index.js b/src/_screens/home/detail-grade/index.js index 34a8587..1c669f8 100644 --- a/src/_screens/home/detail-grade/index.js +++ b/src/_screens/home/detail-grade/index.js @@ -55,7 +55,6 @@ export default function DetailGrade() { setOffsetOnline(0) setLoadMoreOnline(true) setIsEndOnlineClasses(false) - setIsFiltered(true); scrollToTop() getData(); }; diff --git a/src/_screens/home/headmaster/index.js b/src/_screens/home/headmaster/index.js index adb5ac0..66abfc8 100644 --- a/src/_screens/home/headmaster/index.js +++ b/src/_screens/home/headmaster/index.js @@ -66,7 +66,6 @@ export default function HeadmasterHome() { setOffsetOnline(0) setLoadMoreOnline(true) setIsEndOnlineClasses(false) - setIsFiltered(true); scrollToTop() setSemester(item); setMonth(getListMonthBySemester(item?.value)?.[0]); From 239e0734b3b2f4e90156ab87950fd7a87c71299d Mon Sep 17 00:00:00 2001 From: Quy_FE Date: Mon, 28 Apr 2025 10:27:26 +0700 Subject: [PATCH 3/9] Feat : chart style --- src/_components/Header/index.js | 19 ++-- .../boxChart/BoxDoughnutBarChart.js | 89 ++++++++++--------- src/_components/boxChart/BoxDoughnutChar.js | 21 ++++- src/_components/chart/RDoughnutChart.js | 8 ++ src/_components/chart/VerticalBarChart.js | 9 +- src/_components/renderIcon/index.js | 14 +++ .../criteria/criteria-manage/index.js | 1 + src/_screens/home/admin/index.js | 1 + src/_screens/home/detail-grade/index.js | 1 + .../home/detail-room-education/index.js | 64 ++++++------- .../educationDepartmentHome.style.scss | 10 +++ .../home/education-department/index.js | 34 +++++-- src/_screens/home/headmaster/index.js | 1 + .../home/outstanding-teacher/index.js | 2 +- src/_screens/home/teacher/index.js | 1 + 15 files changed, 186 insertions(+), 89 deletions(-) diff --git a/src/_components/Header/index.js b/src/_components/Header/index.js index f95383f..de3a77b 100644 --- a/src/_components/Header/index.js +++ b/src/_components/Header/index.js @@ -2,14 +2,23 @@ import { useSelector } from "react-redux"; import "./header.style.scss"; import { configConstants } from "../../_constants"; -export default function Header({ icon, title, subtitles = [] }) { +export default function Header({ icon, title, subtitles = [],manager=false }) { const authentication = useSelector((state) => state.authentication); const { fullname, organization_name, role } = authentication?.user || {}; const hasFullName = fullname || organization_name; - const fullName = role === "organization_admin" - ? `${organization_name && !organization_name.toLowerCase().includes('giáo dục') ? 'Hiệu trưởng ' : ''}${hasFullName}` - : fullname; + + const handleFullName = () =>{ + let fullName + if(manager){ + fullName = 'Giám đốc ' + hasFullName + }else{ + fullName = role === "organization_admin" + ? `${organization_name ? 'Hiệu trưởng ' : ''}${hasFullName}` + : fullname; + } + return fullName + } return (
@@ -27,7 +36,7 @@ export default function Header({ icon, title, subtitles = [] }) {

-

{fullName}

+

{handleFullName()}

{ + const handleMonthChange = (date) => { setMonth(date) - !!onSetDateBarChart && onSetDateBarChart(date) + onSetDateBarChart?.(date) } - const _dataDoughnut = (dataDoughnut?.[0] / dataDoughnut?.[1] === 1 || dataDoughnut?.[0] > dataDoughnut?.[1]) ? [dataDoughnut?.[0]] : [dataDoughnut?.[0], dataDoughnut?.[1] - dataDoughnut?.[0]] - - - const renderIconDate = () => { - return ( - - - - ) - } - - return ( -
-
- {!!titleDoughnut &&

{titleDoughnut}

} - {!!subtitleDoughnut &&

{subtitleDoughnut}

} -
-
- -
-
-

{dataDoughnut?.[0] + '/' + dataDoughnut?.[1]}

-

{Math.round(dataDoughnut?.[0]/dataDoughnut?.[1] * 100) + '%'}

-
+ const renderDoughnutSection = () => ( +
+ {titleDoughnut &&

{titleDoughnut}

} + {subtitleDoughnut &&

{subtitleDoughnut}

} +
+
+ +
+
+

{current}

+

+ {target > 0 ? target : '...'} +

-
- {!!titleLine &&

{titleLine}

} - {!!subTitleLine &&

{subTitleLine}

} +
+ ) + + const renderBarSection = () => ( +
+ {titleLine &&

{titleLine}

} + {subTitleLine &&

{subTitleLine}

} + {dataBarChart.length > 0 ? (
-
+ ) : ( +
+ Không có dữ liệu để hiển thị +
+ )} +
+ ) + + return ( +
+ {renderDoughnutSection()} + {renderBarSection()}
- {/* {renderArrowLeft()} - Tháng 11 - {renderArrowRight()} */} data?.[1]) ? [data?.[0]] : [data?.[0], data?.[1] - data?.[0]] + const [current, target] = data + + const chartData = (current / target === 1 || current > target) ? [current] : [current, target - current]; + + const renderStats = () => { + return ( + <> +

{current}

+

{target > 0 ? target : '...'}

+ + ) + } + return (

{title}

-
+
+ +
-

{data?.[0] + '/' + data?.[1]}

-

{Math.round(data?.[0]/data?.[1] * 100) + '%'}

+ {renderStats()}
diff --git a/src/_components/chart/RDoughnutChart.js b/src/_components/chart/RDoughnutChart.js index 06cfba5..ea29a09 100644 --- a/src/_components/chart/RDoughnutChart.js +++ b/src/_components/chart/RDoughnutChart.js @@ -10,6 +10,14 @@ export default function RDoughnutChart({data = [], ...other}) { return null } + // data = data.map((item, index) => { + // if (index === 1 && item === 0) { + // return 1 + // } + // return item + // }) + // console.log('data',data); + return item.replace('Tuần', 'W')); const options = { responsive: true, @@ -28,7 +29,7 @@ export function VerticalBarChart({data = [], labels = []}) { align: 'end', // Alignment of the labels (start, end, center, etc.) color: 'blue', // Color of the labels font: { - weight: 'bold', + weight: 'bold', }, formatter: function (value, context) { return value; // Display the actual data value @@ -36,6 +37,12 @@ export function VerticalBarChart({data = [], labels = []}) { } }, scales: { + x: { + ticks: { + maxRotation: 0, + // scrollX : true, + }, + }, y: { max: maxValue < 5 ? 5 : maxValue < 20 ? maxValue + 5 : maxValue + 10, ticks: { diff --git a/src/_components/renderIcon/index.js b/src/_components/renderIcon/index.js index 66d9d01..344be74 100644 --- a/src/_components/renderIcon/index.js +++ b/src/_components/renderIcon/index.js @@ -139,3 +139,17 @@ export const renderIconSearchInput = () => { ); }; +export const renderIconButton = () => { + return ( + + ) +} + +export const renderIconDate = () => ( + + + +) \ No newline at end of file diff --git a/src/_screens/criteria/criteria-manage/index.js b/src/_screens/criteria/criteria-manage/index.js index 0890e14..a889d5c 100644 --- a/src/_screens/criteria/criteria-manage/index.js +++ b/src/_screens/criteria/criteria-manage/index.js @@ -313,6 +313,7 @@ export default function CriteriaManage() { isLoadMoreOnline && !isLoading ) { + if(listData.length < limitOnline) return onLoadMoreClasses(); } }; diff --git a/src/_screens/home/admin/index.js b/src/_screens/home/admin/index.js index 7cf5caf..5b9d07a 100644 --- a/src/_screens/home/admin/index.js +++ b/src/_screens/home/admin/index.js @@ -262,6 +262,7 @@ export default function AdminHome() { isLoadMoreOnline && !isLoading ) { + if(listSchool.length < limitOnline) return onLoadMoreClasses(); } }; diff --git a/src/_screens/home/detail-grade/index.js b/src/_screens/home/detail-grade/index.js index 1c669f8..d3f76ea 100644 --- a/src/_screens/home/detail-grade/index.js +++ b/src/_screens/home/detail-grade/index.js @@ -142,6 +142,7 @@ export default function DetailGrade() { isLoadMoreOnline && !isLoading ) { + if(listClass.length < limitOnline) return onLoadMoreClasses(); } }; diff --git a/src/_screens/home/detail-room-education/index.js b/src/_screens/home/detail-room-education/index.js index 0fabe4f..81eb9c1 100644 --- a/src/_screens/home/detail-room-education/index.js +++ b/src/_screens/home/detail-room-education/index.js @@ -1,6 +1,6 @@ import { useEffect, useState } from "react"; import Header from "../../../_components/Header"; -import { renderIconHome } from "../../../_components/renderIcon"; +import { renderIconButton, renderIconHome } from "../../../_components/renderIcon"; import RateStar from "../../../_components/RateStar"; import { defaultMonthYearSemester, getListMonthBySemester, LIST_SCHOOL_YEAR, LIST_SEMESTER, PRIMARY_COLOR } from "../../../_constants/common"; import { configConstants, PATH } from "../../../_constants"; @@ -211,49 +211,51 @@ export default function DetailRoomEducation() { } }, [isLoadingListOrganization, isLoadingStatisticCircle, isLoadingStudentChart, isLoadingTeacherChart]) - const renderIconButton = () => { - return ( - - ) - } return (
-
+ {data ? + (<> +
-
-
- Number(item?.total_teacher_assignment))} - labelsBarChart={dataTeacherChart?.map(item => item?.label)} - dataDoughnut={[data?.teacher_join, data?.total_teacher]} - titleDoughnut={'Giáo viên'} - subtitleDoughnut={'Số giáo viên đã tham gia'} - subTitleLine={"Số giáo viên giao bài trong tuần"} - /> - Number(item?.total_student_learn))} - labelsBarChart={dataStudentChart?.map(item => item?.label)} - dataDoughnut={[data?.student_join, data?.total_student]} - titleDoughnut={'Học sinh'} - subtitleDoughnut={'Số học sinh đã tham gia'} - subTitleLine={"Số học sinh làm bài trong tuần"} - /> -
+
+
+ Number(item?.total_teacher_assignment))} + labelsBarChart={dataTeacherChart?.map(item => item?.label)} + dataDoughnut={[data?.teacher_join, data?.total_teacher]} + titleDoughnut={'Giáo viên'} + subtitleDoughnut={'Số giáo viên đã tham gia'} + subTitleLine={"Số giáo viên giao bài trong tuần"} + /> + Number(item?.total_student_learn))} + labelsBarChart={dataStudentChart?.map(item => item?.label)} + dataDoughnut={[data?.student_join, data?.total_student]} + titleDoughnut={'Học sinh'} + subtitleDoughnut={'Số học sinh đã tham gia'} + subTitleLine={"Số học sinh làm bài trong tuần"} + /> +
+ ) + : + "Không có dữ liệu để hiển thị" + }
diff --git a/src/_screens/home/education-department/educationDepartmentHome.style.scss b/src/_screens/home/education-department/educationDepartmentHome.style.scss index 0cac2d4..f95d0d2 100644 --- a/src/_screens/home/education-department/educationDepartmentHome.style.scss +++ b/src/_screens/home/education-department/educationDepartmentHome.style.scss @@ -26,6 +26,16 @@ flex-direction: column; background-color: #fff; + // .search-input { + // border-radius: 40px; + // height: 46px; + // width: 50%; + + // @include screen_pc_sm { + // height: 34px; + // } + // } + .education-department-home-note { font-size: 2rem; font-weight: 700; diff --git a/src/_screens/home/education-department/index.js b/src/_screens/home/education-department/index.js index 419c656..029fb81 100644 --- a/src/_screens/home/education-department/index.js +++ b/src/_screens/home/education-department/index.js @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import InputText from "../../../_components/Auth/InputText"; import Header from "../../../_components/Header"; import { + renderIconButton, renderIconHome, renderIconSearchInput, } from "../../../_components/renderIcon"; @@ -24,6 +25,7 @@ export default function EducationDepartmentHome() { const [dataStudentChart, setDataStudentChart] = useState([]) const [dataTeacherChart, setDataTeacherChart] = useState([]) const [listOrganization, setListOrganization] = useState([]) + const [searchText, setSearchText] = useState('') const getDataOrganization = async () => { try { @@ -109,22 +111,21 @@ export default function EducationDepartmentHome() { ); }; - const renderIconButton = () => { - return ( - - ) + const handleSubmit = ()=>{ + } return (
- {!!data &&
+ {!!data ?
@@ -154,7 +155,12 @@ export default function EducationDepartmentHome() { subTitleLine={"Số học sinh làm bài trong tuần"} />
-
} +
+ : +
+ Không có dữ liệu để hiển thị +
+ }
Top 10 giáo viên tiêu biểu @@ -166,6 +172,20 @@ export default function EducationDepartmentHome() {

Danh sách phòng giáo dục

+ {/* { + if (e.which == 13 && !isFilterSchool) { + handleSubmit(); + } + }} + /> */}
{listOrganization.map((item, index) => ( diff --git a/src/_screens/home/headmaster/index.js b/src/_screens/home/headmaster/index.js index 66abfc8..a2e5bed 100644 --- a/src/_screens/home/headmaster/index.js +++ b/src/_screens/home/headmaster/index.js @@ -169,6 +169,7 @@ export default function HeadmasterHome() { isLoadMoreOnline && !isLoading ) { + if(listTeacher.length < limitOnline) return onLoadMoreClasses(); } }; diff --git a/src/_screens/home/outstanding-teacher/index.js b/src/_screens/home/outstanding-teacher/index.js index cdb335e..c7469a7 100644 --- a/src/_screens/home/outstanding-teacher/index.js +++ b/src/_screens/home/outstanding-teacher/index.js @@ -59,7 +59,7 @@ export default function OutstandingTeacher() {
diff --git a/src/_screens/home/teacher/index.js b/src/_screens/home/teacher/index.js index 2d0ec0d..49247ba 100644 --- a/src/_screens/home/teacher/index.js +++ b/src/_screens/home/teacher/index.js @@ -175,6 +175,7 @@ export default function TeacherHome() { isLoadMoreOnline && !isLoading ) { + if(listClass.length < limitOnline) return onLoadMoreClasses(); } }; From 3a1d7d4009e337e91d1ae1486a48beb53a83cdb6 Mon Sep 17 00:00:00 2001 From: Quy_FE Date: Mon, 28 Apr 2025 14:27:03 +0700 Subject: [PATCH 4/9] Feat : handle button change month --- src/_components/Auth/InputDate/index.js | 1 + src/_components/Auth/InputDate/index.scss | 12 +++ .../boxChart/BoxDoughnutBarChart.js | 77 ++++++++++++++----- src/_components/boxChart/boxChart.scss | 28 +++++++ src/_components/renderIcon/index.js | 15 ++++ .../home/education-department/index.js | 9 ++- .../home/outstanding-teacher/index.js | 2 +- 7 files changed, 123 insertions(+), 21 deletions(-) diff --git a/src/_components/Auth/InputDate/index.js b/src/_components/Auth/InputDate/index.js index b90bfba..db8c809 100644 --- a/src/_components/Auth/InputDate/index.js +++ b/src/_components/Auth/InputDate/index.js @@ -72,6 +72,7 @@ const InputDate = (props) => { }`} selected={props.value} onChange={(date) => changeValue(date)} + disabledKeyboardNavigation // showMonthDropdown showYearDropdown showMonthYearPicker={!!props?.isMonthPicker} diff --git a/src/_components/Auth/InputDate/index.scss b/src/_components/Auth/InputDate/index.scss index d45f4f8..edb82c0 100644 --- a/src/_components/Auth/InputDate/index.scss +++ b/src/_components/Auth/InputDate/index.scss @@ -53,6 +53,18 @@ $border-color: #4a4848; } } + .react-datepicker { + &__month-text { + + &--selected, + &--in-selecting-range, + &--in-range { + border-radius: 8px !important; + + } + } + } + input { height: 100%; border: none; diff --git a/src/_components/boxChart/BoxDoughnutBarChart.js b/src/_components/boxChart/BoxDoughnutBarChart.js index b4c69ad..ca53de4 100644 --- a/src/_components/boxChart/BoxDoughnutBarChart.js +++ b/src/_components/boxChart/BoxDoughnutBarChart.js @@ -2,9 +2,19 @@ import { PRIMARY_COLOR } from '../../_constants/common' import RDoughnutChart from '../chart/RDoughnutChart' import './boxChart.scss' import { VerticalBarChart } from '../chart/VerticalBarChart' -import { useState } from 'react' +import { useEffect, useState } from 'react' import InputDate from '../Auth/InputDate' -import { renderIconDate } from '../renderIcon' +import { renderIconButton, renderIconButtonLeft, renderIconDate } from '../renderIcon' + +const Btn = ({ icon, isDisabled = false, onClick }) => { + return ( +
+ +
+ ); +}; export default function BoxDoughnutBarChart({ dataDoughnut = [], @@ -23,7 +33,6 @@ export default function BoxDoughnutBarChart({ const handleMonthChange = (date) => { setMonth(date) - onSetDateBarChart?.(date) } const renderDoughnutSection = () => ( @@ -59,26 +68,58 @@ export default function BoxDoughnutBarChart({ )}
) + const handleClickNext = () => { + const newMonth = month.getMonth() + 1; + const newYear = month.getFullYear(); + + if (newMonth > 11) { + setMonth(new Date(newYear + 1, 0, 1)); + } else { + setMonth(new Date(newYear, newMonth, 1)); + } + }; + + const handleClickPrev = () => { + const newMonth = month.getMonth() - 1; + const newYear = month.getFullYear(); + + if (newMonth < 0) { + setMonth(new Date(newYear - 1, 11, 1)); + } else { + setMonth(new Date(newYear, newMonth, 1)); + } + }; + + useEffect(() => { + onSetDateBarChart?.(month); + }, [month]); + + const isDisabledNext = new Date(month).getMonth() === new Date().getMonth() && new Date(month).getFullYear() === new Date().getFullYear(); + return (
{renderDoughnutSection()} {renderBarSection()} -
- +
+ +
+ +
+
) diff --git a/src/_components/boxChart/boxChart.scss b/src/_components/boxChart/boxChart.scss index cbe3ceb..493f533 100644 --- a/src/_components/boxChart/boxChart.scss +++ b/src/_components/boxChart/boxChart.scss @@ -20,4 +20,32 @@ } .doughnut-chart-content {} + + .custom-button { + padding: 0 32px; + height: 40px; + border-radius: 20px; + border: none; + font-size: 16px; + color: #fff; + font-family: 'Myriadpro-SemiBold'; + background-color: var(--button-bg-color); + display: flex; + justify-content: center; + align-items: center; + white-space: nowrap; + width: max-content; + margin: 0 10px; + } + + .custom-button:hover { + background-color: #c07a05; + } + + .button-disable { + cursor: not-allowed; + /* background: #70707070 !important; */ + background: #c1c1c1 !important; + pointer-events: none; + } } \ No newline at end of file diff --git a/src/_components/renderIcon/index.js b/src/_components/renderIcon/index.js index 344be74..0bf0387 100644 --- a/src/_components/renderIcon/index.js +++ b/src/_components/renderIcon/index.js @@ -145,6 +145,21 @@ export const renderIconButton = () => { ) } +export const renderIconButtonLeft = () => { + return ( + + + + + + + + + + + ); +} + export const renderIconDate = () => ( */}
- {listOrganization.map((item, index) => ( + {listOrganization > 0 ? listOrganization.map((item, index) => (
- ))} + )) + : +
+ Không có phòng giáo dục nào +
+ }
diff --git a/src/_screens/home/outstanding-teacher/index.js b/src/_screens/home/outstanding-teacher/index.js index c7469a7..563245f 100644 --- a/src/_screens/home/outstanding-teacher/index.js +++ b/src/_screens/home/outstanding-teacher/index.js @@ -130,7 +130,7 @@ export default function OutstandingTeacher() {
{!isLoading && !listTeacher?.length && (

- Không có giáo viên nào + Không còn GV nào để hiển thị

)} {listTeacher.map((item, index) => { From 60d2c077b81b75569c3f9b4acbe1613cca6e3d9a Mon Sep 17 00:00:00 2001 From: Quy_FE Date: Mon, 28 Apr 2025 14:52:15 +0700 Subject: [PATCH 5/9] Feat : scroll load more sgd --- .../educationDepartmentHome.style.scss | 1 + .../home/education-department/index.js | 54 ++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/_screens/home/education-department/educationDepartmentHome.style.scss b/src/_screens/home/education-department/educationDepartmentHome.style.scss index f95d0d2..91b08c6 100644 --- a/src/_screens/home/education-department/educationDepartmentHome.style.scss +++ b/src/_screens/home/education-department/educationDepartmentHome.style.scss @@ -48,6 +48,7 @@ display: flex; flex-direction: column; padding: 0 3.2rem; + max-height: 740px; .education-department-home-list-room { flex: 1; diff --git a/src/_screens/home/education-department/index.js b/src/_screens/home/education-department/index.js index a05b46c..3a500da 100644 --- a/src/_screens/home/education-department/index.js +++ b/src/_screens/home/education-department/index.js @@ -26,6 +26,11 @@ export default function EducationDepartmentHome() { const [dataTeacherChart, setDataTeacherChart] = useState([]) const [listOrganization, setListOrganization] = useState([]) const [searchText, setSearchText] = useState('') + const [isLoadMoreOnline, setLoadMoreOnline] = useState(true); + const [limitOnline] = useState(10); + const [offsetOnline, setOffsetOnline] = useState(0); + const [isEndOnlineClasses, setIsEndOnlineClasses] = useState(false); + const [isLoading, setIsLoading] = useState(false); const getDataOrganization = async () => { try { @@ -115,6 +120,51 @@ export default function EducationDepartmentHome() { } + const handleScroll = (e) => { + if ( + e.target.scrollHeight - e.target.scrollTop < e.target.clientHeight + 5 && + isLoadMoreOnline && + !isLoading + ) { + if(listOrganization.length < limitOnline) return + onLoadMoreClasses(); + } + }; + + // Load More + const onLoadMoreClasses = async () => { + let offsetOnlineMore = offsetOnline + limitOnline; + let listNext = []; + setIsLoading(true); + try { + if (!isEndOnlineClasses) { + const endPoint = `/report/api_report/listChildOrganization?organization_id=${authentication?.user?.organization_id}?limit=${limitOnline}&offset=${offsetOnlineMore}`; + const res = await apiCaller(endPoint, "GET"); + + if (!res.data){ + setIsEndOnlineClasses(true); + } else { + listNext = res?.data; + setOffsetOnline(offsetOnline + limitOnline); + if (res?.data?.length < limitOnline) { + setLoadMoreOnline(false); + if (res?.data?.length == 0) setLoadMoreOnline(false); + setIsEndOnlineClasses(true); + } + } + } else { + setIsEndOnlineClasses(true); + } + + let listPrev = listOrganization; + setListOrganization(listPrev?.concat(listNext)); + } catch (e) { + } finally { + setIsLoading(false); + } + }; + + return (
*/} -
+
- {listOrganization > 0 ? listOrganization.map((item, index) => ( + {listOrganization.length > 0 ? listOrganization.map((item, index) => (
Date: Mon, 28 Apr 2025 15:49:47 +0700 Subject: [PATCH 6/9] =?UTF-8?q?Feat=20:=20logic=20b=E1=BA=ADt=20t=E1=BA=AF?= =?UTF-8?q?t=20ch=E1=BB=89=20ti=C3=AAu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../criteria/criteria-setting/index.js | 142 +++++++++++------- 1 file changed, 90 insertions(+), 52 deletions(-) diff --git a/src/_screens/criteria/criteria-setting/index.js b/src/_screens/criteria/criteria-setting/index.js index f063b49..5371987 100644 --- a/src/_screens/criteria/criteria-setting/index.js +++ b/src/_screens/criteria/criteria-setting/index.js @@ -26,6 +26,7 @@ export default function CriteriaSetting() { const [criteriaTarget, setCriteriaTarget] = useState(DEFAULT_SETTING_CRITERIA); const [showAlert, setShowAlert] = useState(false); const [alertMessage, setAlertMessage] = useState(""); + const [isApply, setIsApply] = useState(false) const schoolList = isJsonString(decodeURIComponent(_schoolList)) ? JSON.parse(decodeURIComponent(_schoolList)) @@ -60,30 +61,93 @@ export default function CriteriaSetting() { } } - const saveCriteriaSetting = async () => { - try { - const dataSave = { - school_list: schoolList, - assign_number_active: criteriaTarget.assign.enable ? 1 : 0, - assign_number_target_1: criteriaTarget.assign.target1, - assign_number_target_2: criteriaTarget.assign.target2, - student_done_active: criteriaTarget.studentDone.enable ? 1 : 0, - student_done_target_1: criteriaTarget.studentDone.target1, - student_done_target_2: criteriaTarget.studentDone.target2, - } - const res = await apiCaller( - "/report/api_report/assignCriteriaToOrganization", - "PUT", - dataSave, - ); - if (res?.status) { - setAlertMessage(res?.msg); + const isValid = () => { + if (criteriaTarget.assign.enable) { + if (!criteriaTarget.studentDone.enable) { + return ( + !(criteriaTarget.assign.target1 && + criteriaTarget.assign.target2 && + criteriaTarget.assign.target1 < criteriaTarget.assign.target2) + ); + } else { + return ( + !(criteriaTarget.assign.target1 && + criteriaTarget.assign.target2 && + criteriaTarget.assign.target1 < criteriaTarget.assign.target2 && + criteriaTarget.studentDone.target1 != null && + criteriaTarget.studentDone.target2 != null && + criteriaTarget.studentDone.target1 < criteriaTarget.studentDone.target2) + ); + } + } else if (criteriaTarget.studentDone.enable) { + return ( + !(criteriaTarget.studentDone.target1 != null && + criteriaTarget.studentDone.target2 != null && + criteriaTarget.studentDone.target1 < criteriaTarget.studentDone.target2) + ); + } else { + return true; + } + }; + + const saveCriteriaSetting = async () => { + try { + const dataSave = { + school_list: schoolList, + assign_number_active: criteriaTarget.assign.enable ? 1 : 0, + assign_number_target_1: criteriaTarget.assign.target1, + assign_number_target_2: criteriaTarget.assign.target2, + student_done_active: criteriaTarget.studentDone.enable ? 1 : 0, + student_done_target_1: criteriaTarget.studentDone.target1, + student_done_target_2: criteriaTarget.studentDone.target2, + }; + + let res; + + if (isApply) { + res = await handleApply(dataSave); + } else { + res = await handleNonApply(dataSave); + } + + if (res?.status) { + setAlertMessage(res?.msg); + setShowAlert(true); + } + } catch (err) { + console.error("Error: ", err); + } + }; + + const handleApply = async (dataSave) => { + if (isValid()) { + return await apiCaller( + "/report/api_report/removeCriteriaFromOrganization", + "PUT", + { school_list: schoolList } + ); + } else { + return await apiCaller( + "/report/api_report/assignCriteriaToOrganization", + "PUT", + dataSave + ); + } + }; + + const handleNonApply = async (dataSave) => { + if (!isValid()) { + return await apiCaller( + "/report/api_report/assignCriteriaToOrganization", + "PUT", + dataSave + ); + } else { + setAlertMessage("Bạn chưa thực hiện bất kỳ thay đổi nào"); setShowAlert(true); + return null; } - } catch (err) { - console.log("err: ", err); - } - } + }; const getData = async () => { try { @@ -93,6 +157,7 @@ export default function CriteriaSetting() { "GET", ); if (res?.status) { + setIsApply(res?.data?.status_criteria ==='1') setCriteriaTarget({ assign: { target1: res?.data?.assign_number_target_1 || DEFAULT_SETTING_CRITERIA.assign.target1, @@ -122,6 +187,7 @@ export default function CriteriaSetting() { "GET", ); if (res?.status) { + setIsApply(res?.data?.status_criteria ==='1') setCriteriaTarget({ assign: { target1: res?.data?.assign_number_target_1 || DEFAULT_SETTING_CRITERIA.assign.target1, @@ -160,34 +226,6 @@ export default function CriteriaSetting() { return !isRead } - const isValid = () => { - if (criteriaTarget.assign.enable) { - if (!criteriaTarget.studentDone.enable) { - return ( - !(criteriaTarget.assign.target1 && - criteriaTarget.assign.target2 && - criteriaTarget.assign.target1 < criteriaTarget.assign.target2) - ); - } else { - return ( - !(criteriaTarget.assign.target1 && - criteriaTarget.assign.target2 && - criteriaTarget.assign.target1 < criteriaTarget.assign.target2 && - criteriaTarget.studentDone.target1 != null && - criteriaTarget.studentDone.target2 != null && - criteriaTarget.studentDone.target1 < criteriaTarget.studentDone.target2) - ); - } - } else if (criteriaTarget.studentDone.enable) { - return ( - !(criteriaTarget.studentDone.target1 != null && - criteriaTarget.studentDone.target2 != null && - criteriaTarget.studentDone.target1 < criteriaTarget.studentDone.target2) - ); - } else { - return true; - } - }; const renderRightItem = ({ title, desc, valueName, unit, key, maxLengthInput }) => { return (
Quay lại - {authentication?.user?.role === USER_ROLE.ADMIN && ( - Lưu + {(authentication?.user?.role === USER_ROLE.ADMIN || authentication?.user?.role === USER_ROLE.HEADMASTER) && ( + Lưu )}
From 81205da08cdf857a11d01d492c7dd200177fcd1d Mon Sep 17 00:00:00 2001 From: Quy_FE Date: Mon, 28 Apr 2025 16:04:25 +0700 Subject: [PATCH 7/9] Style : button-custom --- src/_components/boxChart/boxChart.scss | 4 ++-- src/_components/renderIcon/index.js | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/_components/boxChart/boxChart.scss b/src/_components/boxChart/boxChart.scss index 493f533..b562dcf 100644 --- a/src/_components/boxChart/boxChart.scss +++ b/src/_components/boxChart/boxChart.scss @@ -22,8 +22,8 @@ .doughnut-chart-content {} .custom-button { - padding: 0 32px; - height: 40px; + padding: 8px; + height: auto; border-radius: 20px; border: none; font-size: 16px; diff --git a/src/_components/renderIcon/index.js b/src/_components/renderIcon/index.js index 0bf0387..ec7d34a 100644 --- a/src/_components/renderIcon/index.js +++ b/src/_components/renderIcon/index.js @@ -139,15 +139,21 @@ export const renderIconSearchInput = () => { ); }; -export const renderIconButton = () => { +export const renderIconButton = (width = 24, height = 24) => { return ( - + ) } -export const renderIconButtonLeft = () => { +export const renderIconButtonLeft = (width = 24, height = 24) => { return ( - + @@ -158,7 +164,7 @@ export const renderIconButtonLeft = () => { ); -} +}; export const renderIconDate = () => ( From a88f014c12c4d79aa8539ce019b8f88913a4cfa2 Mon Sep 17 00:00:00 2001 From: Quy_FE Date: Mon, 28 Apr 2025 17:03:49 +0700 Subject: [PATCH 8/9] =?UTF-8?q?Feat=20:=20th=C3=AAm=20scroll,=20thay=20sty?= =?UTF-8?q?le=20cho=20trang=20ch=E1=BB=A7=20sgd?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detailRoomEducation.style.scss | 2 +- .../home/detail-room-education/index.js | 76 ++++++++++++++++++- .../home/outstanding-teacher/index.js | 4 +- .../outstandingTeacher.style.scss | 1 + 4 files changed, 76 insertions(+), 7 deletions(-) diff --git a/src/_screens/home/detail-room-education/detailRoomEducation.style.scss b/src/_screens/home/detail-room-education/detailRoomEducation.style.scss index 70af0c4..84d9315 100644 --- a/src/_screens/home/detail-room-education/detailRoomEducation.style.scss +++ b/src/_screens/home/detail-room-education/detailRoomEducation.style.scss @@ -4,7 +4,7 @@ display: flex; .detail-room-education-left-side { - width: 40%; + width: 48%; border-right: 1px solid #c7c7c7; display: flex; flex-direction: column; diff --git a/src/_screens/home/detail-room-education/index.js b/src/_screens/home/detail-room-education/index.js index 81eb9c1..033f92d 100644 --- a/src/_screens/home/detail-room-education/index.js +++ b/src/_screens/home/detail-room-education/index.js @@ -34,6 +34,11 @@ export default function DetailRoomEducation() { const [isLoadingStatisticCircle, setIsLoadingStatisticCircle] = useState(false); const [isLoadingStudentChart, setIsLoadingStudentChart] = useState(false); const [isLoadingTeacherChart, setIsLoadingTeacherChart] = useState(false); + const [isLoadMoreOnline, setLoadMoreOnline] = useState(true); + const [limitOnline] = useState(10); + const [offsetOnline, setOffsetOnline] = useState(0); + const [isEndOnlineClasses, setIsEndOnlineClasses] = useState(false); + const [isLoading, setIsLoading] = useState(false); const getListOrganization = async () => { try { @@ -211,6 +216,69 @@ export default function DetailRoomEducation() { } }, [isLoadingListOrganization, isLoadingStatisticCircle, isLoadingStudentChart, isLoadingTeacherChart]) + const handleScroll = (e) => { + if ( + e.target.scrollHeight - e.target.scrollTop < e.target.clientHeight + 5 && + isLoadMoreOnline && + !isLoading + ) { + if(listOrganization.length < limitOnline) return + onLoadMoreClasses(); + } + }; + + // Load More Classes for Teacher + const onLoadMoreClasses = async () => { + let offsetOnlineMore = offsetOnline + limitOnline; + let listNext = []; + setIsLoading(true); + try { + if (!isEndOnlineClasses) { + const endPoint = `/report/api_report/getListOrganizationFromDistrictOrganization?organization_id=${ + idRoom + }${ + !!schoolYear?.value ? `&year=${schoolYear?.value}` : "" + }${ + !!semester?.value ? `&semester=${semester?.value}` : "" + }${ + !!month?.value ? `&month=${month?.value}` : "" + }&limit=${limitOnline}&offset=${offsetOnlineMore}`; + const res = await apiCaller( + endPoint, + "GET", + {}, + null, + true, + configConstants.API_URL_SETEST, + false + ) + // const endPoint = `/report/api_report/getOrganizationAndCriteria?limit=${limitOnline}&offset=${offsetOnlineMore}${ + // queryParams.length ? `&${queryParams.join("&")}` : "" + // }`; + // const res = await apiCaller(endPoint, "GET"); + + if (!res.data){ + setIsEndOnlineClasses(true); + } else { + listNext = res?.data; + setOffsetOnline(offsetOnline + limitOnline); + if (res?.data?.length < limitOnline) { + setLoadMoreOnline(false); + if (res?.data?.length == 0) setLoadMoreOnline(false); + setIsEndOnlineClasses(true); + } + } + } else { + setIsEndOnlineClasses(true); + } + + let listPrev = listOrganization; + setListOrganization(listPrev?.concat(listNext)); + } catch (e) { + } finally { + setIsLoading(false); + } + }; return (
@@ -273,25 +341,25 @@ export default function DetailRoomEducation() { data={LIST_SCHOOL_YEAR} value={schoolYear} setValue={setSchoolYear} - style={{flex: 1}} + style={{flex: 1,maxWidth: '260px'}} /> Áp dụng
-
+
{!isLoadingListOrganization && !listOrganization?.length && (

Không có trường nào diff --git a/src/_screens/home/outstanding-teacher/index.js b/src/_screens/home/outstanding-teacher/index.js index 563245f..47c2408 100644 --- a/src/_screens/home/outstanding-teacher/index.js +++ b/src/_screens/home/outstanding-teacher/index.js @@ -147,10 +147,10 @@ export default function OutstandingTeacher() { {(index + 2) + '. ' + item?.teacher_name}

- {item?.email} + {item?.district_name}

- {item?.phone} + {item?.school_name}

diff --git a/src/_screens/home/outstanding-teacher/outstandingTeacher.style.scss b/src/_screens/home/outstanding-teacher/outstandingTeacher.style.scss index 8bcf2d2..cea9ee2 100644 --- a/src/_screens/home/outstanding-teacher/outstandingTeacher.style.scss +++ b/src/_screens/home/outstanding-teacher/outstandingTeacher.style.scss @@ -39,6 +39,7 @@ display: flex; align-items: center; justify-content: center; + max-height: 290px; .outstanding-teacher-best-avatar-box { height: 90%; From 4606c42c7a39daf3ee2cec24188c4d516d47985d Mon Sep 17 00:00:00 2001 From: Quy_FE Date: Mon, 28 Apr 2025 17:20:06 +0700 Subject: [PATCH 9/9] =?UTF-8?q?Feat=20:=20n=C3=BAt=20quay=20l=E1=BA=A1i?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/_components/Header/index.js | 15 ++++++++++++++- src/_screens/home/headmaster/index.js | 10 +--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/_components/Header/index.js b/src/_components/Header/index.js index de3a77b..d3aafe1 100644 --- a/src/_components/Header/index.js +++ b/src/_components/Header/index.js @@ -1,8 +1,11 @@ import { useSelector } from "react-redux"; import "./header.style.scss"; import { configConstants } from "../../_constants"; +import PrimaryButton from "../Button/PrimaryButton"; +import { renderIconButtonLeft } from "../renderIcon"; +import { history } from "../../_helpers"; -export default function Header({ icon, title, subtitles = [],manager=false }) { +export default function Header({ icon, title, subtitles = [], manager = false, isBack = false }) { const authentication = useSelector((state) => state.authentication); const { fullname, organization_name, role } = authentication?.user || {}; const hasFullName = fullname || organization_name; @@ -23,6 +26,16 @@ export default function Header({ icon, title, subtitles = [],manager=false }) { return (
+ {isBack && ( +
+ { + history.goBack() + }}> +
{renderIconButtonLeft()}
+ Quay lại +
+
+ )} {icon}

{title} diff --git a/src/_screens/home/headmaster/index.js b/src/_screens/home/headmaster/index.js index a2e5bed..d1bd908 100644 --- a/src/_screens/home/headmaster/index.js +++ b/src/_screens/home/headmaster/index.js @@ -254,19 +254,11 @@ export default function HeadmasterHome() {

- {authentication.user.role ==='supper_admin' &&( -
- { - history.goBack() - }}> - Quay lại - -
- )}

Mức độ hoàn thành của trường