├── client ├── components │ ├── Header.jsx │ ├── Contents.jsx │ ├── Nav.jsx │ ├── UserCards.jsx │ ├── Feed.jsx │ ├── Login.jsx │ ├── Profile.jsx │ └── App.jsx └── index.js ├── .gitignore ├── .DS_Store ├── server ├── .DS_Store ├── data │ ├── .DS_Store │ ├── images │ │ └── axolotl.jpg │ ├── userModel.js │ └── testData.js ├── package.json ├── server.js ├── controllers │ ├── loginController.js │ └── userController.js └── package-lock.json ├── css ├── images │ ├── css.png │ ├── html.png │ ├── logo.png │ ├── software.png │ └── science-formulas-4.jpg └── main.css ├── .eslintrc ├── webpack.config.js ├── index.html ├── package.json └── README.md /client/components/Header.jsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/components/Contents.jsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build/bundle.js 3 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axolotl-cs/axolotl/HEAD/.DS_Store -------------------------------------------------------------------------------- /server/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axolotl-cs/axolotl/HEAD/server/.DS_Store -------------------------------------------------------------------------------- /css/images/css.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axolotl-cs/axolotl/HEAD/css/images/css.png -------------------------------------------------------------------------------- /css/images/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axolotl-cs/axolotl/HEAD/css/images/html.png -------------------------------------------------------------------------------- /css/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axolotl-cs/axolotl/HEAD/css/images/logo.png -------------------------------------------------------------------------------- /server/data/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axolotl-cs/axolotl/HEAD/server/data/.DS_Store -------------------------------------------------------------------------------- /css/images/software.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axolotl-cs/axolotl/HEAD/css/images/software.png -------------------------------------------------------------------------------- /server/data/images/axolotl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axolotl-cs/axolotl/HEAD/server/data/images/axolotl.jpg -------------------------------------------------------------------------------- /css/images/science-formulas-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axolotl-cs/axolotl/HEAD/css/images/science-formulas-4.jpg -------------------------------------------------------------------------------- /client/index.js: -------------------------------------------------------------------------------- 1 | // This is the entry point for the app 2 | import React from 'react'; 3 | import { render } from 'react-dom'; 4 | import App from '../client/components/App.jsx'; //don't erase the .jsx 5 | // import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; 6 | 7 | 8 | 9 | render( 10 | 11 | , document.getElementById('content'), 12 | ); 13 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "1.0.0", 4 | "description": "Server for Axolotl project.", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "nodemon server.js" 8 | }, 9 | "author": "Axolotl", 10 | "license": "ISC", 11 | "dependencies": { 12 | "body-parser": "^1.18.2", 13 | "express": "^4.16.2", 14 | "json-odds-api": "^1.0.2", 15 | "mongoose": "^5.0.3", 16 | "nodemailer": "^4.4.2", 17 | "nodemon": "^1.14.12" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "parserOptions": { 4 | "ecmaVersion": 6, 5 | "sourceType": "module", 6 | "ecmaFeatures": { 7 | "jsx": true 8 | } 9 | }, 10 | "env": { 11 | "browser": true, 12 | "node": true, 13 | "es6": true 14 | }, 15 | "plugins": [ 16 | "react", 17 | "jsx-a11y" 18 | ], 19 | "rules": { 20 | "no-underscore-dangle": 0, 21 | "import/extensions": 0, 22 | "indent": 0 23 | } 24 | } -------------------------------------------------------------------------------- /client/components/Nav.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | class Nav extends Component { 4 | render() { 5 | let buttonText = 'Feed'; 6 | if (this.props.inFeed) buttonText = 'Profile'; 7 | return ( 8 | 15 | ); 16 | } 17 | } 18 | 19 | export default Nav; 20 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | 4 | const BUILD_DIR = path.resolve(__dirname, './build'); 5 | const APP_DIR = path.resolve(__dirname, './client'); 6 | 7 | const config = { 8 | entry: { 9 | main: APP_DIR + '/index.js' 10 | }, 11 | output: { 12 | filename: 'bundle.js', 13 | path: BUILD_DIR 14 | }, 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.(jsx|js)?$/, 19 | use: [{ 20 | loader: 'babel-loader', 21 | options: { 22 | cacheDirectory: true, 23 | presets: ['react', 'es2015'] 24 | } 25 | }] 26 | }] 27 | } 28 | }; 29 | 30 | module.exports = config; 31 | -------------------------------------------------------------------------------- /client/components/UserCards.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | const UserCards = (props) => { 4 | console.log(props); 5 | return ( 6 |
7 | 8 |

