Skip to content

Commit

Permalink
Add Option For Project Switch
Browse files Browse the repository at this point in the history
  • Loading branch information
Harin329 committed Jul 22, 2023
1 parent df58345 commit 69cd1c1
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 1 deletion.
17 changes: 17 additions & 0 deletions backend/src/controllers/taskController.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,23 @@ export default class TaskController {
});
}

updateTaskProject(req) {
return new Promise((resolve, reject) => {
const TaskModel = new Task();
TaskModel.updateTaskProject(
req.params.taskId,
req.body.project_id,
(err, result) => {
if (err) {
reject({ error: err });
}
this.isTaskLoaded = false;
resolve(result);
}
);
});
}

//add subtask given taskID
saveSubtaskByTask(req) {
return new Promise((resolve, reject) => {
Expand Down
19 changes: 18 additions & 1 deletion backend/src/models/task.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,24 @@ export class Task {
result(error, null);
} else {
result(null, {
result: `Task of ${taskId} Saved Successfully for Task ID: ${taskDescription}`,
result: `Task of ${taskId} Saved Successfully for Task ID: ${taskId}`,
});
}
}
);
}

updateTaskProject(taskId, taskProject, result) {
con.query(
"CALL update_task_project(?, ?)",
[taskId, taskProject],
function (error, _) {
if (error) {
console.log("error: ", error);
result(error, null);
} else {
result(null, {
result: `Task of ${taskId} Saved Successfully for Task ID: ${taskId}`,
});
}
}
Expand Down
11 changes: 11 additions & 0 deletions backend/src/routes/taskRoute.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ router.post("/description/:taskId", authorize(), (req, res) => {
});
});

router.post("/project/:taskId", authorize(), (req, res) => {
taskController
.updateTaskProject(req)
.then((response) => {
res.status(200).json(response);
})
.catch((err) => {
res.status(404).json(err);
});
});

