From 3da244905008c245d3989b4e195aae280befda76 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Thu, 21 Nov 2019 18:10:44 -0500 Subject: [PATCH 1/4] change topic display to user-specific topics --- twistter-frontend/src/pages/user.js | 515 ++++++++++++++-------------- 1 file changed, 261 insertions(+), 254 deletions(-) diff --git a/twistter-frontend/src/pages/user.js b/twistter-frontend/src/pages/user.js index 750fc0a..335b1cf 100644 --- a/twistter-frontend/src/pages/user.js +++ b/twistter-frontend/src/pages/user.js @@ -1,290 +1,297 @@ /* eslint-disable */ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import axios from 'axios'; +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import axios from "axios"; //import '../App.css'; // Material-UI -import withStyles from '@material-ui/core/styles/withStyles'; -import { makeStyles, styled } from '@material-ui/core/styles'; -import { Link } from 'react-router-dom'; -import Card from '@material-ui/core/Card'; -import CardMedia from '@material-ui/core/CardMedia'; -import CardContent from '@material-ui/core/CardContent'; -import Button from '@material-ui/core/Button'; -import Grid from '@material-ui/core/Grid'; +import withStyles from "@material-ui/core/styles/withStyles"; +import { makeStyles, styled } from "@material-ui/core/styles"; +import { Link } from "react-router-dom"; +import Card from "@material-ui/core/Card"; +import CardMedia from "@material-ui/core/CardMedia"; +import CardContent from "@material-ui/core/CardContent"; +import Button from "@material-ui/core/Button"; +import Grid from "@material-ui/core/Grid"; -import Chip from '@material-ui/core/Chip'; -import Typography from '@material-ui/core/Typography'; -import AddCircle from '@material-ui/icons/AddCircle'; -import TextField from '@material-ui/core/TextField'; -import VerifiedIcon from '@material-ui/icons/CheckSharp'; -import Paper from '@material-ui/core/Paper'; -import GridList from '@material-ui/core/GridList'; -import GridListTile from '@material-ui/core/GridListTile'; -import GridListTileBar from '@material-ui/core/GridListTileBar'; -import Container from '@material-ui/core/Container'; +import Chip from "@material-ui/core/Chip"; +import Typography from "@material-ui/core/Typography"; +import AddCircle from "@material-ui/icons/AddCircle"; +import TextField from "@material-ui/core/TextField"; +import VerifiedIcon from "@material-ui/icons/CheckSharp"; +import Paper from "@material-ui/core/Paper"; +import GridList from "@material-ui/core/GridList"; +import GridListTile from "@material-ui/core/GridListTile"; +import GridListTileBar from "@material-ui/core/GridListTileBar"; +import Container from "@material-ui/core/Container"; // component -import '../App.css'; -import noImage from '../images/no-img.png'; -import Writing_Microblogs from '../Writing_Microblogs'; +import "../App.css"; +import noImage from "../images/no-img.png"; +import Writing_Microblogs from "../Writing_Microblogs"; const MyChip = styled(Chip)({ - margin: 2, - color: 'primary' + margin: 2, + color: "primary" }); const styles = { - button: { - positon: 'relative', - float: 'left', - marginLeft: 30, - marginTop: 20 - }, - paper: { - // marginLeft: "10%", - // marginRight: "10%" - }, - card: { - marginBottom: 10 - }, - profileImage: { - marginTop: 20 - }, - topicsContainer: { - border: 'lightgray solid 1px', - marginTop: 20, - paddingTop: 10, - paddingBottom: 10, - height: 300 - }, - addCircle: { - width: 65, - height: 65, - marginTop: 10 - }, - username: { - marginBottom: 100 - } + button: { + positon: "relative", + float: "left", + marginLeft: 30, + marginTop: 20 + }, + paper: { + // marginLeft: "10%", + // marginRight: "10%" + }, + card: { + marginBottom: 10 + }, + profileImage: { + marginTop: 20 + }, + topicsContainer: { + border: "lightgray solid 1px", + marginTop: 20, + paddingTop: 10, + paddingBottom: 10, + height: 300 + }, + addCircle: { + width: 65, + height: 65, + marginTop: 10 + }, + username: { + marginBottom: 100 + } }; class user extends Component { - state = { - profile: null, - imageUrl: null, - topics: null, - newTopic: null - }; + state = { + profile: null, + imageUrl: null, + topics: null, + newTopic: null + }; - handleDelete = (topic) => { - axios - .delete(`/deleteTopic/${topic.id}`) - .then(function() { - location.reload(); - }) - .catch(function(err) { - console.log(err); - }); - }; + handleDelete = topic => { + axios + .delete(`/deleteTopic/${topic.id}`) + .then(function() { + location.reload(); + }) + .catch(function(err) { + console.log(err); + }); + }; - handleAddCircle = () => { - axios - .post('/putTopic', { - topic: this.state.newTopic - }) - .then(function() { - location.reload(); - }) - .catch(function(err) { - console.log(err); - }); - }; + handleAddCircle = () => { + axios + .post("/putTopic", { + topic: this.state.newTopic + }) + .then(function() { + location.reload(); + }) + .catch(function(err) { + console.log(err); + }); + }; - handleChange(event) { - this.setState({ - newTopic: event.target.value - }); - } + handleChange(event) { + this.setState({ + newTopic: event.target.value + }); + } - componentDidMount() { - axios - .get('/user') - .then((res) => { - this.setState({ - profile: res.data.credentials.handle, - imageUrl: res.data.credentials.imageUrl, - verified: res.data.credentials.verified ? res.data.credentials.verified : false - }); - }) - .catch((err) => console.log(err)); + componentDidMount() { + axios + .get("/user") + .then(res => { + this.setState({ + profile: res.data.credentials.handle, + imageUrl: res.data.credentials.imageUrl, + verified: res.data.credentials.verified + ? res.data.credentials.verified + : false, + topics: res.data.credentials.followedTopics + }); + }) + .catch(err => console.log(err)); - axios - .get('/getAllTopics') - .then((res) => { - this.setState({ - topics: res.data - }); - }) - .catch((err) => console.log(err)); + axios + .get("/getallPostsforUser") + .then(res => { + console.log(res.data); + this.setState({ + posts: res.data + }); + }) + .catch(err => console.log(err)); + } - axios - .get('/getallPostsforUser') - .then((res) => { - console.log(res.data); - this.setState({ - posts: res.data - }); - }) - .catch((err) => console.log(err)); - } + render() { + const { classes } = this.props; + let authenticated = this.props.user.authenticated; - render() { - const { classes } = this.props; - let authenticated = this.props.user.authenticated; + let profileMarkup = this.state.profile ? ( +
+ + @{this.state.profile}{" "} + {this.state.verified ? ( + + ) : null} + +
+ ) : ( +

loading username...

+ ); - let profileMarkup = this.state.profile ? ( -
- - @{this.state.profile} {this.state.verified ? : null} - -
- ) : ( -

loading username...

- ); + let topicsMarkup = this.state.topics ? ( + this.state.topics.map( + topic => ( + this.handleDelete(topic)} + /> + ) // console.log({ topic }.topic.id) + ) + ) : ( +

 loading topics...

+ ); - let topicsMarkup = this.state.topics ? ( - this.state.topics.map( - (topic) => ( - this.handleDelete(topic)} - /> - ) // console.log({ topic }.topic.id) - ) - ) : ( -

 loading topics...

- ); + let imageMarkup = this.state.imageUrl ? ( + + ) : ( + + ); - let imageMarkup = this.state.imageUrl ? ( - - ) : ( - - ); + let postMarkup = this.state.posts ? ( + this.state.posts.map(post => ( + + + + {this.state.imageUrl ? ( + + ) : ( + + )} + + + {post.userHandle} + + + {post.createdAt} + +
+ + {post.microBlogTitle} + + {post.body} +
+ + Topics: {post.microBlogTopics} + +
+ + Likes {post.likeCount} Comments {post.commentCount} + +
+
+ )) + ) : ( +

My Posts

+ ); - let postMarkup = this.state.posts ? ( - this.state.posts.map((post) => ( - - - - {this.state.imageUrl ? ( - - ) : ( - - )} - - - {post.userHandle} - - - {post.createdAt} - -
- - {post.microBlogTitle} - - {post.body} -
- - Topics: {post.microBlogTopics} - -
- - Likes {post.likeCount} Comments {post.commentCount} - -
-
- )) - ) : ( -

My Posts

- ); - - // FIX: This needs to check if user's profile page being displayed - // is the same as the user who is logged in - // Can't check for that right now, because this page is always - // showing the logged in users profile, instead of retreiving the - // profile based on the URL entered - let editButtonMarkup = true ? ( + // FIX: This needs to check if user's profile page being displayed + // is the same as the user who is logged in + // Can't check for that right now, because this page is always + // showing the logged in users profile, instead of retreiving the + // profile based on the URL entered + let editButtonMarkup = true ? ( - + - ) : null; + ) : null; - return ( -
- {/* */} - - - - - {editButtonMarkup} - - - {/* */} - {/* */} - {imageMarkup} - {profileMarkup} - {/* */} - {/* */} - {/* {postMarkup} */} - {/* */} - {/* */} - - - - {topicsMarkup} - - this.handleChange(event)} - /> - - - - - - - - {postMarkup} - - - - -
- ); - } + return ( +
+ {/* */} + + + + + {editButtonMarkup} + + + {/* */} + {/* */} + {imageMarkup} + {profileMarkup} + {/* */} + {/* */} + {/* {postMarkup} */} + {/* */} + {/* */} + + + + {topicsMarkup} + + this.handleChange(event)} + /> + + + + + + + + {postMarkup} + + + + +
+ ); + } } -const mapStateToProps = (state) => ({ - user: state.user +const mapStateToProps = state => ({ + user: state.user }); user.propTypes = { - user: PropTypes.object.isRequired + user: PropTypes.object.isRequired }; export default connect(mapStateToProps)(withStyles(styles)(user)); From 7976110e2b5faddb9c87bfc01d8e18532fa5c89d Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Thu, 21 Nov 2019 19:59:04 -0500 Subject: [PATCH 2/4] modified function to add/delete topic only from user --- functions/handlers/topic.js | 89 ++++++++++++++++++++++++------------- functions/index.js | 2 +- 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/functions/handlers/topic.js b/functions/handlers/topic.js index bb5b9f1..c2d2a57 100644 --- a/functions/handlers/topic.js +++ b/functions/handlers/topic.js @@ -1,21 +1,24 @@ const { admin, db } = require("../util/admin"); exports.putTopic = (req, res) => { - const newTopic = { - topic: req.body.topic - }; + let new_following = []; + let userRef = db.doc(`/users/${req.userData.handle}`); + userRef.get().then(doc => { + new_following = doc.data().followedTopics; + new_following.push(req.body.following); - admin - .firestore() - .collection("topics") - .add(newTopic) - .then(doc => { - const resTopic = newTopic; - return res.status(200).json(resTopic); - }) - .catch(err => { - console.error(err); - return res.status(500).json({ error: "something is wrong" }); - }); + // add stuff + userRef + .set({ followedTopics: new_following }, { merge: true }) + .then(doc => { + return res + .status(201) + .json({ message: `Following ${req.body.following}` }); + }) + .catch(err => { + return res.status(500).json({ err }); + }); + return res.status(200).json({ message: "OK" }); + }); }; exports.getAllTopics = (req, res) => { @@ -40,25 +43,51 @@ exports.getAllTopics = (req, res) => { }; exports.deleteTopic = (req, res) => { - const topic = db.doc(`/topics/${req.params.topicId}`); - topic - .get() - .then(doc => { - if (!doc.exists) { - return res.status(404).json({ error: "Topic not found" }); - } else { - return topic.delete(); + let new_following = []; + let userRef = db.doc(`/users/${req.userData.handle}`); + userRef.get().then(doc => { + new_following = doc.data().followedTopics; + // remove username from array + new_following.forEach(function(follower, index) { + if (follower === `${req.body.topic}`) { + new_following.splice(index, 1); } - }) - .then(() => { - return res.json({ message: "Topic successfully deleted!" }); - }) - .catch(err => { - console.error(err); - return res.status(500).json({ error: "Failed to delete topic." }); }); + + // update database + userRef + .set({ followedTopics: new_following }, { merge: true }) + .then(doc => { + return res + .status(202) + .json({ message: `Successfully unfollow ${req.body.unfollow}` }); + }) + .catch(err => { + return res.status(500).json({ err }); + }); + return res.status(200).json({ message: "ok" }); + }); }; +// const topic = db.doc(`/topics/${req.params.topicId}`); +// topic +// .get() +// .then(doc => { +// if (!doc.exists) { +// return res.status(404).json({ error: "Topic not found" }); +// } else { +// return topic.delete(); +// } +// }) +// .then(() => { +// return res.json({ message: "Topic successfully deleted!" }); +// }) +// .catch(err => { +// console.error(err); +// return res.status(500).json({ error: "Failed to delete topic." }); +// }); +// }; + exports.getUserTopics = (req, res) => { let data = []; db.doc(`/users/${req.body.handle}`) diff --git a/functions/index.js b/functions/index.js index df44c82..4626e47 100644 --- a/functions/index.js +++ b/functions/index.js @@ -96,7 +96,7 @@ app.post("/putTopic", fbAuth, putTopic); app.get("/getAllTopics", fbAuth, getAllTopics); // delete a specific topic -app.delete("/deleteTopic/:topicId", fbAuth, deleteTopic); +app.post("/deleteTopic", fbAuth, deleteTopic); // get topic for this user app.post("/getUserTopics", fbAuth, getUserTopics); From 4e817c96475c22e9fd0a0bb2d4dd4d5c53d9c3e4 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Thu, 21 Nov 2019 20:09:47 -0500 Subject: [PATCH 3/4] integrated backend change, added pointer cursor --- functions/handlers/topic.js | 2 +- twistter-frontend/src/pages/user.js | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/functions/handlers/topic.js b/functions/handlers/topic.js index c2d2a57..bd7b437 100644 --- a/functions/handlers/topic.js +++ b/functions/handlers/topic.js @@ -49,7 +49,7 @@ exports.deleteTopic = (req, res) => { new_following = doc.data().followedTopics; // remove username from array new_following.forEach(function(follower, index) { - if (follower === `${req.body.topic}`) { + if (follower === `${req.body.unfollow}`) { new_following.splice(index, 1); } }); diff --git a/twistter-frontend/src/pages/user.js b/twistter-frontend/src/pages/user.js index 335b1cf..9896f7d 100644 --- a/twistter-frontend/src/pages/user.js +++ b/twistter-frontend/src/pages/user.js @@ -78,8 +78,11 @@ class user extends Component { }; handleDelete = topic => { + console.log(topic); axios - .delete(`/deleteTopic/${topic.id}`) + .post(`/deleteTopic`, { + unfollow: topic + }) .then(function() { location.reload(); }) @@ -91,7 +94,7 @@ class user extends Component { handleAddCircle = () => { axios .post("/putTopic", { - topic: this.state.newTopic + following: this.state.newTopic }) .then(function() { location.reload(); @@ -125,7 +128,7 @@ class user extends Component { axios .get("/getallPostsforUser") .then(res => { - console.log(res.data); + // console.log(res.data); this.setState({ posts: res.data }); @@ -269,6 +272,7 @@ class user extends Component { // iconStyle={classes.addCircle} clickable onClick={this.handleAddCircle} + cursor="pointer" /> From 6a78d74930df4bae17894caa8d6ee0477429ba1f Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Thu, 21 Nov 2019 20:20:54 -0500 Subject: [PATCH 4/4] simplified backend get/remove topic function --- functions/handlers/topic.js | 103 ++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 56 deletions(-) diff --git a/functions/handlers/topic.js b/functions/handlers/topic.js index bd7b437..88e014e 100644 --- a/functions/handlers/topic.js +++ b/functions/handlers/topic.js @@ -2,23 +2,28 @@ const { admin, db } = require("../util/admin"); exports.putTopic = (req, res) => { let new_following = []; let userRef = db.doc(`/users/${req.userData.handle}`); - userRef.get().then(doc => { - new_following = doc.data().followedTopics; - new_following.push(req.body.following); + userRef + .get() + .then(doc => { + new_following = doc.data().followedTopics; + new_following.push(req.body.following); - // add stuff - userRef - .set({ followedTopics: new_following }, { merge: true }) - .then(doc => { - return res - .status(201) - .json({ message: `Following ${req.body.following}` }); - }) - .catch(err => { - return res.status(500).json({ err }); - }); - return res.status(200).json({ message: "OK" }); - }); + // add stuff + userRef + .set({ followedTopics: new_following }, { merge: true }) + .then(doc => { + return res + .status(201) + .json({ message: `Following ${req.body.following}` }); + }) + .catch(err => { + return res.status(500).json({ err }); + }); + return res.status(200).json({ message: "OK" }); + }) + .catch(err => { + return res.status(500).json({ err }); + }); }; exports.getAllTopics = (req, res) => { @@ -45,48 +50,34 @@ exports.getAllTopics = (req, res) => { exports.deleteTopic = (req, res) => { let new_following = []; let userRef = db.doc(`/users/${req.userData.handle}`); - userRef.get().then(doc => { - new_following = doc.data().followedTopics; - // remove username from array - new_following.forEach(function(follower, index) { - if (follower === `${req.body.unfollow}`) { - new_following.splice(index, 1); - } - }); - - // update database - userRef - .set({ followedTopics: new_following }, { merge: true }) - .then(doc => { - return res - .status(202) - .json({ message: `Successfully unfollow ${req.body.unfollow}` }); - }) - .catch(err => { - return res.status(500).json({ err }); + userRef + .get() + .then(doc => { + new_following = doc.data().followedTopics; + // remove username from array + new_following.forEach(function(follower, index) { + if (follower === `${req.body.unfollow}`) { + new_following.splice(index, 1); + } }); - return res.status(200).json({ message: "ok" }); - }); -}; -// const topic = db.doc(`/topics/${req.params.topicId}`); -// topic -// .get() -// .then(doc => { -// if (!doc.exists) { -// return res.status(404).json({ error: "Topic not found" }); -// } else { -// return topic.delete(); -// } -// }) -// .then(() => { -// return res.json({ message: "Topic successfully deleted!" }); -// }) -// .catch(err => { -// console.error(err); -// return res.status(500).json({ error: "Failed to delete topic." }); -// }); -// }; + // update database + userRef + .set({ followedTopics: new_following }, { merge: true }) + .then(doc => { + return res + .status(202) + .json({ message: `Successfully unfollow ${req.body.unfollow}` }); + }) + .catch(err => { + return res.status(500).json({ err }); + }); + return res.status(200).json({ message: "ok" }); + }) + .catch(err => { + return res.status(500).json({ err }); + }); +}; exports.getUserTopics = (req, res) => { let data = [];