From e140fa25867ef7dbf2fe727f81dd3b49c17b9906 Mon Sep 17 00:00:00 2001 From: Thanh Tuanas Date: Sun, 22 Oct 2023 12:12:18 +0700 Subject: [PATCH 1/5] Done the Organization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Xong thêm xóa sửa hội --- src/app/store.js | 4 +- src/containers/ModalLayout.js | 2 + src/features/commune/SelectedDistrictSlice.js | 16 +++ .../commune/components/AddCommuneModalBody.js | 87 +++++++++++++ src/features/commune/index.js | 122 +++++++++++++++++- src/features/district/index.js | 9 +- src/features/members/index.js | 8 ++ src/features/transactions/index.js | 25 ++-- src/index.js | 2 +- src/pages/protected/Commune.js | 1 - src/pages/protected/District.js | 1 - src/pages/protected/Member.js | 18 +++ src/routes/index.js | 5 + src/routes/sidebar.js | 5 + src/utils/globalConstantUtil.js | 1 + 15 files changed, 280 insertions(+), 26 deletions(-) create mode 100644 src/features/commune/SelectedDistrictSlice.js create mode 100644 src/features/commune/components/AddCommuneModalBody.js create mode 100644 src/features/members/index.js create mode 100644 src/pages/protected/Member.js diff --git a/src/app/store.js b/src/app/store.js index 41473c8..bd3890b 100644 --- a/src/app/store.js +++ b/src/app/store.js @@ -5,6 +5,7 @@ import rightDrawerSlice from '../features/common/rightDrawerSlice' import leadsSlice from '../features/leads/leadSlice' import ProvOrganizationSlice from '../features/transactions/OrganizationSlice' import SelectedProvSlice from '../features/district/SelectedProvSlice' +import SelectedDistrictSlice from '../features/commune/SelectedDistrictSlice' const combinedReducer = { header: headerSlice, @@ -12,7 +13,8 @@ const combinedReducer = { modal: modalSlice, lead: leadsSlice, org: ProvOrganizationSlice, - selectedProv: SelectedProvSlice + selectedProv: SelectedProvSlice, + selectedDistrict: SelectedDistrictSlice } export default configureStore({ diff --git a/src/containers/ModalLayout.js b/src/containers/ModalLayout.js index 36dd96f..505c4e8 100644 --- a/src/containers/ModalLayout.js +++ b/src/containers/ModalLayout.js @@ -6,6 +6,7 @@ import AddLeadModalBody from '../features/leads/components/AddLeadModalBody' import ConfirmationModalBody from '../features/common/components/ConfirmationModalBody' import AddProvinceModalBody from '../features/transactions/components/AddProvinceModalBody' import AddDistrictModalBody from '../features/district/components/AddDistrictModalBody' +import AddCommuneModalBody from '../features/commune/components/AddCommuneModalBody' function ModalLayout() { @@ -39,6 +40,7 @@ function ModalLayout() { [MODAL_BODY_TYPES.PROVINCE_ADD_NEW]: , [MODAL_BODY_TYPES.DISTRICT_ADD_NEW]: , [MODAL_BODY_TYPES.CONFIRMATION]: , + [MODAL_BODY_TYPES.COMMUNE_ADD_NEW]: , [MODAL_BODY_TYPES.DEFAULT]:
}[bodyType] } diff --git a/src/features/commune/SelectedDistrictSlice.js b/src/features/commune/SelectedDistrictSlice.js new file mode 100644 index 0000000..0d3453d --- /dev/null +++ b/src/features/commune/SelectedDistrictSlice.js @@ -0,0 +1,16 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const SelectedDistrictSlice = createSlice({ + name: 'SelectedDistrict', + initialState: { + selectedDistrict: null + }, + reducers: { + setSelectedDistrict: (state, action) => { + state.selectedDistrict = action.payload; + } + } +}) + +export const { setSelectedDistrict } = SelectedDistrictSlice.actions; +export default SelectedDistrictSlice.reducer; \ No newline at end of file diff --git a/src/features/commune/components/AddCommuneModalBody.js b/src/features/commune/components/AddCommuneModalBody.js new file mode 100644 index 0000000..0ed32c5 --- /dev/null +++ b/src/features/commune/components/AddCommuneModalBody.js @@ -0,0 +1,87 @@ +import React, { useEffect } from 'react' +import { useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux' +import { showNotification } from '../../common/headerSlice'; +import { closeModal } from '../../common/modalSlice'; +import InputText from '../../../components/Input/InputText'; +import ErrorText from '../../../components/Typography/ErrorText'; +import organizationApi from '../../../api/OrganizationAPI'; +import { createOrganization, getOrganization } from '../../transactions/OrganizationSlice'; +import SelectBox from '../../../components/Input/SelectBox'; + +const INITIAL_COMMUNE_OBJ = { + parentID: '', + name: '' +} +const AddCommuneModalBody = ({ closeModal }) => { + const dispatch = useDispatch(); + const [errorMessage, setErrorMessage] = useState("") + const [communeObj, setCommuneObj] = useState(INITIAL_COMMUNE_OBJ) + const [selectedProvince, setSelectedProvince] = useState(null) + const { orgs } = useSelector(state => state.org) + const provs = orgs.filter(t => t.type === 'tinh') + const districts = orgs.filter(t => t.parentID === selectedProvince) + + console.log("Tinh huyen dang chon la : " + communeObj); + useEffect(() => { + dispatch(getOrganization()) + }, []) + const saveNewCommune = () => { + if (communeObj.name.trim() === "") return setErrorMessage("Hãy điền tên xã") + else if (communeObj.parentID === "PLACEHOLDER") return setErrorMessage("Hãy chọn huyện") + else { + //Call API to Add Province Organization + console.log(communeObj.parentID); + let newCommuneObj = { + ...communeObj, + type: "xa" + } + dispatch(createOrganization(newCommuneObj)) + dispatch(showNotification({ message: "Thêm xã mới thành công", status: 1 })) + closeModal() + + + } + } + + const updateFormValue = ({ updateType, value }) => { + setErrorMessage(""); + setCommuneObj({ ...communeObj, [updateType]: value }); + } + + const updateDistrictValue = (value) => { + setCommuneObj({...communeObj, parentID: value}) + } + const updateProvinceValue = (value) => { + setSelectedProvince(value) + } + + return ( + <> + + + + {errorMessage} +
+ + +
+ + ) +} + +export default AddCommuneModalBody \ No newline at end of file diff --git a/src/features/commune/index.js b/src/features/commune/index.js index 7180782..26aca88 100644 --- a/src/features/commune/index.js +++ b/src/features/commune/index.js @@ -1,8 +1,128 @@ import React from 'react' +import { useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { openModal } from '../common/modalSlice'; +import { MODAL_BODY_TYPES } from '../../utils/globalConstantUtil'; +import { useEffect } from 'react'; +import SearchBar from '../../components/Input/SearchBar'; +import TitleCard from '../../components/Cards/TitleCard'; +import SelectBox from '../../components/Input/SelectBox'; +import { getOrganization } from '../transactions/OrganizationSlice'; +import TrashIcon from '@heroicons/react/24/outline/TrashIcon'; +import { CONFIRMATION_MODAL_CLOSE_TYPES } from '../../utils/globalConstantUtil'; +import { setSelectedDistrict } from './SelectedDistrictSlice'; + +const TopSideButtons = ({ removeFilter, applyFilter, applySearch }) => { + const dispatch = useDispatch(); + const { orgs, isLoading } = useSelector(state => state.org) + const [selectedProvince, setSelectedProvince] = useState(null) + const provs = orgs.filter(org => org.type === 'tinh') + const districts = orgs.filter(org => org.parentID === selectedProvince) + + console.log(selectedProvince); + useEffect(() => { + dispatch(getOrganization()) + }, []) + + + + const AddNewDistrictModal = () => { + dispatch(openModal({ title: 'Thêm đơn vị xã', bodyType: MODAL_BODY_TYPES.COMMUNE_ADD_NEW})) + } + + const handleSelectProvince = (value) => { + setSelectedProvince(value); + }; + + const handleSelectDistrict = value => { + dispatch(setSelectedDistrict(value)) + } + + + + + return ( +
+ + + + + {/* */} +
+ ) +} const Commune = () => { + + const dispatch = useDispatch() + const {selectedDistrict} = useSelector(state => state.selectedDistrict) + const {orgs, isLoading} = useSelector(state => state.org) + const communes = orgs.filter(org => org.parentID === selectedDistrict) + + useEffect(() => { + dispatch(getOrganization()) + }, []) + + isLoading ? document.body.classList.add('loading-indicator') : document.body.classList.remove('loading-indicator') + + const deleteCurrentOrganization = (index) => { + dispatch(openModal({ + title: "Xác nhận", bodyType: MODAL_BODY_TYPES.CONFIRMATION, + extraObject: { message: `Xóa hội này cũng sẽ xóa các hội trực thuộc nó, bạn có muốn xóa không ?`, type: CONFIRMATION_MODAL_CLOSE_TYPES.ORGANIZATION_DELETE, index: index } + })) + } + + const applySearch = () => { + + } return ( -
This is fkin COMMUNES
+ <> + }> +
+ + + + + + + + + + { + communes.map((l, k) => { + return ( + + + + + + + ) + }) + } + +
Tên huyệnNgười quản lý
+ {l.name} + {l.type}
+
+
+ ) } diff --git a/src/features/district/index.js b/src/features/district/index.js index bc79350..5515f90 100644 --- a/src/features/district/index.js +++ b/src/features/district/index.js @@ -25,9 +25,6 @@ const TopSideButtons = ({ removeFilter, applyFilter, applySearch }) => { }, []) - useEffect(() => { - applySearch(searchText) - }, [searchText]) const AddNewDistrictModal = () => { dispatch(openModal({ title: 'Thêm đơn vị huyện', bodyType: MODAL_BODY_TYPES.DISTRICT_ADD_NEW })) @@ -64,12 +61,8 @@ const District = () => { const { selectedProvince } = useSelector(state => state.selectedProv) const { orgs, isLoading } = useSelector(state => state.org); const districtOrg = orgs.filter(org => org.parentID === selectedProvince) - const [searchText, setSearchText] = useState(""); const [filterdSearchDistrictOrg, setFilterSearchDistrictOrg] = useState(districtOrg); - useEffect(() => { - applySearch(searchText) - }, [searchText, orgs]) isLoading ? document.body.classList.add('loading-indicator') : document.body.classList.remove('loading-indicator') @@ -98,7 +91,7 @@ const District = () => { { - filterdSearchDistrictOrg.map((l, k) => { + districtOrg.map((l, k) => { return ( diff --git a/src/features/members/index.js b/src/features/members/index.js new file mode 100644 index 0000000..cbb65c6 --- /dev/null +++ b/src/features/members/index.js @@ -0,0 +1,8 @@ +const Members = () => { + return( + <> +

This is fukin member

+ + ) +} +export default Members \ No newline at end of file diff --git a/src/features/transactions/index.js b/src/features/transactions/index.js index 02384e3..b03e851 100644 --- a/src/features/transactions/index.js +++ b/src/features/transactions/index.js @@ -15,7 +15,7 @@ import TrashIcon from "@heroicons/react/24/outline/TrashIcon" import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_BODY_TYPES } from '../../utils/globalConstantUtil' -const TopSideButtons = ({ removeFilter, applyFilter, applySearch }) => { +const TopSideButtons = ({ applySearch }) => { const [searchText, setSearchText] = useState(""); @@ -51,19 +51,20 @@ function Transactions() { const dispatch = useDispatch(); const { orgs, isLoading } = useSelector(state => state.org) const provs = orgs.filter(org => org.type === 'tinh'); - const [filteredProvs, setFilteredProvs] = useState(provs); - const [loading, setLoading] = useState(true); - - + const [filteredProvs, setFilteredProvs] = useState([]); console.log("Day la transaction"); + console.log("provs ngoài effect : " + provs); + + useEffect( () => { + dispatch(getOrganization()) + + }, []) useEffect(() => { - dispatch(getOrganization()).then( - setFilteredProvs([...provs]) - ) - }, [] - ) + setFilteredProvs(provs) + },[orgs]) + isLoading ? document.body.classList.add('loading-indicator') : document.body.classList.remove('loading-indicator') const deleteCurrentOrganization = (index) => { @@ -74,10 +75,8 @@ function Transactions() { } const applySearch = (searchText) => { - console.log("Đã chạy vào hàm apply Search"); - console.log("Chuỗi searh là : " + searchText); const filteredSearch = provs.filter((t) => { return searchText === "" || t.name.toLowerCase().includes(searchText.toLowerCase()) }); - setFilteredProvs(filteredSearch); + setFilteredProvs(filteredSearch) } return ( diff --git a/src/index.js b/src/index.js index c6c53d9..df50b52 100644 --- a/src/index.js +++ b/src/index.js @@ -15,7 +15,7 @@ root.render( - // + // ); // If you want to start measuring performance in your app, pass a function diff --git a/src/pages/protected/Commune.js b/src/pages/protected/Commune.js index 68f2214..0a2d218 100644 --- a/src/pages/protected/Commune.js +++ b/src/pages/protected/Commune.js @@ -1,7 +1,6 @@ import { useEffect } from 'react' import { useDispatch } from 'react-redux' import { setPageTitle } from '../../features/common/headerSlice' -import Transactions from '../../features/transactions' import Commune from '../../features/commune' function InternalPage() { diff --git a/src/pages/protected/District.js b/src/pages/protected/District.js index 9479df3..367dc55 100644 --- a/src/pages/protected/District.js +++ b/src/pages/protected/District.js @@ -1,7 +1,6 @@ import { useEffect } from 'react' import { useDispatch } from 'react-redux' import { setPageTitle } from '../../features/common/headerSlice' -import Transactions from '../../features/transactions' import District from '../../features/district' function InternalPage() { diff --git a/src/pages/protected/Member.js b/src/pages/protected/Member.js new file mode 100644 index 0000000..aa37a3b --- /dev/null +++ b/src/pages/protected/Member.js @@ -0,0 +1,18 @@ +import { useEffect } from 'react' +import { useDispatch } from 'react-redux' +import { setPageTitle } from '../../features/common/headerSlice' +import Members from '../../features/members' +function InternalPage() { + const dispatch = useDispatch() + + useEffect(() => { + dispatch(setPageTitle({ title: "Commune" })) + }, []) + + + return ( + + ) +} + +export default InternalPage \ No newline at end of file diff --git a/src/routes/index.js b/src/routes/index.js index fa7c567..308d5f6 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -19,6 +19,7 @@ const DocFeatures = lazy(() => import('../pages/DocFeatures')) const DocComponents = lazy(() => import('../pages/DocComponents')) const District = lazy(() => import('../pages/protected/District')) const Commune = lazy(() => import('../pages/protected/Commune')) +const Members = lazy(() => import('../pages/protected/Member')) const routes = [ { @@ -89,6 +90,10 @@ const routes = [ path: '/blank', component: Blank, }, + { + path: '/members', + component: Members + } ] export default routes diff --git a/src/routes/sidebar.js b/src/routes/sidebar.js index 365fb56..2f29e4b 100644 --- a/src/routes/sidebar.js +++ b/src/routes/sidebar.js @@ -51,6 +51,11 @@ const routes = [ name: 'Đơn vị xã', }, { + path: '/app/members', + icon: , + name: 'Thành viên hội' + } + ,{ path: '/app/charts', // url icon: , // icon component name: 'Analytics', // name that appear in Sidebar diff --git a/src/utils/globalConstantUtil.js b/src/utils/globalConstantUtil.js index 4c5f483..6386efc 100644 --- a/src/utils/globalConstantUtil.js +++ b/src/utils/globalConstantUtil.js @@ -6,6 +6,7 @@ module.exports = Object.freeze({ CONFIRMATION: "CONFIRMATION", PROVINCE_ADD_NEW: "PROVINCE_ADD_NEW", DISTRICT_ADD_NEW: "DISTRICT_ADD_NEW", + COMMUNE_ADD_NEW : "COMMUNE_ADD_NEW", DEFAULT: "", }, From aed58e32732bd0cb1ee6cd01ffb267d30bc42665 Mon Sep 17 00:00:00 2001 From: Thanh Tuanas Date: Mon, 23 Oct 2023 10:55:33 +0700 Subject: [PATCH 2/5] Update index.js --- src/features/members/index.js | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/features/members/index.js b/src/features/members/index.js index cbb65c6..56e35f5 100644 --- a/src/features/members/index.js +++ b/src/features/members/index.js @@ -1,7 +1,35 @@ +import moment from "moment" +import { useEffect } from "react" +import { useDispatch, useSelector } from "react-redux" +import TitleCard from "../../components/Cards/TitleCard" +import { openModal } from "../common/modalSlice" +import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_BODY_TYPES } from '../../utils/globalConstantUtil' +import TrashIcon from '@heroicons/react/24/outline/TrashIcon' +import { showNotification } from '../common/headerSlice' + +const TopSideButtons = () => { + + const dispatch = useDispatch() + + const openAddNewLeadModal = () => { + + } + + return ( +
+ +
+ ) +} + + + const Members = () => { return( <> -

This is fukin member

+ }> + + ) } From 8187bd809b4d146eb1948c791952205668226fa5 Mon Sep 17 00:00:00 2001 From: Roti-R <69901725+Roti-R@users.noreply.github.com> Date: Wed, 25 Oct 2023 01:24:13 +0700 Subject: [PATCH 3/5] Update Member Done createMember --- .gitignore | 1 + package-lock.json | 263 +++++++++++------- src/api/memberAPI.js | 18 ++ src/app/store.js | 2 + src/components/Input/InputText.js | 8 +- src/components/Input/SelectBox.js | 2 - src/containers/ModalLayout.js | 4 +- .../components/ConfirmationModalBody.js | 21 ++ src/features/integration/index.js | 58 ++-- .../members/components/PickCommune.js | 58 ++++ .../members/components/PickDistrict.js | 43 +++ .../members/components/PickProvince.js | 23 ++ .../members/components/addMemberModalBody.js | 115 ++++++++ src/features/members/index.js | 86 +++++- src/features/members/memberSlice.js | 96 +++++++ src/features/members/util.js | 17 ++ src/utils/globalConstantUtil.js | 6 +- 17 files changed, 682 insertions(+), 139 deletions(-) create mode 100644 src/api/memberAPI.js create mode 100644 src/features/members/components/PickCommune.js create mode 100644 src/features/members/components/PickDistrict.js create mode 100644 src/features/members/components/PickProvince.js create mode 100644 src/features/members/components/addMemberModalBody.js create mode 100644 src/features/members/memberSlice.js create mode 100644 src/features/members/util.js diff --git a/.gitignore b/.gitignore index 4d29575..680c904 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +package-lock.json diff --git a/package-lock.json b/package-lock.json index 11e980d..be1bb07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,8 +39,9 @@ } }, "node_modules/@adobe/css-tools": { - "version": "4.0.1", - "license": "MIT" + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.1.tgz", + "integrity": "sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg==" }, "node_modules/@ampproject/remapping": { "version": "2.2.0", @@ -54,10 +55,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "license": "MIT", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" @@ -138,11 +141,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.20.4", - "license": "MIT", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dependencies": { - "@babel/types": "^7.20.2", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { @@ -263,8 +268,9 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "license": "MIT", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } @@ -280,21 +286,23 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "license": "MIT", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -405,25 +413,28 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "license": "MIT", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "license": "MIT", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } @@ -461,11 +472,12 @@ } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "license": "MIT", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -473,8 +485,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.3", - "license": "MIT", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1711,29 +1724,31 @@ } }, "node_modules/@babel/template": { - "version": "7.18.10", - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.20.1", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.1", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.1", - "@babel/types": "^7.20.0", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1742,11 +1757,12 @@ } }, "node_modules/@babel/types": { - "version": "7.20.2", - "license": "MIT", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -5958,14 +5974,19 @@ "license": "MIT" }, "node_modules/daisyui": { - "version": "2.41.0", - "license": "MIT", + "version": "2.52.0", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.52.0.tgz", + "integrity": "sha512-LQTA5/IVXAJHBMFoeaEMfd7/akAFPPcdQPR3O9fzzcFiczneJFM73CFPnScmW2sOgn/D83cvkP854ep2T9OfTg==", "dependencies": { "color": "^4.2", "css-selector-tokenizer": "^0.8.0", "postcss-js": "^4.0.0", "tailwindcss": "^3" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/daisyui" + }, "peerDependencies": { "autoprefixer": "^10.0.2", "postcss": "^8.1.6" @@ -11161,8 +11182,15 @@ } }, "node_modules/nanoid": { - "version": "3.3.4", - "license": "MIT", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -11739,7 +11767,9 @@ } }, "node_modules/postcss": { - "version": "8.4.19", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -11748,11 +11778,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -15942,7 +15975,9 @@ }, "dependencies": { "@adobe/css-tools": { - "version": "4.0.1" + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.1.tgz", + "integrity": "sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg==" }, "@ampproject/remapping": { "version": "2.2.0", @@ -15952,9 +15987,12 @@ } }, "@babel/code-frame": { - "version": "7.18.6", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "requires": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" } }, "@babel/compat-data": { @@ -16006,10 +16044,13 @@ } }, "@babel/generator": { - "version": "7.20.4", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "requires": { - "@babel/types": "^7.20.2", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "dependencies": { @@ -16090,7 +16131,9 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.18.9" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" }, "@babel/helper-explode-assignable-expression": { "version": "7.18.6", @@ -16099,16 +16142,20 @@ } }, "@babel/helper-function-name": { - "version": "7.19.0", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { - "version": "7.18.6", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-member-expression-to-functions": { @@ -16177,16 +16224,22 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.18.6", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-string-parser": { - "version": "7.19.4" + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" }, "@babel/helper-validator-identifier": { - "version": "7.19.1" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" }, "@babel/helper-validator-option": { "version": "7.18.6" @@ -16209,15 +16262,19 @@ } }, "@babel/highlight": { - "version": "7.18.6", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.20.3" + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.18.6", @@ -16899,33 +16956,39 @@ } }, "@babel/template": { - "version": "7.18.10", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.20.1", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.1", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.1", - "@babel/types": "^7.20.0", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.20.2", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -19478,7 +19541,9 @@ "version": "3.1.1" }, "daisyui": { - "version": "2.41.0", + "version": "2.52.0", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.52.0.tgz", + "integrity": "sha512-LQTA5/IVXAJHBMFoeaEMfd7/akAFPPcdQPR3O9fzzcFiczneJFM73CFPnScmW2sOgn/D83cvkP854ep2T9OfTg==", "requires": { "color": "^4.2", "css-selector-tokenizer": "^0.8.0", @@ -22635,7 +22700,9 @@ } }, "nanoid": { - "version": "3.3.4" + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" }, "natural-compare": { "version": "1.4.0" @@ -22960,9 +23027,11 @@ } }, "postcss": { - "version": "8.4.19", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "requires": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } diff --git a/src/api/memberAPI.js b/src/api/memberAPI.js new file mode 100644 index 0000000..1b97ffb --- /dev/null +++ b/src/api/memberAPI.js @@ -0,0 +1,18 @@ +import axiosClient from "./axiosClient"; + +const memberAPI = { + getAllMember() { + const url = '/Member'; + return axiosClient.get(url) + }, + createMember(member) { + const url = '/Member'; + return axiosClient.post(url, member) + }, + deleteMember(memberID) { + const url = '/Member/' + memberID; + return axiosClient.delete(url, memberID); + } +} + +export default memberAPI \ No newline at end of file diff --git a/src/app/store.js b/src/app/store.js index bd3890b..bea23d3 100644 --- a/src/app/store.js +++ b/src/app/store.js @@ -6,6 +6,7 @@ import leadsSlice from '../features/leads/leadSlice' import ProvOrganizationSlice from '../features/transactions/OrganizationSlice' import SelectedProvSlice from '../features/district/SelectedProvSlice' import SelectedDistrictSlice from '../features/commune/SelectedDistrictSlice' +import memberSlice from '../features/members/memberSlice' const combinedReducer = { header: headerSlice, @@ -13,6 +14,7 @@ const combinedReducer = { modal: modalSlice, lead: leadsSlice, org: ProvOrganizationSlice, + member: memberSlice, selectedProv: SelectedProvSlice, selectedDistrict: SelectedDistrictSlice } diff --git a/src/components/Input/InputText.js b/src/components/Input/InputText.js index 05cb1d0..bfdac56 100644 --- a/src/components/Input/InputText.js +++ b/src/components/Input/InputText.js @@ -1,21 +1,21 @@ import { useState } from "react" -function InputText({labelTitle, labelStyle, type, containerStyle, defaultValue, placeholder, updateFormValue, updateType}){ +function InputText({ labelTitle, labelStyle, type, containerStyle, defaultValue, placeholder, updateFormValue, updateType }) { const [value, setValue] = useState(defaultValue) const updateInputValue = (val) => { setValue(val) - updateFormValue({updateType, value : val}) + updateFormValue({ updateType, value: val }) } - return( + return (
- updateInputValue(e.target.value)}className="input input-bordered w-full " /> + updateInputValue(e.target.value)} className="input input-bordered w-full " />
) } diff --git a/src/components/Input/SelectBox.js b/src/components/Input/SelectBox.js index 2bf1474..dd17410 100644 --- a/src/components/Input/SelectBox.js +++ b/src/components/Input/SelectBox.js @@ -12,8 +12,6 @@ function SelectBox(props) { const [value, setValue] = useState(defaultValue || (options.length > 0 ? options[0][nameKey] : '2222')) useEffect(() => { - console.log(labelTitle); - console.log(options); updateFormValue(value) }, []) diff --git a/src/containers/ModalLayout.js b/src/containers/ModalLayout.js index 505c4e8..df62de6 100644 --- a/src/containers/ModalLayout.js +++ b/src/containers/ModalLayout.js @@ -7,6 +7,7 @@ import ConfirmationModalBody from '../features/common/components/ConfirmationMod import AddProvinceModalBody from '../features/transactions/components/AddProvinceModalBody' import AddDistrictModalBody from '../features/district/components/AddDistrictModalBody' import AddCommuneModalBody from '../features/commune/components/AddCommuneModalBody' +import AddMemberModalBody from '../features/members/components/addMemberModalBody' function ModalLayout() { @@ -40,7 +41,8 @@ function ModalLayout() { [MODAL_BODY_TYPES.PROVINCE_ADD_NEW]: , [MODAL_BODY_TYPES.DISTRICT_ADD_NEW]: , [MODAL_BODY_TYPES.CONFIRMATION]: , - [MODAL_BODY_TYPES.COMMUNE_ADD_NEW]: , + [MODAL_BODY_TYPES.COMMUNE_ADD_NEW]: , + [MODAL_BODY_TYPES.MEMBER_ADD_NEW]: , [MODAL_BODY_TYPES.DEFAULT]:
}[bodyType] } diff --git a/src/features/common/components/ConfirmationModalBody.js b/src/features/common/components/ConfirmationModalBody.js index 2537d72..b19632e 100644 --- a/src/features/common/components/ConfirmationModalBody.js +++ b/src/features/common/components/ConfirmationModalBody.js @@ -4,6 +4,7 @@ import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_CLOSE_TYPES } from '../../../util import { deleteLead } from '../../leads/leadSlice' import { showNotification } from '../headerSlice' import { deleteOrganization } from '../../transactions/OrganizationSlice' +import { deleteMember } from '../../members/memberSlice' function ConfirmationModalBody({ extraObject, closeModal }) { @@ -43,6 +44,26 @@ function ConfirmationModalBody({ extraObject, closeModal }) { ); } } + else if (type === CONFIRMATION_MODAL_CLOSE_TYPES.MEMBER_DELETE) { + try { + await dispatch(deleteMember(index)); + dispatch( + showNotification({ + message: 'Xóa thành viên thành công', + status: 1, + }) + ); + } + catch (err) { + console.log(err); + dispatch( + showNotification({ + message: 'Xóa thành viên không thành công', + status: 0, + }) + ); + } + } closeModal() } diff --git a/src/features/integration/index.js b/src/features/integration/index.js index 22c8e87..f0233e3 100644 --- a/src/features/integration/index.js +++ b/src/features/integration/index.js @@ -5,16 +5,16 @@ import { showNotification } from "../common/headerSlice" const INITIAL_INTEGRATION_LIST = [ - {name : "Slack", icon : "https://cdn-icons-png.flaticon.com/512/2111/2111615.png", isActive : true, description : "Slack is an instant messaging program designed by Slack Technologies and owned by Salesforce."}, - {name : "Facebook", icon : "https://cdn-icons-png.flaticon.com/512/124/124010.png", isActive : false, description : "Meta Platforms, Inc., doing business as Meta and formerly named Facebook, Inc., and TheFacebook."}, - {name : "Linkedin", icon : "https://cdn-icons-png.flaticon.com/512/174/174857.png", isActive : true, description : "LinkedIn is a business and employment-focused social media platform that works through websites and mobile apps."}, - {name : "Google Ads", icon : "https://cdn-icons-png.flaticon.com/512/2301/2301145.png", isActive : false, description : "Google Ads is an online advertising platform developed by Google, where advertisers bid to display brief advertisements, service offerings"}, - {name : "Gmail", icon : "https://cdn-icons-png.flaticon.com/512/5968/5968534.png", isActive : false, description : "Gmail is a free email service provided by Google. As of 2019, it had 1.5 billion active users worldwide."}, - {name : "Salesforce", icon : "https://cdn-icons-png.flaticon.com/512/5968/5968880.png", isActive : false, description : "It provides customer relationship management software and applications focused on sales, customer service, marketing automation."}, - {name : "Hubspot", icon : "https://cdn-icons-png.flaticon.com/512/5968/5968872.png", isActive : false, description : "American developer and marketer of software products for inbound marketing, sales, and customer service."}, + { name: "Slack", icon: "https://cdn-icons-png.flaticon.com/512/2111/2111615.png", isActive: true, description: "Slack is an instant messaging program designed by Slack Technologies and owned by Salesforce." }, + { name: "Facebook", icon: "https://cdn-icons-png.flaticon.com/512/124/124010.png", isActive: false, description: "Meta Platforms, Inc., doing business as Meta and formerly named Facebook, Inc., and TheFacebook." }, + { name: "Linkedin", icon: "https://cdn-icons-png.flaticon.com/512/174/174857.png", isActive: true, description: "LinkedIn is a business and employment-focused social media platform that works through websites and mobile apps." }, + { name: "Google Ads", icon: "https://cdn-icons-png.flaticon.com/512/2301/2301145.png", isActive: false, description: "Google Ads is an online advertising platform developed by Google, where advertisers bid to display brief advertisements, service offerings" }, + { name: "Gmail", icon: "https://cdn-icons-png.flaticon.com/512/5968/5968534.png", isActive: false, description: "Gmail is a free email service provided by Google. As of 2019, it had 1.5 billion active users worldwide." }, + { name: "Salesforce", icon: "https://cdn-icons-png.flaticon.com/512/5968/5968880.png", isActive: false, description: "It provides customer relationship management software and applications focused on sales, customer service, marketing automation." }, + { name: "Hubspot", icon: "https://cdn-icons-png.flaticon.com/512/5968/5968872.png", isActive: false, description: "American developer and marketer of software products for inbound marketing, sales, and customer service." }, ] -function Integration(){ +function Integration() { const dispatch = useDispatch() @@ -24,34 +24,34 @@ function Integration(){ const updateIntegrationStatus = (index) => { let integration = integrationList[index] setIntegrationList(integrationList.map((i, k) => { - if(k===index)return {...i, isActive : !i.isActive} + if (k === index) return { ...i, isActive: !i.isActive } return i })) - dispatch(showNotification({message : `${integration.name} ${integration.isActive ? "disabled" : "enabled"}` , status : 1})) + dispatch(showNotification({ message: `${integration.name} ${integration.isActive ? "disabled" : "enabled"}`, status: 1 })) } - return( + return ( <>
- { - integrationList.map((i, k) => { - return( - - -

- icon - {i.description} -

-
- updateIntegrationStatus(k)}/> -
- -
- ) - - }) - } + { + integrationList.map((i, k) => { + return ( + + +

+ icon + {i.description} +

+
+ updateIntegrationStatus(k)} /> +
+ +
+ ) + + }) + }
) diff --git a/src/features/members/components/PickCommune.js b/src/features/members/components/PickCommune.js new file mode 100644 index 0000000..3071ab1 --- /dev/null +++ b/src/features/members/components/PickCommune.js @@ -0,0 +1,58 @@ +import React from 'react' +import { useState } from 'react' +import { useSelector } from 'react-redux' +import SelectBox from '../../../components/Input/SelectBox' + +export const PickCommune = ({ updateType, updateFormValue }) => { + const [selectedProv, setSelectedProv] = useState(null) + const [selectedDistrict, setSelectedDistrict] = useState(null) + const { orgs } = useSelector(state => state.org) + const provs = orgs.filter(o => o.type === 'tinh') + const districts = orgs.filter(o => o.parentID === selectedProv) + const communes = orgs.filter(o => o.parentID === selectedDistrict) + + const handleSelectProvince = (value) => { + setSelectedProv(value); + } + + const handleSelectDistrict = (value) => { + setSelectedDistrict(value) + } + + const updateValue = (value) => { + updateFormValue({ updateType, value: value }) + } + return ( + <> + + + + + + + ) +} diff --git a/src/features/members/components/PickDistrict.js b/src/features/members/components/PickDistrict.js new file mode 100644 index 0000000..621fcab --- /dev/null +++ b/src/features/members/components/PickDistrict.js @@ -0,0 +1,43 @@ +import React from 'react' +import { useState } from 'react' +import { useSelector } from 'react-redux' +import SelectBox from '../../../components/Input/SelectBox' + + +export const PickDistrict = ({ updateType, updateFormValue }) => { + const [selectedProv, setSelectedProv] = useState(null) + const { orgs } = useSelector(state => state.org) + const provs = orgs.filter(o => o.type === 'tinh') + const districts = orgs.filter(o => o.parentID === selectedProv) + + const handleSelectProvince = (value) => { + setSelectedProv(value); + } + + const updateValue = (value) => { + updateFormValue({ updateType, value: value }) + } + return ( + <> + + + + + ) +} diff --git a/src/features/members/components/PickProvince.js b/src/features/members/components/PickProvince.js new file mode 100644 index 0000000..ce092fd --- /dev/null +++ b/src/features/members/components/PickProvince.js @@ -0,0 +1,23 @@ +import React from 'react' +import { useSelector } from 'react-redux' +import SelectBox from '../../../components/Input/SelectBox' + +export const PickProvince = ({ updateType, updateFormValue }) => { + const { orgs } = useSelector(state => state.org) + const provs = orgs.filter(o => o.type === 'tinh') + + const updateValue = (value) => { + updateFormValue({ updateType, value: value }) + } + return ( + + ) +} diff --git a/src/features/members/components/addMemberModalBody.js b/src/features/members/components/addMemberModalBody.js new file mode 100644 index 0000000..dcebc5e --- /dev/null +++ b/src/features/members/components/addMemberModalBody.js @@ -0,0 +1,115 @@ +import { useDispatch } from "react-redux"; +import { useState } from "react"; +import { showNotification } from "../../common/headerSlice"; +import InputText from "../../../components/Input/InputText"; +import ErrorText from "../../../components/Typography/ErrorText"; +import { createMember } from "../memberSlice"; +import { openModal } from "../../common/modalSlice"; +import { MODAL_BODY_TYPES } from "../../../utils/globalConstantUtil"; +import { PickProvince } from "./PickProvince"; +import { PickCommune } from "./PickCommune"; +import { PickDistrict } from "./PickDistrict"; + +const INITIAL_MEMBER_OBJ = { + name: '', + address: '', + phoneNumber: '', + currentOrganizationID: null, + birthDate: '', +} + +const AddMemberModalBody = ({ closeModal }) => { + const dispatch = useDispatch(); + const [errorMessage, setErrorMessage] = useState("") + const [memberObj, setmemberObj] = useState(INITIAL_MEMBER_OBJ) + const [isAddToOrg, setIsAddToOrg] = useState(false) + const [activeButton, setActiveButton] = useState(0) + console.log(memberObj); + + const saveNewMember = () => { + const regexTel = /^\d{10}$/; + if (memberObj.name.trim() === "") return setErrorMessage("Hãy điền tên thành viên") + else if (memberObj.phoneNumber !== '' && !regexTel.test(memberObj.phoneNumber)) return setErrorMessage("Hãy nhập đúng định dạng số điện thoại") + else if (memberObj.currentOrganizationID === "PLACEHOLDER") return setErrorMessage("Hãy hoàn thành việc chọn hội") + else { + //Call API to Add Province Organization + dispatch(createMember(memberObj)).unwrap() + .then(res => { + dispatch(showNotification({ message: "Thêm thành viên mới thành công", status: 1 })) + closeModal(); + }) + .catch(err => { + setErrorMessage(err.error.errors[0].errorMessage); + }) + + + } + } + + const updateFormValue = ({ updateType, value }) => { + setErrorMessage(""); + setmemberObj({ ...memberObj, [updateType]: value }); + } + + const handleAddToOrgToggleChange = () => { + setIsAddToOrg(!isAddToOrg); + } + + const handleOrganizationType = (type) => { + setActiveButton(type); + } + + return ( + <> + + + + + +
+ +
+ + { + isAddToOrg && ( +
+ handleOrganizationType(1)} /> + handleOrganizationType(2)} /> + handleOrganizationType(3)} /> +
+ + ) + + + } + + { + isAddToOrg && { + 1: , + 2: , + 3: , + 0:
+ }[activeButton] + } + + + + + + + + + {errorMessage} + + +
+ + +
+ + ) +} +export default AddMemberModalBody; \ No newline at end of file diff --git a/src/features/members/index.js b/src/features/members/index.js index 56e35f5..ee5c9aa 100644 --- a/src/features/members/index.js +++ b/src/features/members/index.js @@ -6,18 +6,24 @@ import { openModal } from "../common/modalSlice" import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_BODY_TYPES } from '../../utils/globalConstantUtil' import TrashIcon from '@heroicons/react/24/outline/TrashIcon' import { showNotification } from '../common/headerSlice' +import { getMember } from "./memberSlice" +import { formatDateTime } from "./util" +import { getOrganization } from "../transactions/OrganizationSlice" +import { Await } from "react-router-dom" + +const sourceImg = "https://vnn-imgs-a1.vgcloud.vn/icdn.dantri.com.vn/2021/05/26/ngo-ngang-voi-ve-dep-cua-hot-girl-anh-the-chua-tron-18-docx-1622043349706.jpeg" const TopSideButtons = () => { const dispatch = useDispatch() - const openAddNewLeadModal = () => { - + const openAddNewMemberModal = () => { + dispatch(openModal({ title: 'Thêm thành viên', bodyType: MODAL_BODY_TYPES.MEMBER_ADD_NEW })) } return (
- +
) } @@ -25,10 +31,82 @@ const TopSideButtons = () => { const Members = () => { - return( + + const dispatch = useDispatch() + const { members, isLoading } = useSelector(state => state.member) + const { orgs } = useSelector(state => state.org) + useEffect(() => { + dispatch(getOrganization()) + dispatch(getMember()) + }, []) + + + + isLoading ? document.body.classList.add('loading-indicator') : document.body.classList.remove('loading-indicator') + const getMemberOrganization = (currentOrganization) => { + if (orgs) { + return orgs.find(org => org.orgID === currentOrganization).name; + + } + } + + const deleteCurrentMember = (index) => { + dispatch(openModal({ + title: "Xác nhận", bodyType: MODAL_BODY_TYPES.CONFIRMATION, + extraObject: { message: `Bạn có chắc muốn xóa thành viên này không ?`, type: CONFIRMATION_MODAL_CLOSE_TYPES.MEMBER_DELETE, index: index } + })) + } + + + return ( <> }> +
+ + + + + + + + + + + + { + members.map((l, k) => { + return ( + + + + + + + + ) + }) + } + +
TênNgày tham giaTrạng tháiHội
+
+
+
+ Avatar +
+
+
+
{l.name}
+
{l.name}
+
+
+
{formatDateTime(l.joinDate)} + { + l.currentOrganizationID === null ?
Chưa có hội
+ :
Đã có hội
+ } +
{l.currentOrganizationID === null ? "" : getMemberOrganization(l.currentOrganizationID)}
+
) diff --git a/src/features/members/memberSlice.js b/src/features/members/memberSlice.js new file mode 100644 index 0000000..fc329b0 --- /dev/null +++ b/src/features/members/memberSlice.js @@ -0,0 +1,96 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import memberAPI from "../../api/memberAPI"; +import { showNotification } from "../common/headerSlice"; + +export const getMember = createAsyncThunk('/member/contents', async () => { + try { + const response = await memberAPI.getAllMember(); + return response.data; + } catch (error) { + console.error('Lỗi trong quá trình lấy dữ liệu từ API:', error); + throw error; + } +}) + +export const createMember = createAsyncThunk('/member/create', async (value, thunkAPI) => { + try { + const response = await memberAPI.createMember(value); + return response.data; + } + catch (error) { + if (error.response.status === 422) { + return thunkAPI.rejectWithValue(error.response.data) + } + throw error; + } +}) + +export const deleteMember = createAsyncThunk('/member/delete', async (value, thunkAPI) => { + try { + const response = await memberAPI.deleteMember(value); + return value; + } catch (error) { + if (error.response.status === 422) { + return thunkAPI.rejectWithValue(error.response.data) + } + throw error; + } +}) + +export const memberSlice = createSlice({ + name: 'member', + initialState: { + isLoading: false, + members: [] + }, + reducers: { + + }, + extraReducers: { + [getMember.pending]: state => { + state.isLoading = true + }, + [getMember.fulfilled]: (state, action) => { + state.members = action.payload + state.isLoading = false + console.log("Đã chạy vào lấy dữ liệu"); + + }, + + + [getMember.rejected]: state => { + state.isLoading = false; + }, + + + [createMember.pending]: state => { + state.isLoading = true + }, + [createMember.fulfilled]: (state, action) => { + state.isLoading = false; + state.members = [...state.members, action.payload]; + }, + [createMember.rejected]: state => { + state.isLoading = false; + }, + + + [deleteMember.pending]: state => { + state.isLoading = true; + }, + [deleteMember.fulfilled]: (state, action) => { + state.isLoading = false; + state.members = state.members.filter(org => org.memberID !== action.payload) + + }, + [deleteMember.rejected]: state => { + state.isLoading = false; + console.log("Nhay vo rejeject r"); + }, + } + +} + +) + +export default memberSlice.reducer; \ No newline at end of file diff --git a/src/features/members/util.js b/src/features/members/util.js new file mode 100644 index 0000000..b30fbe4 --- /dev/null +++ b/src/features/members/util.js @@ -0,0 +1,17 @@ +export const formatDateTime = (dateTimeStr) => { + const dateTime = new Date(dateTimeStr); + + // Lấy ngày, tháng và năm từ đối tượng Date + const ngay = dateTime.getDate(); + const thang = dateTime.getMonth() + 1; // Tháng bắt đầu từ 0, nên cộng thêm 1 + const nam = dateTime.getFullYear(); + + // Định dạng lại ngày và tháng để thêm số 0 vào đầu nếu cần + const ngayDaDinhDang = ngay < 10 ? '0' + ngay : ngay; + const thangDaDinhDang = thang < 10 ? '0' + thang : thang; + + // Định dạng chuỗi kết quả + const ketQua = `${ngayDaDinhDang} - ${thangDaDinhDang} - ${nam}`; + + return ketQua; +} \ No newline at end of file diff --git a/src/utils/globalConstantUtil.js b/src/utils/globalConstantUtil.js index 6386efc..d215238 100644 --- a/src/utils/globalConstantUtil.js +++ b/src/utils/globalConstantUtil.js @@ -6,7 +6,8 @@ module.exports = Object.freeze({ CONFIRMATION: "CONFIRMATION", PROVINCE_ADD_NEW: "PROVINCE_ADD_NEW", DISTRICT_ADD_NEW: "DISTRICT_ADD_NEW", - COMMUNE_ADD_NEW : "COMMUNE_ADD_NEW", + COMMUNE_ADD_NEW: "COMMUNE_ADD_NEW", + MEMBER_ADD_NEW: "MEMBER_ADD_NEW", DEFAULT: "", }, @@ -18,6 +19,7 @@ module.exports = Object.freeze({ CONFIRMATION_MODAL_CLOSE_TYPES: { LEAD_DELETE: "LEAD_DELETE", - ORGANIZATION_DELETE: "ORGANIZATION_DELETE" + ORGANIZATION_DELETE: "ORGANIZATION_DELETE", + MEMBER_DELETE: "MEMBER_DELETE" }, }); From 3d8b71ae83799d114f2a9992fdd9feff36231d1a Mon Sep 17 00:00:00 2001 From: Roti-R <69901725+Roti-R@users.noreply.github.com> Date: Thu, 26 Oct 2023 03:51:28 +0700 Subject: [PATCH 4/5] update detail organization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thêm và xóa thành viên khỏi hội thành công --- src/api/memberAPI.js | 4 + src/containers/ModalLayout.js | 2 + .../components/ConfirmationModalBody.js | 26 +++- src/features/commune/index.js | 23 ++-- .../dashboard/components/DashboardStats.js | 14 +-- .../components/AddMemberToOrg.js | 78 ++++++++++++ src/features/detailOrganization/index.js | 111 ++++++++++++++++++ src/features/district/index.js | 9 +- .../members/components/PickDistrict.js | 2 +- src/features/members/memberSlice.js | 26 ++++ src/features/transactions/index.js | 32 ++--- src/pages/protected/DetailOrganization.js | 12 ++ src/pages/protected/District.js | 2 + src/routes/index.js | 7 +- src/routes/sidebar.js | 6 +- src/utils/globalConstantUtil.js | 9 +- 16 files changed, 320 insertions(+), 43 deletions(-) create mode 100644 src/features/detailOrganization/components/AddMemberToOrg.js create mode 100644 src/features/detailOrganization/index.js create mode 100644 src/pages/protected/DetailOrganization.js diff --git a/src/api/memberAPI.js b/src/api/memberAPI.js index 1b97ffb..4eb701e 100644 --- a/src/api/memberAPI.js +++ b/src/api/memberAPI.js @@ -12,6 +12,10 @@ const memberAPI = { deleteMember(memberID) { const url = '/Member/' + memberID; return axiosClient.delete(url, memberID); + }, + updateMember(data) { + const url = '/Member/' + data.memberID; + return axiosClient.put(url, data.member) } } diff --git a/src/containers/ModalLayout.js b/src/containers/ModalLayout.js index df62de6..67b306c 100644 --- a/src/containers/ModalLayout.js +++ b/src/containers/ModalLayout.js @@ -8,6 +8,7 @@ import AddProvinceModalBody from '../features/transactions/components/AddProvinc import AddDistrictModalBody from '../features/district/components/AddDistrictModalBody' import AddCommuneModalBody from '../features/commune/components/AddCommuneModalBody' import AddMemberModalBody from '../features/members/components/addMemberModalBody' +import AddMemberToOrg from '../features/detailOrganization/components/AddMemberToOrg' function ModalLayout() { @@ -43,6 +44,7 @@ function ModalLayout() { [MODAL_BODY_TYPES.CONFIRMATION]: , [MODAL_BODY_TYPES.COMMUNE_ADD_NEW]: , [MODAL_BODY_TYPES.MEMBER_ADD_NEW]: , + [MODAL_BODY_TYPES.MEMBER_ADD_ORGANIZATION]: , [MODAL_BODY_TYPES.DEFAULT]:
}[bodyType] } diff --git a/src/features/common/components/ConfirmationModalBody.js b/src/features/common/components/ConfirmationModalBody.js index b19632e..04f8bc9 100644 --- a/src/features/common/components/ConfirmationModalBody.js +++ b/src/features/common/components/ConfirmationModalBody.js @@ -4,13 +4,13 @@ import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_CLOSE_TYPES } from '../../../util import { deleteLead } from '../../leads/leadSlice' import { showNotification } from '../headerSlice' import { deleteOrganization } from '../../transactions/OrganizationSlice' -import { deleteMember } from '../../members/memberSlice' +import { deleteMember, updateMember } from '../../members/memberSlice' function ConfirmationModalBody({ extraObject, closeModal }) { const dispatch = useDispatch() - const { message, type, _id, index } = extraObject + const { message, type, _id, index, updateObject } = extraObject const proceedWithYes = async () => { @@ -64,6 +64,28 @@ function ConfirmationModalBody({ extraObject, closeModal }) { ); } } + else if (type === CONFIRMATION_MODAL_CLOSE_TYPES.MEMBER_OUT_ORGANIZATION) { + dispatch(updateMember({ memberID: index, member: updateObject })).unwrap() + .then((res) => { + dispatch( + showNotification({ + message: 'Xóa thành viên khỏi hội thành công', + status: 1, + }) + ); + }) + .catch(err => { + console.log("index: " + index); + console.log(updateObject); + console.log(err); + dispatch( + showNotification({ + message: 'Xóa thành viên không thành công', + status: 0, + }) + ); + }) + } closeModal() } diff --git a/src/features/commune/index.js b/src/features/commune/index.js index 26aca88..886fc42 100644 --- a/src/features/commune/index.js +++ b/src/features/commune/index.js @@ -11,7 +11,7 @@ import { getOrganization } from '../transactions/OrganizationSlice'; import TrashIcon from '@heroicons/react/24/outline/TrashIcon'; import { CONFIRMATION_MODAL_CLOSE_TYPES } from '../../utils/globalConstantUtil'; import { setSelectedDistrict } from './SelectedDistrictSlice'; - +import { Link } from 'react-router-dom'; const TopSideButtons = ({ removeFilter, applyFilter, applySearch }) => { const dispatch = useDispatch(); const { orgs, isLoading } = useSelector(state => state.org) @@ -27,7 +27,7 @@ const TopSideButtons = ({ removeFilter, applyFilter, applySearch }) => { const AddNewDistrictModal = () => { - dispatch(openModal({ title: 'Thêm đơn vị xã', bodyType: MODAL_BODY_TYPES.COMMUNE_ADD_NEW})) + dispatch(openModal({ title: 'Thêm đơn vị xã', bodyType: MODAL_BODY_TYPES.COMMUNE_ADD_NEW })) } const handleSelectProvince = (value) => { @@ -38,9 +38,9 @@ const TopSideButtons = ({ removeFilter, applyFilter, applySearch }) => { dispatch(setSelectedDistrict(value)) } - - + + return (
{ const Commune = () => { const dispatch = useDispatch() - const {selectedDistrict} = useSelector(state => state.selectedDistrict) - const {orgs, isLoading} = useSelector(state => state.org) + const { selectedDistrict } = useSelector(state => state.selectedDistrict) + const { orgs, isLoading } = useSelector(state => state.org) const communes = orgs.filter(org => org.parentID === selectedDistrict) useEffect(() => { @@ -93,7 +93,7 @@ const Commune = () => { } return ( <> - }> + }>
@@ -104,12 +104,15 @@ const Commune = () => { - { + { communes.map((l, k) => { return ( - diff --git a/src/features/dashboard/components/DashboardStats.js b/src/features/dashboard/components/DashboardStats.js index ebac523..ae7b146 100644 --- a/src/features/dashboard/components/DashboardStats.js +++ b/src/features/dashboard/components/DashboardStats.js @@ -1,19 +1,19 @@ -function DashboardStats({title, icon, value, description, colorIndex}){ +function DashboardStats({ title, icon, value, description, colorIndex, containerStyle }) { const COLORS = ["primary", "primary"] const getDescStyle = () => { - if(description.includes("↗︎"))return "font-bold text-green-700 dark:text-green-300" - else if(description.includes("↙"))return "font-bold text-rose-500 dark:text-red-400" + if (description.includes("↗︎")) return "font-bold text-green-700 dark:text-green-300" + else if (description.includes("↙")) return "font-bold text-rose-500 dark:text-red-400" else return "" } - return( -
+ return ( +
-
{icon}
+
{icon}
{title}
-
{value}
+
{value}
{description}
diff --git a/src/features/detailOrganization/components/AddMemberToOrg.js b/src/features/detailOrganization/components/AddMemberToOrg.js new file mode 100644 index 0000000..197ec96 --- /dev/null +++ b/src/features/detailOrganization/components/AddMemberToOrg.js @@ -0,0 +1,78 @@ +import React from 'react' +import SelectBox from '../../../components/Input/SelectBox'; +import { useDispatch, useSelector } from 'react-redux'; +import { useState } from 'react'; +import SearchBar from '../../../components/Input/SearchBar'; +import ErrorText from '../../../components/Typography/ErrorText'; +import { updateMember } from '../../members/memberSlice'; +import { showNotification } from '../../common/headerSlice'; + +export const AddMemberToOrg = ({ extraObject, closeModal }) => { + + const dispatch = useDispatch(); + + const { index } = extraObject; + const { members } = useSelector(state => state.member) + const memberNotInOrg = members.filter(m => m.currentOrganizationID === null) + const [selectedMember, setSelectedMember] = useState(null); + const [searchText, setSearchText] = useState(""); + const [errorMessage, setErrorMessage] = useState(""); + + const handleSearchChange = (value) => { + setSearchText(value); + } + const updateFormValue = (value) => { + setSelectedMember(value) + } + + const saveNewMember = () => { + if (selectedMember === 'PLACEHOLDER') return setErrorMessage("Hãy chọn người muốn thêm") + else { + let updateObject = { + ...memberNotInOrg.find(m => m.memberID === selectedMember), + currentOrganizationID: index + } + dispatch(updateMember({ memberID: selectedMember, member: updateObject })).unwrap() + .then((res) => { + closeModal(); + dispatch( + showNotification({ + message: 'Thêm thành viên thành công', + status: 1, + }) + ); + }) + .catch(err => { + closeModal(); + console.log(err); + dispatch( + showNotification({ + message: 'Thêm thành viên không thành công', + status: 0, + }) + ); + }) + } + } + return ( + <> + + { return searchText === "" || m.name.toLowerCase().includes(searchText.toLowerCase()) })} + labelTitle="Các thành viên chưa có hội" + placeholder="Chọn thành viên" + containerStyle="w-full mt-4" + updateFormValue={updateFormValue} + nameKey='memberID' + /> + + {errorMessage} +
+ + +
+ + ) + +} +export default AddMemberToOrg diff --git a/src/features/detailOrganization/index.js b/src/features/detailOrganization/index.js new file mode 100644 index 0000000..3c9117f --- /dev/null +++ b/src/features/detailOrganization/index.js @@ -0,0 +1,111 @@ +import React from 'react' +import TitleCard from '../../components/Cards/TitleCard' +import { useParams, useSearchParams } from 'react-router-dom' +import { ORGANIZATION_TYPE } from '../../utils/globalConstantUtil' +import { useDispatch, useSelector } from 'react-redux' +import { useEffect } from 'react' +import { getOrganization } from '../transactions/OrganizationSlice' +import { useState } from 'react' +import DashboardStats from '../dashboard/components/DashboardStats' +import UserGroupIcon from '@heroicons/react/24/outline/UserGroupIcon' +import User from '@heroicons/react/24/outline/UserIcon' +import TrashIcon from '@heroicons/react/24/outline/TrashIcon' +import { getMember, updateMember } from '../members/memberSlice' +import ArrowUpTrayIcon from '@heroicons/react/24/outline/ArrowUpTrayIcon' +import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_BODY_TYPES } from '../../utils/globalConstantUtil' +import { openModal } from '../common/modalSlice' + + +export const DetailOrganization = () => { + + const dispatch = useDispatch() + const param = useParams(); + var typeInTitle = "" + + const { orgs, isLoading } = useSelector(state => state.org) + const { members } = useSelector(state => state.member) + const org = orgs.find(o => o.orgID === param.id) + const memberList = members.filter(mem => mem.currentOrganizationID === param.id) + switch (param.type) { + case ORGANIZATION_TYPE.PROVINCE: + typeInTitle = "tỉnh" + break; + case ORGANIZATION_TYPE.DISTRICT: + typeInTitle = "huyện" + break; + case ORGANIZATION_TYPE.COMMUNE: + typeInTitle = "xã" + break; + default: + break; + } + console.log(org); + useEffect(() => { + dispatch(getOrganization()); + dispatch(getMember()); + }, []) + + isLoading ? document.body.classList.add('loading-indicator') : document.body.classList.remove('loading-indicator') + + + const deleteCurrentMember = (memberID, member) => { + let updateMember = { ...member, currentOrganizationID: null } + dispatch(openModal({ + title: "Xác nhận", bodyType: MODAL_BODY_TYPES.CONFIRMATION, + extraObject: { message: `Bạn có chắc muốn xóa thành viên này khỏi hội không ?`, type: CONFIRMATION_MODAL_CLOSE_TYPES.MEMBER_OUT_ORGANIZATION, index: memberID, updateObject: updateMember } + })) + + } + + const setMemberToManager = () => { + + } + + const AddNewMemberToOrg = () => { + dispatch(openModal({ + title: 'Thêm thành viên vào hội', bodyType: MODAL_BODY_TYPES.MEMBER_ADD_ORGANIZATION, + extraObject: { index: param.id } + })) + } + return ( + <> + + +
+ } description="" /> + + } description="" /> +
+
+
- {l.name} + + + + {l.name} + {l.type}
+ {/* head */} + + + + + + + + + + { + memberList.map((m, index) => { + return ( + + + + + + + ) + }) + } + +
TênXóa khỏi hộiĐặt làm quản lý
{index + 1}{m.name}
+
+
+ + ) +} + +export default DetailOrganization \ No newline at end of file diff --git a/src/features/district/index.js b/src/features/district/index.js index 5515f90..47e7e10 100644 --- a/src/features/district/index.js +++ b/src/features/district/index.js @@ -11,7 +11,7 @@ import { getOrganization } from '../transactions/OrganizationSlice'; import { setSelectedProvince } from './SelectedProvSlice'; import TrashIcon from '@heroicons/react/24/outline/TrashIcon'; import { CONFIRMATION_MODAL_CLOSE_TYPES } from '../../utils/globalConstantUtil'; - +import { Link } from 'react-router-dom'; const TopSideButtons = ({ removeFilter, applyFilter, applySearch }) => { const dispatch = useDispatch(); @@ -94,8 +94,11 @@ const District = () => { districtOrg.map((l, k) => { return ( - - {l.name} + + + + {l.name} + {l.type} diff --git a/src/features/members/components/PickDistrict.js b/src/features/members/components/PickDistrict.js index 621fcab..c75164b 100644 --- a/src/features/members/components/PickDistrict.js +++ b/src/features/members/components/PickDistrict.js @@ -34,7 +34,7 @@ export const PickDistrict = ({ updateType, updateFormValue }) => { placeholder="Chọn huyện" containerStyle="w-full mt-4" labelStyle="" - updateFormValue={updateType} + updateFormValue={updateValue} nameKey='orgID' /> diff --git a/src/features/members/memberSlice.js b/src/features/members/memberSlice.js index fc329b0..89df7f5 100644 --- a/src/features/members/memberSlice.js +++ b/src/features/members/memberSlice.js @@ -37,6 +37,17 @@ export const deleteMember = createAsyncThunk('/member/delete', async (value, thu } }) +export const updateMember = createAsyncThunk('/member/update', async (value, thunkAPI) => { + try { + const response = await memberAPI.updateMember(value); + return response.data; + } catch (error) { + if (error.response.status === 422) { + return thunkAPI.rejectWithValue(error.response.data) + } + throw error; + } +}) export const memberSlice = createSlice({ name: 'member', initialState: { @@ -87,6 +98,21 @@ export const memberSlice = createSlice({ state.isLoading = false; console.log("Nhay vo rejeject r"); }, + + [updateMember.pending]: state => { + state.isLoading = true + }, + [updateMember.fulfilled]: (state, action) => { + state.isLoading = false; + state.members.find((m, index) => { + if (m.memberID === action.payload.memberID) { + state.members[index] = action.payload + } + }) + }, + [updateMember.rejected]: state => { + state.isLoading = false; + }, } } diff --git a/src/features/transactions/index.js b/src/features/transactions/index.js index b03e851..c15b981 100644 --- a/src/features/transactions/index.js +++ b/src/features/transactions/index.js @@ -13,6 +13,7 @@ import { openModal } from "../common/modalSlice" import { getOrganization } from "./OrganizationSlice" import TrashIcon from "@heroicons/react/24/outline/TrashIcon" import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_BODY_TYPES } from '../../utils/globalConstantUtil' +import { Link } from "react-router-dom" const TopSideButtons = ({ applySearch }) => { @@ -20,7 +21,6 @@ const TopSideButtons = ({ applySearch }) => { const [searchText, setSearchText] = useState(""); const dispatch = useDispatch(); - console.log("Day la TopSideButton"); const handleSearchChange = (searchText) => { setSearchText(searchText) @@ -52,25 +52,23 @@ function Transactions() { const { orgs, isLoading } = useSelector(state => state.org) const provs = orgs.filter(org => org.type === 'tinh'); const [filteredProvs, setFilteredProvs] = useState([]); - console.log("Day la transaction"); - console.log("provs ngoài effect : " + provs); - useEffect( () => { + useEffect(() => { dispatch(getOrganization()) - - }, []) + + }, [dispatch]) useEffect(() => { setFilteredProvs(provs) - },[orgs]) + }, [orgs]) isLoading ? document.body.classList.add('loading-indicator') : document.body.classList.remove('loading-indicator') const deleteCurrentOrganization = (index) => { dispatch(openModal({ title: "Xác nhận", bodyType: MODAL_BODY_TYPES.CONFIRMATION, - extraObject: { message: `Xóa hội này cũng sẽ xóa các hội trực thuộc nó, bạn có muốn xóa không ?`, type: CONFIRMATION_MODAL_CLOSE_TYPES.ORGANIZATION_DELETE, index: index } + extraObject: { message: `Xóa hội này sẽ xóa các hội trực thuộc nó, xóa các thành viên khỏi hội, bạn có muốn xóa không ?`, type: CONFIRMATION_MODAL_CLOSE_TYPES.ORGANIZATION_DELETE, index: index } })) } @@ -81,7 +79,6 @@ function Transactions() { return ( <> - }> {/* Team Member list in table format loaded constant */} @@ -98,21 +95,26 @@ function Transactions() { { filteredProvs.map((l, k) => { return ( - - - {l.name} + + + + + {l.name} + + - {l.type} - + {l.type} + + ) }) }
- + ) } diff --git a/src/pages/protected/DetailOrganization.js b/src/pages/protected/DetailOrganization.js new file mode 100644 index 0000000..a59b39f --- /dev/null +++ b/src/pages/protected/DetailOrganization.js @@ -0,0 +1,12 @@ +import React from 'react' +import DetailOrganization from '../../features/detailOrganization' + +function InternalPage() { + + + return ( + + ) +} + +export default InternalPage diff --git a/src/pages/protected/District.js b/src/pages/protected/District.js index 367dc55..bdb134a 100644 --- a/src/pages/protected/District.js +++ b/src/pages/protected/District.js @@ -2,6 +2,7 @@ import { useEffect } from 'react' import { useDispatch } from 'react-redux' import { setPageTitle } from '../../features/common/headerSlice' import District from '../../features/district' +import { Navigate, Router } from 'react-router-dom' function InternalPage() { const dispatch = useDispatch() @@ -13,6 +14,7 @@ function InternalPage() { return ( + ) } diff --git a/src/routes/index.js b/src/routes/index.js index 308d5f6..dfda437 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -20,6 +20,7 @@ const DocComponents = lazy(() => import('../pages/DocComponents')) const District = lazy(() => import('../pages/protected/District')) const Commune = lazy(() => import('../pages/protected/Commune')) const Members = lazy(() => import('../pages/protected/Member')) +const DetailOrganization = lazy(() => import('../pages/protected/DetailOrganization')) const routes = [ { @@ -43,9 +44,13 @@ const routes = [ component: Calendar, }, { - path: '/transactions', + path: '/province', component: Transactions, }, + { + path: '/:type/id=:id', + component: DetailOrganization + }, { path: '/district', component: District, diff --git a/src/routes/sidebar.js b/src/routes/sidebar.js index 2f29e4b..760c0e4 100644 --- a/src/routes/sidebar.js +++ b/src/routes/sidebar.js @@ -36,7 +36,7 @@ const routes = [ name: 'Leads', // name that appear in Sidebar }, { - path: '/app/transactions', // url + path: '/app/province', // url icon: , // icon component name: 'Đơn vị tỉnh', // name that appear in Sidebar }, @@ -52,10 +52,10 @@ const routes = [ }, { path: '/app/members', - icon: , + icon: , name: 'Thành viên hội' } - ,{ + , { path: '/app/charts', // url icon: , // icon component name: 'Analytics', // name that appear in Sidebar diff --git a/src/utils/globalConstantUtil.js b/src/utils/globalConstantUtil.js index d215238..a660916 100644 --- a/src/utils/globalConstantUtil.js +++ b/src/utils/globalConstantUtil.js @@ -8,6 +8,7 @@ module.exports = Object.freeze({ DISTRICT_ADD_NEW: "DISTRICT_ADD_NEW", COMMUNE_ADD_NEW: "COMMUNE_ADD_NEW", MEMBER_ADD_NEW: "MEMBER_ADD_NEW", + MEMBER_ADD_ORGANIZATION: "MEMBER_ADD_ORGANIZATION", DEFAULT: "", }, @@ -20,6 +21,12 @@ module.exports = Object.freeze({ CONFIRMATION_MODAL_CLOSE_TYPES: { LEAD_DELETE: "LEAD_DELETE", ORGANIZATION_DELETE: "ORGANIZATION_DELETE", - MEMBER_DELETE: "MEMBER_DELETE" + MEMBER_DELETE: "MEMBER_DELETE", + MEMBER_OUT_ORGANIZATION: "MEMBER_OUT_ORGANIZATION" }, + ORGANIZATION_TYPE: { + PROVINCE: "province", + DISTRICT: "district", + COMMUNE: "commune" + } }); From 34d9441761b60fa2af7f42eab28890aa7e26e3ab Mon Sep 17 00:00:00 2001 From: Roti-R <69901725+Roti-R@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:56:25 +0700 Subject: [PATCH 5/5] 27/10 Commit --- src/App.js | 13 +- src/api/OrganizationAPI.js | 14 ++ src/app/init.js | 6 +- src/app/store.js | 14 +- src/components/Input/SelectBox.js | 7 +- src/containers/ModalLayout.js | 20 +- .../components/ConfirmationModalBody.js | 42 +++- .../commune/components/AddCommuneModalBody.js | 23 ++- src/features/commune/index.js | 52 +++-- .../components/AddManagerModalBody.js | 72 +++++++ src/features/detailOrganization/index.js | 104 +++++++--- .../detailOrganization/managerSlice.js | 91 +++++++++ src/features/district/index.js | 49 +++-- src/features/members/memberSlice.js | 3 +- .../transactions/OrganizationSlice.js | 9 + src/features/transactions/index.js | 45 +++-- src/features/user/Login.js | 13 +- src/routes/sidebar.js | 185 +++++++++--------- src/utils/globalConstantUtil.js | 4 +- 19 files changed, 551 insertions(+), 215 deletions(-) create mode 100644 src/features/detailOrganization/components/AddManagerModalBody.js create mode 100644 src/features/detailOrganization/managerSlice.js diff --git a/src/App.js b/src/App.js index 43c63d3..fbeff4b 100644 --- a/src/App.js +++ b/src/App.js @@ -1,9 +1,11 @@ -import React, { lazy, useEffect } from 'react' import './App.css'; -import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom' -import { themeChange } from 'theme-change' + +import { Navigate, Route, BrowserRouter as Router, Routes } from 'react-router-dom' +import React, { lazy, useEffect } from 'react' + import checkAuth from './app/auth'; import initializeApp from './app/init'; +import { themeChange } from 'theme-change' // Importing pages const Layout = lazy(() => import('./containers/Layout')) @@ -20,6 +22,7 @@ initializeApp() // Check for login and initialize axios const token = checkAuth() +console.log('dang o app'); function App() { @@ -37,11 +40,11 @@ function App() { } /> } /> } /> - + {/* Place new routes over this */} } /> - }/> + } /> diff --git a/src/api/OrganizationAPI.js b/src/api/OrganizationAPI.js index 90398d2..90627cf 100644 --- a/src/api/OrganizationAPI.js +++ b/src/api/OrganizationAPI.js @@ -18,6 +18,20 @@ const organizationApi = { return axiosClient.delete(url, orgID); }, + getManagerList(orgId) { + const url = '/Organization/manager/' + orgId; + return axiosClient.get(url, orgId); + }, + + createManager(orgId, memberId) { + const url = `/Organization/manager/orgId=${orgId}&memberId=${memberId}`; + return axiosClient.post(url); + }, + + deleteManager(memberId) { + const url = "/Organization/manager/" + memberId; + axiosClient.delete(url, memberId); + } diff --git a/src/app/init.js b/src/app/init.js index c961674..a2d425d 100644 --- a/src/app/init.js +++ b/src/app/init.js @@ -1,9 +1,9 @@ import axios from "axios" const initializeApp = () => { - + // Setting base URL for all API request via axios - axios.defaults.baseURL = process.env.REACT_APP_BASE_URL + axios.defaults.baseURL = process.env.REACT_APP_BASE_URL2 if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') { @@ -17,7 +17,7 @@ const initializeApp = () => { // Removing console.log from prod - console.log = () => {}; + console.log = () => { }; // init analytics here diff --git a/src/app/store.js b/src/app/store.js index bea23d3..8479d68 100644 --- a/src/app/store.js +++ b/src/app/store.js @@ -1,12 +1,13 @@ +import ProvOrganizationSlice from '../features/transactions/OrganizationSlice' +import SelectedDistrictSlice from '../features/commune/SelectedDistrictSlice' +import SelectedProvSlice from '../features/district/SelectedProvSlice' import { configureStore } from '@reduxjs/toolkit' import headerSlice from '../features/common/headerSlice' -import modalSlice from '../features/common/modalSlice' -import rightDrawerSlice from '../features/common/rightDrawerSlice' import leadsSlice from '../features/leads/leadSlice' -import ProvOrganizationSlice from '../features/transactions/OrganizationSlice' -import SelectedProvSlice from '../features/district/SelectedProvSlice' -import SelectedDistrictSlice from '../features/commune/SelectedDistrictSlice' +import managerSlice from '../features/detailOrganization/managerSlice' import memberSlice from '../features/members/memberSlice' +import modalSlice from '../features/common/modalSlice' +import rightDrawerSlice from '../features/common/rightDrawerSlice' const combinedReducer = { header: headerSlice, @@ -16,7 +17,8 @@ const combinedReducer = { org: ProvOrganizationSlice, member: memberSlice, selectedProv: SelectedProvSlice, - selectedDistrict: SelectedDistrictSlice + selectedDistrict: SelectedDistrictSlice, + manager: managerSlice } export default configureStore({ diff --git a/src/components/Input/SelectBox.js b/src/components/Input/SelectBox.js index dd17410..967c24a 100644 --- a/src/components/Input/SelectBox.js +++ b/src/components/Input/SelectBox.js @@ -1,15 +1,14 @@ +import React, { useEffect, useState } from 'react' +import InformationCircleIcon from '@heroicons/react/24/outline/InformationCircleIcon' import axios from 'axios' import capitalize from 'capitalize-the-first-letter' -import React, { useState, useEffect } from 'react' -import InformationCircleIcon from '@heroicons/react/24/outline/InformationCircleIcon' - function SelectBox(props) { const { labelTitle, labelDescription, defaultValue, containerStyle, placeholder, labelStyle, options, updateFormValue, nameKey } = props - const [value, setValue] = useState(defaultValue || (options.length > 0 ? options[0][nameKey] : '2222')) + const [value, setValue] = useState(defaultValue || (options.length > 0 ? options[0][nameKey] : 'PLACEHOLDER')) useEffect(() => { updateFormValue(value) diff --git a/src/containers/ModalLayout.js b/src/containers/ModalLayout.js index 67b306c..6bc8771 100644 --- a/src/containers/ModalLayout.js +++ b/src/containers/ModalLayout.js @@ -1,15 +1,16 @@ -import { useEffect } from 'react' -import { MODAL_BODY_TYPES } from '../utils/globalConstantUtil' -import { useSelector, useDispatch } from 'react-redux' -import { closeModal } from '../features/common/modalSlice' -import AddLeadModalBody from '../features/leads/components/AddLeadModalBody' -import ConfirmationModalBody from '../features/common/components/ConfirmationModalBody' -import AddProvinceModalBody from '../features/transactions/components/AddProvinceModalBody' -import AddDistrictModalBody from '../features/district/components/AddDistrictModalBody' +import { useDispatch, useSelector } from 'react-redux' + import AddCommuneModalBody from '../features/commune/components/AddCommuneModalBody' +import AddDistrictModalBody from '../features/district/components/AddDistrictModalBody' +import AddLeadModalBody from '../features/leads/components/AddLeadModalBody' +import AddManagerModalBody from '../features/detailOrganization/components/AddManagerModalBody' import AddMemberModalBody from '../features/members/components/addMemberModalBody' import AddMemberToOrg from '../features/detailOrganization/components/AddMemberToOrg' - +import AddProvinceModalBody from '../features/transactions/components/AddProvinceModalBody' +import ConfirmationModalBody from '../features/common/components/ConfirmationModalBody' +import { MODAL_BODY_TYPES } from '../utils/globalConstantUtil' +import { closeModal } from '../features/common/modalSlice' +import { useEffect } from 'react' function ModalLayout() { @@ -45,6 +46,7 @@ function ModalLayout() { [MODAL_BODY_TYPES.COMMUNE_ADD_NEW]: , [MODAL_BODY_TYPES.MEMBER_ADD_NEW]: , [MODAL_BODY_TYPES.MEMBER_ADD_ORGANIZATION]: , + [MODAL_BODY_TYPES.MANAGER_ADD_NEW]: , [MODAL_BODY_TYPES.DEFAULT]:
}[bodyType] } diff --git a/src/features/common/components/ConfirmationModalBody.js b/src/features/common/components/ConfirmationModalBody.js index 04f8bc9..a9dde96 100644 --- a/src/features/common/components/ConfirmationModalBody.js +++ b/src/features/common/components/ConfirmationModalBody.js @@ -1,10 +1,12 @@ +import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_CLOSE_TYPES } from '../../../utils/globalConstantUtil' +import { deleteMember, updateMember } from '../../members/memberSlice' import { useDispatch, useSelector } from 'react-redux' + import axios from 'axios' -import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_CLOSE_TYPES } from '../../../utils/globalConstantUtil' import { deleteLead } from '../../leads/leadSlice' -import { showNotification } from '../headerSlice' +import { deleteManager } from '../../detailOrganization/managerSlice' import { deleteOrganization } from '../../transactions/OrganizationSlice' -import { deleteMember, updateMember } from '../../members/memberSlice' +import { showNotification } from '../headerSlice' function ConfirmationModalBody({ extraObject, closeModal }) { @@ -46,6 +48,7 @@ function ConfirmationModalBody({ extraObject, closeModal }) { } else if (type === CONFIRMATION_MODAL_CLOSE_TYPES.MEMBER_DELETE) { try { + await dispatch(deleteMember(index)); dispatch( showNotification({ @@ -65,6 +68,17 @@ function ConfirmationModalBody({ extraObject, closeModal }) { } } else if (type === CONFIRMATION_MODAL_CLOSE_TYPES.MEMBER_OUT_ORGANIZATION) { + + dispatch(deleteManager(index)).unwrap() + .catch(err => { + dispatch( + showNotification({ + message: 'Có lỗi khi xóa quyền quản lý của thành viên này', + status: 0, + }) + ); + return; + }) dispatch(updateMember({ memberID: index, member: updateObject })).unwrap() .then((res) => { dispatch( @@ -75,8 +89,6 @@ function ConfirmationModalBody({ extraObject, closeModal }) { ); }) .catch(err => { - console.log("index: " + index); - console.log(updateObject); console.log(err); dispatch( showNotification({ @@ -86,6 +98,26 @@ function ConfirmationModalBody({ extraObject, closeModal }) { ); }) } + else if (type === CONFIRMATION_MODAL_CLOSE_TYPES.MANAGER_DELETE) { + dispatch(deleteManager(index)).unwrap() + .then(() => { + dispatch( + showNotification({ + message: 'Xóa quyền quản lý thành công', + status: 1, + }) + ); + }) + .catch(err => { + console.log(err); + dispatch( + showNotification({ + message: 'Xóa quyền quản lý không thành công', + status: 0, + }) + ); + }) + } closeModal() } diff --git a/src/features/commune/components/AddCommuneModalBody.js b/src/features/commune/components/AddCommuneModalBody.js index 0ed32c5..51cf86d 100644 --- a/src/features/commune/components/AddCommuneModalBody.js +++ b/src/features/commune/components/AddCommuneModalBody.js @@ -1,13 +1,14 @@ import React, { useEffect } from 'react' -import { useState } from 'react'; +import { createOrganization, getOrganization } from '../../transactions/OrganizationSlice'; import { useDispatch, useSelector } from 'react-redux' -import { showNotification } from '../../common/headerSlice'; -import { closeModal } from '../../common/modalSlice'; -import InputText from '../../../components/Input/InputText'; + import ErrorText from '../../../components/Typography/ErrorText'; -import organizationApi from '../../../api/OrganizationAPI'; -import { createOrganization, getOrganization } from '../../transactions/OrganizationSlice'; +import InputText from '../../../components/Input/InputText'; import SelectBox from '../../../components/Input/SelectBox'; +import { closeModal } from '../../common/modalSlice'; +import organizationApi from '../../../api/OrganizationAPI'; +import { showNotification } from '../../common/headerSlice'; +import { useState } from 'react'; const INITIAL_COMMUNE_OBJ = { parentID: '', @@ -22,13 +23,13 @@ const AddCommuneModalBody = ({ closeModal }) => { const provs = orgs.filter(t => t.type === 'tinh') const districts = orgs.filter(t => t.parentID === selectedProvince) - console.log("Tinh huyen dang chon la : " + communeObj); + console.log(communeObj); useEffect(() => { dispatch(getOrganization()) }, []) const saveNewCommune = () => { if (communeObj.name.trim() === "") return setErrorMessage("Hãy điền tên xã") - else if (communeObj.parentID === "PLACEHOLDER") return setErrorMessage("Hãy chọn huyện") + else if (communeObj.parentID === "PLACEHOLDER" && selectedProvince === "PLACEHOLDER") return setErrorMessage("Hãy chọn đầy đủ các trường") else { //Call API to Add Province Organization console.log(communeObj.parentID); @@ -50,10 +51,12 @@ const AddCommuneModalBody = ({ closeModal }) => { } const updateDistrictValue = (value) => { - setCommuneObj({...communeObj, parentID: value}) + setCommuneObj({ ...communeObj, parentID: value }) } const updateProvinceValue = (value) => { + setSelectedProvince(value) + } return ( @@ -74,7 +77,7 @@ const AddCommuneModalBody = ({ closeModal }) => { updateFormValue={updateDistrictValue} nameKey='orgID' /> - + {errorMessage}
diff --git a/src/features/commune/index.js b/src/features/commune/index.js index 886fc42..60b1d5f 100644 --- a/src/features/commune/index.js +++ b/src/features/commune/index.js @@ -1,30 +1,37 @@ -import React from 'react' -import { useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { openModal } from '../common/modalSlice'; + +import { CONFIRMATION_MODAL_CLOSE_TYPES } from '../../utils/globalConstantUtil'; +import { Link } from 'react-router-dom'; import { MODAL_BODY_TYPES } from '../../utils/globalConstantUtil'; -import { useEffect } from 'react'; +import React from 'react' import SearchBar from '../../components/Input/SearchBar'; -import TitleCard from '../../components/Cards/TitleCard'; import SelectBox from '../../components/Input/SelectBox'; -import { getOrganization } from '../transactions/OrganizationSlice'; +import TitleCard from '../../components/Cards/TitleCard'; import TrashIcon from '@heroicons/react/24/outline/TrashIcon'; -import { CONFIRMATION_MODAL_CLOSE_TYPES } from '../../utils/globalConstantUtil'; +import { getMember } from '../members/memberSlice'; +import { getOrganization } from '../transactions/OrganizationSlice'; +import { openModal } from '../common/modalSlice'; import { setSelectedDistrict } from './SelectedDistrictSlice'; -import { Link } from 'react-router-dom'; +import { useEffect } from 'react'; +import { useState } from 'react'; + const TopSideButtons = ({ removeFilter, applyFilter, applySearch }) => { const dispatch = useDispatch(); const { orgs, isLoading } = useSelector(state => state.org) const [selectedProvince, setSelectedProvince] = useState(null) const provs = orgs.filter(org => org.type === 'tinh') const districts = orgs.filter(org => org.parentID === selectedProvince) + const [searchText, setSearchText] = useState("") console.log(selectedProvince); useEffect(() => { dispatch(getOrganization()) }, []) - + const handleSearchChange = (searchText) => { + setSearchText(searchText) + applySearch(searchText) + } const AddNewDistrictModal = () => { dispatch(openModal({ title: 'Thêm đơn vị xã', bodyType: MODAL_BODY_TYPES.COMMUNE_ADD_NEW })) @@ -63,7 +70,7 @@ const TopSideButtons = ({ removeFilter, applyFilter, applySearch }) => { /> - {/* */} +
) } @@ -74,11 +81,23 @@ const Commune = () => { const { selectedDistrict } = useSelector(state => state.selectedDistrict) const { orgs, isLoading } = useSelector(state => state.org) const communes = orgs.filter(org => org.parentID === selectedDistrict) + const { members } = useSelector(state => state.member) + const [searchText, setSearchText] = useState("") + useEffect(() => { dispatch(getOrganization()) + dispatch(getMember()) }, []) + const countChild = (orgId) => { + return orgs.filter(o => o.parentID === orgId).length + } + + const countMember = (orgId) => { + return members.filter(m => m.currentOrganizationID === orgId).length + } + isLoading ? document.body.classList.add('loading-indicator') : document.body.classList.remove('loading-indicator') const deleteCurrentOrganization = (index) => { @@ -88,8 +107,8 @@ const Commune = () => { })) } - const applySearch = () => { - + const applySearch = (searchText) => { + setSearchText(searchText) } return ( <> @@ -99,13 +118,14 @@ const Commune = () => { Tên huyện - Người quản lý + Số hội con + Số thành viên { - communes.map((l, k) => { + communes.filter((t) => { return searchText === "" || t.name.toLowerCase().includes(searchText.toLowerCase()) }).map((l, k) => { return ( @@ -114,8 +134,8 @@ const Commune = () => { {l.name} - - {l.type} + {countChild(l.orgID)} + {countMember(l.orgID)} ) diff --git a/src/features/detailOrganization/components/AddManagerModalBody.js b/src/features/detailOrganization/components/AddManagerModalBody.js new file mode 100644 index 0000000..7717b04 --- /dev/null +++ b/src/features/detailOrganization/components/AddManagerModalBody.js @@ -0,0 +1,72 @@ +import ErrorText from '../../../components/Typography/ErrorText'; +import React from 'react' +import SearchBar from '../../../components/Input/SearchBar'; +import SelectBox from '../../../components/Input/SelectBox'; +import { createManager } from '../managerSlice'; +import organizationApi from '../../../api/OrganizationAPI'; +import { showNotification } from '../../common/headerSlice'; +import { useDispatch } from 'react-redux'; +import { useSelector } from 'react-redux'; +import { useState } from 'react'; + +export const AddManagerModalBody = ({ extraObject, closeModal }) => { + + const dispatch = useDispatch(); + const { index } = extraObject; + const { members } = useSelector(state => state.member) + const memberInOrg = members.filter(m => m.currentOrganizationID === index) + const [selectedMember, setSelectedMember] = useState(null); + const [searchText, setSearchText] = useState(""); + const [errorMessage, setErrorMessage] = useState(""); + + + const handleSearchChange = (value) => { + setSearchText(value); + } + const updateFormValue = (value) => { + setSelectedMember(value) + } + + const addManager = () => { + dispatch(createManager({ memberId: selectedMember, orgId: index })).unwrap() + .then((res) => { + closeModal(); + dispatch( + showNotification({ + message: 'Thêm quản lý thành công', + status: 1, + }) + ); + }) + .catch((err) => { + setErrorMessage(err.error.errors[0].errorMessage) + dispatch( + showNotification({ + message: 'Thêm quản lý không thành công', + status: 0, + }) + ); + }) + } + return ( + <> + + { return searchText === "" || m.name.toLowerCase().includes(searchText.toLowerCase()) })} + labelTitle="Các thành viên thuộc hội" + placeholder="Chọn thành viên" + containerStyle="w-full mt-4" + updateFormValue={updateFormValue} + nameKey='memberID' + /> + + {errorMessage} +
+ + +
+ + + ) +} +export default AddManagerModalBody; \ No newline at end of file diff --git a/src/features/detailOrganization/index.js b/src/features/detailOrganization/index.js index 3c9117f..b5e4d36 100644 --- a/src/features/detailOrganization/index.js +++ b/src/features/detailOrganization/index.js @@ -1,20 +1,24 @@ -import React from 'react' -import TitleCard from '../../components/Cards/TitleCard' -import { useParams, useSearchParams } from 'react-router-dom' -import { ORGANIZATION_TYPE } from '../../utils/globalConstantUtil' +import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_BODY_TYPES } from '../../utils/globalConstantUtil' +import { getMember, updateMember } from '../members/memberSlice' import { useDispatch, useSelector } from 'react-redux' -import { useEffect } from 'react' -import { getOrganization } from '../transactions/OrganizationSlice' -import { useState } from 'react' +import { useParams, useSearchParams } from 'react-router-dom' + +import ArrowDownTrayIcon from '@heroicons/react/24/outline/ArrowDownTrayIcon' +import CheckIcon from '@heroicons/react/24/outline/CheckIcon' import DashboardStats from '../dashboard/components/DashboardStats' -import UserGroupIcon from '@heroicons/react/24/outline/UserGroupIcon' -import User from '@heroicons/react/24/outline/UserIcon' +import HandRaisedIcon from '@heroicons/react/24/outline/HandRaisedIcon' +import { ORGANIZATION_TYPE } from '../../utils/globalConstantUtil' +import React from 'react' +import TitleCard from '../../components/Cards/TitleCard' import TrashIcon from '@heroicons/react/24/outline/TrashIcon' -import { getMember, updateMember } from '../members/memberSlice' -import ArrowUpTrayIcon from '@heroicons/react/24/outline/ArrowUpTrayIcon' -import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_BODY_TYPES } from '../../utils/globalConstantUtil' +import User from '@heroicons/react/24/outline/UserIcon' +import UserGroupIcon from '@heroicons/react/24/outline/UserGroupIcon' +import { getManagerById } from './managerSlice' +import { getOrganization } from '../transactions/OrganizationSlice' import { openModal } from '../common/modalSlice' - +import organizationApi from '../../api/OrganizationAPI' +import { useEffect } from 'react' +import { useState } from 'react' export const DetailOrganization = () => { @@ -24,6 +28,7 @@ export const DetailOrganization = () => { const { orgs, isLoading } = useSelector(state => state.org) const { members } = useSelector(state => state.member) + const { managers } = useSelector(state => state.manager) const org = orgs.find(o => o.orgID === param.id) const memberList = members.filter(mem => mem.currentOrganizationID === param.id) switch (param.type) { @@ -39,10 +44,10 @@ export const DetailOrganization = () => { default: break; } - console.log(org); useEffect(() => { dispatch(getOrganization()); dispatch(getMember()); + dispatch(getManagerById(param.id)); }, []) isLoading ? document.body.classList.add('loading-indicator') : document.body.classList.remove('loading-indicator') @@ -57,34 +62,56 @@ export const DetailOrganization = () => { } - const setMemberToManager = () => { - - } - const AddNewMemberToOrg = () => { dispatch(openModal({ title: 'Thêm thành viên vào hội', bodyType: MODAL_BODY_TYPES.MEMBER_ADD_ORGANIZATION, extraObject: { index: param.id } })) } + + const addManager = () => { + dispatch(openModal({ + title: 'Cấp quyền quản lý cho thành viên', bodyType: MODAL_BODY_TYPES.MANAGER_ADD_NEW, + extraObject: { index: param.id } + })) + } + + const deleterManager = (managerId) => { + dispatch(openModal({ + title: "Xác nhận", bodyType: MODAL_BODY_TYPES.CONFIRMATION, + extraObject: { message: `Bạn có chắc muốn xóa quyền quản lý của thành viên này không ?`, type: CONFIRMATION_MODAL_CLOSE_TYPES.MANAGER_DELETE, index: managerId } + })) + } + + const checkManagerIsMember = (managerId) => { + return memberList.find(m => m.memberID === managerId) + } return ( <>
+ } description="" /> + - } description="" /> + + } description="" /> + + +
-
- + +
+ +
{/* head */} + - @@ -94,15 +121,46 @@ export const DetailOrganization = () => { + - ) }) }
TênSĐT Xóa khỏi hộiĐặt làm quản lý
{index + 1} {m.name}{m.phoneNumber}
+ + + {/* head */} + + + + + + + + + + { + + managers.map((m, index) => { + let isMember = checkManagerIsMember(m.memberID) + return ( + + + + + + + ) + }) + } + + +
TênQuản lý gián tiếpXóa quyền quản lý
{index + 1}{m.name}{!isMember && }
+
+
) diff --git a/src/features/detailOrganization/managerSlice.js b/src/features/detailOrganization/managerSlice.js new file mode 100644 index 0000000..33c0c7c --- /dev/null +++ b/src/features/detailOrganization/managerSlice.js @@ -0,0 +1,91 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; + +import organizationApi from "../../api/OrganizationAPI"; + +export const getManagerById = createAsyncThunk('manager/contents', async (orgId, thunkAPI) => { + + try { + const response = await organizationApi.getManagerList(orgId); + return response.data; + } catch (error) { + return thunkAPI.rejectWithValue(error); + } +}) + +export const createManager = createAsyncThunk('manager/create', async (value, thunkAPI) => { + try { + const response = await organizationApi.createManager(value.orgId, value.memberId) + return response.data; + } catch (error) { + return thunkAPI.rejectWithValue(error.response.data); + } +}) + +export const deleteManager = createAsyncThunk('manager/delete', async (value, thunkAPI) => { + try { + const response = await organizationApi.deleteManager(value) + return value; + } catch (error) { + return thunkAPI.rejectWithValue(error.response.data); + } +}) +// export const createManager = createAsyncThunk('manager/create', async(value,thunkAPI) => { +// try { +// const response = await organizationApi.(value.orgId, value.memberId) +// return response.data; +// } catch (error) { +// thunkAPI.rejectWithValue(error); +// } +// }) + +export const managerSlice = createSlice({ + name: 'manager', + initialState: { + isLoading: false, + managers: [] + }, + extraReducers: { + + [getManagerById.pending]: (state, action) => { + state.isLoading = true + }, + [getManagerById.rejected]: (state, action) => { + state.isLoading = false + }, + [getManagerById.fulfilled]: (state, action) => { + state.isLoading = false + state.managers = action.payload + }, + + + + [createManager.pending]: (state, action) => { + state.isLoading = true + }, + [createManager.rejected]: (state, action) => { + state.isLoading = false + }, + [createManager.fulfilled]: (state, action) => { + state.isLoading = false + state.managers.push(action.payload) + }, + + + + + [deleteManager.pending]: (state, action) => { + state.isLoading = true + }, + [deleteManager.rejected]: (state, action) => { + state.isLoading = false + }, + [deleteManager.fulfilled]: (state, action) => { + state.isLoading = false + state.managers = state.managers.filter(m => m.memberID !== action.payload) + }, + } + + +}) + +export default managerSlice.reducer; \ No newline at end of file diff --git a/src/features/district/index.js b/src/features/district/index.js index 47e7e10..4ac94f2 100644 --- a/src/features/district/index.js +++ b/src/features/district/index.js @@ -1,17 +1,19 @@ -import React from 'react' -import { useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { openModal } from '../common/modalSlice'; + +import { CONFIRMATION_MODAL_CLOSE_TYPES } from '../../utils/globalConstantUtil'; +import { Link } from 'react-router-dom'; import { MODAL_BODY_TYPES } from '../../utils/globalConstantUtil'; -import { useEffect } from 'react'; +import React from 'react' import SearchBar from '../../components/Input/SearchBar'; -import TitleCard from '../../components/Cards/TitleCard'; import SelectBox from '../../components/Input/SelectBox'; +import TitleCard from '../../components/Cards/TitleCard'; +import TrashIcon from '@heroicons/react/24/outline/TrashIcon'; +import { getMember } from '../members/memberSlice'; import { getOrganization } from '../transactions/OrganizationSlice'; +import { openModal } from '../common/modalSlice'; import { setSelectedProvince } from './SelectedProvSlice'; -import TrashIcon from '@heroicons/react/24/outline/TrashIcon'; -import { CONFIRMATION_MODAL_CLOSE_TYPES } from '../../utils/globalConstantUtil'; -import { Link } from 'react-router-dom'; +import { useEffect } from 'react'; +import { useState } from 'react'; const TopSideButtons = ({ removeFilter, applyFilter, applySearch }) => { const dispatch = useDispatch(); @@ -22,9 +24,13 @@ const TopSideButtons = ({ removeFilter, applyFilter, applySearch }) => { useEffect(() => { dispatch(getOrganization()) + dispatch(getMember()) }, []) - + const handleSearchChange = (searchText) => { + setSearchText(searchText) + applySearch(searchText) + } const AddNewDistrictModal = () => { dispatch(openModal({ title: 'Thêm đơn vị huyện', bodyType: MODAL_BODY_TYPES.DISTRICT_ADD_NEW })) @@ -48,7 +54,7 @@ const TopSideButtons = ({ removeFilter, applyFilter, applySearch }) => { /> - + ) } @@ -62,15 +68,24 @@ const District = () => { const { orgs, isLoading } = useSelector(state => state.org); const districtOrg = orgs.filter(org => org.parentID === selectedProvince) const [filterdSearchDistrictOrg, setFilterSearchDistrictOrg] = useState(districtOrg); - + const { members } = useSelector(state => state.member) + const [searchText, setSearchText] = useState("") isLoading ? document.body.classList.add('loading-indicator') : document.body.classList.remove('loading-indicator') const applySearch = (searchText) => { - const filteredSearch = districtOrg.filter(prov => searchText === "" || prov.name.toLowerCase().includes(searchText.toLowerCase())); - setFilterSearchDistrictOrg(filteredSearch); + // const filteredSearch = districtOrg.filter(prov => searchText === "" || prov.name.toLowerCase().includes(searchText.toLowerCase())); + // setFilterSearchDistrictOrg(filteredSearch); + setSearchText(searchText); } + const countChild = (orgId) => { + return orgs.filter(o => o.parentID === orgId).length + } + + const countMember = (orgId) => { + return members.filter(m => m.currentOrganizationID === orgId).length + } const deleteCurrentOrganization = (index) => { dispatch(openModal({ title: "Xác nhận", bodyType: MODAL_BODY_TYPES.CONFIRMATION, @@ -85,13 +100,14 @@ const District = () => { Tên huyện - Người quản lý + Số hội con + Số thành viên { - districtOrg.map((l, k) => { + districtOrg.filter((t) => { return searchText === "" || t.name.toLowerCase().includes(searchText.toLowerCase()) }).map((l, k) => { return ( @@ -101,7 +117,8 @@ const District = () => { - {l.type} + {countChild(l.orgID)} + {countMember(l.orgID)} ) diff --git a/src/features/members/memberSlice.js b/src/features/members/memberSlice.js index 89df7f5..1207fb1 100644 --- a/src/features/members/memberSlice.js +++ b/src/features/members/memberSlice.js @@ -1,4 +1,5 @@ import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; + import memberAPI from "../../api/memberAPI"; import { showNotification } from "../common/headerSlice"; @@ -91,7 +92,7 @@ export const memberSlice = createSlice({ }, [deleteMember.fulfilled]: (state, action) => { state.isLoading = false; - state.members = state.members.filter(org => org.memberID !== action.payload) + state.members = state.members.filter(member => member.memberID !== action.payload) }, [deleteMember.rejected]: state => { diff --git a/src/features/transactions/OrganizationSlice.js b/src/features/transactions/OrganizationSlice.js index bed473c..9f5ee03 100644 --- a/src/features/transactions/OrganizationSlice.js +++ b/src/features/transactions/OrganizationSlice.js @@ -37,6 +37,15 @@ export const deleteOrganization = createAsyncThunk('/org/delete', async (key, th } }) +export const getManagerList = createAsyncThunk('/org/contents', async (value, thunkAPI) => { + try { + const response = await organizationApi.getManagerList(value); + return response.data; + } catch (error) { + thunkAPI.rejectWithValue(error); + } +}) + export const OrganizationSlice = createSlice({ name: 'org', initialState: { diff --git a/src/features/transactions/index.js b/src/features/transactions/index.js index c15b981..bc9e5b1 100644 --- a/src/features/transactions/index.js +++ b/src/features/transactions/index.js @@ -1,20 +1,21 @@ -import moment from "moment" -import { useEffect, useState } from "react" +import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_BODY_TYPES } from '../../utils/globalConstantUtil' import { useDispatch, useSelector } from "react-redux" -import { showNotification } from "../common/headerSlice" -import TitleCard from "../../components/Cards/TitleCard" -import { RECENT_TRANSACTIONS } from "../../utils/dummyData" +import { useEffect, useState } from "react" + import FunnelIcon from '@heroicons/react/24/outline/FunnelIcon' -import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon' +import { Link } from "react-router-dom" +import { RECENT_TRANSACTIONS } from "../../utils/dummyData" import SearchBar from "../../components/Input/SearchBar" -import organizationApi from "../../api/OrganizationAPI" +import TitleCard from "../../components/Cards/TitleCard" +import TrashIcon from "@heroicons/react/24/outline/TrashIcon" +import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon' import { data } from "autoprefixer" -import { openModal } from "../common/modalSlice" +import { getMember } from '../members/memberSlice' import { getOrganization } from "./OrganizationSlice" -import TrashIcon from "@heroicons/react/24/outline/TrashIcon" -import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_BODY_TYPES } from '../../utils/globalConstantUtil' -import { Link } from "react-router-dom" - +import moment from "moment" +import { openModal } from "../common/modalSlice" +import organizationApi from "../../api/OrganizationAPI" +import { showNotification } from "../common/headerSlice" const TopSideButtons = ({ applySearch }) => { @@ -50,14 +51,14 @@ const TopSideButtons = ({ applySearch }) => { function Transactions() { const dispatch = useDispatch(); const { orgs, isLoading } = useSelector(state => state.org) + const { members } = useSelector(state => state.member) const provs = orgs.filter(org => org.type === 'tinh'); const [filteredProvs, setFilteredProvs] = useState([]); - useEffect(() => { dispatch(getOrganization()) - - }, [dispatch]) + dispatch(getMember()) + }, []) useEffect(() => { setFilteredProvs(provs) @@ -65,6 +66,13 @@ function Transactions() { isLoading ? document.body.classList.add('loading-indicator') : document.body.classList.remove('loading-indicator') + const countChild = (orgId) => { + return orgs.filter(o => o.parentID === orgId).length + } + + const countMember = (orgId) => { + return members.filter(m => m.currentOrganizationID === orgId).length + } const deleteCurrentOrganization = (index) => { dispatch(openModal({ title: "Xác nhận", bodyType: MODAL_BODY_TYPES.CONFIRMATION, @@ -87,7 +95,8 @@ function Transactions() { Tên tỉnh - Người quản lý + Số hội con + Số thành viên @@ -103,8 +112,8 @@ function Transactions() { - - {l.type} + {countChild(l.orgID)} + {countMember(l.orgID)} diff --git a/src/features/user/Login.js b/src/features/user/Login.js index cc480c3..48f065d 100644 --- a/src/features/user/Login.js +++ b/src/features/user/Login.js @@ -1,9 +1,9 @@ -import { useState, useRef } from 'react' -import { Link } from 'react-router-dom' -import LandingIntro from './LandingIntro' +import { useRef, useState } from 'react' + import ErrorText from '../../components/Typography/ErrorText' import InputText from '../../components/Input/InputText' - +import LandingIntro from './LandingIntro' +import { Link } from 'react-router-dom' import userApi from '../../api/userApi' function Login() { @@ -27,8 +27,8 @@ function Login() { var myData; e.preventDefault() setErrorMessage("") - if (loginObj.emailId.trim() === "") return setErrorMessage("Email Id is required! (use any value)") - if (loginObj.password.trim() === "") return setErrorMessage("Password is required! (use any value)") + if (loginObj.emailId.trim() === "") return setErrorMessage("Hãy nhập tài khoản") + if (loginObj.password.trim() === "") return setErrorMessage("Hãy nhập mật khẩu") checkCredential().then(res => { if (res.data.success === false) { return setErrorMessage("Tài khoản và mật khẩu không hợp lệ") @@ -37,6 +37,7 @@ function Login() { setLoading(true) // Call API to check user credentials and save token in localstorage localStorage.setItem("token", res.data.data) + console.log(res.data.data); setLoading(false) window.location.href = '/app/welcome' } diff --git a/src/routes/sidebar.js b/src/routes/sidebar.js index 760c0e4..f6fdbb0 100644 --- a/src/routes/sidebar.js +++ b/src/routes/sidebar.js @@ -1,40 +1,41 @@ /** Icons are imported separatly to reduce build time */ -import BellIcon from '@heroicons/react/24/outline/BellIcon' -import DocumentTextIcon from '@heroicons/react/24/outline/DocumentTextIcon' -import Squares2X2Icon from '@heroicons/react/24/outline/Squares2X2Icon' -import TableCellsIcon from '@heroicons/react/24/outline/TableCellsIcon' -import WalletIcon from '@heroicons/react/24/outline/WalletIcon' -import CodeBracketSquareIcon from '@heroicons/react/24/outline/CodeBracketSquareIcon' -import DocumentIcon from '@heroicons/react/24/outline/DocumentIcon' -import ExclamationTriangleIcon from '@heroicons/react/24/outline/ExclamationTriangleIcon' -import CalendarDaysIcon from '@heroicons/react/24/outline/CalendarDaysIcon' + import ArrowRightOnRectangleIcon from '@heroicons/react/24/outline/ArrowRightOnRectangleIcon' -import UserIcon from '@heroicons/react/24/outline/UserIcon' -import Cog6ToothIcon from '@heroicons/react/24/outline/Cog6ToothIcon' +import BellIcon from '@heroicons/react/24/outline/BellIcon' import BoltIcon from '@heroicons/react/24/outline/BoltIcon' +import CalendarDaysIcon from '@heroicons/react/24/outline/CalendarDaysIcon' import ChartBarIcon from '@heroicons/react/24/outline/ChartBarIcon' +import CodeBracketSquareIcon from '@heroicons/react/24/outline/CodeBracketSquareIcon' +import Cog6ToothIcon from '@heroicons/react/24/outline/Cog6ToothIcon' import CurrencyDollarIcon from '@heroicons/react/24/outline/CurrencyDollarIcon' +import DocumentDuplicateIcon from '@heroicons/react/24/outline/DocumentDuplicateIcon' +import DocumentIcon from '@heroicons/react/24/outline/DocumentIcon' +import DocumentTextIcon from '@heroicons/react/24/outline/DocumentTextIcon' +import ExclamationTriangleIcon from '@heroicons/react/24/outline/ExclamationTriangleIcon' import InboxArrowDownIcon from '@heroicons/react/24/outline/InboxArrowDownIcon' -import UsersIcon from '@heroicons/react/24/outline/UsersIcon' import KeyIcon from '@heroicons/react/24/outline/KeyIcon' -import DocumentDuplicateIcon from '@heroicons/react/24/outline/DocumentDuplicateIcon' import MapIcon from '@heroicons/react/24/outline/MapIcon' +import Squares2X2Icon from '@heroicons/react/24/outline/Squares2X2Icon' +import TableCellsIcon from '@heroicons/react/24/outline/TableCellsIcon' +import UserIcon from '@heroicons/react/24/outline/UserIcon' +import UsersIcon from '@heroicons/react/24/outline/UsersIcon' +import WalletIcon from '@heroicons/react/24/outline/WalletIcon' const iconClasses = `h-6 w-6` const submenuIconClasses = `h-5 w-5` const routes = [ - { - path: '/app/dashboard', - icon: , - name: 'Dashboard', - }, - { - path: '/app/leads', // url - icon: , // icon component - name: 'Leads', // name that appear in Sidebar - }, + // { + // path: '/app/dashboard', + // icon: , + // name: 'Dashboard', + // }, + // { + // path: '/app/leads', // url + // icon: , // icon component + // name: 'Leads', // name that appear in Sidebar + // }, { path: '/app/province', // url icon: , // icon component @@ -54,77 +55,77 @@ const routes = [ path: '/app/members', icon: , name: 'Thành viên hội' - } - , { - path: '/app/charts', // url - icon: , // icon component - name: 'Analytics', // name that appear in Sidebar - }, - { - path: '/app/integration', // url - icon: , // icon component - name: 'Integration', // name that appear in Sidebar - }, - { - path: '/app/calendar', // url - icon: , // icon component - name: 'Calendar', // name that appear in Sidebar }, + // , { + // path: '/app/charts', // url + // icon: , // icon component + // name: 'Analytics', // name that appear in Sidebar + // }, + // { + // path: '/app/integration', // url + // icon: , // icon component + // name: 'Integration', // name that appear in Sidebar + // }, + // { + // path: '/app/calendar', // url + // icon: , // icon component + // name: 'Calendar', // name that appear in Sidebar + // }, - { - path: '', //no url needed as this has submenu - icon: , // icon component - name: 'Pages', // name that appear in Sidebar - submenu: [ - { - path: '/login', - icon: , - name: 'Login', - }, - { - path: '/register', //url - icon: , // icon component - name: 'Register', // name that appear in Sidebar - }, - { - path: '/forgot-password', - icon: , - name: 'Forgot Password', - }, - { - path: '/app/blank', - icon: , - name: 'Blank Page', - }, - { - path: '/app/404', - icon: , - name: '404', - }, - ] - }, - { - path: '', //no url needed as this has submenu - icon: , // icon component - name: 'Settings', // name that appear in Sidebar - submenu: [ - { - path: '/app/settings-profile', //url - icon: , // icon component - name: 'Profile', // name that appear in Sidebar - }, - { - path: '/app/settings-billing', - icon: , - name: 'Billing', - }, - { - path: '/app/settings-team', // url - icon: , // icon component - name: 'Team Members', // name that appear in Sidebar - }, - ] - }, + // { + // path: '', //no url needed as this has submenu + // icon: , // icon component + // name: 'Pages', // name that appear in Sidebar + // submenu: [ + // { + // path: '/login', + // icon: , + // name: 'Login', + // }, + // { + // path: '/register', //url + // icon: , // icon component + // name: 'Register', // name that appear in Sidebar + // }, + // { + // path: '/forgot-password', + // icon: , + // name: 'Forgot Password', + // }, + // { + // path: '/app/blank', + // icon: , + // name: 'Blank Page', + // }, + // { + // path: '/app/404', + // icon: , + // name: '404', + // }, + // ] + // }, + // { + // path: '', //no url needed as this has submenu + // icon: , // icon component + // name: 'Settings', // name that appear in Sidebar + // submenu: [ + // { + // path: '/app/settings-profile', //url + // icon: , // icon component + // name: 'Profile', // name that appear in Sidebar + // }, + // { + // path: '/app/settings-billing', + // icon: , + // name: 'Billing', + // }, + // { + // path: '/app/settings-team', // url + // icon: , // icon component + // name: 'Team Members', // name that appear in Sidebar + // }, + // ] + // }, { path: '', //no url needed as this has submenu icon: , // icon component diff --git a/src/utils/globalConstantUtil.js b/src/utils/globalConstantUtil.js index a660916..0d749b0 100644 --- a/src/utils/globalConstantUtil.js +++ b/src/utils/globalConstantUtil.js @@ -9,6 +9,7 @@ module.exports = Object.freeze({ COMMUNE_ADD_NEW: "COMMUNE_ADD_NEW", MEMBER_ADD_NEW: "MEMBER_ADD_NEW", MEMBER_ADD_ORGANIZATION: "MEMBER_ADD_ORGANIZATION", + MANAGER_ADD_NEW: "MANAGER_ADD_NEW", DEFAULT: "", }, @@ -22,7 +23,8 @@ module.exports = Object.freeze({ LEAD_DELETE: "LEAD_DELETE", ORGANIZATION_DELETE: "ORGANIZATION_DELETE", MEMBER_DELETE: "MEMBER_DELETE", - MEMBER_OUT_ORGANIZATION: "MEMBER_OUT_ORGANIZATION" + MEMBER_OUT_ORGANIZATION: "MEMBER_OUT_ORGANIZATION", + MANAGER_DELETE: "MANAGER_DELETE" }, ORGANIZATION_TYPE: { PROVINCE: "province",