Skip to content

Commit fc801e2

Browse files
committed
Merge branch 'feature/server/graphQL' of https://github.com/khuongdn16/ReacType into navbar
2 parents d32ce0d + cc6dff5 commit fc801e2

File tree

9 files changed

+144
-173
lines changed

9 files changed

+144
-173
lines changed

app/src/Dashboard/Project.tsx

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import React from 'react';
22
import { useMutation } from '@apollo/client';
3-
import { ADD_LIKE, MAKE_COPY, DELETE_PROJECT } from './gqlStrings';
3+
import {
4+
ADD_LIKE,
5+
MAKE_COPY,
6+
DELETE_PROJECT,
7+
PUBLISH_PROJECT,
8+
} from './gqlStrings';
49

510
// Variable validation using typescript
611
type props = {
@@ -9,10 +14,15 @@ type props = {
914
userId: string,
1015
username: string,
1116
likes: number,
17+
published: boolean,
1218
};
1319

20+
// Use current user info to make a make copy of another user's project
21+
const currUserSSID = window.localStorage.getItem('ssid') || 'unavailable';
22+
const currUsername = window.localStorage.getItem('username') || 'unavailable';
23+
1424
const Project = ({
15-
name, likes, id, username,
25+
name, likes, id, username, published,
1626
}: props) : JSX.Element => {
1727
// IMPORTANT:
1828
// 1) schema change projId => id to allows Apollo Client cache auto-update. Only works with 'id'
@@ -21,10 +31,10 @@ const Project = ({
2131
const [addLike] = useMutation(ADD_LIKE);
2232
const [makeCopy] = useMutation(MAKE_COPY);
2333
const [deleteProject] = useMutation(DELETE_PROJECT);
34+
const [publishProject] = useMutation(PUBLISH_PROJECT);
2435

2536
function handleLike(e) {
2637
e.preventDefault();
27-
// IMPORTANT: DO NOT ADD extra comma to the last line of the variable object, the query will not work
2838
const myVar = {
2939
variables:
3040
{
@@ -36,10 +46,6 @@ const Project = ({
3646
addLike(myVar);
3747
}
3848

39-
// Use current user info to make a make copy of another user's project
40-
const currUserSSID = window.localStorage.getItem('ssid') || 'unavailable';
41-
const currUsername = window.localStorage.getItem('username') || 'unavailable';
42-
4349

4450
function handleDownload(e) {
4551
e.preventDefault();
@@ -51,7 +57,6 @@ const Project = ({
5157
username: currUsername,
5258
},
5359
};
54-
// send Mutation
5560
makeCopy(myVar);
5661
}
5762

@@ -66,15 +71,31 @@ const Project = ({
6671
deleteProject(myVar);
6772
}
6873

74+
function handlePublish(e) {
75+
e.preventDefault();
76+
const myVar = {
77+
variables:
78+
{
79+
projId: id,
80+
published: !published,
81+
},
82+
};
83+
publishProject(myVar);
84+
}
85+
86+
6987
return (
7088
<div className = 'project'>
7189
<h2>Project: { name }</h2>
7290
<h3>Author: { username }</h3>
7391
<h3>Likes: { likes }</h3>
7492
<div>
7593
<button onClick={ handleLike }>like me!</button>
76-
{currUsername !== username ? <button onClick={ handleDownload }>download me!</button> : <span></span>}
77-
<button onClick={ handleDelete }>delete</button>
94+
{currUsername !== username ? <button onClick={ handleDownload }>download me!</button> : <span></span>}
95+
{currUsername === username ? <button onClick={ handleDelete }>delete</button> : <span></span>}
96+
{ currUsername === username
97+
? <button onClick={ handlePublish }> {published ? 'Unpublish Me!' : 'Publish Me!'} </button>
98+
: <span></span> }
7899
</div>
79100
</div>
80101
);

app/src/Dashboard/ProjectContainer.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import NavBar from './NavbarDash';
1010
// 2) useQuery hook will update the data stored in Apollo Client's cache and automatically trigger child components rendering
1111

1212
const ProjectContainer = () => {
13-
1413
let myVar = {};
1514
// Need this for the individual user dasboard, for now, dashboard shows all projects from all users
1615
const userSSID = window.localStorage.getItem('ssid') || 'unavailable';
@@ -28,18 +27,19 @@ const ProjectContainer = () => {
2827
console.log('Projects >>> ', projects);
2928
// generate an array of Project components based on data
3029
const publicProjects = [];
31-
const userProjects = [];
30+
const userProjects = [];
3231
projects.forEach((proj, index) => {
3332
const component = <Project
3433
key= { index }
3534
name = {proj.name}
3635
likes = {proj.likes}
36+
published = { proj.published }
3737
userId = {proj.userId}
3838
username = {proj.username}
3939
id = {proj.id}
4040
/>;
4141
if (username === proj.username) userProjects.push(component);
42-
else publicProjects.push(component);
42+
if (proj.published) publicProjects.push(component);
4343
});
4444

4545

app/src/Dashboard/gqlStrings.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ export const GET_PROJECTS = gql`query GetAllProjects($userId: ID) {
88
likes
99
id
1010
userId
11-
username
11+
username
12+
published
1213
}
1314
}`;
1415

@@ -19,11 +20,10 @@ export const ADD_LIKE = gql`
1920
addLike(projId: $projId, likes: $likes)
2021
{
2122
id
22-
likes
2323
}
2424
}`;
2525

26-
export const MAKE_COPY = gql`
26+
export const MAKE_COPY = gql`
2727
mutation MakeCopy ($userId: ID!, $projId: ID!, $username: String!) {
2828
makeCopy(userId: $userId, projId: $projId, username: $username)
2929
{
@@ -38,3 +38,12 @@ export const DELETE_PROJECT = gql`
3838
id
3939
}
4040
}`;
41+
42+
export const PUBLISH_PROJECT = gql`
43+
mutation Publish($projId: ID!, $published: Boolean!) {
44+
publishProject(projId: $projId, published: $published)
45+
{
46+
id
47+
published
48+
}
49+
}`;

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@
171171
"@types/enzyme": "^3.10.5",
172172
"@types/enzyme-adapter-react-16": "^1.0.6",
173173
"@types/jest": "^25.1.5",
174+
"apollo": "^2.32.5",
174175
"babel-eslint": "^8.2.6",
175176
"babel-jest": "^25.2.4",
176177
"babel-loader": "^8.1.0",

server/graphQL/resolvers/mutation.js

Lines changed: 68 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,117 @@
1-
const { Tests, Projects } = require('../../models/reactypeModels');
2-
1+
const { UserInputError } = require('apollo-server-express');
2+
const { Projects, Users } = require('../../models/reactypeModels');
33
/*
44
* resolvers are functions that handles graphQL requests. This file defines the logic for graphQL mutation requests
55
* Link to Apollo Mutations:
66
* https://www.apollographql.com/docs/apollo-server/data/resolvers/#defining-a-resolver
77
*/
88

9-
const Test = {
10-
addTest: async (parent, args) => {
11-
const resp = await Tests.create({ name: args.name, likes: args.likes });
12-
console.log('Added test', resp);
13-
if (resp) return { description: resp.name, id: resp._id, likes: args.likes };
14-
return { description: 'Error creating test', id: 'unknown', likes: 0 };
15-
},
16-
17-
updateTest: async (parent, args) => {
18-
// console.log('args >>> ', args);
19-
const filter = { _id: args.id };
20-
const update = { name: args.name, likes: args.likes };
21-
const options = { new: true };
22-
const resp = await Tests.findOneAndUpdate(filter, update, options);
23-
24-
console.log('Updated database with', resp);
25-
26-
if (resp) return { description: resp.name, id: resp._id, likes: resp.likes };
27-
return { description: 'Error updating', id: resp._id, likes: 0 };
28-
},
29-
30-
deleteTest: async (parent, args) => {
31-
const filter = { _id: args.id };
32-
const resp = await Tests.deleteOne(filter);
33-
if (resp) return { description: resp.name, id: resp._id, likes: 0 };
34-
return { description: 'Error updating', likes: 0 };
35-
},
36-
};
37-
38-
399
const Project = {
4010
addLike: async (parent, { projId, likes }) => {
4111
const filter = { _id: projId };
4212
const update = { likes };
4313
const options = { new: true };
4414
const resp = await Projects.findOneAndUpdate(filter, update, options);
45-
15+
4616
if (resp) {
4717
return ({
4818
name: resp.name,
4919
id: resp._id,
5020
userId: resp.userId,
51-
username: resp.username,
5221
likes: resp.likes,
22+
published: resp.published,
5323
});
5424
}
5525

56-
// TODO: Go back to this to see how to handle error later
57-
return {
58-
name: 'Error',
59-
id: 'Error',
60-
userId: 'Error',
61-
username: 'Error',
62-
likes: -1,
63-
};
26+
throw new UserInputError('Project is not found. Please try another project ID', {
27+
argumentName: 'projId',
28+
});
6429
},
6530

6631
makeCopy: async (parent, { projId, userId, username }) => {
6732
const filter = { _id: projId };
6833
const target = await Projects.findOne(filter);
69-
70-
// make a copy with the passed in userId
71-
// IMPORTANT: DO NOT CHANGE copy.name, it will create a nother copy of the document with the origional project name.
72-
const copy = {
73-
name: target.name,
74-
project: target.project,
75-
userId,
76-
username,
77-
};
78-
79-
// IMPORTANT: MUST MAKE A DEEP COPY OF target.project, otherwise, field 'style' is lost during the copy process. See 'minimize' option in projectSchema
80-
81-
const resp = await Projects.create(copy);
8234

35+
if (!target) {
36+
throw new UserInputError('Project is not found. Please try another project ID', {
37+
argumentName: 'projId',
38+
});
39+
}
40+
41+
// check if user account exists
42+
const user = await Users.findOne({ _id: userId });
43+
44+
if (user) {
45+
// make a copy with the passed in userId
46+
const copy = {
47+
name: target.name,
48+
project: target.project,
49+
userId,
50+
username,
51+
};
52+
53+
// Make a copy of the requested project
54+
const resp = await Projects.create(copy);
55+
if (resp) {
56+
return ({
57+
name: resp.name,
58+
id: resp._id,
59+
userId: resp.userId,
60+
username: resp.username,
61+
likes: resp.likes,
62+
published: resp.published,
63+
});
64+
}
65+
66+
throw new UserInputError('Internal Server Error');
67+
}
68+
69+
throw new UserInputError('User is not found. Please try another user ID', {
70+
argumentName: 'userId',
71+
});
72+
},
73+
74+
deleteProject: async (parent, { projId }) => {
75+
const filter = { _id: projId };
76+
const options = { strict: true };
77+
const resp = await Projects.findOneAndDelete(filter, options);
78+
8379
if (resp) {
8480
return ({
8581
name: resp.name,
8682
id: resp._id,
8783
userId: resp.userId,
88-
username: resp.username,
8984
likes: resp.likes,
85+
published: resp.published,
9086
});
9187
}
9288

93-
// TODO: Go back to this to see how to handle error later
94-
return {
95-
name: 'Error',
96-
id: 'Error',
97-
userId: 'Error',
98-
username: 'Error',
99-
likes: -1,
100-
};
89+
throw new UserInputError('Project is not found. Please try another project ID', {
90+
argumentName: 'projId',
91+
});
10192
},
10293

103-
deleteProject: async (parent, { projId }) => {
94+
publishProject: async (parent, { projId, published }) => {
95+
10496
const filter = { _id: projId };
105-
const options = { strict: true };
106-
const resp = await Projects.findOneAndDelete(filter, options);
107-
// console.log("resp", resp);
97+
const update = { published };
98+
const options = { new: true };
99+
const resp = await Projects.findOneAndUpdate(filter, update, options);
108100
if (resp) {
109101
return ({
110102
name: resp.name,
111-
likes: resp.likes,
112103
id: resp._id,
113104
userId: resp.userId,
114-
username: resp.username,
105+
likes: resp.likes,
106+
published: resp.published,
115107
});
116108
}
117-
return {
118-
name: 'Error',
119-
id: 'Error',
120-
userId: 'Error',
121-
username: 'Error',
122-
likes: -1,
123-
};
109+
110+
throw new UserInputError('Project is not found. Please try another project ID', {
111+
argumentName: 'projId',
112+
});
124113
},
125-
};
126114

127-
module.exports = {
128-
TestMutation: Test,
129-
ProjectMutation: Project,
130115
};
116+
117+
module.exports = Project;

0 commit comments

Comments
 (0)