Skip to content

Commit 81a4dcc

Browse files
authored
Merge pull request #63 from andrewjcho84/projectManagement
Project management and Server Reintegration
2 parents d676cf6 + 014034e commit 81a4dcc

21 files changed

+911
-16
lines changed

app/electron/main.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ async function createWindow() {
6464
webPreferences: {
6565
zoomFactor: 0.7,
6666
// enable devtools when in development mode
67-
devTools: isDev,
67+
devTools: true,
6868
// crucial security feature - blocks rendering process from having access to node moduels
6969
nodeIntegration: false,
7070
// web workers will not have access to node
@@ -340,7 +340,7 @@ ipcMain.on('set_cookie', event => {
340340
// this if statement is necessary or the setInterval on main app will constantly run and will emit this event.reply, causing a memory leak
341341
// checking for a cookie inside array will only emit reply when a cookie exists
342342
if (cookie[0]) {
343-
console.log(cookie);
343+
//console.log(cookie);
344344
event.reply('give_cookie', cookie);
345345
}
346346
})
@@ -353,9 +353,9 @@ ipcMain.on('set_cookie', event => {
353353
ipcMain.on('delete_cookie', event => {
354354
session.defaultSession.cookies
355355
.remove(serverUrl, 'ssid')
356-
.then(removed => {
357-
console.log('Cookies deleted', removed);
358-
})
356+
// .then(removed => {
357+
// console.log('Cookies deleted', removed);
358+
// })
359359
.catch(err => console.log('Error deleting cookie:', err));
360360
});
361361

app/src/components/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { stateContext } from '../context/context';
77
import initialState from '../context/initialState';
88
import reducer from '../reducers/componentReducer';
99
import localforage from 'localforage';
10-
import { getProjects, saveProject } from '../helperFunctions/projectGetSave';
10+
import { getProjects, saveProject } from '../helperFunctions/projectGetSaveDel';
1111
import Cookies from 'js-cookie';
1212

1313
// Intermediary component to wrap main App component with higher order provider components
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import React, { useState, useContext, useEffect } from 'react';
2+
import { makeStyles } from '@material-ui/core/styles';
3+
import Button from '@material-ui/core/Button';
4+
import Avatar from '@material-ui/core/Avatar';
5+
import List from '@material-ui/core/List';
6+
import ListItem from '@material-ui/core/ListItem';
7+
import ListItemAvatar from '@material-ui/core/ListItemAvatar';
8+
import ListItemText from '@material-ui/core/ListItemText';
9+
import DialogTitle from '@material-ui/core/DialogTitle';
10+
import Dialog from '@material-ui/core/Dialog';
11+
import DeleteRoundedIcon from '@material-ui/icons/DeleteRounded';
12+
import { blue } from '@material-ui/core/colors';
13+
14+
import {
15+
getProjects,
16+
deleteProject
17+
} from '../../helperFunctions/projectGetSaveDel';
18+
import localforage from 'localforage';
19+
import { stateContext } from '../../context/context';
20+
import initialState from '../../context/initialState';
21+
22+
export interface ProjectDialogProps {
23+
open: boolean;
24+
projects: Array<Object>;
25+
onClose: () => void;
26+
}
27+
28+
// The options to be rendered when dialog is open
29+
function ProjectsDialog(props: ProjectDialogProps) {
30+
const classes = useStyles();
31+
const { onClose, open, projects } = props;
32+
const [state, dispatch] = useContext(stateContext);
33+
34+
// If no projects selected, keep the name of the current displayed
35+
const handleClose = () => {
36+
// onClose(selectedValue);
37+
onClose();
38+
};
39+
40+
// If new project selected, close and set value to new project name
41+
const handleDelete = (value: string) => {
42+
const selectedProject = projects.filter(
43+
(project: any) => project.name === value
44+
)[0];
45+
console.log('selectedProject is', selectedProject);
46+
deleteProject(selectedProject);
47+
localforage.clear();
48+
dispatch({ type: 'SET INITIAL STATE', payload: initialState });
49+
onClose();
50+
};
51+
52+
return (
53+
<Dialog
54+
onClose={handleClose}
55+
aria-labelledby="project-dialog-title"
56+
open={open}
57+
>
58+
<DialogTitle id="project-dialog-title">Delete Project</DialogTitle>
59+
<List>
60+
{projects.map((project: any, index: number) => (
61+
<ListItem
62+
button
63+
onClick={() => handleDelete(project.name)}
64+
key={index}
65+
>
66+
<ListItemAvatar>
67+
<Avatar className={classes.avatar}>
68+
<DeleteRoundedIcon />
69+
</Avatar>
70+
</ListItemAvatar>
71+
<ListItemText primary={project.name} />
72+
</ListItem>
73+
))}
74+
</List>
75+
</Dialog>
76+
);
77+
}
78+
79+
export default function ProjectsFolder() {
80+
const [open, setOpen] = useState(false);
81+
const [projects, setProjects] = useState([{ hello: 'cat' }]);
82+
83+
const classes = useStyles();
84+
85+
const handleClickOpen = () => {
86+
getProjects().then(data => {
87+
if (data) {
88+
setProjects(data);
89+
setOpen(true);
90+
}
91+
});
92+
};
93+
94+
const handleClose = () => {
95+
setOpen(false);
96+
};
97+
98+
return (
99+
<div>
100+
<Button
101+
className={classes.button}
102+
variant="outlined"
103+
color="primary"
104+
onClick={handleClickOpen}
105+
endIcon={<DeleteRoundedIcon />}
106+
>
107+
Delete Project
108+
</Button>
109+
<ProjectsDialog open={open} onClose={handleClose} projects={projects} />
110+
</div>
111+
);
112+
}
113+
114+
const useStyles = makeStyles({
115+
button: {
116+
width: '55%',
117+
backgroundColor: 'rgba(1,212,109,0.1)',
118+
fontSize: '1em',
119+
minWidth: '300px',
120+
marginTop: '10px',
121+
marginBotton: '10px'
122+
},
123+
avatar: {
124+
backgroundColor: blue[100],
125+
color: blue[600]
126+
}
127+
});

app/src/components/right/ProjectsFolder.tsx renamed to app/src/components/right/OpenProjects.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import FolderOpenIcon from '@material-ui/icons/FolderOpen';
1212
import AddIcon from '@material-ui/icons/Add';
1313
import { blue } from '@material-ui/core/colors';
1414

15-
import { getProjects } from '../../helperFunctions/projectGetSave';
15+
import { getProjects } from '../../helperFunctions/projectGetSaveDel';
1616
import { stateContext } from '../../context/context';
1717

1818
export interface ProjectDialogProps {
@@ -65,14 +65,15 @@ function ProjectsDialog(props: ProjectDialogProps) {
6565
</ListItem>
6666
))}
6767
{/* Change state to empty for new project */}
68+
{/* ***TODO*** Add project functionality
6869
<ListItem autoFocus button onClick={() => handleClose()}>
6970
<ListItemAvatar>
7071
<Avatar>
7172
<AddIcon />
7273
</Avatar>
7374
</ListItemAvatar>
7475
<ListItemText primary="New Project" />
75-
</ListItem>
76+
</ListItem> */}
7677
</List>
7778
</Dialog>
7879
);

app/src/components/right/ProjectManager.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ import { useHistory, withRouter } from 'react-router-dom';
1515

1616
import exportProject from '../../utils/exportProject.util';
1717

18-
import ProjectsFolder from './ProjectsFolder';
18+
import ProjectsFolder from './OpenProjects';
1919
import createModal from './createModal';
2020
import LoginButton from './LoginButton';
2121
import SaveProjectButton from './SaveProjectButton';
22+
import DeleteProjects from './DeleteProjects';
2223

2324
const ProjectManager = () => {
2425
// state to keep track of whether a modal should display
@@ -156,6 +157,17 @@ const ProjectManager = () => {
156157
return (
157158
// <div className={classes.logoutButton}>
158159
<div className={classes.projectManagerWrapper}>
160+
{state.name && state.isLoggedIn ? (
161+
<p style={{ color: 'white' }}>
162+
Your current project is <strong>{state.name}</strong>
163+
</p>
164+
) : null}
165+
{!state.name && state.isLoggedIn ? (
166+
<p style={{ color: 'white' }}>
167+
Project will not be saved until it is named!!!
168+
</p>
169+
) : null}
170+
159171
<div className={classes.projectTypeWrapper}>
160172
<FormControl>
161173
<Select
@@ -173,6 +185,7 @@ const ProjectManager = () => {
173185
</div>
174186
{state.isLoggedIn ? <SaveProjectButton /> : ''}
175187
{state.isLoggedIn ? <ProjectsFolder /> : ''}
188+
{state.isLoggedIn ? <DeleteProjects /> : ''}
176189
{/* <div className={classes.btnGroup}> */}
177190
<Button
178191
className={classes.button}
@@ -209,7 +222,8 @@ const useStyles = makeStyles({
209222
margin: '40px',
210223
display: 'flex',
211224
flexDirection: 'column',
212-
alignItems: 'center'
225+
alignItems: 'center',
226+
justifySelf: 'flex-end'
213227
},
214228

215229
logoutButton: {

app/src/components/right/SaveProjectButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import DialogActions from '@material-ui/core/DialogActions';
99
import DialogContent from '@material-ui/core/DialogContent';
1010
import DialogTitle from '@material-ui/core/DialogTitle';
1111
import SaveOutlinedIcon from '@material-ui/icons/SaveOutlined';
12-
import { saveProject } from '../../helperFunctions/projectGetSave';
12+
import { saveProject } from '../../helperFunctions/projectGetSaveDel';
1313

1414
export default function FormDialog() {
1515
const [open, setOpen] = useState(false);

app/src/helperFunctions/projectGetSave.ts renamed to app/src/helperFunctions/projectGetSaveDel.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ if (isDev) {
55
}
66
// helper functions that will do fetch requests to get and save user/guest projects
77

8-
export const getProjects = (): Promise<Object> => {
8+
export const getProjects = (): Promise<any> => {
9+
//console.log("Loading user's projects...");
910
let userId = window.localStorage.getItem('ssid');
1011
const body = JSON.stringify({ userId });
1112
const projects = fetch(`${serverURL}/getProjects`, {
@@ -29,7 +30,6 @@ export const saveProject = (
2930
name: String,
3031
workspace: Object
3132
): Promise<Object> => {
32-
3333
const body = JSON.stringify({
3434
name,
3535
project: workspace,
@@ -50,3 +50,25 @@ export const saveProject = (
5050
.catch(err => console.log(`Error saving project ${err}`));
5151
return project;
5252
};
53+
54+
export const deleteProject = (project: any): Promise<Object> => {
55+
const body = JSON.stringify({
56+
name: project.name,
57+
userId: window.localStorage.getItem('ssid')
58+
});
59+
const deletedProject = fetch(`${serverURL}/deleteProject`, {
60+
method: 'DELETE',
61+
credentials: 'include',
62+
headers: {
63+
'Content-Type': 'application/json'
64+
},
65+
body
66+
})
67+
.then(res => res.json())
68+
.then(data => {
69+
console.log('deleted project at end of fetch', data);
70+
return data;
71+
})
72+
.catch(err => console.log(`Error deleting project ${err}`));
73+
return deletedProject;
74+
};

package.json

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"scripts": {
2828
"postinstall": "ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=true electron-builder install-app-deps",
2929
"dev-server": "cross-env NODE_ENV=development webpack-dev-server --config ./webpack.development.js",
30-
"dev": "concurrently --success first \"npm run dev-server\" \"cross-env NODE_ENV=development electron .\" -k",
30+
"dev": "concurrently --success first \"npm run dev-server\" \"cross-env NODE_ENV=development electron .\" \"npm run server\" -k",
3131
"prod-build": "cross-env NODE_ENV=production npx webpack --mode=production --config ./webpack.production.js",
3232
"prod": "npm run prod-build && electron .",
3333
"pack": "electron-builder --dir",
@@ -36,7 +36,8 @@
3636
"dist-linux": "npm run prod-build && electron-builder --linux",
3737
"dist-windows": "npm run prod-build && electron-builder --windows",
3838
"dist-all": "npm run prod-build && electron-builder --mac --linux --windows",
39-
"test": "cross-env NODE_ENV=test jest --verbose"
39+
"test": "cross-env NODE_ENV=test jest --verbose",
40+
"server": "nodemon server/server.js"
4041
},
4142
"repository": {
4243
"type": "git",
@@ -100,8 +101,11 @@
100101
"app-root-path": "^3.0.0",
101102
"autoprefixer": "^9.0.1",
102103
"babel-polyfill": "^6.26.0",
104+
"bcryptjs": "^2.4.3",
103105
"concurrently": "^5.1.0",
104106
"connected-react-router": "^6.8.0",
107+
"cookie-parser": "^1.4.5",
108+
"cors": "^2.8.5",
105109
"electron-debug": "^3.1.0",
106110
"electron-devtools-installer": "^2.2.4",
107111
"electron-splashscreen": "^1.0.0",
@@ -110,6 +114,8 @@
110114
"immutable": "^4.0.0-rc.12",
111115
"js-cookie": "^2.2.1",
112116
"localforage": "^1.7.2",
117+
"passport": "^0.4.1",
118+
"passport-github2": "^0.1.12",
113119
"node-fetch": "^2.6.0",
114120
"prettier": "^1.19.1",
115121
"prop-types": "^15.6.2",
@@ -154,7 +160,7 @@
154160
"eslint-plugin-react": "^7.20.3",
155161
"html-loader": "^1.1.0",
156162
"html-webpack-plugin": "^3.1.0",
157-
"jest": "^25.2.6",
163+
"jest": "^25.5.4",
158164
"mini-css-extract-plugin": "^0.9.0",
159165
"mongodb": "^3.5.9",
160166
"mongoose": "^5.9.22",
@@ -164,6 +170,7 @@
164170
"sass-loader": "^7.0.3",
165171
"spectron": "^11.1.0",
166172
"style-loader": "^0.20.3",
173+
"supertest": "^4.0.2",
167174
"ts-jest": "^25.3.0",
168175
"ts-node": "^8.10.2",
169176
"typescript": "^3.9.6",

server/Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: npm run start

server/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<p align="center">
2+
<img width="300" src="reactypeserverlogo.png">
3+
<h1 align="center">ReacType Server</h1>
4+
</p>
5+
6+
**ReacType Server** is the backend complement to the visual React prototyping tool **ReacType**. It is built in **Node.js** with the **Express** framework linked to **MongoDB** to handle user authentication (personal accounts on our own database as well as through Github Oauth), sessions, and user project management. The server itself is officially deployed through Heroku, but you can host your own local environment to communicate with the database with this repo.
7+
8+
If `npm` is your package manager, you just need to run the script `npm run dev` and it will start the server on `http://localhost:5000` for your development environment.
9+
10+
Endpoint testing is currently integrated with Jest and Supertest as well and can be run by `npm run test` or `npm run test:watch` for watch mode.

0 commit comments

Comments
 (0)