Skip to content

Commit 3490621

Browse files
committed
project edit added
1 parent 1817e32 commit 3490621

File tree

4 files changed

+197
-64
lines changed

4 files changed

+197
-64
lines changed

src/components/ProjectModal.tsx

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import React from "react";
2+
import {
3+
Dialog,
4+
DialogTitle,
5+
DialogContent,
6+
TextField,
7+
DialogActions,
8+
Button,
9+
} from "@material-ui/core";
10+
11+
interface IProps {
12+
open: boolean;
13+
title: string;
14+
submitButtonText: string;
15+
projectState: [
16+
{
17+
id: string;
18+
name: string;
19+
mainBranchName: string;
20+
},
21+
React.Dispatch<
22+
React.SetStateAction<{
23+
id: string;
24+
name: string;
25+
mainBranchName: string;
26+
}>
27+
>
28+
];
29+
onSubmit: () => void;
30+
onCancel: () => void;
31+
}
32+
33+
export const ProjectModal: React.FunctionComponent<IProps> = ({
34+
open,
35+
title,
36+
submitButtonText,
37+
projectState,
38+
onSubmit,
39+
onCancel,
40+
}) => {
41+
const [project, setProject] = projectState;
42+
43+
return (
44+
<Dialog open={open} onClose={onCancel} aria-labelledby="form-dialog-title">
45+
<DialogTitle id="form-dialog-title">{title}</DialogTitle>
46+
<DialogContent>
47+
<TextField
48+
autoFocus
49+
margin="dense"
50+
id="name"
51+
label="Project name"
52+
type="text"
53+
fullWidth
54+
value={project.name}
55+
onChange={(event) =>
56+
setProject({
57+
...project,
58+
name: event.target.value,
59+
})
60+
}
61+
/>
62+
<TextField
63+
margin="dense"
64+
id="branchName"
65+
label="Main branch"
66+
type="text"
67+
fullWidth
68+
value={project.mainBranchName}
69+
onChange={(event) =>
70+
setProject({
71+
...project,
72+
mainBranchName: event.target.value,
73+
})
74+
}
75+
/>
76+
</DialogContent>
77+
<DialogActions>
78+
<Button onClick={onCancel} color="primary">
79+
Cancel
80+
</Button>
81+
<Button onClick={onSubmit} color="primary">
82+
{submitButtonText}
83+
</Button>
84+
</DialogActions>
85+
</Dialog>
86+
);
87+
};

src/contexts/project.context.tsx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,22 @@ interface ICreateAction {
1818
payload: Project;
1919
}
2020

21+
interface IUpdateAction {
22+
type: "update";
23+
payload: Project;
24+
}
25+
2126
interface IDeleteAction {
2227
type: "delete";
2328
payload: string;
2429
}
2530

26-
type IAction = IRequestAction | IGetction | ICreateAction | IDeleteAction;
31+
type IAction =
32+
| IRequestAction
33+
| IGetction
34+
| ICreateAction
35+
| IDeleteAction
36+
| IUpdateAction;
2737

2838
type Dispatch = (action: IAction) => void;
2939
type State = { projectList: Project[] };
@@ -51,6 +61,16 @@ function projectReducer(state: State, action: IAction): State {
5161
...state,
5262
projectList: [action.payload, ...state.projectList],
5363
};
64+
case "update":
65+
return {
66+
...state,
67+
projectList: state.projectList.map((p) => {
68+
if (p.id === action.payload.id) {
69+
return action.payload;
70+
}
71+
return p;
72+
}),
73+
};
5474
case "delete":
5575
return {
5676
...state,
@@ -125,6 +145,22 @@ async function createProject(
125145
});
126146
}
127147

