Jelajahi Sumber

User Deletion UI.

Oleksandr Korniienko 3 tahun lalu
induk
melakukan
0e35b6cb59

+ 71 - 2
src/components/IssueTracker/MembersModal.tsx

@@ -1,10 +1,16 @@
 import {
   Button,
+  Chip,
   createStyles,
+  Divider,
+  Fab,
   makeStyles,
+  Paper,
   TextField,
   Theme,
 } from "@material-ui/core";
+import DeleteIcon from "@material-ui/icons/Delete";
+import MoodBadIcon from "@material-ui/icons/MoodBad";
 import { useState } from "react";
 import { IMember } from "./types";
 
@@ -32,19 +38,32 @@ const useStyles = makeStyles((theme: Theme) =>
       },
     },
     member: {
+      display: "flex",
       "& > *": {
         margin: theme.spacing(1, 1, 1, 0),
       },
     },
+    deletedMembers: {
+      display: "flex",
+      justifyContent: "center",
+      flexWrap: "wrap",
+      listStyle: "none",
+      padding: theme.spacing(0.5),
+      margin: 0,
+    },
+    deletedMemberChip: {
+      margin: theme.spacing(0.5),
+    },
   })
 );
 
 const MembersModal = (props: {
   members: IMember[];
-  membersCallback: (members: IMember[]) => void;
+  membersCallback: (members: IMember[], deletedMembers: IMember[]) => void;
 }) => {
   const classes = useStyles();
   const [members, setMembers] = useState(props.members);
+  const [deletedMembers, setDeletedMembers] = useState([] as IMember[]);
 
   const canSave = () =>
     members.filter((m) => m.name && m.name === "").length === 0;
@@ -85,16 +104,66 @@ const MembersModal = (props: {
                   });
                 }}
               />
+              <Fab
+                style={{ float: "left" }}
+                color="secondary"
+                aria-label="delete"
+                onClick={() => {
+                  setDeletedMembers((prev) => [...prev, member]);
+                  setMembers((prev) => {
+                    const index = prev.indexOf(
+                      prev.filter((m) => m.id === member.id)[0]
+                    );
+                    prev.splice(index, 1);
+                    return [...prev];
+                  });
+                }}
+              >
+                <DeleteIcon />
+              </Fab>
             </div>
           );
         })}
+        <Divider hidden={deletedMembers.length === 0} />
+        <Paper
+          hidden={deletedMembers.length === 0}
+          component="ul"
+          className={classes.deletedMembers}
+        >
+          <Chip
+            className={classes.deletedMemberChip}
+            color="secondary"
+            label="Users to be deleted:"
+          />
+          {deletedMembers.map((member) => {
+            return (
+              <li key={member.id}>
+                <Chip
+                  icon={<MoodBadIcon />}
+                  label={member.name}
+                  onDelete={() => {
+                    setMembers((prev) => [...prev, member]);
+                    setDeletedMembers((prev) => {
+                      const index = prev.indexOf(
+                        prev.filter((m) => m.id === member.id)[0]
+                      );
+                      prev.splice(index, 1);
+                      return [...prev];
+                    });
+                  }}
+                  className={classes.deletedMemberChip}
+                />
+              </li>
+            );
+          })}
+        </Paper>
         <Button
           disabled={!canSave()}
           style={{ float: "right" }}
           variant="contained"
           color="primary"
           onClick={() => {
-            props.membersCallback(members);
+            props.membersCallback(members, deletedMembers);
           }}
         >
           Save All

+ 7 - 5
src/components/IssueTracker/Task.tsx

@@ -44,7 +44,9 @@ const Task = (props: {
   const creatorId = () => {
     return !props.task.creatorId
       ? "-"
-      : props.members.filter((m) => m.id === props.task.creatorId)[0].name;
+      : props.members.filter((m) => m.id === props.task.creatorId).length > 0
+      ? props.members.filter((m) => m.id === props.task.creatorId)[0].name
+      : "-";
   };
   const openEditIssueModal = () => {
     setShowEditIssueModal(true);
@@ -101,16 +103,16 @@ const Task = (props: {
   const classes = useStyles();
 
   const AssigneeAvatar = () => {
-    if (!props.task.assigneeId) {
+    const assignee = props.members.filter(
+      (m) => m.id === props.task.assigneeId
+    )[0];
+    if (!props.task.assigneeId || !assignee) {
       return (
         <div className={classes.avatar}>
           <Avatar>NA</Avatar>
         </div>
       );
     }
-    const assignee = props.members.filter(
-      (m) => m.id === props.task.assigneeId
-    )[0];
     if (assignee.avatar) {
       return (
         <div className={classes.avatar}>

+ 19 - 2
src/components/IssueTracker/index.tsx

@@ -81,6 +81,8 @@ const IssueTracker = () => {
     await axios.put(`${tasksEndpoint}/members`, body);
   const updateMember = async (body: IMember) =>
     await axios.put(`${tasksEndpoint}/members/${body.id}`, body);
+  const deleteMember = async (body: IMember) =>
+    await axios.delete(`${tasksEndpoint}/members/${body.id}`);
 
   useEffect(() => {
     loadConfig().then((response) => {
@@ -258,6 +260,7 @@ const IssueTracker = () => {
       const createdTask = response.data;
       setTasks((prev) => [...prev, createdTask]);
       setShouldReloadIssues(true);
+      setShouldReloadMembers(true);
     });
   };
 
@@ -288,16 +291,30 @@ const IssueTracker = () => {
       const createdTask = response.data;
       setTasks((prev) => [...prev, createdTask]);
       setShouldReloadIssues(true);
+      setShouldReloadMembers(true);
     });
   };
 
-  const membersCallback = (updatedMembers: IMember[]) => {
+  const membersCallback = (
+    updatedMembers: IMember[],
+    deletedMembers: IMember[]
+  ) => {
     closeMembersModal();
+    deletedMembers.forEach((m, i) => {
+      deleteMember(m).then((response) => {
+        if (!response.data || response.data.error) {
+          // TODO show alert with the error message
+          console.error(`Failed to delete member.`);
+        }
+        setShouldReloadMembers(i === deletedMembers.length - 1);
+        setShouldReloadIssues(i === deletedMembers.length - 1);
+      });
+    });
     updatedMembers.forEach((m) => {
       updateMember(m).then((response) => {
         if (!response.data || response.data.error) {
           // TODO show alert with the error message
-          console.error(`Failed to create issue.`);
+          console.error(`Failed to update member.`);
         }
       });
     });