diff --git a/functions/handlers/post.js b/functions/handlers/post.js index 13f3057..e23fb63 100644 --- a/functions/handlers/post.js +++ b/functions/handlers/post.js @@ -58,8 +58,10 @@ exports.getallPostsforUser = (req, res) => { myPosts.forEach(function(doc) { posts.push(doc.data()); }); + posts.sort((a, b) => -a.createdAt.localeCompare(b.createdAt)); return res.status(200).json(posts); }) + .then(function() { return res .status(200) @@ -68,7 +70,7 @@ exports.getallPostsforUser = (req, res) => { .catch(function(err) { return res .status(500) - .json("Failed to retrieve user's posts from database.", err); + .json({message: "Failed to retrieve user's posts from database.", error: err}); }); }; @@ -95,46 +97,79 @@ exports.getallPosts = (req, res) => { // Get all the posts var postsPromise = new Promise((resolve, reject) => { - db.collection("posts").get() - .then((allPosts) => { - allPosts.forEach((post) => { + db.collection("posts") + .get() + .then(allPosts => { + allPosts.forEach(post => { posts.push(post.data()); }); + posts.sort((a, b) => -a.createdAt.localeCompare(b.createdAt)); resolve(); }) - .catch((error) => { + .catch(error => { reject(error); - }) + }); }); // Get all users var usersPromise = new Promise((resolve, reject) => { - db.collection("users").get() - .then((allUsers) => { - allUsers.forEach((user) => { + db.collection("users") + .get() + .then(allUsers => { + allUsers.forEach(user => { users[user.data().handle] = user.data(); - }) + }); resolve(); }) - .catch((error) => { + .catch(error => { reject(error); - }) + }); }); // Wait for the two promises Promise.all([postsPromise, usersPromise]) .then(() => { - let newPosts = [] + let newPosts = []; // Add the image url of the person who made the post to all of the post objects - posts.forEach((post) => { - post.profileImage = users[post.userHandle].imageUrl ? users[post.userHandle].imageUrl : null; + posts.forEach(post => { + post.profileImage = users[post.userHandle].imageUrl + ? users[post.userHandle].imageUrl + : null; newPosts.push(post); }); return res.status(200).json(newPosts); }) - .catch((error) => { - return res.status(500).json({error}); + .catch(error => { + return res.status(500).json({ error }); + }); +}; + +exports.getAlert = (req, res) => { + var post_query = admin + .firestore() + .collection("posts") + .where("microBlogTitle", "==", "Alert"); + + post_query + .get() + .then(function(myPosts) { + let posts = []; + myPosts.forEach(function(doc) { + posts.push(doc.data()); + }); + posts.sort((a, b) => -a.createdAt.localeCompare(b.createdAt)); + return res.status(200).json(posts); }) + .then(function() { + return res + .status(200) + .json("Successfully retrieved all user's posts from database."); + }) + .catch(function(err) { + return res + .status(500) + .json("Failed to retrieve user's posts from database.", err); + }); }; exports.getOtherUsersPosts = (req, res) => { @@ -155,6 +190,7 @@ exports.getOtherUsersPosts = (req, res) => { myPosts.forEach(function(doc) { posts.push(doc.data()); }); + posts.sort((a, b) => -a.createdAt.localeCompare(b.createdAt)); return res.status(200).json(posts); }) .then(function() { @@ -170,23 +206,25 @@ exports.getOtherUsersPosts = (req, res) => { }; exports.quoteWithPost = (req, res) => { - let quoteData; - const quoteDoc = admin.firestore().collection('quote'). - where('userHandle', '==', req.user.handle). - where('quoteId', '==', req.params.postId).limit(1); + let quoteData; + const quoteDoc = admin + .firestore() + .collection("quote") + .where("userHandle", "==", req.user.handle) + .where("quoteId", "==", req.params.postId) + .limit(1); - const postDoc = db.doc(`/posts/${req.params.postId}`); + const postDoc = db.doc(`/posts/${req.params.postId}`); - postDoc.get() - .then((doc) => { - if(doc.exists) { - quoteData = doc.data(); - return quoteDoc.get(); - } - else - { - return res.status(404).json({error: 'Post not found'}); - } + postDoc + .get() + .then(doc => { + if (doc.exists) { + quoteData = doc.data(); + return quoteDoc.get(); + } else { + return res.status(404).json({ error: "Post not found" }); + } }) .then(data => { if (data.empty) { @@ -234,23 +272,25 @@ exports.quoteWithPost = (req, res) => { }; exports.quoteWithoutPost = (req, res) => { - let quoteData; - const quoteDoc = admin.firestore().collection('quote'). - where('userHandle', '==', req.user.handle). - where('quoteId', '==', req.params.postId).limit(1); + let quoteData; + const quoteDoc = admin + .firestore() + .collection("quote") + .where("userHandle", "==", req.user.handle) + .where("quoteId", "==", req.params.postId) + .limit(1); - const postDoc = db.doc(`/posts/${req.params.postId}`); + const postDoc = db.doc(`/posts/${req.params.postId}`); - postDoc.get() - .then((doc) => { - if(doc.exists) { - quoteData = doc.data(); - return quoteDoc.get(); - } - else - { - return res.status(404).json({error: 'Post not found'}); - } + postDoc + .get() + .then(doc => { + if (doc.exists) { + quoteData = doc.data(); + return quoteDoc.get(); + } else { + return res.status(404).json({ error: "Post not found" }); + } }) .then(data => { if (data.empty) { @@ -292,7 +332,7 @@ exports.quoteWithoutPost = (req, res) => { } }) .catch(err => { - // return res.status(500).json({ error: "Something is wrong" }); + // return res.status(500).json({ error: "Something is wrong" }); return res.status(500).json({ error: err }); }); }; @@ -306,202 +346,198 @@ exports.checkforLikePost = (req, res) => { .limit(1); let result; - likedPostDoc.get().then(data => { - if (data.empty) { - result = false; - return res.status(200).json(result); - } else { - result = true; - return res.status(200).json(result); - } - }) - .catch((err) => { + likedPostDoc + .get() + .then(data => { + if (data.empty) { + result = false; + return res.status(200).json(result); + } else { + result = true; + return res.status(200).json(result); + } + }) + .catch(err => { console.log(err); - return res.status(500).json({error: err}); - }) + return res.status(500).json({ error: err }); + }); }; exports.likePost = (req, res) => { + const postId = req.params.postId; + let likedPostDoc; + db.doc(`/users/${req.userData.handle}`) + .get() + .then(userDoc => { + let likes = userDoc.data().likes; + if (likes === undefined || likes === null) { + likes = []; + } - const postId = req.params.postId; - let likedPostDoc; - db.doc(`/users/${req.userData.handle}`) - .get() - .then((userDoc) => { - let likes = userDoc.data().likes; - if (likes === undefined || likes === null) { - likes = []; - } + if (likes.includes(postId)) { + return res + .status(400) + .json({ error: "This user has already liked this post" }); + } - if (likes.includes(postId)) { - return res.status(400).json({error: "This user has already liked this post"}); - } + likes.push(postId); - likes.push(postId); + return userDoc.ref.update({ likes }); + }) + .then(() => { + return db.doc(`/posts/${postId}`).get(); + }) + .then(postDoc => { + let postData = postDoc.data(); + postData.likeCount++; + likedPostDoc = postData; + return postDoc.ref.update({ likeCount: postData.likeCount }); + }) + .then(() => { + return res.status(201).json(likedPostDoc); + }) + .catch(err => { + console.log(err); + return res.status(500).json({ error: err }); + }); - return userDoc.ref.update({likes}) - }) - .then(() => { - return db.doc(`/posts/${postId}`).get() - - }) - .then((postDoc) => { - let postData = postDoc.data(); - postData.likeCount++; - likedPostDoc = postData; - return postDoc.ref.update({likeCount : postData.likeCount}) - }) - .then(() => { - return res.status(201).json(likedPostDoc); - }) - .catch((err) => { - console.log(err); - return res.status(500).json({error: err}); - }) + // let postData; + // const likeDoc = admin.firestore().collection('likes').where('userHandle', '==', req.user.handle) + // .where('postId', '==', req.params.postId).limit(1); - // let postData; - // const likeDoc = admin.firestore().collection('likes').where('userHandle', '==', req.user.handle) - // .where('postId', '==', req.params.postId).limit(1); + // const postDoc = db.doc(`/posts/${req.params.postId}`); - // const postDoc = db.doc(`/posts/${req.params.postId}`); - - // postDoc.get() - // .then((doc) => { - // if(doc.exists) { - // postData = doc.data(); - // return likeDoc.get(); - // } - // else - // { - // return res.status(404).json({error: 'Post not found'}); - // } - // }) - // .then((data) => { - // if (data.empty) { - // return admin.firestore().collection('likes').add({ - // postId : req.params.postId, - // userHandle: req.user.handle - - // }) - // .then(() => { - // postData.likeCount++; - // return postDoc.update({likeCount : postData.likeCount}) - // }) - // .then(() => { - // return res.status(200).json(postData); - // }) - // } - // }) - // .catch((err) => { - // return res.status(500).json({error: 'Something is wrong'}); - // }) - -} + // postDoc.get() + // .then((doc) => { + // if(doc.exists) { + // postData = doc.data(); + // return likeDoc.get(); + // } + // else + // { + // return res.status(404).json({error: 'Post not found'}); + // } + // }) + // .then((data) => { + // if (data.empty) { + // return admin.firestore().collection('likes').add({ + // postId : req.params.postId, + // userHandle: req.user.handle + // }) + // .then(() => { + // postData.likeCount++; + // return postDoc.update({likeCount : postData.likeCount}) + // }) + // .then(() => { + // return res.status(200).json(postData); + // }) + // } + // }) + // .catch((err) => { + // return res.status(500).json({error: 'Something is wrong'}); + // }) +}; exports.unlikePost = (req, res) => { + const postId = req.params.postId; + let likedPostDoc; + db.doc(`/users/${req.userData.handle}`) + .get() + .then(userDoc => { + let likes = userDoc.data().likes; + if (likes === undefined || likes === null) { + likes = []; + } - const postId = req.params.postId; - let likedPostDoc; - db.doc(`/users/${req.userData.handle}`) - .get() - .then((userDoc) => { - let likes = userDoc.data().likes; - if (likes === undefined || likes === null) { - likes = []; - } + if (!likes.includes(postId)) { + return res + .status(400) + .json({ error: "This user hasn't liked this post yet" }); + } - if (!likes.includes(postId)) { - return res.status(400).json({error: "This user hasn't liked this post yet"}); - } + let i; + for (i = 0; i < likes.length; i++) { + if (likes[i] === postId) { + likes.splice(i, 1); + } + } - let i; - for (i = 0; i < likes.length; i++) { - if (likes[i] === postId) { - likes.splice(i, 1); - } - } + return userDoc.ref.update({ likes }); + }) + .then(() => { + return db.doc(`/posts/${postId}`).get(); + }) + .then(postDoc => { + let postData = postDoc.data(); + postData.likeCount--; + likedPostDoc = postData; + return postDoc.ref.update({ likeCount: postData.likeCount }); + }) + .then(() => { + return res.status(201).json(likedPostDoc); + }) + .catch(err => { + console.log(err); + return res.status(500).json({ error: err }); + }); - return userDoc.ref.update({likes}) - }) - .then(() => { - return db.doc(`/posts/${postId}`).get() - - }) - .then((postDoc) => { - let postData = postDoc.data(); - postData.likeCount--; - likedPostDoc = postData; - return postDoc.ref.update({likeCount : postData.likeCount}) - }) - .then(() => { - return res.status(201).json(likedPostDoc); - }) - .catch((err) => { - console.log(err); - return res.status(500).json({error: err}); - }) + // let postData; + // const likeDoc = admin.firestore().collection('likes').where('userHandle', '==', req.user.handle) + // .where('postId', '==', req.params.postId).limit(1); - // let postData; - // const likeDoc = admin.firestore().collection('likes').where('userHandle', '==', req.user.handle) - // .where('postId', '==', req.params.postId).limit(1); + // const postDoc = db.doc(`/posts/${req.params.postId}`); - // const postDoc = db.doc(`/posts/${req.params.postId}`); - - // postDoc.get() - // .then((doc) => { - // if(doc.exists) { - // postData = doc.data(); - // return likeDoc.get(); - // } - // else - // { - // return res.status(404).json({error: 'Post not found'}); - // } - // }) - // .then((data) => { - // return db - // .doc(`/likes/${data.docs[0].id}`) - // .delete() - // .then(() => { - // postData.likeCount--; - // return postDoc.update({ likeCount: postData.likeCount }); - // }) - // .then(() => { - // res.status(200).json(postData); - // }); - - // }) - // .catch((err) => { - // console.error(err); - // return res.status(500).json({error: 'Something is wrong'}); - // }) - -} + // postDoc.get() + // .then((doc) => { + // if(doc.exists) { + // postData = doc.data(); + // return likeDoc.get(); + // } + // else + // { + // return res.status(404).json({error: 'Post not found'}); + // } + // }) + // .then((data) => { + // return db + // .doc(`/likes/${data.docs[0].id}`) + // .delete() + // .then(() => { + // postData.likeCount--; + // return postDoc.update({ likeCount: postData.likeCount }); + // }) + // .then(() => { + // res.status(200).json(postData); + // }); + // }) + // .catch((err) => { + // console.error(err); + // return res.status(500).json({error: 'Something is wrong'}); + // }) +}; exports.getLikes = (req, res) => { - db.doc(`/users/${req.userData.handle}`) - .get() - .then((doc) => { - let likes = doc.data().likes; - if (likes === undefined || likes === null) { - likes = []; - } - return res.status(200).json({likes}); - }) - .catch((err) => { - console.log(err); - return res.status(500).json({error: err}); - }) -} + db.doc(`/users/${req.userData.handle}`) + .get() + .then(doc => { + let likes = doc.data().likes; + if (likes === undefined || likes === null) { + likes = []; + } + return res.status(200).json({ likes }); + }) + .catch(err => { + console.log(err); + return res.status(500).json({ error: err }); + }); +}; exports.getFilteredPosts = (req, res) => { - admin .firestore() .collection("posts") .where("userHandle", "==", "new user") .where("microBlogTopics", "=="); }; - diff --git a/functions/handlers/topic.js b/functions/handlers/topic.js index 88e014e..3a81810 100644 --- a/functions/handlers/topic.js +++ b/functions/handlers/topic.js @@ -26,6 +26,41 @@ exports.putTopic = (req, res) => { }); }; +exports.putNewTopic = (req, res) => { + let new_following = []; + let userRef = db.doc(`/users/${req.userData.handle}`); + userRef + .get() + .then(doc => { + let topics = []; + new_following = doc.data().following; + // new_following.push(req.body.following); + new_following.forEach(follow => { + if (follow.handle === req.body.handle) { + // topics = follow.topics; + follow.topics.push(req.body.topic); + } + }); + // return res.status(201).json({ new_following }); + + // add stuff + userRef + .set({ following: new_following }, { merge: true }) + .then(doc => { + return res + .status(201) + .json({ message: `Following ${req.body.topic}` }); + }) + .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) => { admin .firestore() diff --git a/functions/handlers/users.js b/functions/handlers/users.js index 7d2b5c0..b837fbc 100644 --- a/functions/handlers/users.js +++ b/functions/handlers/users.js @@ -163,11 +163,13 @@ exports.login = (req, res) => { return; }) .catch(function(err) { - if (!doc.exists) { - return res - .status(403) - .json({ general: "Invalid credentials. Please try again." }); - } + // FIX: doc variable is out of scope + // if (!doc.exists) { + // return res + // .status(403) + // .json({ general: "Invalid credentials. Please try again." }); + // } + console.log(err); return res.status(500).send(err); }); } @@ -223,103 +225,110 @@ exports.deleteUser = (req, res) => { return new Promise((resolve, reject) => { const deleteUsername = req.userData.handle; db.doc(`/users/${deleteUsername}`) - .get() - .then((deleteUserDocSnap) => { - const dms = deleteUserDocSnap.data().dms; - const dmRecipients = deleteUserDocSnap.data().dmRecipients; - - if (!dms) { - resolve(); - return; - } + .get() + .then(deleteUserDocSnap => { + const dms = deleteUserDocSnap.data().dms; + const dmRecipients = deleteUserDocSnap.data().dmRecipients; - // Iterate over the list of users who this person has DM'd - let otherUsersPromises = []; - - // Resolve if they don't have a dmRecipients list - if (dmRecipients === undefined || dmRecipients === null || dmRecipients.length === 0) { - resolve(); - return; - } - dmRecipients.forEach((dmRecipient) => { - otherUsersPromises.push( - // Get each users data - db.doc(`/users/${dmRecipient}`).get() - .then((otherUserDocSnap) => { - // Get the index of deleteUsername so that we can remove the dangling - // reference to the DM document - let otherUserDMRecipients = otherUserDocSnap.data().dmRecipients; - let otherUserDMs = otherUserDocSnap.data().dms; - let index = -1; - otherUserDMRecipients.forEach((dmRecip, i) => { - if (dmRecip === deleteUsername) { - index = i; - } - }) - - if (index !== -1) { - // Remove deleteUsername from their dmRecipients list - otherUserDMRecipients.splice(index, 1); - - // Remove the DM channel with deleteUsername - otherUserDMs.splice(index, 1); - - // Update the users data - return otherUserDocSnap.ref.update({ - dmRecipients: otherUserDMRecipients, - dms: otherUserDMs - }); - } - - }) - ) - }) - - // Wait for the removal of DM data stored on other users to be deleted - Promise.all(otherUsersPromises) - .then(() => { - // Iterate through DM references and delete them from the dm collection - let dmRefsPromises = []; - dms.forEach((dmRef) => { - // Create a delete queue - let batch = db.batch(); - dmRefsPromises.push( - // Add the messages to the delete queue - db.collection(`/dm/${dmRef.id}/messages`).listDocuments() - .then((docs) => { - console.log("second") - console.log(docs); - docs.map((doc) => { - batch.delete(doc); - }) - - // Add the doc that the DM is stored in to the delete queue - batch.delete(dmRef); - - // Commit the writes - return batch.commit(); - }) - ) - }) - - return Promise.all(dmRefsPromises); - }) - .then(() => { + if (!dms) { resolve(); return; - }) - .catch((err) => { - console.log("error " + err); - reject(err); - return; - }) - }) - .catch((err) => { - console.log(err); - return res.status(500).json({error: err}); - }) + } - }) + // Iterate over the list of users who this person has DM'd + let otherUsersPromises = []; + + // Resolve if they don't have a dmRecipients list + if ( + dmRecipients === undefined || + dmRecipients === null || + dmRecipients.length === 0 + ) { + resolve(); + return; + } + dmRecipients.forEach(dmRecipient => { + otherUsersPromises.push( + // Get each users data + db + .doc(`/users/${dmRecipient}`) + .get() + .then(otherUserDocSnap => { + // Get the index of deleteUsername so that we can remove the dangling + // reference to the DM document + let otherUserDMRecipients = otherUserDocSnap.data() + .dmRecipients; + let otherUserDMs = otherUserDocSnap.data().dms; + let index = -1; + otherUserDMRecipients.forEach((dmRecip, i) => { + if (dmRecip === deleteUsername) { + index = i; + } + }); + + if (index !== -1) { + // Remove deleteUsername from their dmRecipients list + otherUserDMRecipients.splice(index, 1); + + // Remove the DM channel with deleteUsername + otherUserDMs.splice(index, 1); + + // Update the users data + return otherUserDocSnap.ref.update({ + dmRecipients: otherUserDMRecipients, + dms: otherUserDMs + }); + } + }) + ); + }); + + // Wait for the removal of DM data stored on other users to be deleted + Promise.all(otherUsersPromises) + .then(() => { + // Iterate through DM references and delete them from the dm collection + let dmRefsPromises = []; + dms.forEach(dmRef => { + // Create a delete queue + let batch = db.batch(); + dmRefsPromises.push( + // Add the messages to the delete queue + db + .collection(`/dm/${dmRef.id}/messages`) + .listDocuments() + .then(docs => { + console.log("second"); + console.log(docs); + docs.map(doc => { + batch.delete(doc); + }); + + // Add the doc that the DM is stored in to the delete queue + batch.delete(dmRef); + + // Commit the writes + return batch.commit(); + }) + ); + }); + + return Promise.all(dmRefsPromises); + }) + .then(() => { + resolve(); + return; + }) + .catch(err => { + console.log("error " + err); + reject(err); + return; + }); + }) + .catch(err => { + console.log(err); + return res.status(500).json({ error: err }); + }); + }); } // Deletes user from authentication @@ -332,18 +341,18 @@ exports.deleteUser = (req, res) => { return db .collection("users") .doc(`${req.user.handle}`) - .delete() + .delete(); }) .then(() => { resolve(); return; }) - .catch((err) => { + .catch(err => { console.log(err); reject(err); return; - }) - }) + }); + }); // Deletes any custom profile image let image; @@ -452,20 +461,21 @@ exports.getUserDetails = (req, res) => { exports.getAllHandles = (req, res) => { var user_query = admin.firestore().collection("users"); - user_query.get() - .then((allUsers) => { + user_query + .get() + .then(allUsers => { let users = []; - allUsers.forEach((user) => { - users.push(user.data().handle); + allUsers.forEach(user => { + users.push(user.data().handle); }); return res.status(200).json(users); - }) - .catch((err) => { - return res.status(500).json({ - message:"Failed to retrieve posts from database.", - error: err + }) + .catch(err => { + return res.status(500).json({ + message: "Failed to retrieve posts from database.", + error: err + }); }); - }); }; // Returns all data stored for a user @@ -552,6 +562,614 @@ exports.unverifyUser = (req, res) => { return res.status(500).json({ error: err.code }); }); }; + +// Returns all the DMs that the user is currently participating in +exports.getDirectMessages = (req, res) => { + /* Return value + * data: [DMs] + * dm : { + * dmId: str + * messages: [msgs] + * msg: { + * author: str + * createdAt: ISOString + * message: str + * messageId: str + * } + * recipient: str + * hasDirectMessagesEnabled: bool + * recentMessage: str + * recentMessageTimestamp: ISOString + * } + */ + + // Returns all the messages in a dm documentSnapshot + function getMessages(dm) { + let promise = new Promise((resolve, reject) => { + let messagesCollection = dm.collection("messages"); + + // If the messagesCollection is missing, that means that there aren't any messages + if (messagesCollection === null || messagesCollection === undefined) { + return; + } + + let msgs = []; + let promises = []; + + // Get all of the messages in the DM + messagesCollection.get().then(dmQuerySnap => { + dmQuerySnap.forEach(dmQueryDocSnap => { + promises.push( + dmQueryDocSnap.ref.get().then(messageData => { + msgs.push(messageData.data()); + return; + }) + ); + }); + + let waitPromise = Promise.all(promises); + waitPromise.then(() => { + // Sort the messages in reverse order by date + // Newest should be at the bottom, because that's how they will be displayed on the front-end + msgs.sort((a, b) => { + return b.createdAt > a.createdAt + ? -1 + : b.createdAt < a.createdAt + ? 1 + : 0; + }); + resolve(msgs); + }); + }); + }); + return promise; + } + + const dms = req.userData.dms; + const dmRecipients = req.userData.dmRecipients; + + // Return null if this user has no DMs + if (dms === undefined || dms === null || dms.length === 0) + return res.status(200).json({ data: null }); + + let dmsData = []; + let dmPromises = []; + + dms.forEach(dm => { + let dmData = {}; + // Make a new promise for each DM document + dmPromises.push( + new Promise((resolve, reject) => { + dm.get() // DM document reference + .then(doc => { + let docData = doc.data(); + + // Recipient is the person you are messaging + docData.authors[0] === req.userData.handle + ? (dmData.recipient = docData.authors[1]) + : (dmData.recipient = docData.authors[0]); + + // Save the createdAt time + dmData.createdAt = docData.createdAt; + + // Get all the messages from this dm document + getMessages(dm).then(msgs => { + dmData.messages = msgs; + dmData.recentMessage = + msgs.length !== 0 ? msgs[msgs.length - 1].message : null; + dmData.recentMessageTimestamp = + msgs.length !== 0 ? msgs[msgs.length - 1].createdAt : null; + dmData.dmId = doc.id; + resolve(dmData); + }); + }) + .catch(err => { + console.err(err); + return res.status(400).json({ + error: { + message: + "An error occurred when reading the DM document reference", + error: err + } + }); + }); + }).then(dmData => { + dmsData.push(dmData); + }) + ); + }); + + // Get all the data from the users to get the data on whether they have DMs enabled or not + let userPromises = []; + dmRecipients.forEach(recipient => { + userPromises.push(db.doc(`/users/${recipient}`).get()); + }); + + // Wait for all DM document promises to resolve before returning data + Promise.all(dmPromises) + .then(() => { + return Promise.all(userPromises); + }) + .then(userData => { + // Sort the DMs so that the ones with the newest messages are at the top + dmsData.sort((a, b) => { + if ( + a.recentMessageTimestamp === null && + b.recentMessageTimestamp === null + ) { + if (b.createdAt < a.createdAt) { + return -1; + } else if (b.createdAt > a.createdAt) { + return 1; + } else { + return 0; + } + } else if (a.recentMessageTimestamp === null) { + return 1; + } else if (b.recentMessageTimestamp === null) { + return -1; + } else if (b.recentMessageTimestamp < a.recentMessageTimestamp) { + return -1; + } else if (b.recentMessageTimestamp > a.recentMessageTimestamp) { + return 1; + } else { + return 0; + } + }); + + dmsData.forEach(dm => { + dm.hasDirectMessagesEnabled = + userData + .find(user => { + if (dm.recipient === user.data().handle) { + return true; + } else { + return false; + } + }) + .data().dmEnabled === false + ? false + : true; + }); + return res.status(200).json({ data: dmsData }); + }) + .catch(err => { + return res.status(500).json({ + error: { + message: "An error occurred while sorting", + error: err + } + }); + }); +}; + +// Toggles direct messages on or off depending on the requese +/* Request Parameters + * enable: bool + */ +exports.toggleDirectMessages = (req, res) => { + const enable = req.body.enable; + const user = req.userData.handle; + db.doc(`/users/${user}`) + .update({ dmEnabled: enable }) + .then(() => { + return res.status(201).json({ message: "Success" }); + }) + .catch(err => { + return res.status(500).json({ error: err }); + }); +}; + +// Returns a promise that resolves if user has DMs enabled +// and rejects if there is an error or DMs are disabled +isDirectMessageEnabled = username => { + return new Promise((resolve, reject) => { + let result = {}; + result.code = null; + result.message = null; + if (username === null || username === undefined || username === "") { + result.code = 400; + result.message = + "No user was sent in the request. The request should have a non-empty 'user' key."; + reject(result); + } + + db.doc(`/users/${username}`) + .get() + .then(doc => { + if (doc.exists) { + // console.log(doc.data()) + if ( + doc.data().dmEnabled === true || + doc.data().dmEnabled === null || + doc.data().dmEnabled === undefined + ) { + // Assume DMs are enabled if they don't have a dmEnabled key + resolve(result); + } else { + result.code = 400; + result.message = `${username} has DMs disabled`; + reject(result); + } + } else { + console.log(`${username} is not in the database`); + result.code = 400; + result.message = `${username} is not in the database`; + reject(result); + } + }) + .catch(err => { + console.log("HI"); + console.error(err); + result.code = 500; + result.message = err; + reject(result); + }); + }); +}; + +// Returns a promise that resolves if the data in the DM is valid and +// rejects if there are any error. Errors are returned in the promise +verifyDirectMessageIntegrity = dmRef => { + return new Promise((resolve, reject) => { + resolve("Not implemented yet"); + }); +}; + +// Checks if there are any DM channels open with userB on userA's side +oneWayCheck = (userA, userB) => { + return new Promise((resolve, reject) => { + db.doc(`/users/${userA}`) + .get() + .then(userASnapshot => { + const dmList = userASnapshot.data().dms; + const dmRecipients = userASnapshot.data().dmRecipients; + + if ( + dmList === null || + dmList === undefined || + dmRecipients === null || + dmRecipients === undefined + ) { + // They don't have any DMs yet + console.log("No DMs array"); + userASnapshot.ref + .set({ dms: [], dmRecipients: [] }, { merge: true }) + .then(() => { + resolve(); + }); + } else if (dmList.length === 0) { + // Their DMs are empty + console.log("DMs array is empty"); + resolve(); + } else { + // let dmDocs = []; + // let forEachPromises = []; + // dmList.forEach((dmRef) => { + // forEachPromises.push( + // dmRef.get() + // // .then((dmDoc) => { + // // TODO: Figure out why dmDoc.exists() isn't working + // // Make sure all of the docs exist and none of the references + // // are broken + // // if (dmDoc.exists()) { + // // dmDocs.push(dmDoc); + // // } else { + // // console.log(`DM reference /dm/${dmDoc.id} is invalid`); + // // reject(`DM reference /dm/${dmDoc.id} is invalid`); + // // } + // // }) + // ) + // }) + + dmRecipients.forEach(dmRecipient => { + if (dmRecipient === userB) { + console.log(`You already have a DM with ${userB}`); + // reject(new Error(`You already have a DM with ${userB}`)); + reject({ + code: 400, + message: `You already have a DM with that user` + }); + return; + } + }); + + resolve(); + + // Promise.all(forEachPromises) + // .then((dmDocs) => { + // // Check if any of the DMs have for userA have userA and userB as the authors. + // // This would mean that they already have a DM channel + // dmDocs.forEach((dmDoc) => { + // // Checking if any of the authors key in any of their DMs are missing + // let authors = dmDoc.data().authors; + + // // if (authors[0] === "keanureeves") { + // // console.log("it is") + // // resolve(); + // // } else { + // // console.log("it is not") + // // reject("not my keanu"); + // // } + // // if (authors === null || authors === undefined || authors.length !== 2) { + // // // console.log(`The authors key in /dm/${dmDoc.id} is undefined or missing values`); + // // // reject(`The authors key in /dm/${dmDoc.id} is undefined or missing values`); + // // console.log('a') + // // reject("a") + // // } else if ((authors[0] === userA && authors[1] === userB) || (authors[1] === userA && authors[0] === userB)) { + // // // console.log(`${userA} already has a DM channel between ${userA} and ${userB}`); + // // // reject(`${userA} already has a DM channel between ${userA} and ${userB}`); + // // console.log('b') + // // reject('b') + // // } else { + // // // BUG: For some reason the promise.all is resolving even though there are multiple rejects + // // // and only one resolve + // // console.log("c"); + // // resolve(); + // // } + // // console.log(authors) + // // console.log([userA, userB]) + // if (authors[0] === null || authors === undefined || authors.length !== 2) { + // console.log('a'); + // reject('a'); + // } else if (authors[0] === userA && authors[1] === userB) { + // console.log("b"); + // reject('b'); + // } else { + // console.log('c'); + // resolve(); + // } + // }) + // }) + } + }); + }); +}; + +// Returns a promise that resolves if there is not already a DM channel +// between the creator and recipient usernames. It rejects if one already +// exists or there is an error. +checkNoDirectMessageExists = (creator, recipient) => { + return new Promise((resolve, reject) => { + let creatorPromise = oneWayCheck(creator, recipient); + let recipientPromise = oneWayCheck(recipient, creator); + let temp_array = []; + temp_array.push(creatorPromise); + temp_array.push(recipientPromise); + + Promise.all(temp_array) + .then(() => { + resolve(); + }) + .catch(err => { + reject(err); + }); + }); +}; + +addDirectMessageToUser = (username, recipient, dmRef) => { + return new Promise((resolve, reject) => { + db.doc(`/users/${username}`) + .get() + .then(docSnap => { + let dmList = docSnap.data().dms; + let dmRecipients = docSnap.data().dmRecipients; + dmList.push(dmRef); + dmRecipients.push(recipient); + return db + .doc(`/users/${username}`) + .update({ dms: dmList, dmRecipients }); + }) + .then(() => { + resolve(); + }) + .catch(err => { + reject(err); + }); + }); +}; + +// Sends a DM from the caller to the requested DM document +/* Request Parameters + * message: str + * user: str + */ +exports.sendDirectMessage = (req, res) => { + // TODO: add error checking for if message or user is null + const creator = req.userData.handle; + const recipient = req.body.user; + const message = req.body.message; + + const newMessage = { + author: creator, + createdAt: new Date().toISOString(), + message, + messageId: null + }; + + db.doc(`/users/${recipient}`) + .get() + .then(recipDoc => { + // Return if the other user has DM's disabled + if ( + recipDoc.data().dmEnabled === false && + recipDoc.data().dmEnabled !== null && + recipDoc.data().dmEnabled !== undefined + ) { + return res.status(400).json({ error: "This user has DMs disabled" }); + } + }); + + db.doc(`/users/${creator}`) + .get() + .then(userDoc => { + let dmList = userDoc.data().dms; + + // Return if the creator doesn't have any DMs. + // This means they have not created a DM's channel yet + if (dmList === null || dmList === undefined) { + return res + .status(400) + .json({ + error: `There is no DM channel between ${creator} and ${recipient}. Use /api/dms/new.` + }); + } + + let dmRefPromises = []; + dmList.forEach(dmRef => { + dmRefPromises.push( + new Promise((resolve, reject) => { + dmRef + .get() + .then(dmDoc => { + let authors = dmDoc.data().authors; + if ( + (authors[0] === creator && authors[1] === recipient) || + (authors[1] === creator && authors[0] === recipient) + ) { + resolve({ correct: true, dmRef }); + } else { + resolve({ correct: false, dmRef }); + } + }) + .catch(err => { + reject(err); + }); + }) + ); + }); + + return Promise.all(dmRefPromises); + }) + .then(results => { + let correctDMRef = null; + results.forEach(result => { + if (result.correct) { + correctDMRef = result.dmRef; + } + }); + + if (correctDMRef === null) { + console.log( + `There is no DM channel between ${creator} and ${recipient}. Use /api/dms/new.` + ); + return res.status(400).json({ + error: `There is no DM channel between ${creator} and ${recipient}. Use /api/dms/new.` + }); + } + + return db.collection(`/dm/${correctDMRef.id}/messages`).add(newMessage); + }) + .then(newMsgRef => { + return newMsgRef.update({ messageId: newMsgRef.id }, { merge: true }); + }) + .then(() => { + return res.status(200).json({ message: "OK" }); + }) + .catch(err => { + console.log(err); + return res.status(500).json({ error: err }); + }); +}; + +// Creates a DM between the caller and the user in the request +/* Request Parameters + * user: str + */ +exports.createDirectMessage = (req, res) => { + const creator = req.userData.handle; + const recipient = req.body.user; + + // Check if they are DMing themselves + if (creator === recipient) + return res.status(400).json({ error: "You can't DM yourself" }); + + // Check if this user has DMs enabled + let creatorEnabled = isDirectMessageEnabled(creator); + + // Check if the requested user has DMs enabled + let recipientEnabled = isDirectMessageEnabled(recipient); + + // Make sure that they don't already have a DM channel + let noDMExists = checkNoDirectMessageExists(creator, recipient); + + let dataValidations = [creatorEnabled, recipientEnabled, noDMExists]; + + Promise.all(dataValidations) + .then(() => { + // Create a new DM document + return db.collection("dm").add({}); + }) + .then(dmDocRef => { + // Fill it with some data. + // Note that there isn't a messages collection by default. + let dmData = { + dmId: dmDocRef.id, + authors: [creator, recipient], + createdAt: new Date().toISOString() + }; + + // Update DM document + let dmDocPromise = dmDocRef.set(dmData); + + // Add the DM reference to the creator + let updateCreatorPromise = addDirectMessageToUser( + creator, + recipient, + dmDocRef + ); + + // Add the DM reference to the recipient + let updateRecipientPromise = addDirectMessageToUser( + recipient, + creator, + dmDocRef + ); + + // Wait for all promises + return Promise.all([ + dmDocPromise, + updateCreatorPromise, + updateRecipientPromise + ]); + }) + .then(() => { + return res.status(201).json({ message: "Success!" }); + }) + .catch(err => { + console.log(err); + + if (err.code && err.message && err.code > 0) { + // Specific error that I've created + return res.status(err.code).json({ error: err.message }); + } else { + // Generic or firebase error + return res.status(500).json({ error: err }); + } + }); +}; + +// Checks if the requested user has DMs enable or not +/* Request Parameters + * user: str + */ +exports.checkDirectMessagesEnabled = (req, res) => { + isDirectMessageEnabled(req.body.user) + .then(() => { + return res.status(200).json({ enabled: true }); + }) + .catch(result => { + console.log(result); + if (result.code === 200) { + // DMs are disabled + return res.status(200).json({ enabled: false }); + } else { + // Some other error occured + return res.status(result.code).json({ err: result.message }); + } + }); +}; + exports.getUserHandles = (req, res) => { db.doc(`/users/${req.body.userHandle}`) .get() @@ -574,7 +1192,13 @@ exports.addSubscription = (req, res) => { let userRef = db.doc(`/users/${req.userData.handle}`); userRef.get().then(doc => { new_following = doc.data().following; - new_following.push(req.body.following); + const struct = { + handle: req.body.following, + topics: ["Admin"] + }; + new_following + ? new_following.push(struct) + : (new_following = req.body.following); // add stuff userRef @@ -587,7 +1211,7 @@ exports.addSubscription = (req, res) => { .catch(err => { return res.status(500).json({ err }); }); - return res.status(200).json({ message: "ok" }); + // return res.status(200).json({ message: "ok" }); }); }; @@ -615,58 +1239,74 @@ exports.uploadProfileImage = (req, res) => { let imageFileName; let imageToBeUploaded = {}; - let oldImageFileName = req.userData.imageUrl ? req.userData.imageUrl.split("/o/")[1].split("?alt")[0] : null; + let oldImageFileName = req.userData.imageUrl + ? req.userData.imageUrl.split("/o/")[1].split("?alt")[0] + : null; // console.log(`old file: ${oldImageFileName}`); busboy.on("file", (fieldname, file, filename, encoding, mimetype) => { - if (mimetype !== 'image/jpeg' && mimetype !== 'image/png') { + if (mimetype !== "image/jpeg" && mimetype !== "image/png") { return res.status(400).json({ error: "Wrong filetype submitted" }); } // console.log(fieldname); // console.log(filename); // console.log(mimetype); - const imageExtension = filename.split(".")[filename.split(".").length - 1]; // Get the image file extension - imageFileName = `${Math.round(Math.random() * 100000000000)}.${imageExtension}`; // Get a random filename + const imageExtension = filename.split(".")[filename.split(".").length - 1]; // Get the image file extension + imageFileName = `${Math.round( + Math.random() * 100000000000 + )}.${imageExtension}`; // Get a random filename const filepath = path.join(os.tmpdir(), imageFileName); imageToBeUploaded = { filepath, mimetype }; file.pipe(fs.createWriteStream(filepath)); }); busboy.on("finish", () => { // Save the file to the storage bucket - admin.storage().bucket(config.storageBucket).upload(imageToBeUploaded.filepath, { - resumable: false, - metadata: { + admin + .storage() + .bucket(config.storageBucket) + .upload(imageToBeUploaded.filepath, { + resumable: false, metadata: { - contentType: imageToBeUploaded.mimetype + metadata: { + contentType: imageToBeUploaded.mimetype + } } - } - }) - .then(() => { - // Add the new URL to the user's profile - const imageUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}?alt=media`; - return db.doc(`/users/${req.user.handle}`).update({ imageUrl }); - }) - .then(() => { - // Delete their old image if they have one - if (oldImageFileName !== null && oldImageFileName !== "no-img.png") { - admin.storage().bucket(config.storageBucket).file(oldImageFileName).delete() - .then(() => { - return res.status(201).json({ message: "Image uploaded successfully1"}); - }) - .catch((err) => { - console.log(err); - return res.status(201).json({ message: "Image uploaded successfully2"}); - }) + }) + .then(() => { + // Add the new URL to the user's profile + const imageUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}?alt=media`; + return db.doc(`/users/${req.user.handle}`).update({ imageUrl }); + }) + .then(() => { + // Delete their old image if they have one + if (oldImageFileName !== null && oldImageFileName !== "no-img.png") { + admin + .storage() + .bucket(config.storageBucket) + .file(oldImageFileName) + .delete() + .then(() => { + return res + .status(201) + .json({ message: "Image uploaded successfully1" }); + }) + .catch(err => { + console.log(err); + return res + .status(201) + .json({ message: "Image uploaded successfully2" }); + }); // return res.status(201).json({ message: "Image uploaded successfully"}); - } else { - return res.status(201).json({ message: "Image uploaded successfully3"}); - } - - }) - .catch((err) => { - console.error(err); - return res.status(500).json({ error: err.code}) - }) + } else { + return res + .status(201) + .json({ message: "Image uploaded successfully3" }); + } + }) + .catch(err => { + console.error(err); + return res.status(500).json({ error: err.code }); + }); }); busboy.end(req.rawBody); @@ -722,7 +1362,7 @@ exports.uploadProfileImage = (req, res) => { // }); // }); // busboy.end(req.rawBody); -} +}; exports.removeSub = (req, res) => { let new_following = []; @@ -731,7 +1371,7 @@ exports.removeSub = (req, res) => { new_following = doc.data().following; // remove username from array new_following.forEach(function(follower, index) { - if (follower === `${req.body.unfollow}`) { + if (follower.handle === `${req.body.unfollow}`) { new_following.splice(index, 1); } }); diff --git a/functions/index.js b/functions/index.js index d2ceb95..5306ae7 100644 --- a/functions/index.js +++ b/functions/index.js @@ -11,6 +11,11 @@ app.use(cors()); *------------------------------------------------------------------*/ const { getAuthenticatedUser, + getDirectMessages, + sendDirectMessage, + createDirectMessage, + checkDirectMessagesEnabled, + toggleDirectMessages, getAllHandles, getUserDetails, getProfileInfo, @@ -39,6 +44,22 @@ app.post("/login", login); //Deletes user account app.delete("/delete", fbAuth, deleteUser); +// Returns all direct messages that the user is participating in +app.get("/dms", fbAuth, getDirectMessages); + +// Send a message in a DM from one user to another +app.post("/dms/send", fbAuth, sendDirectMessage); + +// Create a new DM between two users +app.post("/dms/new", fbAuth, createDirectMessage); + +// Checks if the user provided has DMs enabled or not +app.post("/dms/enabled", checkDirectMessagesEnabled); + +// Used to toggle DMs on or off for the current user +app.post("/dms/toggle", fbAuth, toggleDirectMessages); + +app.get("/getUser", fbAuth, getUserDetails); app.post("/getUserDetails", fbAuth, getUserDetails); @@ -83,8 +104,21 @@ app.post("/removeSub", fbAuth, removeSub); * handlers/post.js * *------------------------------------------------------------------*/ -const { getallPostsforUser, getallPosts, putPost, hidePost, likePost, unlikePost, getLikes, quoteWithPost, quoteWithoutPost, checkforLikePost, getOtherUsersPosts} = require("./handlers/post"); +const { + getallPostsforUser, + getallPosts, + putPost, + hidePost, + likePost, + unlikePost, + getLikes, + quoteWithPost, + quoteWithoutPost, + checkforLikePost, + getOtherUsersPosts, + getAlert +} = require("./handlers/post"); app.get("/getallPostsforUser", fbAuth, getallPostsforUser); @@ -106,6 +140,8 @@ app.post("/quoteWithoutPost/:postId", fbAuth, quoteWithoutPost); app.post("/getOtherUsersPosts", fbAuth, getOtherUsersPosts); +app.get("/getAlert", fbAuth, getAlert); + /*------------------------------------------------------------------* * handlers/topic.js * *------------------------------------------------------------------*/ @@ -113,7 +149,8 @@ const { putTopic, getAllTopics, deleteTopic, - getUserTopics + getUserTopics, + putNewTopic } = require("./handlers/topic"); // add topic to database @@ -128,4 +165,6 @@ app.post("/deleteTopic", fbAuth, deleteTopic); // get topic for this user app.post("/getUserTopics", fbAuth, getUserTopics); +app.post("/putNewTopic", fbAuth, putNewTopic); + exports.api = functions.https.onRequest(app); diff --git a/twistter-frontend/package.json b/twistter-frontend/package.json index c048bb4..daf9b48 100644 --- a/twistter-frontend/package.json +++ b/twistter-frontend/package.json @@ -10,7 +10,7 @@ "axios": "^0.19.0", "clsx": "^1.0.4", "create-react-app": "^3.1.2", - "firebase-admin": "^8.8.0", + "dayjs": "^1.8.17", "fuse.js": "^3.4.6", "install": "^0.13.0", "jwt-decode": "^2.2.0", @@ -23,7 +23,8 @@ "react-scripts": "0.9.5", "redux": "^4.0.4", "redux-thunk": "^2.3.0", - "typeface-roboto": "0.0.75" + "typeface-roboto": "0.0.75", + "underscore": "^1.9.1" }, "devDependencies": {}, "scripts": { diff --git a/twistter-frontend/src/App.js b/twistter-frontend/src/App.js index 1ed56dc..6dd4550 100644 --- a/twistter-frontend/src/App.js +++ b/twistter-frontend/src/App.js @@ -31,6 +31,7 @@ import editProfile from "./pages/editProfile"; import userLine from "./Userline.js"; import verify from "./pages/verify"; import Search from "./pages/Search.js"; +import directMessages from "./pages/directMessages"; import otherUser from "./pages/otherUser"; const theme = createMuiTheme(themeObject); @@ -62,7 +63,7 @@ class App extends Component {
-
+
{/* AuthRoute checks if the user is logged in and if they are it redirects them to /home */} @@ -77,6 +78,7 @@ class App extends Component { + diff --git a/twistter-frontend/src/Writing_Microblogs.js b/twistter-frontend/src/Writing_Microblogs.js index 70b67d0..2b31bb5 100644 --- a/twistter-frontend/src/Writing_Microblogs.js +++ b/twistter-frontend/src/Writing_Microblogs.js @@ -8,6 +8,7 @@ import TextField from '@material-ui/core/TextField'; // import Typography from '@material-ui/core/Typography'; import Button from '@material-ui/core/Button'; import withStyles from "@material-ui/styles/withStyles"; +import CircularProgress from "@material-ui/core/CircularProgress"; const styles = { container: { @@ -21,6 +22,13 @@ const styles = { }, textField: { marginBottom: 15 + }, + progress: { + position: "absolute" + }, + button: { + positon: "relative", + marginBottom: 30 } } @@ -31,7 +39,8 @@ class Writing_Microblogs extends Component { value: "", title: "", topics: "", - characterCount: 250 + characterCount: 250, + loading: false }; this.handleChange = this.handleChange.bind(this); @@ -56,11 +65,15 @@ class Writing_Microblogs extends Component { microBlogTitle: this.state.title, microBlogTopics: this.state.topics.split(", ") }; + + this.setState({ + loading: true + }) const headers = { headers: { "Content-Type": "application/json" } }; - axios + let postPromise = axios .post("/putPost", postData, headers) // TODO: add topics .then(res => { // alert("Post was shared successfully!"); @@ -71,8 +84,9 @@ class Writing_Microblogs extends Component { console.error(err); }); console.log(postData.microBlogTopics); + let topicPromises = []; postData.microBlogTopics.forEach(topic => { - axios + topicPromises.push(axios .post("/putTopic", { following: topic }) @@ -81,10 +95,24 @@ class Writing_Microblogs extends Component { }) .catch(err => { console.error(err); - }); + }) + ) }); event.preventDefault(); - this.setState({ value: "", title: "", characterCount: 250, topics: "" }); + topicPromises.push(postPromise); + Promise.all(topicPromises) + .then(() => { + this.setState({ + value: "", + title: "", + characterCount: 250, + topics: "", + loading: false + }); + }) + .catch((error) => { + console.log(error); + }) } handleChangeforPost(event) { @@ -149,12 +177,14 @@ class Writing_Microblogs extends Component { autoComplete='off' />
diff --git a/twistter-frontend/src/components/layout/NavBar.js b/twistter-frontend/src/components/layout/NavBar.js index f1e1b4a..761db65 100644 --- a/twistter-frontend/src/components/layout/NavBar.js +++ b/twistter-frontend/src/components/layout/NavBar.js @@ -46,6 +46,11 @@ export class Navbar extends Component { Profile )} + {authenticated && ( + + )} {!authenticated && ( )} {authenticated && ( - )} diff --git a/twistter-frontend/src/pages/Home.js b/twistter-frontend/src/pages/Home.js index 0704b60..d635587 100644 --- a/twistter-frontend/src/pages/Home.js +++ b/twistter-frontend/src/pages/Home.js @@ -6,41 +6,58 @@ import axios from "axios"; // Material UI and React Router -import CircularProgress from '@material-ui/core/CircularProgress'; -import Button from '@material-ui/core/Button'; +import CircularProgress from "@material-ui/core/CircularProgress"; +import Button from "@material-ui/core/Button"; import Grid from "@material-ui/core/Grid"; import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; -import TextField from '@material-ui/core/TextField'; +import TextField from "@material-ui/core/TextField"; import Typography from "@material-ui/core/Typography"; -import withStyles from '@material-ui/styles/withStyles'; +import withStyles from "@material-ui/styles/withStyles"; // component -import '../App.css'; -import logo from '../images/twistter-logo.png'; -import noImage from '../images/no-img.png'; -import Writing_Microblogs from '../Writing_Microblogs'; -import ReactModal from 'react-modal'; +import "../App.css"; +import logo from "../images/twistter-logo.png"; +import noImage from "../images/no-img.png"; +import Writing_Microblogs from "../Writing_Microblogs"; +import ReactModal from "react-modal"; // Redux -import { likePost, unlikePost, getLikes } from '../redux/actions/userActions'; - +import { likePost, unlikePost, getLikes } from "../redux/actions/userActions"; const styles = { card: { marginBottom: 5 } -} +}; class Home extends Component { state = { - likes: [] + likes: [], + loading: false, + following: null, + topics: null }; - componentDidMount() { - axios + this.setState({ loading: true }); + let userPromise = axios + .get("/user") + .then(res => { + console.log(res.data.credentials.following); + let list = []; + res.data.credentials.following.forEach(element => { + list.push(element.handle); + }); + this.setState({ + following: list, + topics: res.data.credentials.followedTopics + }); + }) + .catch(err => console.log(err)); + + let postPromise = axios .get("/getallPosts") .then(res => { // console.log(res.data); @@ -50,13 +67,23 @@ class Home extends Component { }) .catch(err => console.log(err)); + Promise.all([userPromise, postPromise]) + .then(() => { + this.setState({ + loading: false + }); + }) + .catch(error => { + console.log(error); + }); + this.props.getLikes(); } componentWillReceiveProps(nextProps) { this.setState({ likes: nextProps.user.likes - }) + }); } flagPost = (event) => { @@ -76,22 +103,23 @@ class Home extends Component { handleClickLikeButton = (event) => { // Need the ternary if statement because the user can click on the text or body of the // Button and they are two different html elements - let postId = event.target.dataset.key ? event.target.dataset.key : event.target.parentNode.dataset.key; - console.log(postId) + let postId = event.target.dataset.key + ? event.target.dataset.key + : event.target.parentNode.dataset.key; + console.log(postId); let doc = document.getElementById(postId); // console.log(postId); if (this.state.likes.includes(postId)) { - this.props.unlikePost(postId, this.state.likes) + this.props.unlikePost(postId, this.state.likes); doc.dataset.likes--; - } else { - this.props.likePost(postId, this.state.likes) + } else { + this.props.likePost(postId, this.state.likes); doc.dataset.likes++; } doc.innerHTML = "Likes " + doc.dataset.likes; - - } + }; formatDate(dateString) { let newDate = new Date(Date.parse(dateString)); @@ -99,10 +127,11 @@ class Home extends Component { } render() { - - const { UI:{ loading } } = this.props; + const { + UI: { loading } + } = this.props; let authenticated = this.props.user.authenticated; - let {classes} = this.props; + let { classes } = this.props; let username = this.props.user.credentials.handle; console.log(username); var hiddenBool = true; @@ -112,7 +141,10 @@ class Home extends Component { console.log(hiddenBool); let postMarkup = this.state.posts ? ( +// <<<<<<< admin-delete this.state.posts.map(post => post.hidden ? null : + this.state.following ? + this.state.following.includes(post.userHandle) ? ( @@ -133,7 +165,7 @@ class Home extends Component {
{post.body}
- Topics: {post.microBlogTopics} + Topics: {post.microBlogTopics.join(", ")}
{!hiddenBool && - -
-
- -
-
- - )); +
+ Join today or sign in if you already have an account. +
+
+
+ +
+
+
+ +
+
+ + ); } } @@ -218,38 +281,36 @@ class Quote extends Component { characterCount: 250, showModal: false, value: "" - } + }; - this.handleSubmitWithoutPost = this.handleSubmitWithoutPost.bind(this); - this.handleOpenModal = this.handleOpenModal.bind(this); - this.handleCloseModal = this.handleCloseModal.bind(this); - this.handleSubmit = this.handleSubmit.bind(this); + this.handleSubmitWithoutPost = this.handleSubmitWithoutPost.bind(this); + this.handleOpenModal = this.handleOpenModal.bind(this); + this.handleCloseModal = this.handleCloseModal.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); } handleSubmitWithoutPost(event) { const post = { - - userImage: "bing-url", - } + userImage: "bing-url" + }; const headers = { headers: { "Content-Type": "application/json" } }; - axios.post(`/quoteWithoutPost/${this.props.microblog}`, post, headers) - .then((res) => { - - console.log(res.data); - }) - .catch(err => { - - console.error(err); - }); + axios + .post(`/quoteWithoutPost/${this.props.microblog}`, post, headers) + .then(res => { + console.log(res.data); + }) + .catch(err => { + console.error(err); + }); event.preventDefault(); } handleOpenModal() { this.setState({ showModal: true }); } - + handleCloseModal() { this.setState({ showModal: false, characterCount: 250, value: "" }); } @@ -267,20 +328,19 @@ class Quote extends Component { handleSubmit(event) { const quotedPost = { quoteBody: this.state.value, - userImage: "bing-url", + userImage: "bing-url" }; const headers = { headers: { "Content-Type": "application/json" } }; - axios.post(`/quoteWithPost/${this.props.microblog}`, quotedPost, headers) - .then((res) => { - - console.log(res.data); - }) - .catch(err => { - - console.error(err); - }); + axios + .post(`/quoteWithPost/${this.props.microblog}`, quotedPost, headers) + .then(res => { + console.log(res.data); + }) + .catch(err => { + console.error(err); + }); event.preventDefault(); this.setState({ showModal: false, characterCount: 250, value: "" }); } @@ -288,14 +348,29 @@ class Quote extends Component { render() { return (
- - + Quote with Post + +
-
- {/*