diff --git a/app/package.json b/app/package.json index eba885a..666c029 100644 --- a/app/package.json +++ b/app/package.json @@ -21,10 +21,12 @@ "react-file-reader": "^1.1.4", "react-js-pagination": "^3.0.3", "react-loading-overlay": "^1.0.1", + "react-redux": "^7.2.6", "react-router-dom": "5.2.0", "react-scripts": "5.0.0", "react-select": "^5.2.1", "react-spinners": "^0.11.0", + "react-switch": "^6.0.0", "sweetalert": "^2.1.2", "web-vitals": "^2.1.2" }, diff --git a/app/public/img/BI_Logo.png b/app/public/img/BI_Logo.png new file mode 100644 index 0000000..4a5f4f2 Binary files /dev/null and b/app/public/img/BI_Logo.png differ diff --git a/app/src/App.css b/app/src/App.css index 611c57d..72768df 100644 --- a/app/src/App.css +++ b/app/src/App.css @@ -365,4 +365,111 @@ button.close:hover { height: 60px; } +} + +.login-block { + /* background-image: url("/img/Bg_login.jpg"); */ + background-repeat: no-repeat; + background-size: cover; + float: left; + width: 100%; + padding: 50px 0; + margin-top: 150px; +} +.login-sec { + padding: 50px 30px 10px; + position: relative; +} +.login-sec .copy-text { + position: absolute; + width: 80%; + bottom: 20px; + font-size: 13px; + text-align: center; +} +.login-sec .copy-text i { + color: #feb58a; +} +.login-sec .copy-text a { + color: #e36262; +} +.login-sec h2 { + margin-bottom: 30px; + font-weight: 800; + font-size: 30px; + color: #0695e2; +} +.login-sec h2:after { + content: " "; + width: 100px; + height: 5px; + background: #0695e2; + display: block; + border-radius: 3px; + margin-top: 20px; + margin-left: auto; + margin-right: auto; +} +.login-sec ul li a { + padding: 8px !important; + border-top-right-radius: 3px !important; + border-top-left-radius: 3px !important; +} +.login-sec ul li a.active { + color: white !important; +} + +.banner-sec { + background-size: cover; + min-height: 300px; + border-radius: 0 10px 10px 0; + padding: 0; +} +.banner-text { + width: 70%; + position: absolute; + bottom: 0px; + padding-left: 20px; +} +.banner-text h2 { + color: #fff; + font-weight: 600; +} +.banner-text h2:after { + content: " "; + width: 100px; + height: 5px; + background: #fff; + display: block; + margin-top: 20px; + border-radius: 3px; +} +.banner-text p { + color: #fff; +} + +.container { + box-shadow: 0 1px 15px 1px rgba(69, 65, 78, 0.08); + background-color: #fff; + border-radius: 10px; +} +.container_form_infor { + box-shadow: 0 1px 15px 1px rgba(69, 65, 78, 0.08); + background-color: #fff; + border-radius: 10px; +} + +.carousel-inner { + border-radius: 0 10px 10px 0; +} +.carousel-caption { + text-align: left; + left: 5%; +} + +.btn-login { + background: #0695e2; + color: #fff; + font-weight: 600; + font-family: inherit !important; } \ No newline at end of file diff --git a/app/src/App.js b/app/src/App.js index a85cc1a..511cda2 100644 --- a/app/src/App.js +++ b/app/src/App.js @@ -3,38 +3,41 @@ import ListItem from './components/List/ListItem'; import Login from './components/Login/Login'; import LabelImage from './components/LabelImg/LabelImage'; import SearchImage from './components/SearchImg/SearchImage'; +import User from './components/User/User'; import ImportImage from './components/ImportImg/ImportImage'; import Test from './components/Test/Test'; import MenuBar from './components/layouts/MenuBar' import Header from './components/layouts/Header' import 'antd/dist/antd.css'; import "./App.css"; -import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import store from './store'; +import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; function App() { return ( -
+ - -
+ + } /> +
- {/* */} - + -
+
-
- + +
-
+ ); } diff --git a/app/src/actions/isLogin/index.js b/app/src/actions/isLogin/index.js new file mode 100644 index 0000000..a78075a --- /dev/null +++ b/app/src/actions/isLogin/index.js @@ -0,0 +1,15 @@ +export const LOGIN = 'LOGIN'; +export const LOGOUT = 'LOGOUT'; +export function login(access_token){ + return { + type: LOGIN, + payload:{ + access_token: access_token + } + } +} +export function logout(){ + return { + type: LOGOUT + } +} diff --git a/app/src/actions/role/index.js b/app/src/actions/role/index.js new file mode 100644 index 0000000..aaa42f5 --- /dev/null +++ b/app/src/actions/role/index.js @@ -0,0 +1,9 @@ +export const ROLE = 'ROLE'; +export function role(role){ + return { + type: ROLE, + payload:{ + role: role + } + } +} diff --git a/app/src/components/Login/Login.js b/app/src/components/Login/Login.js index c18c8ac..e4b109d 100644 --- a/app/src/components/Login/Login.js +++ b/app/src/components/Login/Login.js @@ -1,128 +1,157 @@ -import { LockOutlined, UserOutlined } from '@ant-design/icons'; -import { Button, Form, Input, Typography } from 'antd'; -import axios from 'axios'; -// import { dispatchBox, dispatchToken } from 'features/Login/loginSlice'; -import React, { useState } from 'react'; -// import { useDispatch } from 'react-redux'; -// import { useHistory } from "react-router-dom"; -import { HOST } from '../../config/index'; +import React, { Component } from 'react'; +import { Row, Col } from 'react-bootstrap'; +import swal from 'sweetalert'; +import $ from 'jquery'; +import { HOST } from '../../config'; +import Store from '../../store'; +import { login } from '../../actions/isLogin'; -const { Text } = Typography; - -const Login = () => { - - const [error, setError] = useState(''); - const [loading, setLoading] = useState(false); - - // const dispatch = useDispatch(); - - // let history = useHistory(); - - const onFinish = async (values) => { - setLoading(true); - const dataReq = { - email: values.email, - password: values.password, - } - - await axios({ - method: 'POST', - url: `${HOST}/api/login`, - headers: {}, - data: dataReq - }).then((res) => { - if (res.data.status === 10000) { - // dispatch(dispatchToken({ token: 'Bearer ' + res.data.access_token })); - // dispatch(dispatchBox({ rule: res.data.user_info.rule })) - setError(''); - localStorage.setItem('refresh_token', 'Bearer ' + res.data.refresh_token); - localStorage.setItem('access_token', 'Bearer ' + res.data.access_token); - localStorage.setItem('rule', res.data.user_info.rule); - - // history.push('/preferential-management') - } else { - setError('Sai tài khoản hoặc mật khẩu'); +class Login extends Component { + constructor(props) { + super(props); + this.state = { + error: 0, + loadingbtn: false, + datalogin: { + email: "", + password: "", } - }) - .catch(err => { - setError('Vui lòng kiểm tra lại đường truyền mạng') - console.error(err); + } + localStorage.clear(); + } + + CheckLogin = async (event) => { + var form = $("#formLoginCheck") + if (form[0].checkValidity() === false) { + event.preventDefault() + event.stopPropagation() + form.addClass('was-validated') + } else { + event.preventDefault() + event.stopPropagation() + this.setState({ + loadingbtn: true + }, () => { + if (this.state.datalogin.password.length < 6) { + this.setState({ + error: 1, + loadingbtn: false + }) + } else { + fetch(`${HOST}/api/login`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(this.state.datalogin) + }).then((response) => { + if (response.status === 500) { + this.setState({ + error: 0, + loadingbtn: false + }) + swal("Cảnh báo!", "Hiện tại hệ thống của chúng tôi đang nâng cấp, vui lòng đăng nhập lại sau 30 phút", "info"); + return; + } + return response.json() + }).then((data) => { + if (data.status === 10000) { + this.setState({ + error: 0, + loadingbtn: false + }) + localStorage.setItem("access_token", "Bearer " + data.access_token); + Store.dispatch(login("Bearer " + data.access_token)); + localStorage.setItem("api_url", data.api_url); + localStorage.setItem("api2_url", data.api2_url); + window.location.href = "/"; + // return; + } else if (data.status === 10003) { + this.setState({ + loadingbtn: false + }) + swal("Cảnh báo!", "Tài khoản không tồn tại", "warning"); + } else if (data.status === 10005) { + this.setState({ + loadingbtn: false + }) + swal("Cảnh báo", "Tài khoản của bạn đã bị khóa, vui lòng chờ 30 phút rồi đăng nhập lại hoặc liên hệ admin", "warning"); + } else { + this.setState({ + error: 1, + loadingbtn: false + }) + } + }).catch((error) => { + if (error) { + this.setState({ + loadingbtn: false + }) + swal("Lỗi!", "Vui lòng kiểm tra lại đường truyền", "error"); + } + }) + } }) - setLoading(false); - }; + + } + } - const onFinishFailed = (errorInfo) => { - console.log('Failed:', errorInfo); - }; + onEnterPress = (e) => { + if (e.keyCode === 13 && e.shiftKey === false) { + e.preventDefault(); + this.CheckLogin(e); + } + } + HandleLogin = (e) => { + var datalogin = this.state.datalogin; + datalogin[e.target.name] = e.target.value.trim(); + this.setState({ datalogin: datalogin }); + } - return ( -
-
-
-

