diff --git a/package.json b/package.json index da08efaab..1a2cb95de 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": "react-scripts start", @@ -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..bf29f7e10 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..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' @@ -18,288 +20,305 @@ import { CNavGroup, CNavItem, CNavTitle } from '@coreui/react' const _nav = [ { component: CNavItem, - name: 'Dashboard', - to: '/dashboard', - icon: , + name: 'User', + to: '/user', + 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: 'File', + to: '/file', + 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: , + name: 'Customer', + to: '/customer', + icon: , + badge: { + color: 'info', + }, }, + // // { + // // 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/checkToken.js b/src/checkToken.js new file mode 100644 index 000000000..657ea991d --- /dev/null +++ b/src/checkToken.js @@ -0,0 +1,6 @@ +import Cookies from "js-cookie"; +import axios from "axios"; + +const token = Cookies.get('authToken'); + +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/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/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 new file mode 100644 index 000000000..a9be83b71 --- /dev/null +++ b/src/constant.js @@ -0,0 +1,4 @@ +export const BACKEND_HOST = + process.env.NODE_ENV === 'development' + ? 'http://51.79.147.198:3000' + : 'http://api.namthanhdatholdings.com' 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/routes.js b/src/routes.js index d168b1ca4..16665fbc4 100644 --- a/src/routes.js +++ b/src/routes.js @@ -50,6 +50,10 @@ 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 Customer = React.lazy(() => import('./views/data/Customer')) + const routes = [ { path: '/', exact: true, name: 'Home' }, { path: '/dashboard', name: 'Dashboard', element: Dashboard }, @@ -95,6 +99,9 @@ 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: '/file', name: 'File', element: File }, + { path: '/customer', name: 'Customer', element: Customer }, ] 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/Auth.js b/src/views/Auth.js new file mode 100644 index 000000000..fec2824f6 --- /dev/null +++ b/src/views/Auth.js @@ -0,0 +1,18 @@ +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) { + setTimeout(() => { + navigate('/login'); + }, 100) + } + }, []); + + return null; +} 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 new file mode 100644 index 000000000..7f872262e --- /dev/null +++ b/src/views/data/Customer.js @@ -0,0 +1,109 @@ +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 CustomerCreateModel from '../modal/CustomerCreateModel' + +const Customer = () => { + const [customer, setCustomer] = useState([]) + const [limit, setLimit] = useState(20) + const [offset, setOffset] = useState(0) + + const createUserModalRef = useRef() + + useEffect(() => { + getCustomersData() + }, []) + + const getCustomersData = () => { + axios + .get(`${BACKEND_HOST}/customer`, { + params: { + limit, + offset, + }, + }) + .then((res) => { + const newCustomer = res.data.customers + setCustomer(newCustomer) + }) + .catch((err) => { + console.log('Error while getting Customer', err) + }) + } + + const openCreateUser = () => { + createUserModalRef.current?.show() + } + console.log(customer) + return ( + + + + Create Customer + + + + + + Name + Phone + Age + Job + Location + GoodWill + Intimacy + MinBudget + MaxBudget + CaringArea + CaringProduct + + + + {customer.map((item, index) => { + return ( + + {item.name} + {item.phone} + {item.age} + {item.job} + {item.userArea} + {item.goodwill} + {item.intimacy} + {item.minBudget} + {item.maxBudget} + {item.caringArea.toString()} + {item.caringProduct.toString()} + + ) + })} + + + + + + + 1 + + + + + + + ) +} + +export default Customer diff --git a/src/views/data/File.js b/src/views/data/File.js new file mode 100644 index 000000000..5dd8bc26e --- /dev/null +++ b/src/views/data/File.js @@ -0,0 +1,90 @@ +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/data/User.js b/src/views/data/User.js new file mode 100644 index 000000000..d29f65b13 --- /dev/null +++ b/src/views/data/User.js @@ -0,0 +1,101 @@ +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' +import Actions from './Actions' + +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() + } + console.log(users) + + return ( + + + + Create user + + + + + + Action + Username + Role + Name + + + + {users.map((item, index) => { + return ( + + + + + {item.username} + {item.role} + {item.name} + + ) + })} + + + + + + + 1 + + + + + + + ) +} + +export default 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/ErrorModal.js b/src/views/modal/ErrorModal.js new file mode 100644 index 000000000..e69de29bb 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 new file mode 100644 index 000000000..c4291448f --- /dev/null +++ b/src/views/modal/UploadFileModal.js @@ -0,0 +1,115 @@ +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) + const [success, setSuccess] = useState(false) + const [error, setError] = useState(false) + + 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/modal/UserCreateModal.js b/src/views/modal/UserCreateModal.js new file mode 100644 index 000000000..bb7a33d7c --- /dev/null +++ b/src/views/modal/UserCreateModal.js @@ -0,0 +1,106 @@ +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..f5f28ca8b 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,37 @@ 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'; const Login = () => { + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + 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); + } + } + return (
@@ -32,7 +58,11 @@ const Login = () => { - + setUsername(event.target.value)} + placeholder="Username" + autoComplete="username"/> @@ -41,43 +71,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.

+
+
)