{props.user.username}

9 |

{props.user.location}

10 |
11 | 14 |
15 |
16 | 19 |
20 |
21 | ); 22 | }; 23 | 24 | export default UserCards; 25 | -------------------------------------------------------------------------------- /server/data/userModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const { Schema } = mongoose; 4 | 5 | // mongoose.connect('mongodb://localhost/axolotl'); 6 | 7 | // Hosting db on mlab 8 | mongoose.connect('mongodb://axol:ilovetesting@ds231228.mlab.com:31228/axolotl'); 9 | console.log('Connected to mongodb'); 10 | 11 | const userSchema = new Schema({ 12 | username: { type: String, unique: true, require: true }, 13 | password: { type: String, require: true }, 14 | location: { type: String, default: '' }, 15 | email: String, 16 | invited: [String], // Store the userId of the people you've invited to pair 17 | requests: [String], // List of people who have requested to pair with you 18 | connected: [String], // Store the userId of the people you've connected with 19 | bio: { type: String, default: '' }, 20 | skills: { type: String, default: '' }, 21 | interests: { type: String, default: '' }, 22 | image: { data: Buffer, contentType: String }, 23 | }); 24 | 25 | const User = mongoose.model('Users', userSchema); 26 | 27 | module.exports = User; 28 | -------------------------------------------------------------------------------- /client/components/Feed.jsx: -------------------------------------------------------------------------------- 1 | import fetch from 'isomorphic-fetch'; 2 | import React, { Component } from 'react'; 3 | import UserCards from './UserCards.jsx'; 4 | 5 | 6 | class Feed extends Component { 7 | constructor(props) { 8 | super(props); 9 | } 10 | 11 | render() { 12 | console.log('feed props', this.props); 13 | //console.log(props); 14 | 15 | // set to temp vars so they're accessible within map and filter 16 | let connect = this.props.connect; 17 | let userComp = this.props.user; 18 | let toProfile = this.props.toProfile; 19 | 20 | let feed = this.props.feed.filter(function(u){ 21 | return (u.username !== userComp.username); // don't put current user in feed 22 | }).map(function(feedUser, index) { 23 | // create UserCard from each user in list 24 | return 25 | }); 26 | 27 | return ( 28 |
29 |

Feed

