Skip to content

Commit 859bfc2

Browse files
committed
implement projects sync between Dashboard and main App. Dashboard actively polls the server for syncing
1 parent 6b26b1b commit 859bfc2

File tree

10 files changed

+144
-21
lines changed

10 files changed

+144
-21
lines changed

app/src/Dashboard/Form.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const Form = ({ description, id, likes }) => {
4646
// Variable validation using propTypes
4747
Form.propTypes = {
4848
description: PropTypes.string.isRequired,
49-
id: PropTypes.id.isRequired,
49+
id: PropTypes.string.isRequired,
5050
likes: PropTypes.number.isRequired,
5151
};
5252

app/src/Dashboard/Project.jsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import React from 'react';
2+
import { gql, useMutation } from '@apollo/client';
3+
import PropTypes from 'prop-types';
4+
5+
6+
const Project = ({ name, likes, projId, userId }) => {
7+
8+
// IMPORTANT:
9+
// 1) schema change projId => id to allows Apollo Client cache auto-update. Only works with 'id'
10+
// 2) always request the 'id' in a mutation request
11+
12+
const ADD_LIKE = gql`
13+
mutation AddLike($projId: ID!, $likes: Int!) {
14+
addLike(projId: $projId, likes: $likes)
15+
{
16+
id
17+
likes
18+
}
19+
}`;
20+
21+
const [addLike] = useMutation(ADD_LIKE);
22+
23+
function handleClick(e) {
24+
e.preventDefault();
25+
// IMPORTANT: DO NOT ADD extra comma to the last line of the variable object, the query will not work
26+
const myVar = {
27+
variables:
28+
{
29+
projId,
30+
likes: likes + 1,
31+
},
32+
};
33+
// send Mutation
34+
addLike(myVar);
35+
}
36+
37+
return (
38+
<div className = 'project'>
39+
<h2>Project: { name }</h2>
40+
{/* <h3>Project ID: {projId} </h3> */}
41+
<h3>Likes: { likes }</h3>
42+
<button onClick={ handleClick }>like me!</button>
43+
</div>
44+
);
45+
};
46+
47+
// Variable validation using propTypes
48+
Project.propTypes = {
49+
name: PropTypes.string.isRequired,
50+
projId: PropTypes.string.isRequired,
51+
userId: PropTypes.string.isRequired,
52+
likes: PropTypes.number.isRequired,
53+
};
54+
55+
56+
export default Project;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React from 'react';
2+
import { Link } from 'react-router-dom';
3+
4+
import { gql, useQuery } from '@apollo/client';
5+
6+
import Project from './Project.jsx';
7+
// Implement Apollo Client useQuery hook to retrieve data from the server through graphQL. This includes 2 steps:
8+
// 1) Impliment Apollo Provider in the top component in ./src/index.js, this allows children components access to the queried data
9+
// 2) useQuery hook will update the data stored in Apollo Client's cache and automatically trigger child components rendering
10+
11+
const ProjectContainer = () => {
12+
// define the graphQL query string
13+
const GET_PROJECTS = gql`query GetAllProjects($userId: ID) {
14+
getAllProjects(userId: $userId) {
15+
name
16+
likes
17+
id
18+
}
19+
}`;
20+
21+
// For now, if cookie exists, pull projects for the specific user only, otherwise pull all projects
22+
const userSSID = window.localStorage.getItem('ssid') || '';
23+
let myVar = {};
24+
if (userSSID !== 'guest') {
25+
myVar = { userId: userSSID };
26+
}
27+
// useQuery hook abstracts fetch request
28+
const { loading, error, data } = useQuery(GET_PROJECTS, { pollInterval: 2000, variables: myVar } ); // Need to find where the userId is stored for the logged in user.
29+
if (loading) return <p>Loading...</p>;
30+
if (error) return <p>Error :{error}</p>;
31+
// based on resolver(getAllProject) for this query, the data is stored in the data object with the key 'getAllProjects'
32+
const myProjs = data.getAllProjects;
33+
console.log('Projects >>> ', myProjs);
34+
// generate an array of Project components based on data
35+
const projects = myProjs.map((proj, index) => <Project
36+
key= { index }
37+
name = {proj.name}
38+
likes = {proj.likes}
39+
userId = {userSSID}
40+
projId = {proj.id}
41+
/>);
42+
43+
return (
44+
<div>
45+
<Link to="/">
46+
<button type="button">Go Back</button>
47+
</Link>
48+
<div className = "projectContainer">
49+
{projects}
50+
</div>
51+
</div>
52+
);
53+
};
54+
55+
export default ProjectContainer;

app/src/Dashboard/navbar.jsx

Whitespace-only changes.

app/src/Dashboard/styles.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ $light-grey: #bfcbd4;
88
$light-blue: #759cc9;
99
$button-blue: #24BCFF; */
1010

11-
.form {
11+
.form , .project{
1212
display: flex;
1313
flex-direction: column;
1414
background-color: white;
@@ -23,7 +23,7 @@ $button-blue: #24BCFF; */
2323
width: 250px;
2424
}
2525

26-
.formContainer {
26+
.formContainer , .projectContainer{
2727
display: flex;
2828
flex-flow: row wrap;
2929
}

app/src/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ import {
2020
/*
2121
* Dashboard
2222
*/
23-
import Dashboard from './Dashboard/FormsContainer.jsx';
23+
// import TestDashboard from './Dashboard/FormsContainer.jsx';
24+
import ProjectDashboard from './Dashboard/ProjectContainer.jsx';
25+
2426
import styles from './Dashboard/styles.css';
2527
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
2628

@@ -56,7 +58,7 @@ ReactDOM.render(
5658
<Route exact path="/signup" component={SignUp} />
5759
<Route exact path="/password" component={FBPassWord} />
5860
<PrivateRoute exact path="/" component={App} />
59-
<Route exact path="/dashboard" component={Dashboard} />
61+
<Route exact path="/dashboard" component={ProjectDashboard} />
6062
<Route exact path="/tutorial" component={Tutorial} />
6163
<Route exact path="/tutorialPage/:learn" component={TutorialPage} />
6264
</Switch>

server/graphQL/resolvers/mutation.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,15 @@ const Project = {
4545
if (resp) {
4646
return ({
4747
name: resp.name,
48-
projId: resp._id,
48+
id: resp._id,
4949
userId: resp.userId,
5050
likes: resp.likes,
5151
})}
5252

5353
// TODO: Go back to this to see how to handle error later
5454
return {
5555
name: 'Error',
56-
projId: 'Error',
56+
id: 'Error',
5757
userId: 'Error',
5858
likes: -1,
5959
};
@@ -74,15 +74,15 @@ const Project = {
7474
if (resp) {
7575
return ({
7676
name: resp.name,
77-
projId: resp._id,
77+
id: resp._id,
7878
userId: resp.userId,
7979
likes: resp.likes,
8080
})}
8181

8282
// TODO: Go back to this to see how to handle error later
8383
return {
8484
name: 'Error',
85-
projId: 'Error',
85+
id: 'Error',
8686
userId: 'Error',
8787
likes: -1,
8888
};

server/graphQL/resolvers/query.js

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,39 +30,48 @@ const Project = {
3030
if (resp) {
3131
return ({
3232
name: resp.name,
33-
projId: resp._id,
33+
id: resp._id,
3434
userId: resp.userId,
3535
likes: resp.likes,
36-
})}
36+
});
37+
}
3738

3839
// TODO: Go back to this to see how to handle error later
39-
return {
40+
return {
4041
name: 'Error',
41-
projId: 'Error',
42+
id: 'Error',
4243
userId: 'Error',
4344
likes: -1,
4445
};
4546
},
4647

47-
getAllProjects: async () => {
48-
const resp = await Projects.find({});
48+
getAllProjects: async (parent, { userId }) => {
49+
let resp = await Projects.find({});
50+
// console.log('resp >>> ', resp);
51+
if (userId) {
52+
// use loosely equal for the callback because there are some discrepancy between the type of userId from the db vs from the mutation query
53+
resp = resp.filter(proj => proj.userId == userId);
54+
}
55+
4956
if (resp) {
5057
return resp.map(proj => ({
5158
name: proj.name,
52-
projId: proj._id,
59+
id: proj._id,
5360
userId: proj.userId,
5461
likes: proj.likes,
5562
}));
5663
}
64+
5765
// TODO: Go back to this to see how to handle error later
58-
return [{
66+
return [{
5967
name: 'Error',
60-
projId: 'Error',
68+
id: 'Error',
6169
userId: 'Error',
6270
likes: -1,
6371
}];
6472
},
6573

74+
6675
};
6776

6877
module.exports = {

server/graphQL/typeDefs.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,14 @@ const Project = gql`
3535
type Project {
3636
name: String!
3737
likes: Int
38-
projId: ID!
38+
id: ID!
3939
userId: ID!
4040
}
4141
4242
type Query {
4343
getProject(projId: ID!): Project
44-
getAllProjects: [Project]
44+
getAllProjects(userId: ID): [Project]
45+
getLikedProjects(userId: ID): [Project]
4546
}
4647
`;
4748

server/models/reactypeModels.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const sessionSchema = new Schema({
5858

5959
const projectSchema = new Schema({
6060
name: String,
61-
likes: Number,
61+
likes: { type: Number, default: 0 },
6262
project: { type: Object, required: true },
6363
userId: {
6464
type: Schema.Types.ObjectId,

0 commit comments

Comments
 (0)