//add subtask given task_id
router.post("/addsubtask/:taskId", authorize(), (req, res) => {
if (!req.body) {
Expand Down
11 changes: 11 additions & 0 deletions database/procedures/ticketManagement/saveProcedures.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ DROP procedure IF EXISTS `save_subtask`;
DROP procedure IF EXISTS `update_task_status`;
DROP procedure IF EXISTS `update_task_title`;
DROP procedure IF EXISTS `update_task_description`;
DROP procedure IF EXISTS `update_task_project`;
DROP procedure IF EXISTS `update_subtask_status`;

DELIMITER $$
Expand Down Expand Up @@ -74,6 +75,16 @@ UPDATE `subtasks` SET `subtask_description`=`_task_description`, `subtask_update

END $$

CREATE PROCEDURE `update_task_project` (
IN `_task_uuid` VARCHAR(50),
IN `_task_project` VARCHAR(250)

) BEGIN
UPDATE `tasks` SET `fk_project_id`=`_task_project`, `task_updated` = NOW() WHERE `task_uuid`=`_task_uuid`;
UPDATE `billable` SET `fk_project_id`=`_task_project` WHERE `task_uuid`=`_task_uuid`;

END $$

CREATE PROCEDURE `save_subtask` (
IN `_subtask_uuid` VARCHAR(50),
IN `_subtask_title` VARCHAR(100),
Expand Down
58 changes: 58 additions & 0 deletions frontend/src/components/TicketBoard/TicketInfo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
SET_ACTIVE_TICKET,
UNASSIGN_USER,
UPDATE_TICKET_DESCRIPTION,
UPDATE_TICKET_PROJECT,
UPDATE_TICKET_STATUS,
UPDATE_TICKET_TITLE,
} from "../../../redux/actions/ticketActions";
Expand All @@ -22,6 +23,7 @@ import Subtasks from "../Subtasks";
import ServiceList from "../ServiceList";
import { SuccessToast } from "../../Toasts";
import AWS from "aws-sdk";
import { GET_PROJECT } from "../../../redux/actions/billingActions";

export const getColorNum = (id, colorArray) => {
if (colorArray) {
Expand All @@ -48,11 +50,15 @@ export const TicketInfo = () => {
const currentTicketAttachments = useSelector(
(state) => state.ticketReducer.currentTicketAttachments
);
const projectList = useSelector((state) => state.projectReducer.projectList);
const [currentProject, setCurrentProject] = useState();

const [assigneeAddModal, setAssigneeAddModal] = useState(false);
const [projectSwitchModal, setProjectSwitchModal] = useState(false);

useEffect(() => {
dispatch({ type: LOAD_EMPLOYEE });
dispatch({ type: GET_PROJECT });
dispatch({ type: GET_TICKET_BOARD });
if (currentTicket?.id) {
dispatch({
Expand All @@ -70,13 +76,21 @@ export const TicketInfo = () => {
}
}, [dispatch, currentTicket]);

useEffect(() => {
if (currentTicket?.id) {
const currentProj = projectList.find((proj) => proj.project_id === currentTicket.project_id);
setCurrentProject(currentProj);
}
}, [projectList, currentTicket])

return (
<div
className="ticketDetailBackground"
key={currentTicket.task_uuid}
onClick={() => {
if (assigneeAddModal) {
setAssigneeAddModal(false);
setProjectSwitchModal(false);
} else {
const inputs = document.querySelectorAll("input");
for (let i = 0; i < inputs.length; i++) {
Expand All @@ -90,6 +104,7 @@ export const TicketInfo = () => {
className="ticketDetail"
onClick={(event) => {
setAssigneeAddModal(false);
setProjectSwitchModal(false);
event.stopPropagation();
}}
>
Expand All @@ -108,6 +123,49 @@ export const TicketInfo = () => {
});
}}
/>
<button
className="ChangeProjectButton"
onClick={(e) => {
setProjectSwitchModal(true);
e.stopPropagation();
}}
style={{
backgroundColor: appColor.lightGray,
color: appColor.gray,
}}
onMouseOver={(e) => {
e.target.style.backgroundColor = "#627BF6";
e.target.style.color = "#FFFFFF";
}}
onMouseOut={(e) => {
e.target.style.backgroundColor = appColor.lightGray;
e.target.style.color = appColor.gray;
}}
>
Change Project
</button>
{projectSwitchModal ? (
<div className="projectSelectModal">
<div className="ticketSectionTitle">Change project from {currentProject?.project_name} to:</div>
{/* <div className="ticketSectionText">NOTE: Changing projects will reset custom service costs to the default values set for the organization</div> */}
<div>
{projectList.map((project) => {
return (
<div key={project.project_id} className="projectChoiceCell" onClick={() => {
dispatch({
type: UPDATE_TICKET_PROJECT,
payload: {
ticketId: currentTicket.task_uuid,
project_id: project.project_id,
},
});
setCurrentProject(project);
}}>{project.project_name}</div>
);
})}
</div>
</div>
) : null}
<button
className="TicketArchiveButton"
onClick={() => {
Expand Down
48 changes: 48 additions & 0 deletions frontend/src/components/TicketBoard/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,35 @@
flex-direction: column;
}

.projectSelectModal {
background-color: #eeeeee;
border-radius: 10px;
width: 98%;
height: 30%;
position: absolute;
left: 1%;
top: 6%;
z-index: 2;
display: flex;
justify-content: flex-start;
padding: 10px;
flex-direction: column;
overflow: scroll;
}

.projectChoiceCell {
background-color: #627BF6;
margin-top: 10px;
width: 25%;
height: 30px;
border-radius: 10px;
color: white;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}

.newMemberView {
display: flex;
flex-direction: row;
Expand Down Expand Up @@ -279,6 +308,18 @@
margin-left: 20px;
}

.ChangeProjectButton {
height: 45px;
width: 140px;
border: 0;
border-radius: 15px;
font-size: 12px;
font-weight: 600;
transition-duration: 0.4s;
cursor: pointer;
margin-left: 20px;
}

.TicketArchiveButton:hover {
background-color: #4caf50;
color: white;
Expand Down Expand Up @@ -320,6 +361,13 @@
color: #666666;
}

.ticketSectionText {
font-weight: 300;
font-size: 12px;
text-align: left;
color: #666666;
}

.ticketDescriptionInput {
border-radius: 10px;
padding: 10px;
Expand Down
1 change: 1 addition & 0 deletions frontend/src/redux/actions/ticketActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const SET_TICKETS = "SET_TICKETS";
export const UPDATE_TICKET_STATUS = "UPDATE_TICKET_STATUS";
export const UPDATE_TICKET_TITLE = "UPDATE_TICKET_TITLE";
export const UPDATE_TICKET_DESCRIPTION = "UPDATE_TICKET_DESCRIPTION";
export const UPDATE_TICKET_PROJECT = "UPDATE_TICKET_PROJECT";

export const SET_ACTIVE_TICKET = "SET_ACTIVE_TICKET";

Expand Down
21 changes: 21 additions & 0 deletions frontend/src/redux/api/ticketApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,27 @@ export const updateTicketDescriptionApi = async (payload) => {
}
};

export const updateTicketProjectApi = async (payload) => {
try {
const token = JSON.parse(localStorage.getItem("currentUser")).token;
var headers = {
Authorization: `Bearer ${token}`,
};
var data = JSON.stringify({
project_id: payload.project_id,
});

const tickets = await axios.post(
`task/project/${payload.ticketId}`,
data,
{ headers: headers }
);
return tickets;
} catch (err) {
return console.error(err);
}
};

export const getServiceCostApi = async (payload) => {
try {
const token = JSON.parse(localStorage.getItem("currentUser")).token;
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/redux/saga/ticketSaga.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
UPDATE_TICKET_TITLE,
CLEAR_ATTACHMENTS,
DELETE_VIEW_SUMMARY,
UPDATE_TICKET_PROJECT,
} from "../actions/ticketActions";
import {
assignUserApi,
Expand All @@ -36,6 +37,7 @@ import {
getSubTicketsById,
createSubtask,
updateTicketTitleApi,
updateTicketProjectApi,
} from "../api/ticketApi";

import { getAnswersBySurvey } from "../api/questionApi";
Expand Down Expand Up @@ -86,6 +88,13 @@ export function* updateTicketDescription(action) {
yield call(fetchTickets);
}

export function* updateTicketProject(action) {
const { ticketId, project_id } = action.payload;
yield call(updateTicketProjectApi, { ticketId, project_id });
yield call(fetchTickets);
}


export function* assignUser(action) {
yield call(assignUserApi, action.payload);
yield call(fetchTickets);
Expand Down Expand Up @@ -214,6 +223,7 @@ export default function* ticketSaga() {
yield takeLatest(UPDATE_TICKET_STATUS, updateTicketStatus);
yield takeLatest(UPDATE_TICKET_TITLE, updateTicketTitle);
yield takeLatest(UPDATE_TICKET_DESCRIPTION, updateTicketDescription);
yield takeLatest(UPDATE_TICKET_PROJECT, updateTicketProject);
yield takeLatest(ASSIGN_USER, assignUser);
yield takeLatest(UNASSIGN_USER, unassignUser);
yield takeLatest(POST_SERVICE_COST, postServiceCost);
Expand Down

0 comments on commit 69cd1c1

Please sign in to comment.