30 | {feed} 31 |
32 | ); 33 | } 34 | } 35 | 36 | export default Feed; 37 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "src", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "webpack": "./node_modules/.bin/webpack -w", 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "build": "./node_modules/.bin/webpack -w" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "bcryptjs": "^2.4.3", 15 | "body-parser": "^1.18.2", 16 | "bootstrap": "^4.0.0", 17 | "cheerio": "^1.0.0-rc.2", 18 | "cookie-parser": "^1.4.3", 19 | "ejs": "^2.5.7", 20 | "express": "^4.16.2", 21 | "material-ui": "^0.20.0", 22 | "mongoose": "^5.0.3", 23 | "react": "^16.2.0", 24 | "react-dom": "^16.2.0", 25 | "react-materialize": "^1.1.2", 26 | "redux": "^3.7.2", 27 | "request": "^2.83.0" 28 | }, 29 | "devDependencies": { 30 | "babel": "^6.23.0", 31 | "babel-core": "^6.26.0", 32 | "babel-loader": "^7.1.2", 33 | "babel-preset-es2015": "^6.24.1", 34 | "babel-preset-react": "^6.24.1", 35 | "babel-register": "^6.26.0", 36 | "eslint": "^4.17.0", 37 | "eslint-config-airbnb": "^16.1.0", 38 | "eslint-plugin-import": "^2.8.0", 39 | "eslint-plugin-jsx-a11y": "^6.0.3", 40 | "eslint-plugin-react": "^7.6.1", 41 | "history": "^4.7.2", 42 | "react-router": "^4.2.0", 43 | "webpack": "^3.10.0" 44 | }, 45 | "proxy": "http://localhost:5000/" 46 | } 47 | -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const path = require('path'); 3 | const bodyParser = require('body-parser'); 4 | 5 | // Controllers to handle login and user functions 6 | const loginController = require('./controllers/loginController.js'); 7 | const userController = require('./controllers/userController.js'); 8 | 9 | // Function to set test data in db 10 | const testData = require('./data/testData.js'); 11 | 12 | const app = express(); 13 | 14 | app.use(express.static(path.join(__dirname, '../'))); 15 | app.use(bodyParser.json()); 16 | // app.use((req, res, next) => { 17 | // res.header(‘Access-Control-Allow-Origin’, ‘*’); 18 | // res.header(‘Access-Control-Allow-Headers’, ‘Origin, X-Requested-With, Content-Type, Accept’); 19 | // next(); 20 | // }); 21 | 22 | // Send root react page 23 | app.get('/', (req, res) => { res.sendFile('index.html'); }); 24 | 25 | // User logs in 26 | app.post('/login', loginController.login); 27 | 28 | // User signs up 29 | app.post('/signup', loginController.signup); 30 | 31 | // User sends an invite 32 | app.post('/invite', userController.invite); 33 | 34 | // User accepts an invite 35 | app.post('/connect', userController.connect); 36 | 37 | // Update user info 38 | app.post('/profile', userController.update); 39 | 40 | // Return list of users to render in feed 41 | app.get('/feed', userController.getUsers); 42 | 43 | // REMOVE ME!!! 44 | // I set fake data for testing 45 | // testData(); 46 | 47 | const port = process.env.PORT || 5000; 48 | app.listen(port, () => console.log(`Listening on port ${port}`)); 49 | -------------------------------------------------------------------------------- /client/components/Login.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | 4 | const Login = (props) => { 5 | console.log(props); 6 | 7 | //buttons change text when in signup / login 8 | let heading = (props.isSignup) ? 'Sign Up' : 'Log In'; 9 | let buttonText = (props.isSignup) ? 'Sign Up' : 'Log In'; 10 | let toggleText = (props.isSignup) ? 'Log In' : 'Sign Up'; 11 | 12 | // only added while in signup mode 13 | let extra = ( 14 |
15 | 19 |
20 |
21 | ) 22 | extra = (props.isSignup) ? extra : ''; 23 | 24 | return ( 25 |
26 |

{heading}

27 | 31 |
32 | 36 |
37 | {extra} 38 | { 39 | let username = document.getElementById('userIn').value; 40 | let password = document.getElementById('passIn').value; 41 | let email = (props.isSignup) ? document.getElementById('emailIn').value : null; 42 | console.log(username, password, email); 43 | props.clickFun(username, password, email); 44 | }}/> 45 | { 46 | props.toggle(); 47 | }}/> 48 |
49 | ); 50 | }; 51 | 52 | export default Login; 53 | -------------------------------------------------------------------------------- /server/data/testData.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File that sets up test data. 3 | */ 4 | 5 | const User = require('./userModel.js'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | 9 | // Path to test image 10 | const imgPath = path.join(__dirname, 'images/axolotl.jpg'); 11 | 12 | const image = {}; 13 | image.data = fs.readFileSync(imgPath); 14 | image.contentType = 'image/jpg'; 15 | // Clear database 16 | const testData = () => { 17 | User.remove({}, (err) => { 18 | if (err) throw err; 19 | }) 20 | .catch((err) => { 21 | // Add error handling... 22 | console.log(err); 23 | }); 24 | 25 | const andrew = new User({ 26 | username: 'andrew', 27 | password: 'ilovetesting', 28 | location: 'Playa Vista', 29 | email: 'afuselier23@gmail.com', 30 | bio: 'I love programming!', 31 | skills: 'Javascript', 32 | }); 33 | 34 | const eric = new User({ 35 | username: 'eric', 36 | password: 'ilovetesting', 37 | location: 'Venice', 38 | email: 'eric.rudolph.carrillo@gmail.com', 39 | bio: 'I love surfing!', 40 | skills: 'Javascript', 41 | }); 42 | 43 | const john = new User({ 44 | username: 'john', 45 | password: 'ilovetesting', 46 | location: 'Playa Vista', 47 | email: 'john@gmail.com', 48 | bio: 'I love programming!', 49 | skills: 'Javascript', 50 | }); 51 | 52 | const max = new User({ 53 | username: 'max', 54 | password: 'ilovetesting', 55 | location: 'Playa Vista', 56 | email: 'max@gmail.com', 57 | bio: 'I love programming!', 58 | skills: 'Javascript', 59 | }); 60 | 61 | const star = new User({ 62 | username: 'star', 63 | password: 'ilovetesting', 64 | location: 'Playa Vista', 65 | email: 'star@gmail.com', 66 | bio: 'I love programming!', 67 | skills: 'Javascript', 68 | }); 69 | 70 | andrew.save(); 71 | eric.save(); 72 | john.save(); 73 | max.save(); 74 | star.save(); 75 | }; 76 | 77 | module.exports = testData; 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | Axolotl* is a platform that brings coders together. It connects prospective pair-programmers, allowing them to search for similarly-inclined people in their area and choose potential partners based on their skills, interests and background. When matched, our app shares their contact information so they can meet up and start coding! 4 | 5 | ## Features 6 | - Persistent user profiles stored on a cloud database 7 | - Email notification on successful match 8 | - Stable user interface that allows users to: 9 | - Sign up, login and sign out 10 | - View and edit profile information 11 | - Scroll through other users and invite them to pair program 12 | - Navigate to other user profiles to read bios and get more info 13 | - Easily navigate between views in the app 14 | 15 | ## Getting Started 16 | - Fork repo to GitHub profile and clone files to your computer 17 | - Open two terminal windows 18 | - Navigate first window to main project folder (`axolotl`) 19 | - Navigate second window to `axolotl/server` 20 | - Run `npm install` in both folders (server has a separate package.json) 21 | - Run `npm run build` from within main project folder, keep running for auto rebuilds 22 | - Run `npm start` in server folder 23 | - Navigate to [localhost:5000](http://localhost:5000/) in browser to view application 24 | - Database (Mongo, using Mongoose) is hosted by [mLab](https://mlab.com/) 25 | 26 | ## Future Features 27 | 28 | Iterate on our project! It's stable and well-documented(ish), so you can jump right in and add the stuff you think would be cool! 29 | 30 | ### Iteration Ideas 31 | - Add support for user photos 32 | - Render a list of matched users in Profile 33 | - Separate matched, invited and nearby users in Feed 34 | - Rework how skills and interests are handled 35 | - Search users by skills / interests / location in Feed 36 | - Add support for chat between matched users 37 | - Could use web sockets for instant updates and save content to DB 38 | - Might show up when you navigate to a matched user's profile 39 | - Finish styling application 40 | - Add React Router support 41 | -------------------------------------------------------------------------------- /server/controllers/loginController.js: -------------------------------------------------------------------------------- 1 | const User = require('../data/userModel.js'); 2 | 3 | const loginController = {}; 4 | 5 | // Handle user login 6 | loginController.login = (req, res, next) => { 7 | const user = { 8 | username: req.body.username, 9 | password: req.body.password, 10 | }; 11 | // Object to respond to client with 12 | const data = {}; 13 | // Look for the user with the given username and password 14 | User.find(user, (err, result) => { 15 | if (err) throw err; 16 | if (result[0]) { 17 | data.user = result[0]; 18 | } else { 19 | res.status(200).json('Not found.'); 20 | return next(); 21 | } 22 | }) 23 | .then(() => { 24 | User.find({}, (err, userList) => { 25 | if (err) throw err; 26 | data.list = userList; 27 | res.status(200).json(data); 28 | return next(); 29 | }); 30 | }) 31 | .catch((err) => { 32 | // Add error handling... 33 | console.log(err); 34 | }); 35 | }; 36 | 37 | // Handle new user creation 38 | loginController.signup = (req, res, next) => { 39 | const { username, password, email } = req.body; 40 | // const newUser = new User({ username, password, email }); 41 | // Object to respond to client with 42 | const data = {}; 43 | // Save the user and send back the user object 44 | User.find({ username }, (err, result) => { 45 | if (err) throw err; 46 | if (result.length === 0) { 47 | const newUser = new User({ username, password, email }); 48 | newUser.save() 49 | .then(() => { 50 | User.find({ username }, (err, result) => { 51 | if (err) throw err; 52 | data.user = result[0]; 53 | }); 54 | }) 55 | .then(() => { 56 | User.find({}, (err, userList) => { 57 | if (err) throw err; 58 | data.list = userList; 59 | res.status(200).json(data); 60 | return next(); 61 | }); 62 | }) 63 | .catch((err) => { 64 | // Add error handling... 65 | console.log(err); 66 | }); 67 | } else { 68 | return res.json('Seats taken.'); 69 | } 70 | }) 71 | .catch((err) => { 72 | // Add error handling... 73 | console.log(err); 74 | }); 75 | }; 76 | 77 | module.exports = loginController; 78 | -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | /* Profile STYLING */ 2 | /* 3 | body { 4 | background: #1D212A; 5 | } */ 6 | 7 | /* //PROFILE STYLING */ 8 | 9 | /* .responsive-image { 10 | background-image: url(client/images/science-formulas-4.jpg); 11 | } 12 | 13 | @media screen and (min-width: 320px) { 14 | .responsive-image { 15 | background-image: url(http://placehold.it/640x400); 16 | } 17 | } 18 | @media screen and (min-width: 640px) 19 | { 20 | .responsive-image { 21 | background-image: url(http://placehold.it/1024x1024); 22 | } 23 | } 24 | @media screen and (min-width: 1024px) { 25 | .responsive-image { 26 | background-image: url(client/images/science-formulas-4.jpg); 27 | } 28 | } */ 29 | body { 30 | background: #1D212A; 31 | color: whitesmoke; 32 | } 33 | 34 | .masthead { 35 | background-image: url("https://www.hongkiat.com/blog/wp-content/uploads/css3-circular-elliptical-gradient/ellipse-gradient-syntax.jpg"); 36 | overflow: hidden; 37 | color: rgb(230, 225, 225); 38 | padding: 1em; 39 | /* border-top: 6px solid #9BA800; */ 40 | background-color: #404040; 41 | height: 500px; 42 | width: 100%; 43 | 44 | 45 | &.responsive-image { 46 | background-position: center; 47 | background-attachment: scroll; 48 | background-repeat: no-repeat; 49 | -webkit-background-size: cover; 50 | -moz-background-size: cover; 51 | -o-background-size: cover; 52 | background-size: cover; 53 | } 54 | } 55 | 56 | .buttonConnect { 57 | position: relative; 58 | top: -22px; 59 | bottom: 5px; 60 | left: 986px; 61 | right: 14px; 62 | width: 261px; 63 | height: 73px; 64 | } 65 | 66 | .profile-Image { 67 | position: relative; 68 | top: -31px; 69 | height: 250px; 70 | width: 250px; 71 | border: 5px solid white; 72 | } 73 | 74 | 75 | textarea { 76 | margin-top: 11px; 77 | margin-left: -2px; 78 | width: 500px; 79 | height: 100px; 80 | background: none repeat scroll 0 0 whitesmoke; 81 | border-color: -moz-use-text-color rgb(194, 125, 125) #FFFFFF -moz-use-text-color; 82 | border-image: none; 83 | border-radius: 6px 6px 6px 6px; 84 | border-style: none solid solid none; 85 | border-width: medium 1px 1px medium; 86 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12) inset; 87 | color: black; 88 | /* font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; */ 89 | font-size: 1em; 90 | line-height: 1.4em; 91 | padding: 5px 8px; 92 | transition: background-color 0.2s ease 0s; 93 | } 94 | 95 | 96 | textarea:focus { 97 | background: none repeat scroll 0 0 #FFFFFF; 98 | outline-width: 0; 99 | } 100 | 101 | #bio { 102 | position: relative; 103 | top: 5px; 104 | left: 5px; 105 | right: 5px; 106 | bottom: 5px; 107 | } 108 | 109 | #userInfo { 110 | position: relative; 111 | top: 5px; 112 | left: 5px; 113 | right: 5px; 114 | bottom: 5px; 115 | } 116 | 117 | .languages { 118 | position: relative; 119 | float: right; 120 | top: -503px; 121 | right -49px; 122 | padding-top: 15px; 123 | } -------------------------------------------------------------------------------- /server/controllers/userController.js: -------------------------------------------------------------------------------- 1 | const User = require('../data/userModel.js'); 2 | 3 | // Email API 4 | const nodemailer = require('nodemailer'); 5 | 6 | const transporter = nodemailer.createTransport({ 7 | service: 'gmail', 8 | auth: { 9 | user: 'axolotl.codesmith@gmail.com', 10 | pass: 'ilovetesting', 11 | }, 12 | }); 13 | 14 | const userController = {}; 15 | 16 | // Return the entire list of users 17 | userController.getUsers = (req, res) => { 18 | User.find({}, (err, userList) => { 19 | if (userList.length > 0) { 20 | res.status(200).json(userList); 21 | } 22 | }); 23 | }; 24 | 25 | // Add a user to the invite array 26 | userController.invite = (req, res) => { 27 | const { username, target } = req.body; 28 | User.update({ username }, { $push: { invited: target } }) 29 | .then(() => { 30 | User.find({ username }, (err, user) => { 31 | if (err) throw err; 32 | res.status(200).json(user[0]); 33 | }); 34 | }) 35 | .then(() => { 36 | User.update({ username: target }, { $push: { requests: username } }, (err) => { 37 | if (err) throw err; 38 | }); 39 | }) 40 | .catch((err) => { 41 | // Add error handling... 42 | console.log(err); 43 | }); 44 | }; 45 | 46 | // Accept a request to pair 47 | userController.connect = (req, res) => { 48 | const { username, target } = req.body; 49 | let email = ''; 50 | User.update({ username }, { $push: { connected: target } }) 51 | .then(() => { 52 | User.find({ username }, (err, user) => { 53 | if (err) throw err; 54 | res.status(200).json(user[0]); 55 | }); 56 | }) 57 | .then(() => { 58 | User.update({ username: target }, { $push: { connected: username } }, (err) => { 59 | if (err) throw err; 60 | }); 61 | }) 62 | .then(() => { 63 | User.find({ username }, (err, result) => { 64 | if (err) throw err; 65 | email = result.email; 66 | }); 67 | }) 68 | .then(() => { 69 | User.find({ username: target }, (err, result) => { 70 | const mailOptions = { 71 | from: 'axolotl.codesmith@gmail.com', 72 | to: result[0].email, 73 | subject: 'New Pair Programming Connect', 74 | html: `Contact your potential abductor: ${username} (${email})`, 75 | }; 76 | transporter.sendMail(mailOptions, (err, info) => { 77 | if (err) throw err; 78 | }); 79 | }); 80 | }) 81 | .catch((err) => { 82 | // Add error handling... 83 | console.log(err); 84 | }); 85 | }; 86 | 87 | // Update user info 88 | userController.update = (req, res) => { 89 | // The post request includes a user property that stores the 90 | // contents of the user object with updates 91 | let user = req.body; 92 | const { password, location, bio, email, skills, interests } = user; 93 | const updates = { password, email, location, bio, skills, interests }; 94 | User.update({ username: user.username }, updates) 95 | .then(() => { 96 | User.find({username: user.username }, (err, user) => { 97 | res.status(200).json(user[0]); 98 | }); 99 | }) 100 | .catch((err) => { 101 | // Add error handling... 102 | console.log(err); 103 | }); 104 | } 105 | 106 | module.exports = userController; 107 | -------------------------------------------------------------------------------- /client/components/Profile.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Button } from 'react-bootstrap'; 3 | // import CardExampleWithAvatar from './CardExampleWithAvatar.jsx' 4 | 5 | // user object passed 6 | // edit: boolean 7 | // edit: function 8 | // sumbit : function 9 | 10 | class Profile extends Component { 11 | constructor(props) { 12 | super(props) 13 | } 14 | 15 | render() { 16 | 17 | let connectOrEdit = (!this.props.myProfile) ? 'Connect' : 'Edit'; 18 | //let connectOrEdit = (this.props.myProfile) ? 'Edit' : 'Connect'; 19 | let user = this.props.user; 20 | let clickFun = this.props.clickFun; 21 | console.log('user', user); 22 | 23 | let submit = ( 24 | { 25 | 26 | // have to update new user obect with new info 27 | let bio = document.getElementById('bioIn').value; 28 | let skills = document.getElementById('skillsIn').value; 29 | let interests = document.getElementById('interestsIn').value; 30 | console.log(bio, skills, interests); 31 | 32 | let updatedUser = Object.assign( 33 | user, 34 | {bio, skills, interests} 35 | ) 36 | this.props.submit(updatedUser); 37 | }}/> 38 | ) 39 | submit = (this.props.edit) ? submit : ''; 40 | 41 | return ( 42 | 43 |
44 | 45 |
46 |
47 | {/*

Headding Spaced with padding

48 |

Some sort of lovely supporting title

*/} 49 |
50 |
51 |
52 | { 53 | clickFun(user); 54 | }}/> 55 |
56 | {/* */} 57 | 58 |
59 |
60 |
61 |

{user.username}

62 |
63 |
64 |

Bio

65 |