Đăng nhập

-
- - } - placeholder="Email" /> - - - } - type="password" - placeholder="Password" - /> - -
- {error && * Sai tài khoản mật khẩu } -
- - - -
+ render() { + return ( +
+
+ + + +
+
+ + + +
+
+ + < div className="form-group"> + + { + this.HandleLogin(e) + }} /> +
+
+ + { + this.HandleLogin(e) + }} /> +
+
+ +
+
+ + + +
- -
- -
- ); + + ) + } } - -export default Login; \ No newline at end of file +export default Login; diff --git a/app/src/components/Modal/ModaEditLabel.js b/app/src/components/Modal/ModaEditLabel.js index 9cc403f..9f4e9c0 100644 --- a/app/src/components/Modal/ModaEditLabel.js +++ b/app/src/components/Modal/ModaEditLabel.js @@ -30,6 +30,8 @@ const ModalEditLabel = (props) => { const [dateImage, setDateImg] = useState("") + const [dataUpload, setDataUpload] = useState([]) + const [hostImg, setHostImg] = useState(''); useEffect(() => { @@ -124,7 +126,7 @@ const ModalEditLabel = (props) => {
{ checkDeleteMulti === false ? - { setCrrIdx(index) }} className={"opacity_img_click img_check " + (crrIdx === index ? 'active' : '')} /> + { setCrrIdx(index) }} className={"opacity_img_click img_check " + (crrIdx === index ? 'active' : '')} /> : } @@ -143,13 +145,16 @@ const ModalEditLabel = (props) => { ) }) + const checkLength= (file,fileList) => { + if (crrImages.length + fileList.length > 3) { + swal("Cảnh báo", "Bạn chỉ được tải lên tối đa 3 ảnh!", "warning"); + return false + } + } + const uploadImage = async (options) => { - if (crrImages.length >= 3) { - swal("Cảnh báo", "Bạn chỉ được tải lên tối đa 3 ảnh!", "warning"); - return - } else { const { file } = options; const base64 = await convertBase64(file) @@ -158,32 +163,54 @@ const ModalEditLabel = (props) => { base64_image_list: [base64.split(',')[1]] } - fetch(`${HOST}/api/face_images/famous_person`, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - // 'Authorization': token - }, - body: JSON.stringify(dataUploadImg) - }) - .then(res => res.json()) - .then(data => { - if (data.status === 10000) { - setHostImg(data.image_host) - let listImg = [...crrImages] - listImg.unshift(data.data.toString()) - setCrrImages(listImg) - setCheckDeleteMulti(false) - } else if (data.status === 10003) { - if (data.message === "Too many face in image") { - swal("Thất bại", "Ảnh có nhiều khuôn mặt!", "error"); - } else { - swal("Thất bại", "Ảnh không hợp lệ", "error"); + let promises = []; + promises.push( + axios + .post(`${HOST}/api/face_images/famous_person`, dataUploadImg, { + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', } - } + }) + ) + await Promise.all(promises) + .then((data) => { + let success = false + let manyFace = false + let noFace = false + for (let i = 0; i < data.length; i++) { + const element = data[i]; + if (element.data.status === 10000) { + let listImg = dataUpload + setHostImg(element.data.image_host) + listImg.unshift(element.data.data.toString()) + setDataUpload(...dataUpload) + success = true + } else if (element.data.status === 10003 && element.data.message === "Too many face in image") { + manyFace = true + } else if (element.data.status === 10003 && element.data.message === "No face in image") { + noFace = true + } else { + success = false + } + } + if (success) { + let originData = crrImages + originData.unshift(dataUpload[0].toString()) + let arrSet = [...new Set(originData)] + setCrrImages(arrSet) + setCheckDeleteMulti(false) + } else if (manyFace) { + swal("Thất bại", "Ảnh có nhiều khuôn mặt!", "error"); + } else if (noFace) { + swal("Thất bại", "Ảnh không có khuôn mặt!", "error"); + } else { + swal("Thất bại", "Lỗi hệ thống!", "error"); + } }) - } + .catch((err) => { + console.log(err) + }); }; @@ -260,7 +287,7 @@ const ModalEditLabel = (props) => {
{ crrImages[crrIdx] ? - } /> : + } /> : } /> } @@ -323,11 +350,14 @@ const ModalEditLabel = (props) => { }>Tải ảnh lên + {!disableBtn &&
* Giới hạn 3 ảnh
}
diff --git a/app/src/components/Modal/ModalEdit.js b/app/src/components/Modal/ModalEdit.js index 2bb8b0b..1cba733 100644 --- a/app/src/components/Modal/ModalEdit.js +++ b/app/src/components/Modal/ModalEdit.js @@ -32,6 +32,8 @@ const Modaledit = (props) => { const [hostImg, setHostImg] = useState(''); + const [dataUpload, setDataUpload] = useState([]) + useEffect(() => { setCrrData(data); setCrrImages(data.sample_images) @@ -124,7 +126,7 @@ const Modaledit = (props) => {
{ checkDeleteMulti === false ? - { setCrrIdx(index) }} className={"opacity_img_click img_check " + (crrIdx === index ? 'active' : '')} /> + { setCrrIdx(index) }} className={"opacity_img_click img_check " + (crrIdx === index ? 'active' : '')} /> : } @@ -143,13 +145,14 @@ const Modaledit = (props) => { ) }) - + const checkLength= (file,fileList) => { + if (crrImages.length + fileList.length > 3) { + swal("Cảnh báo", "Bạn chỉ được tải lên tối đa 3 ảnh!", "warning"); + return false + } + } const uploadImage = async (options) => { - if (crrImages.length >= 3) { - swal("Cảnh báo", "Bạn chỉ được tải lên tối đa 3 ảnh!", "warning"); - return - } else { const { file } = options; const base64 = await convertBase64(file) @@ -158,32 +161,54 @@ const Modaledit = (props) => { base64_image_list: [base64.split(',')[1]] } - fetch(`${HOST}/api/face_images/famous_person`, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - // 'Authorization': token - }, - body: JSON.stringify(dataUploadImg) - }) - .then(res => res.json()) - .then(data => { - if (data.status === 10000) { - setHostImg(data.image_host) - let listImg = [...crrImages] - listImg.unshift(data.data.toString()) - setCrrImages(listImg) - setCheckDeleteMulti(false) - } else if (data.status === 10003) { - if (data.message === "Too many face in image") { - swal("Thất bại", "Ảnh có nhiều khuôn mặt!", "error"); - } else { - swal("Thất bại", "Ảnh không hợp lệ", "error"); + let promises = []; + promises.push( + axios + .post(`${HOST}/api/face_images/famous_person`, dataUploadImg, { + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', } - } + }) + ) + await Promise.all(promises) + .then((data) => { + let success = false + let manyFace = false + let noFace = false + for (let i = 0; i < data.length; i++) { + const element = data[i]; + if (element.data.status === 10000) { + let listImg = dataUpload + setHostImg(element.data.image_host) + listImg.unshift(element.data.data.toString()) + setDataUpload(...dataUpload) + success = true + } else if (element.data.status === 10003 && element.data.message === "Too many face in image") { + manyFace = true + } else if (element.data.status === 10003 && element.data.message === "No face in image") { + noFace = true + } else { + success = false + } + } + if (success) { + let originData = crrImages + originData.unshift(dataUpload[0].toString()) + let arrSet = [...new Set(originData)] + setCrrImages(arrSet) + setCheckDeleteMulti(false) + } else if (manyFace) { + swal("Thất bại", "Ảnh có nhiều khuôn mặt!", "error"); + } else if (noFace) { + swal("Thất bại", "Ảnh không có khuôn mặt!", "error"); + } else { + swal("Thất bại", "Lỗi hệ thống!", "error"); + } }) - } + .catch((err) => { + console.log(err) + }); }; @@ -260,8 +285,8 @@ const Modaledit = (props) => {
{ crrImages[crrIdx] ? - } /> : - } /> + } /> : + } /> }
@@ -323,11 +348,14 @@ const Modaledit = (props) => { }>Tải ảnh lên + {!disableBtn &&
* Giới hạn 3 ảnh
}
diff --git a/app/src/components/Modal/ModalPassword.js b/app/src/components/Modal/ModalPassword.js new file mode 100644 index 0000000..12d05bf --- /dev/null +++ b/app/src/components/Modal/ModalPassword.js @@ -0,0 +1,117 @@ +import { Form, Input } from 'antd'; +import axios from 'axios'; +import 'moment/locale/vi'; +import React from 'react'; +import { Button, Modal } from 'react-bootstrap'; +import swal from 'sweetalert'; +import { HOST } from '../../config/index'; + +const ModalPassword = (props) => { + const { show, onHide, obj_id } = props; + + const [form] = Form.useForm() + + const click_handle = async () => { + let dataPost = {password: form.getFieldValue('password')} + console.log(dataPost, obj_id) + const result = await axios.patch(`${HOST}/api/users/${obj_id}/password`, { password: form.getFieldValue('password') }) + if (result.data.status === 10000) { + swal({ + icon: 'success', + title: 'Thành công', + text: 'Thay đổi mật khẩu thành công', + timer: 1500, + buttons: false, + }) + onHide() + } else if (result.data.status === 10002) { + swal("Thất bại", "Lỗi hệ thống!", "error"); + } else { + swal("Thất bại", "Thay đổi mật khẩu thất bại!", "error"); + } + } + + + return ( + = 1920 ? "modal-size-res" : "modal-size"}`} + aria-labelledby="contained-modal-title-vcenter" + > + + Đổi mật khẩu + + + + +
+
+
+
+
click_handle()} + autoComplete="off" + initialValues={{ + + }} + > + + + + + ({ + validator(_, value) { + if (!value || getFieldValue('password') === value) { + return Promise.resolve(); + } + return Promise.reject(new Error('Mật khẩu không khớp')); + }, + }), + ]} + > + + +
+
+
+
+
+
+ + + + +
+ ); +} + +export default ModalPassword; diff --git a/app/src/components/Modal/ModalRole.js b/app/src/components/Modal/ModalRole.js new file mode 100644 index 0000000..e69de29 diff --git a/app/src/components/Modal/ModalUser.js b/app/src/components/Modal/ModalUser.js new file mode 100644 index 0000000..adf1e3b --- /dev/null +++ b/app/src/components/Modal/ModalUser.js @@ -0,0 +1,298 @@ +import { UploadOutlined, UserOutlined } from '@ant-design/icons'; +import { Avatar, Button as ButtonAntd, DatePicker, Form, Input, Radio, Upload, Select,Switch } from 'antd'; +import { useLocation } from 'react-router-dom'; +import viVN from 'antd/lib/locale/vi_VN'; +import axios from 'axios'; +import moment from 'moment'; +import 'moment/locale/vi'; +import React, { useEffect, useRef, useState } from 'react'; +import { Button, Modal } from 'react-bootstrap'; +import swal from 'sweetalert'; +import { HOST } from '../../config/index'; + +const { Option } = Select; + + +const ModalUser = (props) => { + const { show, onHide, data } = props; + const [crrImages, setCrrImages] = useState([]); + + const [form] = Form.useForm() + + + const [birthday, setBirthday] = useState(moment()) + const [crrData, setCrrData] = useState(null); + + const [selectedRole, setSelectedRole] = useState([]) + const [active, setActive] = useState(false) + + const [checkDeleteMulti, setCheckDeleteMulti] = useState(false); + const [crrIdx, setCrrIdx] = useState(0) + const [listChecked, setListChecked] = useState({ url: [] }); + + const [disableBtn, setDisableBtn] = useState(true); + + const [dateImage, setDateImg] = useState("") + + const [dataUpload, setDataUpload] = useState([]) + + const [hostImg, setHostImg] = useState(''); + + useEffect(() => { + setCrrData(data); + console.log(data) + // setCrrImages(data.sample_images) + // setBirthday(data.birthday !== "" ? moment(data.birthday) : null) + // setDisableBtn(data._id ? false : true) + // setHostImg(data.image_host) + // return () => { + // setCrrData(null); + // } + }, [data]); + + + // const handleCheckedImg = (event, value) => { + // let newListChecked = { ...listChecked } + // if (newListChecked.url.indexOf(event.target.value) === -1) { + // newListChecked.url.push(event.target.value) + // } else { + // var i = newListChecked.url.indexOf(event.target.value); + // if (i !== -1) { + // newListChecked.url.splice(i, 1); + // } + // } + // setListChecked(newListChecked) + + // } + + // useEffect(() => { + // if (crrImages.length > 0) { + // let crrDateImg = crrImages[crrIdx] + // let getDateImg = crrDateImg !== "" && crrDateImg.split("_") + // let dataImg = getDateImg.length > 0 && getDateImg[1].slice(0,6) + // setDateImg(dataImg) + // } + // },[crrImages,crrIdx]) + + const click_handle = async () => { + let dataPost = { + obj_id: crrData?._id ? crrData._id : "", + username: crrData.username, + full_name: crrData.full_name, + password: crrData.password, + is_deleted: 0, + birthday: crrData.birthday, + gender: crrData?.gender ? crrData.gender : "", + phone_number: crrData?.phone_number ? crrData?.phone_number : "", + role_id_list: selectedRole + } + const result = await axios({ + method: 'POST', + url: `${HOST}/api/users/insert_or_update`, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + // 'Authorization': token, + }, + data: dataPost, + }) + if (result.data.status === 10000) { + if (crrData._id) { + swal({ + icon: 'success', + title: 'Thành công', + text: 'Sửa thông tin thành công', + timer: 1500, + buttons: false, + }) + } else { + swal({ + icon: 'success', + title: 'Thành công', + text: 'Thêm mới thành công', + timer: 1500, + buttons: false, + }) + onHide() + } + } else if (result.data.status === 10002) { + swal("Thất bại", "Lỗi hệ thống!", "error"); + } else if (result.data.status === 10004) { + swal("Thất bại", "Tài khoản đã tồn tại!", "error"); + } else if (result.data.status === 10003) { + swal("Thất bại", "Tài khoản không được để trống!", "error"); + } else { + if (crrData._id) { + swal("Thất bại", "Sửa thông tin thất bại!", "error"); + } else { + swal("Thất bại", "Thêm mới thất bại!", "error"); + } + } + } + + + const UserHandle = (e) => { + setCrrData({ ...crrData, [e.target.name]: e.target.value }) + } + + const onChangeBirthday = (date) => { + setBirthday(date) + setCrrData({ ...crrData, birthday: moment(date).format("YYYY-MM-DD") }) + } + + const listOptions = []; + for (let i = 10; i < 36; i++) { + listOptions.push(); + } + + const handleChangeSelect = (value) => { + setSelectedRole(value) + } + + const onChangeActive = (value) => { + setActive(value) + } + + if (!crrData) return <>; + + return ( + = 1920 ? "modal-size-res" : "modal-size"}`} + aria-labelledby="contained-modal-title-vcenter" + > + + {crrData?._id ? "Sửa thông tin" : "Thêm mới"} + + + + +
+
+
+
+
click_handle()} + // onFinishFailed={onFinishFailed} + autoComplete="off" + initialValues={{ + full_name: crrData?.full_name, + gender: crrData?.gender, + username: crrData?.username, + role_id_list: crrData?.role_id_list, + phone_number: crrData?.phone_number + }} + > + + UserHandle(e)} name='username' /> + + {!crrData?._id && + + UserHandle(e)} name='password' /> + + } + + + UserHandle(e)} name='full_name' /> + + + UserHandle(e)} name='phone_number' /> + + + + UserHandle(e)} defaultValue={crrData?.gender}> + Nam + Nữ + Giới tính khác + + + + + onChangeBirthday(e)} + placeholder="Ngày sinh" + /> + + + {/* + + */} + + + + + +
+ {/*
+ +
*/} +
+
+
+
+
+ + + + +
+ ); +} + +export default ModalUser; diff --git a/app/src/components/User/User.js b/app/src/components/User/User.js new file mode 100644 index 0000000..23e2711 --- /dev/null +++ b/app/src/components/User/User.js @@ -0,0 +1,432 @@ +import { UserOutlined } from '@ant-design/icons'; +import { Avatar, Tooltip } from 'antd'; +import axios from 'axios'; +import ModalUser from '../Modal/ModalUser'; +import ModalPassword from '../Modal/ModalPassword'; +import momment from 'moment'; +import React, { useEffect, useState } from 'react'; +import Pagination from "react-js-pagination"; +import { PulseLoader } from 'react-spinners'; +import { HOST } from '../../config/index'; +import swal from 'sweetalert'; +import { useLocation } from 'react-router-dom'; +import Switch from "react-switch"; +import Select from "react-select"; + +const initialDataPost = { + index: 1, + item_per_page: 5, + search_data: "", + is_deleted: -1, +} + +export default function User() { + + const [data, setData] = useState(null) + const [showModal, setShowModal] = useState(false) + const [showModalPassword, setShowModalPassword] = useState(false) + const [dataEdit, setDataEdit] = useState(null) + + + const [optionSelect, setOptionSelect] = useState([ + {value: -1, label: "Tất cả"}, + {value: 0, label:"Hoạt động"}, + {value: 1, label: "Không hoạt động"}, + ]) + + const [valueSelected, setValueSelected] = useState({value: -1, label:"Tất cả"}) + + const [loading, setLoading] = useState(true) + + const [activePage, setActivePage] = useState(1) + const [totalItems, setTotalItems] = useState(0) + + const [offset, setOffset] = useState(0) + + const [dataPost, setDataPost] = useState(initialDataPost) + const itemsPerPage = 5 + + const [token, setToken] = useState(''); + + const location = useLocation(); + + useEffect(() => { + if (location.search) { + let path = location.search.replace('?', '').split('&'); + let obj = {} + path.forEach(value => { + let arr = value.split('='); + obj[arr[0]] = arr[1] + }) + setToken(decodeURIComponent(obj.token)) + setToken((obj.token)) + } + }, [location]) + + useEffect(() => { + getData() + }, []) + + const onClickEdit = (data) => { + setDataEdit(data) + setShowModal(true) + } + + const onClickPassword = (data) => { + setDataEdit(data._id) + setShowModalPassword(true) + } + + const onDelete = async (value) => { + try { + const result = await axios({ + method: 'DELETE', + url: `${HOST}/api/users/${value._id}`, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + // 'Authorization': token, + }, + }) + if (result.data.status === 10000) { + if (data.length === 1) { + setActivePage(activePage - 1) + setDataPost({ ...dataPost, index: activePage - 1 }) + } + swal({ + icon: 'success', + title: 'Thành công', + text: 'Xoá thành công', + timer: 1500, + buttons: false, + }) + getData(dataPost) + } else { + swal("Thất bại", "Xoá thất bại!", "error"); + } + } catch (error) { + setLoading(false) + console.log(error); + } + } + + useEffect(() => { + FilterItem() + }, [activePage]) + + const FilterItem = () => { + const offset = (activePage - 1) * itemsPerPage; + setOffset(offset) + } + + const handlePageChange = (pageNumber) => { + setActivePage(pageNumber); + const data = { + ...dataPost, + index: pageNumber, + } + getData(data); + } + + const getData = async (data) => { + try { + const result = await axios({ + method: 'POST', + url: `${HOST}/api/users/search`, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + // 'Authorization': token + }, + data: data ? data : dataPost, + }) + if (result.data.status === 10000) { + setData(result.data.data) + setTotalItems(result.data.count) + setLoading(false) + + } + } catch (error) { + setLoading(false) + console.log(error); + } + } + + const handleOnKeyDown = e => { + if (e.key === 'Enter') { + setActivePage(1) + getData(dataPost); + } + } + + const tableRows = (dataAll) => dataAll.map((value, index) => { + var gender = "" + if (value.gender === "1") { + gender = "Nam" + } else if (value.gender === "2") { + gender = "Nữ" + } else if (value.gender === "3") { + gender = "Giới tính khác" + } else { + gender = "" + } + + var checked = true; + if (value.is_deteted === 1) { + checked = true + + } + if (value.is_deteted === 0) { + checked = false + + } + + + return ( + + {(index + offset + 1)} + {value.username} + {value.full_name} + {gender} + {value.birthday !== "" ? momment(value.birthday).format("DD-MM-YYYY") : ""} + {value.phone_number} + + { + value.is_deleted === 1 + ? + Không hoạt động + : + Hoạt động + } + + + + + + + + + + + + + + ) + }) + + + const onCloseModal = () => { + setShowModal(false) + // setActivePage(activePage) + const data = { + ...dataPost, + index: activePage, + } + getData(data); + } + + const changeHandleFilter = (e) => { + setDataPost({ ...dataPost, is_deleted: e.value }) + setValueSelected(e) + } + const onCloseModalPassword = () => { + setShowModalPassword(false) + const data = { + ...dataPost, + index: activePage, + } + getData(data); + } + + const reset = () => { + setActivePage(1) + setDataPost({ ...dataPost, search_data: "" }) + getData(initialDataPost) + setValueSelected({ value: -1, label: "Tất cả" }) + } + + return ( +
+
+
+
+
+
+

+ Quản lí người dùng +

+
+
+
+
    +
  • + {/* { + this.state.dataRole.indexOf(this.state.type + '/' + nameTab + ':insert_or_update') !== -1 + ? */} + + {/* : + "" + } */} +
  • +
+
+
+
+
+
+
+
+
+ handleOnKeyDown(e)} + onChange={(e) => { + setDataPost({ ...dataPost, search_data: e.target.value }) + }} + value={dataPost.search_data} + id="inputSearch" + className="form-control m-input" + placeholder="Tên đăng nhập..." + data-col-index={0} /> +
+
+