taskcafe/frontend/src/Projects/Project/index.tsx

293 lines
9.6 KiB
TypeScript
Raw Normal View History

// LOC830
import React, { useRef, useEffect } from 'react';
import updateApolloCache from 'shared/utils/cache';
2021-04-30 23:33:38 +02:00
import GlobalTopNavbar from 'App/TopNavbar';
import ProjectPopup from 'App/TopNavbar/ProjectPopup';
import { usePopup } from 'shared/components/PopupMenu';
import {
useParams,
Route,
useRouteMatch,
useHistory,
RouteComponentProps,
useLocation,
Redirect,
} from 'react-router-dom';
import {
useUpdateProjectMemberRoleMutation,
useInviteProjectMembersMutation,
useDeleteProjectMemberMutation,
2020-05-31 06:11:19 +02:00
useToggleTaskLabelMutation,
useUpdateProjectNameMutation,
useFindProjectQuery,
useDeleteInvitedProjectMemberMutation,
useUpdateTaskNameMutation,
useDeleteTaskMutation,
2020-04-20 05:02:55 +02:00
useUpdateTaskDescriptionMutation,
2020-05-27 02:53:31 +02:00
FindProjectDocument,
FindProjectQuery,
} from 'shared/generated/graphql';
2020-05-27 02:53:31 +02:00
import produce from 'immer';
import NOOP from 'shared/utils/noop';
import useStateWithLocalStorage from 'shared/hooks/useStateWithLocalStorage';
import localStorage from 'shared/utils/localStorage';
import Board, { BoardLoading } from './Board';
import Details from './Details';
import LabelManagerEditor from './LabelManagerEditor';
import UserManagementPopup from './UserManagementPopup';
import polling from 'shared/utils/polling';
2020-04-10 04:40:22 +02:00
type TaskRouteProps = {
taskID: string;
};
2020-04-10 04:40:22 +02:00
interface ProjectParams {
projectID: string;
2020-04-10 04:40:22 +02:00
}
const Project = () => {
const { projectID } = useParams<ProjectParams>();
2020-05-31 06:11:19 +02:00
const history = useHistory();
const match = useRouteMatch();
const location = useLocation();
const { showPopup, hidePopup } = usePopup();
const labelsRef = useRef<Array<ProjectLabel>>([]);
const [value, setValue] = useStateWithLocalStorage(localStorage.CARD_LABEL_VARIANT_STORAGE_KEY);
const taskLabelsRef = useRef<Array<TaskLabel>>([]);
const [updateTaskDescription] = useUpdateTaskDescriptionMutation();
const [updateProjectMemberRole] = useUpdateProjectMemberRoleMutation();
const [updateTaskName] = useUpdateTaskNameMutation();
const { data, error } = useFindProjectQuery({
variables: { projectID },
pollInterval: polling.PROJECT,
});
2020-05-31 06:11:19 +02:00
const [toggleTaskLabel] = useToggleTaskLabelMutation({
onCompleted: newTaskLabel => {
taskLabelsRef.current = newTaskLabel.toggleTaskLabel.task.labels;
2020-04-10 04:40:22 +02:00
},
});
const [deleteTask] = useDeleteTaskMutation({
update: (client, resp) =>
updateApolloCache<FindProjectQuery>(
client,
FindProjectDocument,
cache =>
produce(cache, draftCache => {
2020-12-19 03:34:35 +01:00
if (resp.data) {
const taskGroupIdx = draftCache.findProject.taskGroups.findIndex(
tg => tg.tasks.findIndex(t => t.id === resp.data?.deleteTask.taskID) !== -1,
);
if (taskGroupIdx !== -1) {
draftCache.findProject.taskGroups[taskGroupIdx].tasks = cache.findProject.taskGroups[
taskGroupIdx
].tasks.filter(t => t.id !== resp.data?.deleteTask.taskID);
}
}
}),
{ projectID },
),
});
2020-04-20 05:02:55 +02:00
const [updateProjectName] = useUpdateProjectNameMutation({
update: (client, newName) => {
updateApolloCache<FindProjectQuery>(
client,
FindProjectDocument,
cache =>
produce(cache, draftCache => {
2020-12-19 03:34:35 +01:00
draftCache.findProject.name = newName.data?.updateProjectName.name ?? '';
}),
{ projectID },
);
},
});
2020-05-31 06:11:19 +02:00
const [inviteProjectMembers] = useInviteProjectMembersMutation({
update: (client, response) => {
updateApolloCache<FindProjectQuery>(
client,
FindProjectDocument,
cache =>
produce(cache, draftCache => {
2020-12-19 03:34:35 +01:00
if (response.data) {
draftCache.findProject.members = [
...cache.findProject.members,
...response.data.inviteProjectMembers.members,
];
draftCache.findProject.invitedMembers = [
...cache.findProject.invitedMembers,
...response.data.inviteProjectMembers.invitedMembers,
];
}
}),
{ projectID },
);
},
});
const [deleteInvitedProjectMember] = useDeleteInvitedProjectMemberMutation({
update: (client, response) => {
updateApolloCache<FindProjectQuery>(
client,
FindProjectDocument,
cache =>
produce(cache, draftCache => {
draftCache.findProject.invitedMembers = cache.findProject.invitedMembers.filter(
2020-12-19 03:34:35 +01:00
m => m.email !== response.data?.deleteInvitedProjectMember.invitedMember.email ?? '',
);
}),
{ projectID },
);
},
});
const [deleteProjectMember] = useDeleteProjectMemberMutation({
update: (client, response) => {
updateApolloCache<FindProjectQuery>(
client,
FindProjectDocument,
cache =>
produce(cache, draftCache => {
draftCache.findProject.members = cache.findProject.members.filter(
2020-12-19 03:34:35 +01:00
m => m.id !== response.data?.deleteProjectMember.member.id,
);
}),
{ projectID },
);
},
});
2020-06-19 01:12:15 +02:00
2020-06-13 00:21:58 +02:00
useEffect(() => {
if (data) {
2020-08-07 03:50:35 +02:00
document.title = `${data.findProject.name} | Taskcafé`;
2020-06-13 00:21:58 +02:00
}
}, [data]);
2020-04-10 04:40:22 +02:00
if (data) {
2020-05-31 06:11:19 +02:00
labelsRef.current = data.findProject.labels;
2020-04-10 04:40:22 +02:00
return (
<>
2020-05-31 06:11:19 +02:00
<GlobalTopNavbar
onChangeRole={(userID, roleCode) => {
updateProjectMemberRole({ variables: { userID, roleCode, projectID } });
}}
onChangeProjectOwner={() => {
hidePopup();
}}
onRemoveFromBoard={userID => {
deleteProjectMember({ variables: { userID, projectID } });
hidePopup();
}}
onRemoveInvitedFromBoard={email => {
deleteInvitedProjectMember({ variables: { projectID, email } });
hidePopup();
}}
2020-05-31 06:11:19 +02:00
onSaveProjectName={projectName => {
updateProjectName({ variables: { projectID, name: projectName } });
2020-05-31 06:11:19 +02:00
}}
onInviteUser={$target => {
showPopup(
$target,
<UserManagementPopup
projectID={projectID}
onInviteProjectMembers={members => {
inviteProjectMembers({ variables: { projectID, members } });
hidePopup();
}}
users={data.users}
projectMembers={data.findProject.members}
/>,
);
}}
2021-05-01 05:55:37 +02:00
popupContent={
<ProjectPopup // eslint-disable-line
history={history}
publicOn={data.findProject.publicOn}
name={data.findProject.name}
projectID={projectID}
/>
}
menuType={[{ name: 'Board', link: location.pathname }]}
currentTab={0}
2020-05-31 06:11:19 +02:00
projectMembers={data.findProject.members}
projectInvitedMembers={data.findProject.invitedMembers}
projectID={projectID}
teamID={data.findProject.team ? data.findProject.team.id : null}
2020-05-31 06:11:19 +02:00
name={data.findProject.name}
/>
<Route path={`${match.path}`} exact render={() => <Redirect to={`${match.url}/board`} />} />
2020-07-12 09:06:11 +02:00
<Route
path={`${match.path}/board`}
render={() => (
<Board
cardLabelVariant={value === 'small' ? 'small' : 'large'}
onCardLabelClick={() => {
const variant = value === 'small' ? 'large' : 'small';
setValue(() => variant);
}}
projectID={projectID}
/>
2020-07-12 09:06:11 +02:00
)}
2020-04-20 05:02:55 +02:00
/>
<Route
2020-07-12 09:06:11 +02:00
path={`${match.path}/board/c/:taskID`}
render={(routeProps: RouteComponentProps<TaskRouteProps>) => (
2020-04-20 05:02:55 +02:00
<Details
refreshCache={NOOP}
2020-05-31 06:11:19 +02:00
availableMembers={data.findProject.members}
2020-07-12 09:06:11 +02:00
projectURL={`${match.url}/board`}
2020-04-20 05:02:55 +02:00
taskID={routeProps.match.params.taskID}
onTaskNameChange={(updatedTask, newName) => {
updateTaskName({ variables: { taskID: updatedTask.id, name: newName } });
2020-04-20 05:02:55 +02:00
}}
onTaskDescriptionChange={(updatedTask, newDescription) => {
2020-09-03 03:25:28 +02:00
updateTaskDescription({
variables: { taskID: updatedTask.id, description: newDescription },
optimisticResponse: {
__typename: 'Mutation',
updateTaskDescription: {
__typename: 'Task',
id: updatedTask.id,
description: newDescription,
},
},
});
}}
2020-04-20 05:02:55 +02:00
onDeleteTask={deletedTask => {
deleteTask({ variables: { taskID: deletedTask.id } });
history.push(`${match.url}/board`);
2020-05-31 06:11:19 +02:00
}}
onOpenAddLabelPopup={(task, $targetRef) => {
taskLabelsRef.current = task.labels;
showPopup(
$targetRef,
<LabelManagerEditor
onLabelToggle={labelID => {
toggleTaskLabel({ variables: { taskID: task.id, projectLabelID: labelID } });
2020-05-31 06:11:19 +02:00
}}
taskID={task.id}
2020-05-31 06:11:19 +02:00
labelColors={data.labelColors}
labels={labelsRef}
taskLabels={taskLabelsRef}
projectID={projectID}
/>,
);
}}
/>
)}
/>
2020-04-10 04:40:22 +02:00
</>
);
}
2020-12-24 03:02:38 +01:00
return (
<>
<GlobalTopNavbar onSaveProjectName={NOOP} name="" projectID={null} />
<BoardLoading />
</>
);
2020-04-10 04:40:22 +02:00
};
export default Project;