diff --git a/src/components/JobGroups/AddGroup.jsx b/src/components/JobGroups/AddGroup.jsx new file mode 100644 index 0000000..8f8a62b --- /dev/null +++ b/src/components/JobGroups/AddGroup.jsx @@ -0,0 +1,157 @@ +import React, { useState } from 'react' + +import ModalCom from '../Helpers/ModalCom' +import LoadingSpinner from '../Spinners/LoadingSpinner' +import InputCom from '../Helpers/Inputs/InputCom/index' + +import usersService from '../../services/UsersService' + +export default function AddGroup({action, situation , setUpdateList}) { + + const api = new usersService() + + const [name, setName] = useState('') + + const handleChange = ({target:{name, value}}) =>{ + setName(value) + } + + let [requestStatus, setRequestStatus] = useState({ + loading: false, + status: false, + message: "", + }); // STATE FOR KNOWING WHEN A REQUEST IS MADE TO THE SERVER + + const addGroup = () => { + setRequestStatus({loading:true, status:false, message:''}) + if(name == ''){ + setRequestStatus({loading:false, status:false, message:'Please enter a group name'}) + return setTimeout(()=>{ + setRequestStatus({loading:false, status:false, message:''}) + },3000) + } + if(name.length < 6){ + setRequestStatus({loading:false, status:false, message:'Group name must be up to six characters'}) + return setTimeout(()=>{ + setRequestStatus({loading:false, status:false, message:''}) + },3000) + } + api.jobGroupAdd({group_name:name, action:13025}).then(response => { + let {status, data} = response + if(status != 200 || data.internal_return < 0){ + setRequestStatus({loading:false, status:false, message:'Unable to add Group'}) + return + } + setRequestStatus({loading:false, status:true, message:'Group Added'}) + setTimeout(()=>{ + setRequestStatus({loading:false, status:false, message:''}) + // close modal + action() + // reload group page + setUpdateList(prev => !prev) + },3000) + }).catch(error => { + setRequestStatus({loading:false, status:false, message:'Unable to add Group, try again later'}) + }).finally(()=>{ + setTimeout(()=>{ + setRequestStatus({loading:false, status:false, message:''}) + },3000) + }) + } + + return ( + +
+
+

+ Add Group +

+ +
+
+
+
+ +
+
+
+ + {requestStatus.loading ? ( + + ) : ( + + )} +
+ + {/* ERROR DISPLAY AND SUBMIT BUTTON */} + {requestStatus.message != "" && + (!requestStatus.status ? ( +
+ {requestStatus.message} +
+ ) : ( + requestStatus.status && ( +
+ {requestStatus.message} +
+ ) + ))} + {/* End of error or success display */} +
+
+
+ ) +} diff --git a/src/components/JobGroups/DeleteGroup.jsx b/src/components/JobGroups/DeleteGroup.jsx new file mode 100644 index 0000000..6c646d3 --- /dev/null +++ b/src/components/JobGroups/DeleteGroup.jsx @@ -0,0 +1,122 @@ +import React, { useState } from 'react' + +import ModalCom from '../Helpers/ModalCom' +import LoadingSpinner from '../Spinners/LoadingSpinner' + +export default function DeleteGroup({action, situation, details}) { + + let [requestStatus, setRequestStatus] = useState({ + laoding: false, + status: false, + message: "", + }); // STATE FOR KNOWING WHEN A REQUEST IS MADE TO THE SERVER + + const deleteGroup = () => { + + } + + return ( + +
+
+

+ Delete Group +

+ +
+
+
+ + + + + +
+
+

+ Are you sure, you want to delete
'{details?.group_name}' +

+
+
+ + {requestStatus.laoding ? ( + + ) : ( + + )} +
+ + {/* ERROR DISPLAY AND SUBMIT BUTTON */} + {requestStatus.message != "" && + (!requestStatus.status ? ( +
+ {requestStatus.message} +
+ ) : ( + requestStatus.status && ( +
+ {requestStatus.message} +
+ ) + ))} + {/* End of error or success display */} +
+
+
+ ) +} diff --git a/src/components/JobGroups/DeleteMember.jsx b/src/components/JobGroups/DeleteMember.jsx new file mode 100644 index 0000000..e899cff --- /dev/null +++ b/src/components/JobGroups/DeleteMember.jsx @@ -0,0 +1,122 @@ +import React, { useState } from 'react' + +import ModalCom from '../Helpers/ModalCom' +import LoadingSpinner from '../Spinners/LoadingSpinner' + +export default function DeleteMember({action, situation, details}) { + + let [requestStatus, setRequestStatus] = useState({ + laoding: false, + status: false, + message: "", + }); // STATE FOR KNOWING WHEN A REQUEST IS MADE TO THE SERVER + + const deleteMember = () => { + + } + + return ( + +
+
+

+ Delete Member +

+ +
+
+
+ + + + + +
+
+

+ Are you sure, you want to delete
'{details?.firstname} {details.lastname}' +

+
+
+ + {requestStatus.laoding ? ( + + ) : ( + + )} +
+ + {/* ERROR DISPLAY AND SUBMIT BUTTON */} + {requestStatus.message != "" && + (!requestStatus.status ? ( +
+ {requestStatus.message} +
+ ) : ( + requestStatus.status && ( +
+ {requestStatus.message} +
+ ) + ))} + {/* End of error or success display */} +
+
+
+ ) +} diff --git a/src/components/JobGroups/GroupList.jsx b/src/components/JobGroups/GroupList.jsx new file mode 100644 index 0000000..c5ba8db --- /dev/null +++ b/src/components/JobGroups/GroupList.jsx @@ -0,0 +1,72 @@ +import React, { useState } from 'react' + +import InputCom from '../../components/Helpers/Inputs/InputCom/index' +import DeleteGroup from './DeleteGroup' +import AddGroup from './AddGroup' + +export default function GroupList({groupList, selectedGroup, changeSelectedGroup, setUpdateList}) { + + const [deletePopout, setDeletePopout] = useState({ + status: false, + data: {} + }) + + const [addGroupPopout, setAddGroupPopout] = useState(false) + + const handleAddGroup = () => { + setAddGroupPopout(true) + } + + const handleDeleteGroup = (item) => { + setDeletePopout({ + status: true, + data: {...item} + }) + } + + + return ( + <> +
+ {/*

Jobs Groups

*/} +
+ +
+ + {groupList && groupList.length < 1 ? +

No Group Found!

+ : +
+
+ {groupList.map(item=> ( +
+
+ +

{item.group_name}

+
+ +
+ ))} +
+
+ } +
+ + {deletePopout.status && + setDeletePopout({status:false, data:{}})} + situation={deletePopout.status} + details={deletePopout.data} + /> + } + + {addGroupPopout && + setAddGroupPopout(false)} + situation={addGroupPopout} + setUpdateList={setUpdateList} + /> + } + + ) +} diff --git a/src/components/JobGroups/GroupMemberTable.jsx b/src/components/JobGroups/GroupMemberTable.jsx new file mode 100644 index 0000000..2bfe99b --- /dev/null +++ b/src/components/JobGroups/GroupMemberTable.jsx @@ -0,0 +1,103 @@ +import React, { useState } from 'react' +import { handlePagingFunc } from '../Pagination/HandlePagination'; +import PaginatedList from '../Pagination/PaginatedList'; +import DeleteMember from './DeleteMember'; + +export default function GroupMemberTable({selectedList}) { + + // Handle Pagination + const [currentPage, setCurrentPage] = useState(0); + const indexOfFirstItem = Number(currentPage); + const indexOfLastItem =Number(indexOfFirstItem) + Number(process.env.REACT_APP_ITEM_PER_PAGE); + + const currentSelectedList = selectedList?.slice(indexOfFirstItem, indexOfLastItem); + + + const handlePagination = (e) => { + handlePagingFunc(e, setCurrentPage); + }; + + const [deletePopout, setDeletePopout] = useState({ + status: false, + data: {} + }) + + const handleDeleteMember = (item) => { + setDeletePopout({ + status: true, + data: {...item} + }) + } + + return ( +
+
+ + + <> + + + + + + + + + + {selectedList && selectedList?.length > 0 ? ( + currentSelectedList?.length ? ( + currentSelectedList.map((value, index) => ( + + + + + + + )) + ) : ( + + + + ) + ) : ( + + + + )} + + +
First NameLast NameEmail
{value?.firstname}{value?.lastname}{value?.email} + +
+ No Members Found +
No Members Found
+ + {/* PAGINATION BUTTON */} + = + currentSelectedList?.length + ? true + : false + } + data={currentSelectedList} + start={indexOfFirstItem} + stop={indexOfLastItem} + /> + {/* END OF PAGINATION BUTTON */} +
+ + {/* DELETE MEMBER POPOUT */} + {deletePopout.status && + setDeletePopout({status:false, data:{}})} + situation={deletePopout.status} + details={deletePopout.data} + /> + } + {/* END OF DELETE MEMBER POPOUT */} +
+ ); + }; diff --git a/src/components/JobGroups/JobGroups.jsx b/src/components/JobGroups/JobGroups.jsx index 87d96c9..1a47054 100644 --- a/src/components/JobGroups/JobGroups.jsx +++ b/src/components/JobGroups/JobGroups.jsx @@ -1,10 +1,74 @@ -import React from 'react' +import React, { useEffect, useState } from 'react' import Layout from '../Partials/Layout' +import GroupList from './GroupList' +import MemberList from './MemberList' +import LoadingSpinner from '../Spinners/LoadingSpinner' + +import usersService from '../../services/UsersService' + export default function JobGroups() { + + const userApi = new usersService(); + + const [updateList, setUpdateList] = useState(false) + + + const [groupList, setGroupList] = useState({ + loading:true, + groups: [], + members: [] + }) + + const [selectedGroup, setSelectedGroup] = useState({id:'', data: []}) + + const changeSelectedGroup = (e) => { + let groupID = e.target.value + const activeMembers = groupList?.members?.filter(item => item.group_id == groupID) + const activeGroup = groupList?.groups?.filter(item => item.group_id == groupID) + setSelectedGroup({id: groupID, name:activeGroup[0]?.group_name, data:activeMembers}) + } + + useEffect(()=>{ + setGroupList({loading: true, groups: [], members: []}) + userApi.jobGroupList({}).then(res => { + const {status, data} = res + if(status != 200 || data?.internal_return < 0){ + setGroupList({loading: false, groups: [], members: []}) + return + } + if(data.result_list.length < 0){ + setGroupList({loading: false, groups: [], members: []}) + return + } + setGroupList({loading: false, groups: data.result_list, members: data.result_list_member}) + let activeGroupId = data.result_list[0].group_id + let activeGroup = data.result_list[0].group_name + let activeMembers = data.result_list_member.filter(item => item.group_id == activeGroupId) + setSelectedGroup({id: activeGroupId, name:activeGroup, data:activeMembers}) + }).catch(error => { + setGroupList({loading: false, groups: [], members: []}) + console.log(error) + }) + },[updateList]) + return ( -
JobGroups
+
+

Jobs Groups

+
+
+ {groupList.loading ? +
+ +
+ : + <> + + + + } +
) } diff --git a/src/components/JobGroups/MemberList.jsx b/src/components/JobGroups/MemberList.jsx new file mode 100644 index 0000000..dcef796 --- /dev/null +++ b/src/components/JobGroups/MemberList.jsx @@ -0,0 +1,224 @@ +import React, { useState } from 'react' + +import InputCom from '../../components/Helpers/Inputs/InputCom/index' +import LoadingSpinner from '../Spinners/LoadingSpinner' +import GroupMemberTable from './GroupMemberTable' + +import EmailValidator from '../../lib/EmailValidator' + +import usersService from '../../services/UsersService' + +export default function MemberList({groupList, selectedGroup, setUpdateList}) { + + const api = new usersService() + + const [fields, setFields] = useState({ + firstname: '', + lastname: '', + email: '' + }) + + const handleFieldsChange = ({target:{name, value}}) => { + setFields(prev => ({...prev, [name]:value})) + let error = requestState?.errors?.indexOf(name) //// checks if the input field was in error array and removes it when the input changes + if(error >= 0){ + let oldErrorArr = requestState.errors + let newErrorArr = oldErrorArr.splice(error, 1) + setRequestState(prev => ({...prev, errors:oldErrorArr})) + } + } + + const [requestState, setRequestState] = useState({ + loading: false, + status: false, + message: '', + data: [], + errors: [] + }) + + const addMember = () => { + let errors = Object.keys(fields).filter((item) => { // CHECKS FOR EMPTY STRINGS + if(typeof item == 'string' && fields[item] === ''){ + return item + } + }) + + if(errors.length){ + setRequestState({ + loading: false, + status: false, + message: '', + data: [], + errors: [...errors] + }) + return + } + + //checks if email is a valid email address + let regEx = /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/; + if (!EmailValidator(fields.email)) { + setRequestState({ + loading: false, + status: false, + message: 'Email is invalid', + data: [], + errors: [] + }) + return setTimeout(()=>{ + setRequestState({ + loading: false, + status: false, + message: '', + data: [], + errors: [] + }) + },3000) + } + + setRequestState({ + loading: true, + status: false, + message: '', + data: [], + errors: [] + }) + const requestData = { + firstname:fields.firstname,lastname:fields.lastname, email:fields.email, group_id: selectedGroup?.id, action:13015 + } + + api.groupMemberAdd(requestData).then(response => { + let {status, data} = response + if(status != 200 || data?.internal_return < 0){ + setRequestState({ + loading: false, + status: false, + message: 'Unable to add member', + data: [], + errors: [] + }) + return + } + setRequestState({ + loading: false, + status: true, + message: 'Member added', + data: [], + errors: [] + }) + + setTimeout(()=>{ + // trigger group page reload + setUpdateList(prev => !prev) + setRequestState({ + loading: false, + status: false, + message: '', + data: [], + errors: [] + }) + }, 3000) + + }).catch(error=>{ + setRequestState({ + loading: false, + status: false, + message: 'Something went wrong, try again', + data: [], + errors: [] + }) + }).finally(()=>{ + setTimeout(()=>{ + setRequestState({ + loading: false, + status: false, + message: '', + data: [], + errors: [] + }) + setFields({ + firstname: '', + lastname: '', + email: '' + }) + }, 3000) + }) + } + + return ( + <> +
+ {groupList && groupList.length < 1 ? + <> +

No Group selected

+ + : + <> +

{selectedGroup?.name}

+
+
+
+
+ + {/* */} +
+
+ + {/* */} +
+
+ + {/* */} +
+
+ {requestState.loading ? + + : + + } +
+ {!requestState.loading && requestState.message && +

{requestState.message}

+ } +
+
+
+ {selectedGroup?.data?.length < 1 ? +

No Member Found, Please Add

+ : + + } +
+
+ + } +
+ + ) +} diff --git a/src/components/Partials/Layout.jsx b/src/components/Partials/Layout.jsx index f7963b2..6bd8c47 100644 --- a/src/components/Partials/Layout.jsx +++ b/src/components/Partials/Layout.jsx @@ -79,7 +79,7 @@ export default function Layout({ children }) { {children && children}
- +
diff --git a/src/components/Partials/RightSideBar.jsx b/src/components/Partials/RightSideBar.jsx index 5a73988..179bbe6 100644 --- a/src/components/Partials/RightSideBar.jsx +++ b/src/components/Partials/RightSideBar.jsx @@ -3,7 +3,7 @@ import { useSelector } from "react-redux"; import { NavLink } from "react-router-dom"; //import SideStatistics from "./SideStatistics"; -export default function RightSideBar() { +export default function RightSideBar({myJobList}) { const filterDatas = ["Last 15 days", "Last Month", "Last 6 month"]; const [filterDataSet, setFilterDataSet] = useState([10, 30, 20, 40]); const dataSetHandler = (value) => { @@ -156,6 +156,7 @@ export default function RightSideBar() { {/*JOB LINKS*/} + {myJobList?.data?.result_list?.length > 0 &&
{/* heading */}
@@ -190,7 +191,7 @@ export default function RightSideBar() { {/* name */}

- Active Task + Active Task

{/* action */} @@ -227,7 +228,7 @@ export default function RightSideBar() { {/* name */}

- Review Pending + Review Pending

@@ -265,13 +266,13 @@ export default function RightSideBar() { {/* name */}

- Past Due + Past Due

{/* Line */} -
+
{/* image */} @@ -314,6 +315,7 @@ export default function RightSideBar() { )}
+ } ); diff --git a/src/services/UsersService.js b/src/services/UsersService.js index 159b0e9..70a5087 100644 --- a/src/services/UsersService.js +++ b/src/services/UsersService.js @@ -1145,6 +1145,41 @@ class usersService { return this.postAuxEnd("/familytransfer", postData); } + + // FUNCTION GET JOB GROUP LIST + jobGroupList(reqData) { + var postData = { + uid: localStorage.getItem("uid"), + member_id: localStorage.getItem("member_id"), + sessionid: localStorage.getItem("session_token"), + action: 13045, + ...reqData, + }; + return this.postAuxEnd("/jobgrouplist", postData); + } + + // FUNCTION TO ADD JOB GROUP + jobGroupAdd(reqData) { + var postData = { + uid: localStorage.getItem("uid"), + member_id: localStorage.getItem("member_id"), + sessionid: localStorage.getItem("session_token"), + ...reqData, + }; + return this.postAuxEnd("/jobgroupadd", postData); + } + + // FUNCTION TO ADD JOB GROUP MEMBER + groupMemberAdd(reqData) { + var postData = { + uid: localStorage.getItem("uid"), + member_id: localStorage.getItem("member_id"), + sessionid: localStorage.getItem("session_token"), + ...reqData, + }; + return this.postAuxEnd("/groupmemberadd", postData); + } + /* - 20:27:30.118 FLOG_MAX [757411]: REQ_STRING(username) - 20:27:30.118 FLOG_MAX [757411]: REQ_STRING(password)