148+
async function updateProject(
149+
dispatch: Dispatch,
150+
project: { id: string; name: string; mainBranchName: string }
151+
) {
152+
dispatch({ type: "request" });
153+
154+
projectsService
155+
.update(project)
156+
.then((project: Project) => {
157+
dispatch({ type: "update", payload: project });
158+
})
159+
.catch((error) => {
160+
console.log(error.toString());
161+
});
162+
}
163+
128164
async function deleteProject(dispatch: Dispatch, id: string) {
129165
dispatch({ type: "request" });
130166

@@ -145,6 +181,7 @@ export {
145181
useProjectState,
146182
useProjectDispatch,
147183
createProject,
184+
updateProject,
148185
getProjectList,
149186
deleteProject,
150187
};

src/pages/ProjectListPage.tsx

Lines changed: 57 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -23,34 +23,41 @@ import {
2323
getProjectList,
2424
deleteProject,
2525
createProject,
26+
updateProject,
2627
} from "../contexts";
2728
import { Link } from "react-router-dom";
28-
import { Delete, Add } from "@material-ui/icons";
29+
import { Delete, Add, Edit } from "@material-ui/icons";
2930
import { routes } from "../constants";
3031
import { formatDateTime } from "../_helpers/format.helper";
32+
import { ProjectModal } from "../components/ProjectModal";
3133

3234
const ProjectsListPage = () => {
3335
const theme = useTheme();
3436
const projectState = useProjectState();
3537
const projectDispatch = useProjectDispatch();
3638

3739
const [createDialogOpen, setCreateDialogOpen] = React.useState(false);
38-
const [newProjectName, setNewProjectName] = React.useState<string>("");
39-
const [
40-
newProjectMainBranchName,
41-
setNewProjectMainBranchName,
42-
] = React.useState<string>("");
40+
const [updateDialogOpen, setUpdateDialogOpen] = React.useState(false);
41+
const [project, setProject] = React.useState<{
42+
id: string;
43+
name: string;
44+
mainBranchName: string;
45+
}>({
46+
id: "",
47+
name: "",
48+
mainBranchName: "",
49+
});
4350

4451
useEffect(() => {
4552
getProjectList(projectDispatch);
4653
}, [projectDispatch]);
4754

48-
const handleCreateClickOpen = () => {
49-
setCreateDialogOpen(true);
55+
const toggleCreateDialogOpen = () => {
56+
setCreateDialogOpen(!createDialogOpen);
5057
};
5158

52-
const handleCreateClose = () => {
53-
setCreateDialogOpen(false);
59+
const toggleUpdateDialogOpen = () => {
60+
setUpdateDialogOpen(!updateDialogOpen);
5461
};
5562

5663
return (
@@ -70,62 +77,44 @@ const ProjectsListPage = () => {
7077
<Fab
7178
color="primary"
7279
aria-label="add"
73-
onClick={handleCreateClickOpen}
80+
onClick={() => {
81+
toggleCreateDialogOpen();
82+
setProject({
83+
id: "",
84+
name: "",
85+
mainBranchName: "",
86+
});
87+
}}
7488
>
7589
<Add />
7690
</Fab>
7791
</Box>
7892

79-
<Dialog
93+
<ProjectModal
8094
open={createDialogOpen}
81-
onClose={handleCreateClose}
82-
aria-labelledby="form-dialog-title"
83-
>
84-
<DialogTitle id="form-dialog-title">Create Project</DialogTitle>
85-
<DialogContent>
86-
<TextField
87-
autoFocus
88-
margin="dense"
89-
id="name"
90-
label="Project name"
91-
type="text"
92-
fullWidth
93-
value={newProjectName}
94-
onChange={(event) => setNewProjectName(event.target.value)}
95-
/>
96-
<TextField
97-
margin="dense"
98-
id="branchName"
99-
label="Main branch"
100-
type="text"
101-
fullWidth
102-
value={newProjectMainBranchName}
103-
onChange={(event) =>
104-
setNewProjectMainBranchName(event.target.value)
105-
}
106-
/>
107-
</DialogContent>
108-
<DialogActions>
109-
<Button onClick={handleCreateClose} color="primary">
110-
Cancel
111-
</Button>
112-
<Button
113-
onClick={() => {
114-
createProject(projectDispatch, {
115-
name: newProjectName,
116-
mainBranchName: newProjectMainBranchName,
117-
}).then((project) => {
118-
setNewProjectName("");
119-
setNewProjectMainBranchName("");
120-
handleCreateClose();
121-
});
122-
}}
123-
color="primary"
124-
>
125-
Create
126-
</Button>
127-
</DialogActions>
128-
</Dialog>
95+
title={"Create Project"}
96+
submitButtonText={"Create"}
97+
onCancel={toggleCreateDialogOpen}
98+
projectState={[project, setProject]}
99+
onSubmit={() =>
100+
createProject(projectDispatch, project).then((project) => {
101+
toggleCreateDialogOpen();
102+
})
103+
}
104+
/>
105+
106+
<ProjectModal
107+
open={updateDialogOpen}
108+
title={"Update Project"}
109+
submitButtonText={"Update"}
110+
onCancel={toggleUpdateDialogOpen}
111+
projectState={[project, setProject]}
112+
onSubmit={() =>
113+
updateProject(projectDispatch, project).then((project) => {
114+
toggleUpdateDialogOpen();
115+
})
116+
}
117+
/>
129118
</Grid>
130119
{projectState.projectList.map((project) => (
131120
<Grid item xs={4} key={project.id}>
@@ -151,10 +140,15 @@ const ProjectsListPage = () => {
151140
</Button>
152141
<IconButton
153142
onClick={(event: React.MouseEvent<HTMLElement>) => {
154-
deleteProject(projectDispatch, project.id);
143+
toggleUpdateDialogOpen();
144+
setProject(project);
155145
}}
156-
style={{
157-
marginLeft: "auto",
146+
>
147+
<Edit />
148+
</IconButton>
149+
<IconButton
150+
onClick={(event: React.MouseEvent<HTMLElement>) => {
151+
deleteProject(projectDispatch, project.id);
158152
}}
159153
>
160154
<Delete />

src/services/projects.service.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const projectsService = {
66
getAll,
77
remove,
88
create,
9+
update,
910
};
1011

1112
function getAll(): Promise<Project[]> {
@@ -40,3 +41,17 @@ function create(project: {
4041

4142
return fetch(`${API_URL}/projects`, requestOptions).then(handleResponse);
4243
}
44+
45+
function update(project: {
46+
id: string;
47+
name: string;
48+
mainBranchName: string;
49+
}): Promise<Project> {
50+
const requestOptions = {
51+
method: "PUT",
52+
headers: { "Content-Type": "application/json", ...authHeader() },
53+
body: JSON.stringify(project),
54+
};
55+
56+
return fetch(`${API_URL}/projects`, requestOptions).then(handleResponse);
57+
}

0 commit comments

Comments
 (0)