Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Peterson implement toast when user is already in a team #2332

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 29 additions & 27 deletions src/actions/allTeamsAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
* set allteams in store
* @param payload : allteams []
*/
export const teamMembersFectchACtion = (payload) => ({
export const teamMembersFectchACtion = payload => ({
type: RECEIVE_ALL_USER_TEAMS,
payload,
});
Expand All @@ -27,7 +27,7 @@ export const teamMembersFectchACtion = (payload) => ({
* Action for Updating an teams
* @param {*} team : the updated user
*/
export const userTeamsUpdateAction = (team) => ({
export const userTeamsUpdateAction = team => ({
type: USER_TEAMS_UPDATE,
team,
});
Expand All @@ -45,7 +45,7 @@ export const addNewTeam = (payload, status) => ({
* Delete team action
* @param {*} team : the deleted team
*/
export const teamsDeleteAction = (team) => ({
export const teamsDeleteAction = team => ({
type: TEAMS_DELETE,
team,
});
Expand All @@ -72,7 +72,7 @@ export const teamUsersFetchAction = () => ({
* setting team users in store
* @param payload : allteams []
*/
export const teamUsersFetchCompleteAction = (payload) => ({
export const teamUsersFetchCompleteAction = payload => ({
type: RECEIVE_TEAM_USERS,
payload,
});
Expand All @@ -81,23 +81,23 @@ export const teamUsersFetchCompleteAction = (payload) => ({
* Error when setting the team users list
* @param payload : error status code
*/
export const teamUsersFetchErrorAction = (payload) => ({
export const teamUsersFetchErrorAction = payload => ({
type: FETCH_TEAM_USERS_ERROR,
payload,
});

/*
delete team member action
*/
export const teamMemberDeleteAction = (member) => ({
export const teamMemberDeleteAction = member => ({
type: TEAM_MEMBER_DELETE,
member,
});

/*
delete team member action
*/
export const teamMemberAddAction = (member) => ({
export const teamMemberAddAction = member => ({
type: TEAM_MEMBER_ADD,
member,
});
Expand All @@ -107,9 +107,9 @@ export const teamMemberAddAction = (member) => ({
*/
export const getAllUserTeams = () => {
const userTeamsPromise = axios.get(ENDPOINTS.TEAM);
return async (dispatch) => {
return async dispatch => {
return userTeamsPromise
.then((res) => {
.then(res => {
dispatch(teamMembersFectchACtion(res.data));
return res.data;
// console.log("getAllUserTeams: res:", res.data)
Expand All @@ -122,17 +122,20 @@ export const getAllUserTeams = () => {

/**
* posting new team
*/
export const postNewTeam = (name, status) => {
*/
export const postNewTeam = (name, status, source) => {
const data = { teamName: name, isActive: status };
const teamCreationPromise = axios.post(ENDPOINTS.TEAM, data);
return (dispatch) => {

const config = source ? { cancelToken: source.token } : {};

const teamCreationPromise = axios.post(ENDPOINTS.TEAM, data, config);
return dispatch => {
return teamCreationPromise
.then((res) => {
.then(res => {
dispatch(addNewTeam(res.data, true));
return res; // return the server response
})
.catch((error) => {
.catch(error => {
if (error.response) {
return error.response; // return the server response
} else if (error.request) {
Expand All @@ -141,17 +144,16 @@ export const postNewTeam = (name, status) => {
return { status: 500, message: error.message };
}
});
};
};
};


/**
* delete an existing team
* @param {*} teamId - the team to be deleted
*/
export const deleteTeam = (teamId) => {
const url = ENDPOINTS.TEAM_DATA(teamId)
return async (dispatch) => {
export const deleteTeam = teamId => {
const url = ENDPOINTS.TEAM_DATA(teamId);
return async dispatch => {
try {
const deleteTeamResponse = await axios.delete(url);
dispatch(teamsDeleteAction(teamId));
Expand All @@ -168,7 +170,7 @@ export const deleteTeam = (teamId) => {
export const updateTeam = (teamName, teamId, isActive, teamCode) => {
const requestData = { teamName, isActive, teamCode };
const url = ENDPOINTS.TEAM_DATA(teamId);
return async (dispatch) => {
return async dispatch => {
try {
const updateTeamResponse = await axios.put(url, requestData);
dispatch(updateTeamAction(teamId, isActive, teamName, teamCode));
Expand All @@ -182,12 +184,12 @@ export const updateTeam = (teamName, teamId, isActive, teamCode) => {
/**
* fetching team members
*/
export const getTeamMembers = (teamId) => {
export const getTeamMembers = teamId => {
const teamMembersPromise = axios.get(ENDPOINTS.TEAM_USERS(teamId));
return async (dispatch) => {
return async dispatch => {
await dispatch(teamUsersFetchAction());
return teamMembersPromise
.then((res) => {
.then(res => {
dispatch(teamUsersFetchCompleteAction(res.data));
return res.data;
})
Expand All @@ -204,7 +206,7 @@ export const getTeamMembers = (teamId) => {
export const deleteTeamMember = (teamId, userId) => {
const requestData = { userId, operation: 'UnAssign' };
const teamMemberDeletePromise = axios.post(ENDPOINTS.TEAM_USERS(teamId), requestData);
return async (dispatch) => {
return async dispatch => {
teamMemberDeletePromise.then(() => {
dispatch(teamMemberDeleteAction(userId));
});
Expand All @@ -217,8 +219,8 @@ export const deleteTeamMember = (teamId, userId) => {
export const addTeamMember = (teamId, userId, firstName, lastName, role, addDateTime) => {
const requestData = { userId, operation: 'Assign' };
const teamMemberAddPromise = axios.post(ENDPOINTS.TEAM_USERS(teamId), requestData);
return async (dispatch) => {
teamMemberAddPromise.then((res) => {
return async dispatch => {
teamMemberAddPromise.then(res => {
dispatch(teamMemberAddAction(res.data.newMember));
});
};
Expand Down
165 changes: 107 additions & 58 deletions src/components/UserProfile/TeamsAndProjects/AddTeamPopup.jsx
Original file line number Diff line number Diff line change
@@ -1,117 +1,166 @@
import React, { useEffect, useState } from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Alert } from 'reactstrap';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Alert, Spinner } from 'reactstrap';
import AddTeamsAutoComplete from './AddTeamsAutoComplete';
import { useDispatch } from 'react-redux';
import { toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import '../../Header/DarkMode.css'
import '../../Header/DarkMode.css';
import { postNewTeam, getAllUserTeams } from '../../../../src/actions/allTeamsAction';

import axios from 'axios';
const AddTeamPopup = React.memo(props => {
const {darkMode} = props;
const { darkMode } = props;

const dispatch = useDispatch();
const closePopup = () => {
props.onClose();
};

const [selectedTeam, onSelectTeam] = useState(undefined);
const [isValidTeam, onValidation] = useState(true);
const [isValidNewTeam, onNewTeamValidation] = useState(true);
const [searchText, setSearchText] = useState(''); // add searchText state

// states and onrs for the new team form
const [newTeamName, setNewTeamName] = useState('');
const [newTeamIsActive, setNewTeamIsActive] = useState(true);
const [isDuplicateTeam, setDuplicateTeam] = useState(false);
const [isNotDisplayAlert, setIsNotDisplayAlert] = useState(true);
const [isLoading, setIsLoading] = useState(false);

const onAssignTeam = () => {
if (!searchText) {
// when the user typed nothing
onValidation(false);
return;
}
if (selectedTeam && !props.userTeamsById.some(x => x._id === selectedTeam._id)) {
props.onSelectAssignTeam(selectedTeam);
toast.success('Team assigned successfully'); // toast notification
onSelectTeam(undefined);
} else {
// when the user typed something but didn't select a team
onValidation(false);
}
const closePopup = () => {
props.onClose();
!isNotDisplayAlert && setIsNotDisplayAlert(true);
};

const selectTeam = team => {
onSelectTeam(team);
onValidation(true);
// prettier-ignore
const format = result => result.toLowerCase().trim().replace(/\s+/g, '');

const FilteredToTeamSpecific = arrayOrObj => {
const result = props.teamsData.allTeams.filter(
item => format(item.teamName) === format(searchText),
);
if (result.length > 0) {
if (arrayOrObj) return result[0];
else return result;
} else return undefined;
};

const IfTheUserNotSelectedSuggestionAutoComplete = () => {
// prettier-ignore
if(searchText === '') {onValidation(false); return;}

const filterTeamData = FilteredToTeamSpecific(true);

if (filterTeamData) {
onAssignTeam(filterTeamData);
onValidation(true);
!isNotDisplayAlert && setIsNotDisplayAlert(true);
} else setIsNotDisplayAlert(false);
};

const onAssignTeam = result => {
// prettier-ignore
if (!searchText) {onValidation(false); return;} /* when the user typed nothing */

const idToCheck = result ? result._id : selectedTeam._id;

const some = !props.userTeamsById.some(x => x._id === idToCheck);

if ((result || selectedTeam) && some) {
props.onSelectAssignTeam(result ? result : selectedTeam);

toast.success('Team assigned successfully '); // toast notification
setSearchText('');

selectedTeam && (onSelectTeam(undefined), onValidation(false));
} else
toast.error(
'Your user has been found in this team. Please select another team to add your user.',
);
};

const axiosResponseExceededTimeout = source => {
setIsLoading(false);
source.cancel();
};

const onCreateTeam = async () => {
if (newTeamName !== '') {
const response = await dispatch(postNewTeam(newTeamName, newTeamIsActive));

if (searchText !== '') {
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
const timeout = setTimeout(() => axiosResponseExceededTimeout(source), 20000);

setIsLoading(true);
const response = await dispatch(postNewTeam(searchText, true, source));
clearTimeout(timeout);
if (response.status === 200) {
toast.success('Team created successfully');
setNewTeamName('');
setNewTeamIsActive(true);
setDuplicateTeam(false);

// Get updated teams list and select the new team
await dispatch(getAllUserTeams());
toast.success('Team created successfully');
const newTeam = response.data; // Assuming response contains the new team data
onSelectTeam(newTeam);
setSearchText(newTeam.teamName); // Update search text to reflect new team name

} else if (response.status === 400) {
setDuplicateTeam(true);
setIsLoading(false);
} else {
toast.error('Error occurred while creating team');
setIsLoading(false);
const messageToastError =
response.status === 500
? 'No response received from the server'
: 'Error occurred while creating team';
response.status === 403 ? setDuplicateTeam(true) : toast.error(messageToastError);
}
} else {
onNewTeamValidation(false);
}
};


useEffect(() => {
onValidation(true);
onNewTeamValidation(true);
}, [props.open]);

useEffect(() => {
dispatch(getAllUserTeams());
}, [newTeamName, newTeamIsActive, dispatch]);

return (
<Modal isOpen={props.open} toggle={closePopup} autoFocus={false} className={darkMode ? 'text-light dark-mode' : ''}>
<ModalHeader className={darkMode ? 'bg-space-cadet' : ''} toggle={closePopup}>Add Team</ModalHeader>
<Modal
isOpen={props.open}
toggle={closePopup}
autoFocus={false}
className={darkMode ? 'text-light dark-mode' : ''}
>
<ModalHeader className={darkMode ? 'bg-space-cadet' : ''} toggle={closePopup}>
Add Team
</ModalHeader>
<ModalBody className={darkMode ? 'bg-yinmn-blue' : ''} style={{ textAlign: 'center' }}>
<label className={darkMode ? 'text-light' : ''} style={{textAlign: 'left'}}>Add to Team</label>
<label className={darkMode ? 'text-light' : ''} style={{ textAlign: 'left' }}>
Add to Team
</label>
<div className="input-group-prepend" style={{ marginBottom: '10px' }}>
<AddTeamsAutoComplete
teamsData={props.teamsData}
onDropDownSelect={selectTeam}
onCreateNewTeam={onCreateTeam}
selectedTeam={selectedTeam}
searchText={searchText}
setNewTeamName={setNewTeamName}
newTeamName={newTeamName}
setSearchText={setSearchText} // Added setSearchText prop
setSearchText={setSearchText} // Added setSearchText prop
/>
<Button color="primary" style={{ marginLeft: '5px' }} onClick={onAssignTeam}>
Confirm
<Button
color="primary"
style={{ marginLeft: '5px' }}
onClick={() => {
if (!searchText) onValidation(false);
else IfTheUserNotSelectedSuggestionAutoComplete();
}}
disabled={isLoading}
>
{isLoading ? <Spinner color="light" size="sm" /> : 'Confirm'}
</Button>
</div>
{!isValidTeam && searchText && !selectedTeam && (
{!isNotDisplayAlert && (
<Alert color="danger">Oops, this team does not exist! Create it if you want it.</Alert>
)}
)}

{!isValidTeam && !searchText && (
<Alert color="danger">Hey, You need to pick a team first!</Alert>
)}
{!isValidNewTeam && !isDuplicateTeam ? <Alert color="danger">Please enter a team name.</Alert> : null}
{isDuplicateTeam && (
<Alert color="danger">A team with this name already exists</Alert>
)}

{!isValidNewTeam && !isDuplicateTeam ? (
<Alert color="danger">Please enter a team name.</Alert>
) : null}
{isDuplicateTeam && <Alert color="danger">A team with this name already exists</Alert>}
</ModalBody>
<ModalFooter className={darkMode ? 'bg-yinmn-blue' : ''}>
<Button color="secondary" onClick={closePopup}>
Expand Down
Loading
Loading