From 5158781ed37b30d64d5d48902ff4422e7bb48cf2 Mon Sep 17 00:00:00 2001 From: triracle97 Date: Sat, 15 Apr 2023 12:41:45 +0700 Subject: [PATCH 1/8] New user table --- package.json | 4 +- src/App.js | 7 +- src/_nav.js | 10 +++ src/checkToken.js | 10 +++ src/components/AppHeader.js | 30 --------- src/constant.js | 1 + src/routes.js | 3 + src/store.js | 1 + src/views/data/User.js | 91 +++++++++++++++++++++++++ src/views/modal/ErrorModal.js | 0 src/views/modal/UserCreateModal.js | 104 +++++++++++++++++++++++++++++ src/views/pages/login/Login.js | 75 +++++++++++++-------- 12 files changed, 276 insertions(+), 60 deletions(-) create mode 100644 src/checkToken.js create mode 100644 src/constant.js create mode 100644 src/views/data/User.js create mode 100644 src/views/modal/ErrorModal.js create mode 100644 src/views/modal/UserCreateModal.js diff --git a/package.json b/package.json index da08efaab..3c1ec87f3 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "build": "react-scripts build", "eject": "react-scripts eject", "lint": "eslint \"src/**/*.js\"", - "start": "react-scripts start", + "start": "DISABLE_ESLINT_PLUGIN=true react-scripts start", "test": "react-scripts test", "test:cov": "npm test -- --coverage --watchAll=false", "test:debug": "react-scripts --inspect-brk test --runInBand" @@ -29,9 +29,11 @@ "@coreui/react": "^4.6.0", "@coreui/react-chartjs": "^2.1.2", "@coreui/utils": "^2.0.1", + "axios": "^1.3.5", "chart.js": "^3.9.1", "classnames": "^2.3.2", "core-js": "^3.29.0", + "js-cookie": "^3.0.1", "prop-types": "^15.8.1", "react": "^18.2.0", "react-app-polyfill": "^3.0.0", diff --git a/src/App.js b/src/App.js index 7c2488188..5866c2723 100644 --- a/src/App.js +++ b/src/App.js @@ -1,6 +1,7 @@ import React, { Component, Suspense } from 'react' -import { HashRouter, Route, Routes } from 'react-router-dom' +import { Route, Routes, BrowserRouter } from 'react-router-dom' import './scss/style.scss' +import './checkToken'; const loading = (
@@ -20,7 +21,7 @@ const Page500 = React.lazy(() => import('./views/pages/page500/Page500')) class App extends Component { render() { return ( - + } /> @@ -30,7 +31,7 @@ class App extends Component { } /> - + ) } } diff --git a/src/_nav.js b/src/_nav.js index 8f3d730db..343fa3e83 100644 --- a/src/_nav.js +++ b/src/_nav.js @@ -26,6 +26,16 @@ const _nav = [ text: 'NEW', }, }, + { + component: CNavItem, + name: 'User', + to: '/user', + icon: , + badge: { + color: 'info', + text: 'NEW', + }, + }, { component: CNavTitle, name: 'Theme', diff --git a/src/checkToken.js b/src/checkToken.js new file mode 100644 index 000000000..4e5c7f378 --- /dev/null +++ b/src/checkToken.js @@ -0,0 +1,10 @@ +import { redirect } from 'react-router-dom'; +import Cookies from "js-cookie"; +import axios from "axios"; + +const token = Cookies.get('authToken'); +if (!token) { + redirect('/login'); +} + +axios.defaults.headers.common['Authorization'] = `Bearer ${token}`; diff --git a/src/components/AppHeader.js b/src/components/AppHeader.js index dd5f544e3..0e6f16aaa 100644 --- a/src/components/AppHeader.js +++ b/src/components/AppHeader.js @@ -34,36 +34,6 @@ const AppHeader = () => { - - - - Dashboard - - - - Users - - - Settings - - - - - - - - - - - - - - - - - - - diff --git a/src/constant.js b/src/constant.js new file mode 100644 index 000000000..8db85283d --- /dev/null +++ b/src/constant.js @@ -0,0 +1 @@ +export const BACKEND_HOST = process.env.NODE_ENV === 'development' ? 'http://51.79.147.198:3000' : ''; diff --git a/src/routes.js b/src/routes.js index d168b1ca4..2c2ca4171 100644 --- a/src/routes.js +++ b/src/routes.js @@ -50,6 +50,8 @@ const Toasts = React.lazy(() => import('./views/notifications/toasts/Toasts')) const Widgets = React.lazy(() => import('./views/widgets/Widgets')) +const User = React.lazy(() => import('./views/data/User')) + const routes = [ { path: '/', exact: true, name: 'Home' }, { path: '/dashboard', name: 'Dashboard', element: Dashboard }, @@ -95,6 +97,7 @@ const routes = [ { path: '/notifications/modals', name: 'Modals', element: Modals }, { path: '/notifications/toasts', name: 'Toasts', element: Toasts }, { path: '/widgets', name: 'Widgets', element: Widgets }, + { path: '/user', name: 'User', element: User } ] export default routes diff --git a/src/store.js b/src/store.js index ab446364c..743345492 100644 --- a/src/store.js +++ b/src/store.js @@ -2,6 +2,7 @@ import { createStore } from 'redux' const initialState = { sidebarShow: true, + authToken: null } const changeState = (state = initialState, { type, ...rest }) => { diff --git a/src/views/data/User.js b/src/views/data/User.js new file mode 100644 index 000000000..a575d3c14 --- /dev/null +++ b/src/views/data/User.js @@ -0,0 +1,91 @@ +import { + CButton, CCol, + CPagination, CPaginationItem, + CRow, + CTable, CTableBody, CTableDataCell, + CTableHead, + CTableHeaderCell, + CTableRow +} from '@coreui/react'; +import React, {useEffect, useState, useRef} from 'react'; +import { useNavigate } from 'react-router-dom'; +import axios from 'axios'; +import { BACKEND_HOST } from '../../constant'; +import UserCreateModal from "../modal/UserCreateModal"; + +const User = () => { + const [users, setUsers] = useState([]); + const [limit, setLimit] = useState(20); + const [offset, setOffset] = useState(0); + + const createUserModalRef = useRef(); + + const navigate = useNavigate(); + + useEffect(() => { + getUsersData(); + }, []) + + const getUsersData = () => { + axios.get(`${BACKEND_HOST}/user`, { + params: { + limit, + offset + } + }) + .then(res => { + const newUsers = res.data.users; + setUsers(newUsers); + }) + .catch(err => { + console.log('Error while getting user', err); + }) + } + + const openCreateUser = () => { + createUserModalRef.current?.show(); + } + + return ( + + + + Create user + + + + + + Username + Role + Name + + + + {users.map((item, index) => { + return ( + + {item.username} + {item.role} + {item.name} + + ) + })} + + + + + + + 1 + + + + + + + ) +} + +export default User diff --git a/src/views/modal/ErrorModal.js b/src/views/modal/ErrorModal.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/views/modal/UserCreateModal.js b/src/views/modal/UserCreateModal.js new file mode 100644 index 000000000..7ee702430 --- /dev/null +++ b/src/views/modal/UserCreateModal.js @@ -0,0 +1,104 @@ +import React, { useState, useImperativeHandle } from 'react'; +import { + CButton, + CModal, + CModalBody, + CModalFooter, + CModalHeader, + CModalTitle, + CForm, + CInputGroupText, + CFormInput, + CInputGroup, + CAlert +} from '@coreui/react'; +import CIcon from "@coreui/icons-react"; +import {cilLockLocked, cilUser, cilText} from "@coreui/icons"; +import axios from "axios"; +import { BACKEND_HOST } from "../../constant"; + +const UserCreateModal = ({}, ref) => { + const [visible, setVisible] = useState(false); + const [username, setUsername] = useState(''); + const [name, setName] = useState(''); + const [password, setPassword] = useState(''); + const [error, setError] = useState(false); + const [success, setSuccess] = useState(false); + + useImperativeHandle(ref, () => ({ + show: () => { + setVisible(true); + } + })) + + const handleSubmit = () => { + axios.post(`${BACKEND_HOST}/user/create`, { + username, + password, + name + }) + .then(res => { + setSuccess(true); + }) + .catch(err => { + console.log('Error', err); + setError(true); + }); + }; + + return ( + setVisible(false)}> + + Create User + + + {error && {'Error'}} + {success && {'Done'}} + + + + + + setUsername(event.target.value)} + placeholder="Username" + autoComplete="username"/> + + + + + + setPassword(event.target.value)} + /> + + + + + + setName(event.target.value)} + /> + + + + + setVisible(false)}> + Cancel + + + Create + + + + ); +}; + +export default React.forwardRef(UserCreateModal); diff --git a/src/views/pages/login/Login.js b/src/views/pages/login/Login.js index 6b889d530..6deb5c975 100644 --- a/src/views/pages/login/Login.js +++ b/src/views/pages/login/Login.js @@ -1,5 +1,5 @@ -import React from 'react' -import { Link } from 'react-router-dom' +import React, { useState, useEffect } from 'react' +import { Link, useNavigate } from 'react-router-dom' import { CButton, CCard, @@ -12,11 +12,43 @@ import { CInputGroup, CInputGroupText, CRow, + CModal, + CModalBody } from '@coreui/react' import CIcon from '@coreui/icons-react' import { cilLockLocked, cilUser } from '@coreui/icons' +import axios from 'axios'; +import { BACKEND_HOST } from '../../../constant'; +import { useDispatch } from 'react-redux'; +import Cookies from 'js-cookie'; +import UserCreateModal from "../../modal/UserCreateModal"; const Login = () => { + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + const [showErrorModal, setShowErrorModal] = useState(false); + const dispatch = useDispatch(); + const navigate = useNavigate(); + + // useEffect(() => { + // const token = Cookies.get('authToken'); + // if (token) { + // navigate('/dashboard'); + // } + // }, []); + + const doLogin = async () => { + try { + const response = await axios.post(`${BACKEND_HOST}/auth/login`, {username, password}); + const token = response?.data?.token; + dispatch({ type: 'set', authToken: token }); + Cookies.set('authToken', token, { expires: 1 }); + navigate('/dashboard'); + } catch (err) { + setShowErrorModal(true); + } + } + return (
@@ -32,7 +64,11 @@ const Login = () => { - + setUsername(event.target.value)} + placeholder="Username" + autoComplete="username"/> @@ -41,43 +77,30 @@ const Login = () => { setPassword(event.target.value)} /> - + Login - - - Forgot password? - - - - -
-

Sign up

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod - tempor incididunt ut labore et dolore magna aliqua. -

- - - Register Now! - - -
-
-
+ setShowErrorModal(false)}> + +

Incorrect username or password. Please try again.

+
+
) From 6eecf4181648d05d948963387cfd7176db06da72 Mon Sep 17 00:00:00 2001 From: triracle97 Date: Sat, 15 Apr 2023 16:22:26 +0700 Subject: [PATCH 2/8] Add loading to modal --- src/_nav.js | 8 +- src/routes.js | 4 +- src/views/data/Customer.js | 88 ++++++++++++++++++++++ src/views/data/File.js | 86 ++++++++++++++++++++++ src/views/modal/UploadFileModal.js | 114 +++++++++++++++++++++++++++++ src/views/pages/login/Login.js | 8 -- 6 files changed, 295 insertions(+), 13 deletions(-) create mode 100644 src/views/data/Customer.js create mode 100644 src/views/data/File.js create mode 100644 src/views/modal/UploadFileModal.js diff --git a/src/_nav.js b/src/_nav.js index 343fa3e83..1414b35e7 100644 --- a/src/_nav.js +++ b/src/_nav.js @@ -18,8 +18,8 @@ import { CNavGroup, CNavItem, CNavTitle } from '@coreui/react' const _nav = [ { component: CNavItem, - name: 'Dashboard', - to: '/dashboard', + name: 'User', + to: '/user', icon: , badge: { color: 'info', @@ -28,8 +28,8 @@ const _nav = [ }, { component: CNavItem, - name: 'User', - to: '/user', + name: 'File', + to: '/file', icon: , badge: { color: 'info', diff --git a/src/routes.js b/src/routes.js index 2c2ca4171..ed0ef3297 100644 --- a/src/routes.js +++ b/src/routes.js @@ -51,6 +51,7 @@ const Toasts = React.lazy(() => import('./views/notifications/toasts/Toasts')) const Widgets = React.lazy(() => import('./views/widgets/Widgets')) const User = React.lazy(() => import('./views/data/User')) +const File = React.lazy(() => import('./views/data/File')) const routes = [ { path: '/', exact: true, name: 'Home' }, @@ -97,7 +98,8 @@ const routes = [ { path: '/notifications/modals', name: 'Modals', element: Modals }, { path: '/notifications/toasts', name: 'Toasts', element: Toasts }, { path: '/widgets', name: 'Widgets', element: Widgets }, - { path: '/user', name: 'User', element: User } + { path: '/user', name: 'User', element: User }, + { path: '/file', name: 'File', element: File } ] export default routes diff --git a/src/views/data/Customer.js b/src/views/data/Customer.js new file mode 100644 index 000000000..ee1fe324d --- /dev/null +++ b/src/views/data/Customer.js @@ -0,0 +1,88 @@ +import { + CButton, CCol, + CPagination, CPaginationItem, + CRow, + CTable, CTableBody, CTableDataCell, + CTableHead, + CTableHeaderCell, + CTableRow +} from '@coreui/react'; +import React, {useEffect, useState, useRef} from 'react'; +import axios from 'axios'; +import { BACKEND_HOST } from '../../constant'; +import UserCreateModal from "../modal/UserCreateModal"; + +const Customer = () => { + const [users, setUsers] = useState([]); + const [limit, setLimit] = useState(20); + const [offset, setOffset] = useState(0); + + const createUserModalRef = useRef(); + + useEffect(() => { + getCustomersData(); + }, []) + + const getCustomersData = () => { + axios.get(`${BACKEND_HOST}/user`, { + params: { + limit, + offset + } + }) + .then(res => { + const newUsers = res.data.users; + setUsers(newUsers); + }) + .catch(err => { + console.log('Error while getting user', err); + }) + } + + const openCreateUser = () => { + createUserModalRef.current?.show(); + } + + return ( + + + + Create user + + + + + + Username + Role + Name + + + + {users.map((item, index) => { + return ( + + {item.username} + {item.role} + {item.name} + + ) + })} + + + + + + + 1 + + + + + + + ) +} + +export default Customer diff --git a/src/views/data/File.js b/src/views/data/File.js new file mode 100644 index 000000000..fc416c111 --- /dev/null +++ b/src/views/data/File.js @@ -0,0 +1,86 @@ +import { + CButton, CCol, + CPagination, CPaginationItem, + CRow, + CTable, CTableBody, CTableDataCell, + CTableHead, + CTableHeaderCell, + CTableRow +} from '@coreui/react'; +import React, {useEffect, useState, useRef} from 'react'; +import axios from 'axios'; +import { BACKEND_HOST } from '../../constant'; +import UploadFileModal from "../modal/UploadFileModal"; + +const File = () => { + const [files, setFiles] = useState([]); + const [limit, setLimit] = useState(20); + const [offset, setOffset] = useState(0); + + const uploadFileRef = useRef(); + + useEffect(() => { + console.log('shit'); + getFilesData(); + }, []) + + const getFilesData = () => { + axios.get(`${BACKEND_HOST}/file`, { + params: { + limit, + offset + } + }) + .then(res => { + const newFiles = res.data.files; + console.log('123123', newFiles); + setFiles(newFiles); + }) + .catch(err => { + console.log('Error while getting user', err); + }) + } + + const openUploadFile = () => { + uploadFileRef.current?.show(); + } + + return ( + + + + Upload file + + + + + + Filename + + + + {files.map((item, index) => { + return ( + + {item.originalName} + + ) + })} + + + + + + + 1 + + + + + + + ) +} + +export default File; diff --git a/src/views/modal/UploadFileModal.js b/src/views/modal/UploadFileModal.js new file mode 100644 index 000000000..4741ab789 --- /dev/null +++ b/src/views/modal/UploadFileModal.js @@ -0,0 +1,114 @@ +import React, { useState, useImperativeHandle } from 'react'; +import { + CButton, + CModal, + CModalBody, + CModalFooter, + CModalHeader, + CModalTitle, + CForm, + CInputGroupText, + CFormInput, + CInputGroup, + CAlert, CProgress +} from '@coreui/react'; +import CIcon from "@coreui/icons-react"; +import {cilLockLocked, cilUser, cilText} from "@coreui/icons"; +import axios from "axios"; +import { BACKEND_HOST } from "../../constant"; +import * as PropTypes from "prop-types"; + +function CFormGroup(props) { + return null; +} + +CFormGroup.propTypes = {children: PropTypes.node}; + +function CLabel(props) { + return null; +} + +CLabel.propTypes = {children: PropTypes.node}; + +function CInputFile(props) { + return null; +} + +CInputFile.propTypes = { + onChange: PropTypes.func, + name: PropTypes.string, + id: PropTypes.string, + required: PropTypes.bool +}; +const UploadFileModal = ({}, ref) => { + const [visible, setVisible] = useState(false); + const [file, setFile] = useState(null); + const [uploading, setUploading] = useState(false); + const [progress, setProgress] = useState(0); + + useImperativeHandle(ref, () => ({ + show: () => { + setVisible(true); + } + })) + + const handleUpload = () => { + setUploading(true); + axios.post(`${BACKEND_HOST}/file/upload`, { + file + }, { + headers: { + 'content-type': 'multipart/form-data', + }, + onUploadProgress: (progressEvent) => { + const percentCompleted = Math.round( + (progressEvent.loaded * 100) / progressEvent.total + ); + setProgress(percentCompleted); + }, + }) + .then(res => { + setSuccess(true); + }) + .catch(err => { + console.log('Error', err); + setError(true); + }); + }; + + return ( + setVisible(false)}> + + Upload file + + +
+ setFile(event.target.files[0])} + type="file" + id="formFile" + label="Choose file" /> +
+ {uploading && ( + + )} +
+ + setVisible(false)}> + Cancel + + + Create + + +
+ ); +}; + +export default React.forwardRef(UploadFileModal); diff --git a/src/views/pages/login/Login.js b/src/views/pages/login/Login.js index 6deb5c975..375df0b32 100644 --- a/src/views/pages/login/Login.js +++ b/src/views/pages/login/Login.js @@ -28,14 +28,6 @@ const Login = () => { const [password, setPassword] = useState(''); const [showErrorModal, setShowErrorModal] = useState(false); const dispatch = useDispatch(); - const navigate = useNavigate(); - - // useEffect(() => { - // const token = Cookies.get('authToken'); - // if (token) { - // navigate('/dashboard'); - // } - // }, []); const doLogin = async () => { try { From 44d20a112c2b7daae98d2f7f8bed3632ede00264 Mon Sep 17 00:00:00 2001 From: triracle97 Date: Sat, 15 Apr 2023 17:07:04 +0700 Subject: [PATCH 3/8] Tweak auth --- src/checkToken.js | 4 -- src/components/header/AppHeaderDropdown.js | 77 ++++------------------ src/layout/DefaultLayout.js | 2 + src/views/Auth.js | 16 +++++ src/views/pages/login/Login.js | 4 +- 5 files changed, 32 insertions(+), 71 deletions(-) create mode 100644 src/views/Auth.js diff --git a/src/checkToken.js b/src/checkToken.js index 4e5c7f378..657ea991d 100644 --- a/src/checkToken.js +++ b/src/checkToken.js @@ -1,10 +1,6 @@ -import { redirect } from 'react-router-dom'; import Cookies from "js-cookie"; import axios from "axios"; const token = Cookies.get('authToken'); -if (!token) { - redirect('/login'); -} axios.defaults.headers.common['Authorization'] = `Bearer ${token}`; diff --git a/src/components/header/AppHeaderDropdown.js b/src/components/header/AppHeaderDropdown.js index 5be919ee9..6a2c94bf5 100644 --- a/src/components/header/AppHeaderDropdown.js +++ b/src/components/header/AppHeaderDropdown.js @@ -1,92 +1,37 @@ import React from 'react' import { CAvatar, - CBadge, CDropdown, - CDropdownDivider, - CDropdownHeader, CDropdownItem, CDropdownMenu, CDropdownToggle, } from '@coreui/react' import { - cilBell, - cilCreditCard, - cilCommentSquare, - cilEnvelopeOpen, - cilFile, cilLockLocked, - cilSettings, - cilTask, - cilUser, } from '@coreui/icons' import CIcon from '@coreui/icons-react' +import Cookies from 'js-cookie' +import { useNavigate } from 'react-router-dom'; import avatar8 from './../../assets/images/avatars/8.jpg' const AppHeaderDropdown = () => { + const navigate = useNavigate(); + + const doLogOut = () => { + Cookies.remove('authToken') + navigate('/login') + } + return ( - Account - - - Updates - - 42 - - - - - Messages - - 42 - - - - - Tasks - - 42 - - - - - Comments - - 42 - - - Settings - - - Profile - - - - Settings - - - - Payments - - 42 - - - - - Projects - - 42 - - - - + - Lock Account + Log out diff --git a/src/layout/DefaultLayout.js b/src/layout/DefaultLayout.js index 43bd64432..34626157a 100644 --- a/src/layout/DefaultLayout.js +++ b/src/layout/DefaultLayout.js @@ -1,9 +1,11 @@ import React from 'react' import { AppContent, AppSidebar, AppFooter, AppHeader } from '../components/index' +import Auth from '../views/Auth'; const DefaultLayout = () => { return (
+
diff --git a/src/views/Auth.js b/src/views/Auth.js new file mode 100644 index 000000000..5839d6b0e --- /dev/null +++ b/src/views/Auth.js @@ -0,0 +1,16 @@ +import React, { useEffect } from 'react'; +import Cookies from 'js-cookie'; +import { useNavigate } from 'react-router-dom'; + +export default function Auth() { + const navigate = useNavigate(); + + useEffect(() => { + const token = Cookies.get('authToken'); + if (!token) { + navigate('/login'); + } + }, []); + + return null; +} diff --git a/src/views/pages/login/Login.js b/src/views/pages/login/Login.js index 375df0b32..f5f28ca8b 100644 --- a/src/views/pages/login/Login.js +++ b/src/views/pages/login/Login.js @@ -21,7 +21,6 @@ import axios from 'axios'; import { BACKEND_HOST } from '../../../constant'; import { useDispatch } from 'react-redux'; import Cookies from 'js-cookie'; -import UserCreateModal from "../../modal/UserCreateModal"; const Login = () => { const [username, setUsername] = useState(''); @@ -29,14 +28,17 @@ const Login = () => { const [showErrorModal, setShowErrorModal] = useState(false); const dispatch = useDispatch(); + const navigate = useNavigate(); const doLogin = async () => { try { const response = await axios.post(`${BACKEND_HOST}/auth/login`, {username, password}); const token = response?.data?.token; dispatch({ type: 'set', authToken: token }); + axios.defaults.headers.common['Authorization'] = `Bearer ${token}`; Cookies.set('authToken', token, { expires: 1 }); navigate('/dashboard'); } catch (err) { + console.log('Error while login', err); setShowErrorModal(true); } } From 1badc3b3b63b328968b718fcf1faf279a4980aca Mon Sep 17 00:00:00 2001 From: triracle97 Date: Sat, 15 Apr 2023 20:14:53 +0700 Subject: [PATCH 4/8] Disable eslint --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3c1ec87f3..dade0e08c 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "license": "MIT", "author": "The CoreUI Team (https://github.com/orgs/coreui/people)", "scripts": { - "build": "react-scripts build", + "build": "DISABLE_ESLINT_PLUGIN=true react-scripts build", "eject": "react-scripts eject", "lint": "eslint \"src/**/*.js\"", "start": "DISABLE_ESLINT_PLUGIN=true react-scripts start", From 7e3353e64f138ba6059f597e28488061960a6a2e Mon Sep 17 00:00:00 2001 From: triracle97 Date: Sat, 15 Apr 2023 21:32:15 +0700 Subject: [PATCH 5/8] Wait a bit before navigating --- src/views/Auth.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/views/Auth.js b/src/views/Auth.js index 5839d6b0e..fec2824f6 100644 --- a/src/views/Auth.js +++ b/src/views/Auth.js @@ -8,7 +8,9 @@ export default function Auth() { useEffect(() => { const token = Cookies.get('authToken'); if (!token) { - navigate('/login'); + setTimeout(() => { + navigate('/login'); + }, 100) } }, []); From faec25094533a4ab83f8ee970a8dfbdb81059763 Mon Sep 17 00:00:00 2001 From: triracle97 Date: Sat, 15 Apr 2023 21:41:09 +0700 Subject: [PATCH 6/8] Update production url --- src/constant.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constant.js b/src/constant.js index 8db85283d..c58c74749 100644 --- a/src/constant.js +++ b/src/constant.js @@ -1 +1 @@ -export const BACKEND_HOST = process.env.NODE_ENV === 'development' ? 'http://51.79.147.198:3000' : ''; +export const BACKEND_HOST = process.env.NODE_ENV === 'development' ? 'http://51.79.147.198:3000' : 'http://localhost:3000'; From 972e448a6e21111bd88fd0aa7d7be3da9d659a05 Mon Sep 17 00:00:00 2001 From: triracle97 Date: Sat, 15 Apr 2023 21:50:31 +0700 Subject: [PATCH 7/8] Update url --- src/constant.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constant.js b/src/constant.js index c58c74749..b5053346e 100644 --- a/src/constant.js +++ b/src/constant.js @@ -1 +1 @@ -export const BACKEND_HOST = process.env.NODE_ENV === 'development' ? 'http://51.79.147.198:3000' : 'http://localhost:3000'; +export const BACKEND_HOST = process.env.NODE_ENV === 'development' ? 'http://51.79.147.198:3000' : 'http://api.namthanhdatholdings.com'; From f214ab8dd0b951eeb73d064e8b264496a9759676 Mon Sep 17 00:00:00 2001 From: hieu Date: Tue, 18 Apr 2023 02:32:26 +0700 Subject: [PATCH 8/8] create Custommer --- package.json | 2 +- src/App.js | 2 +- src/_nav.js | 553 ++++++++++---------- src/components/multiselect/MultiSelect.js | 46 ++ src/components/multiselect/MultiSelect.scss | 37 ++ src/constant.js | 5 +- src/routes.js | 4 +- src/views/data/Actions.js | 18 + src/views/data/Customer.js | 93 ++-- src/views/data/File.js | 68 +-- src/views/data/User.js | 76 +-- src/views/modal/CustomerCreateModel.js | 265 ++++++++++ src/views/modal/Provinces.json | 443 ++++++++++++++++ src/views/modal/UploadFileModal.js | 107 ++-- src/views/modal/UserCreateModal.js | 64 +-- 15 files changed, 1322 insertions(+), 461 deletions(-) create mode 100644 src/components/multiselect/MultiSelect.js create mode 100644 src/components/multiselect/MultiSelect.scss create mode 100644 src/views/data/Actions.js create mode 100644 src/views/modal/CustomerCreateModel.js create mode 100644 src/views/modal/Provinces.json diff --git a/package.json b/package.json index dade0e08c..1a2cb95de 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "build": "DISABLE_ESLINT_PLUGIN=true react-scripts build", "eject": "react-scripts eject", "lint": "eslint \"src/**/*.js\"", - "start": "DISABLE_ESLINT_PLUGIN=true react-scripts start", + "start": "react-scripts start", "test": "react-scripts test", "test:cov": "npm test -- --coverage --watchAll=false", "test:debug": "react-scripts --inspect-brk test --runInBand" diff --git a/src/App.js b/src/App.js index 5866c2723..bf29f7e10 100644 --- a/src/App.js +++ b/src/App.js @@ -1,7 +1,7 @@ import React, { Component, Suspense } from 'react' import { Route, Routes, BrowserRouter } from 'react-router-dom' import './scss/style.scss' -import './checkToken'; +import './checkToken' const loading = (
diff --git a/src/_nav.js b/src/_nav.js index 1414b35e7..cdc38bd93 100644 --- a/src/_nav.js +++ b/src/_nav.js @@ -11,6 +11,8 @@ import { cilPencil, cilPuzzle, cilSpeedometer, + cilFile, + cilPeople, cilStar, } from '@coreui/icons' import { CNavGroup, CNavItem, CNavTitle } from '@coreui/react' @@ -20,296 +22,303 @@ const _nav = [ component: CNavItem, name: 'User', to: '/user', - icon: , + icon: , badge: { color: 'info', - text: 'NEW', }, }, { component: CNavItem, name: 'File', to: '/file', - icon: , + icon: , badge: { color: 'info', - text: 'NEW', }, }, - { - component: CNavTitle, - name: 'Theme', - }, - { - component: CNavItem, - name: 'Colors', - to: '/theme/colors', - icon: , - }, - { - component: CNavItem, - name: 'Typography', - to: '/theme/typography', - icon: , - }, - { - component: CNavTitle, - name: 'Components', - }, - { - component: CNavGroup, - name: 'Base', - to: '/base', - icon: , - items: [ - { - component: CNavItem, - name: 'Accordion', - to: '/base/accordion', - }, - { - component: CNavItem, - name: 'Breadcrumb', - to: '/base/breadcrumbs', - }, - { - component: CNavItem, - name: 'Cards', - to: '/base/cards', - }, - { - component: CNavItem, - name: 'Carousel', - to: '/base/carousels', - }, - { - component: CNavItem, - name: 'Collapse', - to: '/base/collapses', - }, - { - component: CNavItem, - name: 'List group', - to: '/base/list-groups', - }, - { - component: CNavItem, - name: 'Navs & Tabs', - to: '/base/navs', - }, - { - component: CNavItem, - name: 'Pagination', - to: '/base/paginations', - }, - { - component: CNavItem, - name: 'Placeholders', - to: '/base/placeholders', - }, - { - component: CNavItem, - name: 'Popovers', - to: '/base/popovers', - }, - { - component: CNavItem, - name: 'Progress', - to: '/base/progress', - }, - { - component: CNavItem, - name: 'Spinners', - to: '/base/spinners', - }, - { - component: CNavItem, - name: 'Tables', - to: '/base/tables', - }, - { - component: CNavItem, - name: 'Tooltips', - to: '/base/tooltips', - }, - ], - }, - { - component: CNavGroup, - name: 'Buttons', - to: '/buttons', - icon: , - items: [ - { - component: CNavItem, - name: 'Buttons', - to: '/buttons/buttons', - }, - { - component: CNavItem, - name: 'Buttons groups', - to: '/buttons/button-groups', - }, - { - component: CNavItem, - name: 'Dropdowns', - to: '/buttons/dropdowns', - }, - ], - }, - { - component: CNavGroup, - name: 'Forms', - icon: , - items: [ - { - component: CNavItem, - name: 'Form Control', - to: '/forms/form-control', - }, - { - component: CNavItem, - name: 'Select', - to: '/forms/select', - }, - { - component: CNavItem, - name: 'Checks & Radios', - to: '/forms/checks-radios', - }, - { - component: CNavItem, - name: 'Range', - to: '/forms/range', - }, - { - component: CNavItem, - name: 'Input Group', - to: '/forms/input-group', - }, - { - component: CNavItem, - name: 'Floating Labels', - to: '/forms/floating-labels', - }, - { - component: CNavItem, - name: 'Layout', - to: '/forms/layout', - }, - { - component: CNavItem, - name: 'Validation', - to: '/forms/validation', - }, - ], - }, - { - component: CNavItem, - name: 'Charts', - to: '/charts', - icon: , - }, - { - component: CNavGroup, - name: 'Icons', - icon: , - items: [ - { - component: CNavItem, - name: 'CoreUI Free', - to: '/icons/coreui-icons', - badge: { - color: 'success', - text: 'NEW', - }, - }, - { - component: CNavItem, - name: 'CoreUI Flags', - to: '/icons/flags', - }, - { - component: CNavItem, - name: 'CoreUI Brands', - to: '/icons/brands', - }, - ], - }, - { - component: CNavGroup, - name: 'Notifications', - icon: , - items: [ - { - component: CNavItem, - name: 'Alerts', - to: '/notifications/alerts', - }, - { - component: CNavItem, - name: 'Badges', - to: '/notifications/badges', - }, - { - component: CNavItem, - name: 'Modal', - to: '/notifications/modals', - }, - { - component: CNavItem, - name: 'Toasts', - to: '/notifications/toasts', - }, - ], - }, { component: CNavItem, - name: 'Widgets', - to: '/widgets', - icon: , + name: 'Customer', + to: '/customer', + icon: , badge: { color: 'info', - text: 'NEW', }, }, - { - component: CNavTitle, - name: 'Extras', - }, - { - component: CNavGroup, - name: 'Pages', - icon: , - items: [ - { - component: CNavItem, - name: 'Login', - to: '/login', - }, - { - component: CNavItem, - name: 'Register', - to: '/register', - }, - { - component: CNavItem, - name: 'Error 404', - to: '/404', - }, - { - component: CNavItem, - name: 'Error 500', - to: '/500', - }, - ], - }, - { - component: CNavItem, - name: 'Docs', - href: 'https://coreui.io/react/docs/templates/installation/', - icon: , - }, + // // { + // // component: CNavTitle, + // // name: 'Theme', + // // }, + // // { + // // component: CNavItem, + // // name: 'Colors', + // // to: '/theme/colors', + // // icon: , + // // }, + // { + // component: CNavItem, + // name: 'Typography', + // to: '/theme/typography', + // icon: , + // }, + // { + // component: CNavTitle, + // name: 'Components', + // }, + // { + // component: CNavGroup, + // name: 'Base', + // to: '/base', + // icon: , + // items: [ + // { + // component: CNavItem, + // name: 'Accordion', + // to: '/base/accordion', + // }, + // { + // component: CNavItem, + // name: 'Breadcrumb', + // to: '/base/breadcrumbs', + // }, + // { + // component: CNavItem, + // name: 'Cards', + // to: '/base/cards', + // }, + // { + // component: CNavItem, + // name: 'Carousel', + // to: '/base/carousels', + // }, + // { + // component: CNavItem, + // name: 'Collapse', + // to: '/base/collapses', + // }, + // { + // component: CNavItem, + // name: 'List group', + // to: '/base/list-groups', + // }, + // { + // component: CNavItem, + // name: 'Navs & Tabs', + // to: '/base/navs', + // }, + // { + // component: CNavItem, + // name: 'Pagination', + // to: '/base/paginations', + // }, + // { + // component: CNavItem, + // name: 'Placeholders', + // to: '/base/placeholders', + // }, + // { + // component: CNavItem, + // name: 'Popovers', + // to: '/base/popovers', + // }, + // { + // component: CNavItem, + // name: 'Progress', + // to: '/base/progress', + // }, + // { + // component: CNavItem, + // name: 'Spinners', + // to: '/base/spinners', + // }, + // { + // component: CNavItem, + // name: 'Tables', + // to: '/base/tables', + // }, + // { + // component: CNavItem, + // name: 'Tooltips', + // to: '/base/tooltips', + // }, + // ], + // }, + // { + // component: CNavGroup, + // name: 'Buttons', + // to: '/buttons', + // icon: , + // items: [ + // { + // component: CNavItem, + // name: 'Buttons', + // to: '/buttons/buttons', + // }, + // { + // component: CNavItem, + // name: 'Buttons groups', + // to: '/buttons/button-groups', + // }, + // { + // component: CNavItem, + // name: 'Dropdowns', + // to: '/buttons/dropdowns', + // }, + // ], + // }, + // { + // component: CNavGroup, + // name: 'Forms', + // icon: , + // items: [ + // { + // component: CNavItem, + // name: 'Form Control', + // to: '/forms/form-control', + // }, + // { + // component: CNavItem, + // name: 'Select', + // to: '/forms/select', + // }, + // { + // component: CNavItem, + // name: 'Checks & Radios', + // to: '/forms/checks-radios', + // }, + // { + // component: CNavItem, + // name: 'Range', + // to: '/forms/range', + // }, + // { + // component: CNavItem, + // name: 'Input Group', + // to: '/forms/input-group', + // }, + // { + // component: CNavItem, + // name: 'Floating Labels', + // to: '/forms/floating-labels', + // }, + // { + // component: CNavItem, + // name: 'Layout', + // to: '/forms/layout', + // }, + // { + // component: CNavItem, + // name: 'Validation', + // to: '/forms/validation', + // }, + // ], + // }, + // { + // component: CNavItem, + // name: 'Charts', + // to: '/charts', + // icon: , + // }, + // { + // component: CNavGroup, + // name: 'Icons', + // icon: , + // items: [ + // { + // component: CNavItem, + // name: 'CoreUI Free', + // to: '/icons/coreui-icons', + // badge: { + // color: 'success', + // text: 'NEW', + // }, + // }, + // { + // component: CNavItem, + // name: 'CoreUI Flags', + // to: '/icons/flags', + // }, + // { + // component: CNavItem, + // name: 'CoreUI Brands', + // to: '/icons/brands', + // }, + // ], + // }, + // { + // component: CNavGroup, + // name: 'Notifications', + // icon: , + // items: [ + // { + // component: CNavItem, + // name: 'Alerts', + // to: '/notifications/alerts', + // }, + // { + // component: CNavItem, + // name: 'Badges', + // to: '/notifications/badges', + // }, + // { + // component: CNavItem, + // name: 'Modal', + // to: '/notifications/modals', + // }, + // { + // component: CNavItem, + // name: 'Toasts', + // to: '/notifications/toasts', + // }, + // ], + // }, + // { + // component: CNavItem, + // name: 'Widgets', + // to: '/widgets', + // icon: , + // badge: { + // color: 'info', + // text: 'NEW', + // }, + // }, + // { + // component: CNavTitle, + // name: 'Extras', + // }, + // { + // component: CNavGroup, + // name: 'Pages', + // icon: , + // items: [ + // { + // component: CNavItem, + // name: 'Login', + // to: '/login', + // }, + // { + // component: CNavItem, + // name: 'Register', + // to: '/register', + // }, + // { + // component: CNavItem, + // name: 'Error 404', + // to: '/404', + // }, + // { + // component: CNavItem, + // name: 'Error 500', + // to: '/500', + // }, + // ], + // }, + // { + // component: CNavItem, + // name: 'Docs', + // href: 'https://coreui.io/react/docs/templates/installation/', + // icon: , + // }, ] export default _nav diff --git a/src/components/multiselect/MultiSelect.js b/src/components/multiselect/MultiSelect.js new file mode 100644 index 000000000..77085724f --- /dev/null +++ b/src/components/multiselect/MultiSelect.js @@ -0,0 +1,46 @@ +/* eslint-disable prettier/prettier */ +import React, { useState } from 'react' +import './MultiSelect.scss' +import { CCloseButton } from '@coreui/react' + +export default function MultiSelect() { + const [text, setText] = useState('') + + const data = [ + { id: 1, name: 'hieu' }, + { id: 2, name: 'hieu2' }, + { id: 3, name: 'hieu3' }, + { id: 4, name: 'hieu4s' }, + { id: 5, name: 'hieu4s' }, + { id: 6, name: 'hieu4s' }, + { id: 7, name: 'hieu4s' }, + ] + + return ( +
+
+ {data.map((d, i) => { + return ( +

+ {d.name} + +

+ ) + })} + setText(e.target.value)} + /> +
+
+
    + {data.map((d) => { + return
  • {d.name}
  • + })} +
+
+
+ ) +} diff --git a/src/components/multiselect/MultiSelect.scss b/src/components/multiselect/MultiSelect.scss new file mode 100644 index 000000000..110ae5963 --- /dev/null +++ b/src/components/multiselect/MultiSelect.scss @@ -0,0 +1,37 @@ +.multi-select { + position: relative; + width: 100%; + display: flex; + flex-direction: column; + + .search-bar { + width: 100%; + display: flex; + align-items: center; + height: 38px; + flex-wrap: wrap; + border: 1px solid #ccc; + .search-item { + width: 60px; + display: flex; + align-items: center; + justify-content: space-around; + background-color: #ccc; + margin: 4px; + border-radius: 2px; + padding: 2px; + .item-icon { + font-size: 10px; + } + } + .search-input { + border: none; + padding: 4px; + outline: none; + } + } + .search-option { + position: absolute; + display: none; + } +} diff --git a/src/constant.js b/src/constant.js index b5053346e..a9be83b71 100644 --- a/src/constant.js +++ b/src/constant.js @@ -1 +1,4 @@ -export const BACKEND_HOST = process.env.NODE_ENV === 'development' ? 'http://51.79.147.198:3000' : 'http://api.namthanhdatholdings.com'; +export const BACKEND_HOST = + process.env.NODE_ENV === 'development' + ? 'http://51.79.147.198:3000' + : 'http://api.namthanhdatholdings.com' diff --git a/src/routes.js b/src/routes.js index ed0ef3297..16665fbc4 100644 --- a/src/routes.js +++ b/src/routes.js @@ -52,6 +52,7 @@ const Widgets = React.lazy(() => import('./views/widgets/Widgets')) const User = React.lazy(() => import('./views/data/User')) const File = React.lazy(() => import('./views/data/File')) +const Customer = React.lazy(() => import('./views/data/Customer')) const routes = [ { path: '/', exact: true, name: 'Home' }, @@ -99,7 +100,8 @@ const routes = [ { path: '/notifications/toasts', name: 'Toasts', element: Toasts }, { path: '/widgets', name: 'Widgets', element: Widgets }, { path: '/user', name: 'User', element: User }, - { path: '/file', name: 'File', element: File } + { path: '/file', name: 'File', element: File }, + { path: '/customer', name: 'Customer', element: Customer }, ] export default routes diff --git a/src/views/data/Actions.js b/src/views/data/Actions.js new file mode 100644 index 000000000..f2cbe59ec --- /dev/null +++ b/src/views/data/Actions.js @@ -0,0 +1,18 @@ +/* eslint-disable prettier/prettier */ +import { CButton, CCol, CContainer, CRow, CTable, CTableHeaderCell, CTableRow } from '@coreui/react' +import React from 'react' +export default function Actions() { + return ( + + edit + delete + change password + + + //
+ // edit + // delete + // change password + //
+ ) +} diff --git a/src/views/data/Customer.js b/src/views/data/Customer.js index ee1fe324d..7f872262e 100644 --- a/src/views/data/Customer.js +++ b/src/views/data/Customer.js @@ -1,70 +1,92 @@ import { - CButton, CCol, - CPagination, CPaginationItem, + CButton, + CCol, + CPagination, + CPaginationItem, CRow, - CTable, CTableBody, CTableDataCell, + CTable, + CTableBody, + CTableDataCell, CTableHead, CTableHeaderCell, - CTableRow -} from '@coreui/react'; -import React, {useEffect, useState, useRef} from 'react'; -import axios from 'axios'; -import { BACKEND_HOST } from '../../constant'; -import UserCreateModal from "../modal/UserCreateModal"; + CTableRow, +} from '@coreui/react' +import React, { useEffect, useState, useRef } from 'react' +import axios from 'axios' +import { BACKEND_HOST } from '../../constant' + +import CustomerCreateModel from '../modal/CustomerCreateModel' const Customer = () => { - const [users, setUsers] = useState([]); - const [limit, setLimit] = useState(20); - const [offset, setOffset] = useState(0); + const [customer, setCustomer] = useState([]) + const [limit, setLimit] = useState(20) + const [offset, setOffset] = useState(0) - const createUserModalRef = useRef(); + const createUserModalRef = useRef() useEffect(() => { - getCustomersData(); + getCustomersData() }, []) const getCustomersData = () => { - axios.get(`${BACKEND_HOST}/user`, { - params: { - limit, - offset - } - }) - .then(res => { - const newUsers = res.data.users; - setUsers(newUsers); + axios + .get(`${BACKEND_HOST}/customer`, { + params: { + limit, + offset, + }, + }) + .then((res) => { + const newCustomer = res.data.customers + setCustomer(newCustomer) }) - .catch(err => { - console.log('Error while getting user', err); + .catch((err) => { + console.log('Error while getting Customer', err) }) } const openCreateUser = () => { - createUserModalRef.current?.show(); + createUserModalRef.current?.show() } - + console.log(customer) return ( - Create user + Create Customer - Username - Role - Name + Name + Phone + Age + Job + Location + GoodWill + Intimacy + MinBudget + MaxBudget + CaringArea + CaringProduct - {users.map((item, index) => { + {customer.map((item, index) => { return ( - {item.username} - {item.role} {item.name} + {item.phone} + {item.age} + {item.job} + {item.userArea} + {item.goodwill} + {item.intimacy} + {item.minBudget} + {item.maxBudget} + {item.caringArea.toString()} + {item.caringProduct.toString()} ) })} @@ -79,8 +101,7 @@ const Customer = () => { - + ) } diff --git a/src/views/data/File.js b/src/views/data/File.js index fc416c111..5dd8bc26e 100644 --- a/src/views/data/File.js +++ b/src/views/data/File.js @@ -1,48 +1,53 @@ import { - CButton, CCol, - CPagination, CPaginationItem, + CButton, + CCol, + CPagination, + CPaginationItem, CRow, - CTable, CTableBody, CTableDataCell, + CTable, + CTableBody, + CTableDataCell, CTableHead, CTableHeaderCell, - CTableRow -} from '@coreui/react'; -import React, {useEffect, useState, useRef} from 'react'; -import axios from 'axios'; -import { BACKEND_HOST } from '../../constant'; -import UploadFileModal from "../modal/UploadFileModal"; + CTableRow, +} from '@coreui/react' +import React, { useEffect, useState, useRef } from 'react' +import axios from 'axios' +import { BACKEND_HOST } from '../../constant' +import UploadFileModal from '../modal/UploadFileModal' const File = () => { - const [files, setFiles] = useState([]); - const [limit, setLimit] = useState(20); - const [offset, setOffset] = useState(0); + const [files, setFiles] = useState([]) + const [limit, setLimit] = useState(20) + const [offset, setOffset] = useState(0) - const uploadFileRef = useRef(); + const uploadFileRef = useRef() useEffect(() => { - console.log('shit'); - getFilesData(); + console.log('shit') + getFilesData() }, []) const getFilesData = () => { - axios.get(`${BACKEND_HOST}/file`, { - params: { - limit, - offset - } - }) - .then(res => { - const newFiles = res.data.files; - console.log('123123', newFiles); - setFiles(newFiles); + axios + .get(`${BACKEND_HOST}/file`, { + params: { + limit, + offset, + }, }) - .catch(err => { - console.log('Error while getting user', err); + .then((res) => { + const newFiles = res.data.files + console.log('123123', newFiles) + setFiles(newFiles) + }) + .catch((err) => { + console.log('Error while getting user', err) }) } const openUploadFile = () => { - uploadFileRef.current?.show(); + uploadFileRef.current?.show() } return ( @@ -55,7 +60,7 @@ const File = () => { - Filename + Filename @@ -77,10 +82,9 @@ const File = () => { - + ) } -export default File; +export default File diff --git a/src/views/data/User.js b/src/views/data/User.js index a575d3c14..d29f65b13 100644 --- a/src/views/data/User.js +++ b/src/views/data/User.js @@ -1,50 +1,57 @@ import { - CButton, CCol, - CPagination, CPaginationItem, + CButton, + CCol, + CPagination, + CPaginationItem, CRow, - CTable, CTableBody, CTableDataCell, + CTable, + CTableBody, + CTableDataCell, CTableHead, CTableHeaderCell, - CTableRow -} from '@coreui/react'; -import React, {useEffect, useState, useRef} from 'react'; -import { useNavigate } from 'react-router-dom'; -import axios from 'axios'; -import { BACKEND_HOST } from '../../constant'; -import UserCreateModal from "../modal/UserCreateModal"; + CTableRow, +} from '@coreui/react' +import React, { useEffect, useState, useRef } from 'react' +import { useNavigate } from 'react-router-dom' +import axios from 'axios' +import { BACKEND_HOST } from '../../constant' +import UserCreateModal from '../modal/UserCreateModal' +import Actions from './Actions' const User = () => { - const [users, setUsers] = useState([]); - const [limit, setLimit] = useState(20); - const [offset, setOffset] = useState(0); + const [users, setUsers] = useState([]) + const [limit, setLimit] = useState(20) + const [offset, setOffset] = useState(0) - const createUserModalRef = useRef(); + const createUserModalRef = useRef() - const navigate = useNavigate(); + const navigate = useNavigate() useEffect(() => { - getUsersData(); + getUsersData() }, []) const getUsersData = () => { - axios.get(`${BACKEND_HOST}/user`, { - params: { - limit, - offset - } - }) - .then(res => { - const newUsers = res.data.users; - setUsers(newUsers); + axios + .get(`${BACKEND_HOST}/user`, { + params: { + limit, + offset, + }, }) - .catch(err => { - console.log('Error while getting user', err); + .then((res) => { + const newUsers = res.data.users + setUsers(newUsers) + }) + .catch((err) => { + console.log('Error while getting user', err) }) } const openCreateUser = () => { - createUserModalRef.current?.show(); + createUserModalRef.current?.show() } + console.log(users) return ( @@ -56,15 +63,19 @@ const User = () => { - Username - Role - Name + Action + Username + Role + Name {users.map((item, index) => { return ( + + + {item.username} {item.role} {item.name} @@ -82,8 +93,7 @@ const User = () => { - + ) } diff --git a/src/views/modal/CustomerCreateModel.js b/src/views/modal/CustomerCreateModel.js new file mode 100644 index 000000000..623740253 --- /dev/null +++ b/src/views/modal/CustomerCreateModel.js @@ -0,0 +1,265 @@ +/* eslint-disable prettier/prettier */ +/* eslint-disable no-undef */ +/* eslint-disable prettier/prettier */ +import React, { useState, useImperativeHandle, useEffect } from 'react' +import { + CButton, + CModal, + CModalBody, + CModalFooter, + CModalHeader, + CModalTitle, + CForm, + CInputGroupText, + CFormInput, + CInputGroup, + CAlert, + CFormSelect, + CFormCheck, +} from '@coreui/react' +import CIcon from '@coreui/icons-react' +import { + cilLockLocked, + cilUser, + cilText, + cilPhone, + cilFactory, + cilBriefcase, + cilLocationPin, + cilStar, + cilMoney, + cilArrowRight, +} from '@coreui/icons' +import axios from 'axios' +import { BACKEND_HOST } from '../../constant' +import provinces_item from './Provinces.json' +import MultiSelect from 'src/components/multiselect/MultiSelect' + +const CustomerCreateModel = ({}, ref) => { + const [visible, setVisible] = useState(false) + const [phone, setPhone] = useState('') + const [name, setName] = useState('') + const [age, setAge] = useState('') + const [job, setJob] = useState('') + const [userArea, setUserArea] = useState('') + const [goodwill, setGoodWill] = useState('') + const [intimacy, setIntimacy] = useState('') + const [minBudget, setMinBudget] = useState('') + const [maxBudget, setMaxBudget] = useState('') + const [caringArea, setcaringArea] = useState([]) + const [caringProduct, setCaringProduct] = useState([]) + + const [error, setError] = useState(false) + const [success, setSuccess] = useState(false) + + const provinces = provinces_item + + useImperativeHandle(ref, () => ({ + show: () => { + setVisible(true) + }, + })) + + const handleSubmit = () => { + axios + .post(`${BACKEND_HOST}/customer/create`, { + name, + phone, + age, + job, + userArea, + goodwill, + intimacy, + minBudget, + maxBudget, + caringArea, + caringProduct, + }) + .then((res) => { + setSuccess(true) + }) + .catch((err) => { + console.log('Error', err) + setError(true) + }) + } + + return ( + setVisible(false)}> + + Create User + + + {error && {'Error'}} + {success && {'Done'}} + + + + + + setName(event.target.value)} + placeholder="Name" + autoComplete="name" + /> + + + + + + setPhone(event.target.value)} + /> + + + + + + setAge(event.target.value)} + /> + + + + + + setJob(event.target.value)} + /> + + + + + + setUserArea(e.target.value)} + > + {provinces.map((p) => { + return + })} + + + + + + + setGoodWill(e.target.value)} + > + + + + + + setIntimacy(e.target.value)} + > + + + + + + + + + + + + setMinBudget(e.target.value)} + > + + + + + + + + + + setMaxBudget(e.target.value)} + > + + + + + + + + +
+ CaringArea +
+ + + + + + + + +
+ +
+ CaringProduct +
+ + + + + + + +
+
+
+
+ + setVisible(false)}> + Cancel + + + Create + + +
+ ) +} + +export default React.forwardRef(CustomerCreateModel) diff --git a/src/views/modal/Provinces.json b/src/views/modal/Provinces.json new file mode 100644 index 000000000..00e815605 --- /dev/null +++ b/src/views/modal/Provinces.json @@ -0,0 +1,443 @@ +[ + { + "name": "Hà Nội", + "slug": "ha-noi", + "type": "thanh-pho", + "name_with_type": "Thành phố Hà Nội", + "code": "01" + }, + { + "name": "Hà Giang", + "slug": "ha-giang", + "type": "tinh", + "name_with_type": "Tỉnh Hà Giang", + "code": "02" + }, + { + "name": "Cao Bằng", + "slug": "cao-bang", + "type": "tinh", + "name_with_type": "Tỉnh Cao Bằng", + "code": "04" + }, + { + "name": "Bắc Kạn", + "slug": "bac-kan", + "type": "tinh", + "name_with_type": "Tỉnh Bắc Kạn", + "code": "06" + }, + { + "name": "Tuyên Quang", + "slug": "tuyen-quang", + "type": "tinh", + "name_with_type": "Tỉnh Tuyên Quang", + "code": "08" + }, + { + "name": "Lào Cai", + "slug": "lao-cai", + "type": "tinh", + "name_with_type": "Tỉnh Lào Cai", + "code": "10" + }, + { + "name": "Điện Biên", + "slug": "dien-bien", + "type": "tinh", + "name_with_type": "Tỉnh Điện Biên", + "code": "11" + }, + { + "name": "Lai Châu", + "slug": "lai-chau", + "type": "tinh", + "name_with_type": "Tỉnh Lai Châu", + "code": "12" + }, + { + "name": "Sơn La", + "slug": "son-la", + "type": "tinh", + "name_with_type": "Tỉnh Sơn La", + "code": "14" + }, + { + "name": "Yên Bái", + "slug": "yen-bai", + "type": "tinh", + "name_with_type": "Tỉnh Yên Bái", + "code": "15" + }, + { + "name": "Hoà Bình", + "slug": "hoa-binh", + "type": "tinh", + "name_with_type": "Tỉnh Hoà Bình", + "code": "17" + }, + { + "name": "Thái Nguyên", + "slug": "thai-nguyen", + "type": "tinh", + "name_with_type": "Tỉnh Thái Nguyên", + "code": "19" + }, + { + "name": "Lạng Sơn", + "slug": "lang-son", + "type": "tinh", + "name_with_type": "Tỉnh Lạng Sơn", + "code": "20" + }, + { + "name": "Quảng Ninh", + "slug": "quang-ninh", + "type": "tinh", + "name_with_type": "Tỉnh Quảng Ninh", + "code": "22" + }, + { + "name": "Bắc Giang", + "slug": "bac-giang", + "type": "tinh", + "name_with_type": "Tỉnh Bắc Giang", + "code": "24" + }, + { + "name": "Phú Thọ", + "slug": "phu-tho", + "type": "tinh", + "name_with_type": "Tỉnh Phú Thọ", + "code": "25" + }, + { + "name": "Vĩnh Phúc", + "slug": "vinh-phuc", + "type": "tinh", + "name_with_type": "Tỉnh Vĩnh Phúc", + "code": "26" + }, + { + "name": "Bắc Ninh", + "slug": "bac-ninh", + "type": "tinh", + "name_with_type": "Tỉnh Bắc Ninh", + "code": "27" + }, + { + "name": "Hải Dương", + "slug": "hai-duong", + "type": "tinh", + "name_with_type": "Tỉnh Hải Dương", + "code": "30" + }, + { + "name": "Hải Phòng", + "slug": "hai-phong", + "type": "thanh-pho", + "name_with_type": "Thành phố Hải Phòng", + "code": "31" + }, + { + "name": "Hưng Yên", + "slug": "hung-yen", + "type": "tinh", + "name_with_type": "Tỉnh Hưng Yên", + "code": "33" + }, + { + "name": "Thái Bình", + "slug": "thai-binh", + "type": "tinh", + "name_with_type": "Tỉnh Thái Bình", + "code": "34" + }, + { + "name": "Hà Nam", + "slug": "ha-nam", + "type": "tinh", + "name_with_type": "Tỉnh Hà Nam", + "code": "35" + }, + { + "name": "Nam Định", + "slug": "nam-dinh", + "type": "tinh", + "name_with_type": "Tỉnh Nam Định", + "code": "36" + }, + { + "name": "Ninh Bình", + "slug": "ninh-binh", + "type": "tinh", + "name_with_type": "Tỉnh Ninh Bình", + "code": "37" + }, + { + "name": "Thanh Hóa", + "slug": "thanh-hoa", + "type": "tinh", + "name_with_type": "Tỉnh Thanh Hóa", + "code": "38" + }, + { + "name": "Nghệ An", + "slug": "nghe-an", + "type": "tinh", + "name_with_type": "Tỉnh Nghệ An", + "code": "40" + }, + { + "name": "Hà Tĩnh", + "slug": "ha-tinh", + "type": "tinh", + "name_with_type": "Tỉnh Hà Tĩnh", + "code": "42" + }, + { + "name": "Quảng Bình", + "slug": "quang-binh", + "type": "tinh", + "name_with_type": "Tỉnh Quảng Bình", + "code": "44" + }, + { + "name": "Quảng Trị", + "slug": "quang-tri", + "type": "tinh", + "name_with_type": "Tỉnh Quảng Trị", + "code": "45" + }, + { + "name": "Thừa Thiên Huế", + "slug": "thua-thien-hue", + "type": "tinh", + "name_with_type": "Tỉnh Thừa Thiên Huế", + "code": "46" + }, + { + "name": "Đà Nẵng", + "slug": "da-nang", + "type": "thanh-pho", + "name_with_type": "Thành phố Đà Nẵng", + "code": "48" + }, + { + "name": "Quảng Nam", + "slug": "quang-nam", + "type": "tinh", + "name_with_type": "Tỉnh Quảng Nam", + "code": "49" + }, + { + "name": "Quảng Ngãi", + "slug": "quang-ngai", + "type": "tinh", + "name_with_type": "Tỉnh Quảng Ngãi", + "code": "51" + }, + { + "name": "Bình Định", + "slug": "binh-dinh", + "type": "tinh", + "name_with_type": "Tỉnh Bình Định", + "code": "52" + }, + { + "name": "Phú Yên", + "slug": "phu-yen", + "type": "tinh", + "name_with_type": "Tỉnh Phú Yên", + "code": "54" + }, + { + "name": "Khánh Hòa", + "slug": "khanh-hoa", + "type": "tinh", + "name_with_type": "Tỉnh Khánh Hòa", + "code": "56" + }, + { + "name": "Ninh Thuận", + "slug": "ninh-thuan", + "type": "tinh", + "name_with_type": "Tỉnh Ninh Thuận", + "code": "58" + }, + { + "name": "Bình Thuận", + "slug": "binh-thuan", + "type": "tinh", + "name_with_type": "Tỉnh Bình Thuận", + "code": "60" + }, + { + "name": "Kon Tum", + "slug": "kon-tum", + "type": "tinh", + "name_with_type": "Tỉnh Kon Tum", + "code": "62" + }, + { + "name": "Gia Lai", + "slug": "gia-lai", + "type": "tinh", + "name_with_type": "Tỉnh Gia Lai", + "code": "64" + }, + { + "name": "Đắk Lắk", + "slug": "dak-lak", + "type": "tinh", + "name_with_type": "Tỉnh Đắk Lắk", + "code": "66" + }, + { + "name": "Đắk Nông", + "slug": "dak-nong", + "type": "tinh", + "name_with_type": "Tỉnh Đắk Nông", + "code": "67" + }, + { + "name": "Lâm Đồng", + "slug": "lam-dong", + "type": "tinh", + "name_with_type": "Tỉnh Lâm Đồng", + "code": "68" + }, + { + "name": "Bình Phước", + "slug": "binh-phuoc", + "type": "tinh", + "name_with_type": "Tỉnh Bình Phước", + "code": "70" + }, + { + "name": "Tây Ninh", + "slug": "tay-ninh", + "type": "tinh", + "name_with_type": "Tỉnh Tây Ninh", + "code": "72" + }, + { + "name": "Bình Dương", + "slug": "binh-duong", + "type": "tinh", + "name_with_type": "Tỉnh Bình Dương", + "code": "74" + }, + { + "name": "Đồng Nai", + "slug": "dong-nai", + "type": "tinh", + "name_with_type": "Tỉnh Đồng Nai", + "code": "75" + }, + { + "name": "Bà Rịa - Vũng Tàu", + "slug": "ba-ria-vung-tau", + "type": "tinh", + "name_with_type": "Tỉnh Bà Rịa - Vũng Tàu", + "code": "77" + }, + { + "name": "Hồ Chí Minh", + "slug": "ho-chi-minh", + "type": "thanh-pho", + "name_with_type": "Thành phố Hồ Chí Minh", + "code": "79" + }, + { + "name": "Long An", + "slug": "long-an", + "type": "tinh", + "name_with_type": "Tỉnh Long An", + "code": "80" + }, + { + "name": "Tiền Giang", + "slug": "tien-giang", + "type": "tinh", + "name_with_type": "Tỉnh Tiền Giang", + "code": "82" + }, + { + "name": "Bến Tre", + "slug": "ben-tre", + "type": "tinh", + "name_with_type": "Tỉnh Bến Tre", + "code": "83" + }, + { + "name": "Trà Vinh", + "slug": "tra-vinh", + "type": "tinh", + "name_with_type": "Tỉnh Trà Vinh", + "code": "84" + }, + { + "name": "Vĩnh Long", + "slug": "vinh-long", + "type": "tinh", + "name_with_type": "Tỉnh Vĩnh Long", + "code": "86" + }, + { + "name": "Đồng Tháp", + "slug": "dong-thap", + "type": "tinh", + "name_with_type": "Tỉnh Đồng Tháp", + "code": "87" + }, + { + "name": "An Giang", + "slug": "an-giang", + "type": "tinh", + "name_with_type": "Tỉnh An Giang", + "code": "89" + }, + { + "name": "Kiên Giang", + "slug": "kien-giang", + "type": "tinh", + "name_with_type": "Tỉnh Kiên Giang", + "code": "91" + }, + { + "name": "Cần Thơ", + "slug": "can-tho", + "type": "thanh-pho", + "name_with_type": "Thành phố Cần Thơ", + "code": "92" + }, + { + "name": "Hậu Giang", + "slug": "hau-giang", + "type": "tinh", + "name_with_type": "Tỉnh Hậu Giang", + "code": "93" + }, + { + "name": "Sóc Trăng", + "slug": "soc-trang", + "type": "tinh", + "name_with_type": "Tỉnh Sóc Trăng", + "code": "94" + }, + { + "name": "Bạc Liêu", + "slug": "bac-lieu", + "type": "tinh", + "name_with_type": "Tỉnh Bạc Liêu", + "code": "95" + }, + { + "name": "Cà Mau", + "slug": "ca-mau", + "type": "tinh", + "name_with_type": "Tỉnh Cà Mau", + "code": "96" + } +] diff --git a/src/views/modal/UploadFileModal.js b/src/views/modal/UploadFileModal.js index 4741ab789..c4291448f 100644 --- a/src/views/modal/UploadFileModal.js +++ b/src/views/modal/UploadFileModal.js @@ -1,4 +1,4 @@ -import React, { useState, useImperativeHandle } from 'react'; +import React, { useState, useImperativeHandle } from 'react' import { CButton, CModal, @@ -10,71 +10,77 @@ import { CInputGroupText, CFormInput, CInputGroup, - CAlert, CProgress -} from '@coreui/react'; -import CIcon from "@coreui/icons-react"; -import {cilLockLocked, cilUser, cilText} from "@coreui/icons"; -import axios from "axios"; -import { BACKEND_HOST } from "../../constant"; -import * as PropTypes from "prop-types"; + CAlert, + CProgress, +} from '@coreui/react' +import CIcon from '@coreui/icons-react' +import { cilLockLocked, cilUser, cilText } from '@coreui/icons' +import axios from 'axios' +import { BACKEND_HOST } from '../../constant' +import * as PropTypes from 'prop-types' function CFormGroup(props) { - return null; + return null } -CFormGroup.propTypes = {children: PropTypes.node}; +CFormGroup.propTypes = { children: PropTypes.node } function CLabel(props) { - return null; + return null } -CLabel.propTypes = {children: PropTypes.node}; +CLabel.propTypes = { children: PropTypes.node } function CInputFile(props) { - return null; + return null } CInputFile.propTypes = { onChange: PropTypes.func, name: PropTypes.string, id: PropTypes.string, - required: PropTypes.bool -}; + required: PropTypes.bool, +} const UploadFileModal = ({}, ref) => { - const [visible, setVisible] = useState(false); - const [file, setFile] = useState(null); - const [uploading, setUploading] = useState(false); - const [progress, setProgress] = useState(0); + const [visible, setVisible] = useState(false) + const [file, setFile] = useState(null) + const [uploading, setUploading] = useState(false) + const [progress, setProgress] = useState(0) + const [success, setSuccess] = useState(false) + const [error, setError] = useState(false) useImperativeHandle(ref, () => ({ show: () => { - setVisible(true); - } + setVisible(true) + }, })) const handleUpload = () => { - setUploading(true); - axios.post(`${BACKEND_HOST}/file/upload`, { - file - }, { - headers: { - 'content-type': 'multipart/form-data', - }, - onUploadProgress: (progressEvent) => { - const percentCompleted = Math.round( - (progressEvent.loaded * 100) / progressEvent.total - ); - setProgress(percentCompleted); - }, - }) - .then(res => { - setSuccess(true); + setUploading(true) + axios + .post( + `${BACKEND_HOST}/file/upload`, + { + file, + }, + { + headers: { + 'content-type': 'multipart/form-data', + }, + onUploadProgress: (progressEvent) => { + const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total) + setProgress(percentCompleted) + }, + }, + ) + .then((res) => { + setSuccess(true) + }) + .catch((err) => { + console.log('Error', err) + setError(true) }) - .catch(err => { - console.log('Error', err); - setError(true); - }); - }; + } return ( setVisible(false)}> @@ -87,16 +93,11 @@ const UploadFileModal = ({}, ref) => { onChange={(event) => setFile(event.target.files[0])} type="file" id="formFile" - label="Choose file" /> + label="Choose file" + />
{uploading && ( - + )} @@ -108,7 +109,7 @@ const UploadFileModal = ({}, ref) => { - ); -}; + ) +} -export default React.forwardRef(UploadFileModal); +export default React.forwardRef(UploadFileModal) diff --git a/src/views/modal/UserCreateModal.js b/src/views/modal/UserCreateModal.js index 7ee702430..bb7a33d7c 100644 --- a/src/views/modal/UserCreateModal.js +++ b/src/views/modal/UserCreateModal.js @@ -1,4 +1,4 @@ -import React, { useState, useImperativeHandle } from 'react'; +import React, { useState, useImperativeHandle } from 'react' import { CButton, CModal, @@ -10,41 +10,42 @@ import { CInputGroupText, CFormInput, CInputGroup, - CAlert -} from '@coreui/react'; -import CIcon from "@coreui/icons-react"; -import {cilLockLocked, cilUser, cilText} from "@coreui/icons"; -import axios from "axios"; -import { BACKEND_HOST } from "../../constant"; + CAlert, +} from '@coreui/react' +import CIcon from '@coreui/icons-react' +import { cilLockLocked, cilUser, cilText } from '@coreui/icons' +import axios from 'axios' +import { BACKEND_HOST } from '../../constant' const UserCreateModal = ({}, ref) => { - const [visible, setVisible] = useState(false); - const [username, setUsername] = useState(''); - const [name, setName] = useState(''); - const [password, setPassword] = useState(''); - const [error, setError] = useState(false); - const [success, setSuccess] = useState(false); + const [visible, setVisible] = useState(false) + const [username, setUsername] = useState('') + const [name, setName] = useState('') + const [password, setPassword] = useState('') + const [error, setError] = useState(false) + const [success, setSuccess] = useState(false) useImperativeHandle(ref, () => ({ show: () => { - setVisible(true); - } + setVisible(true) + }, })) const handleSubmit = () => { - axios.post(`${BACKEND_HOST}/user/create`, { - username, - password, - name - }) - .then(res => { - setSuccess(true); + axios + .post(`${BACKEND_HOST}/user/create`, { + username, + password, + name, }) - .catch(err => { - console.log('Error', err); - setError(true); - }); - }; + .then((res) => { + setSuccess(true) + }) + .catch((err) => { + console.log('Error', err) + setError(true) + }) + } return ( setVisible(false)}> @@ -63,7 +64,8 @@ const UserCreateModal = ({}, ref) => { value={username} onChange={(event) => setUsername(event.target.value)} placeholder="Username" - autoComplete="username"/> + autoComplete="username" + /> @@ -98,7 +100,7 @@ const UserCreateModal = ({}, ref) => { - ); -}; + ) +} -export default React.forwardRef(UserCreateModal); +export default React.forwardRef(UserCreateModal)