From 44d3450b1040b31442d1933e48b6fb663f6e0728 Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Sun, 27 Oct 2019 18:06:47 -0400 Subject: [PATCH 01/31] Profile image upload frontend and backend finished --- functions/handlers/users.js | 53 +++++++- functions/index.js | 8 +- functions/package.json | 1 + functions/util/fbAuth.js | 12 +- twistter-frontend/src/pages/editProfile.js | 121 +++++++++++++++++- .../src/redux/actions/userActions.js | 23 +++- .../src/redux/reducers/userReducer.js | 8 +- 7 files changed, 210 insertions(+), 16 deletions(-) diff --git a/functions/handlers/users.js b/functions/handlers/users.js index 1af539d..5fc219c 100644 --- a/functions/handlers/users.js +++ b/functions/handlers/users.js @@ -53,6 +53,8 @@ exports.signup = (req, res) => { return res.status(400).json(errors); } + const noImg = 'no-img.png'; + let token, userId; db.doc(`/users/${newUser.handle}`) @@ -77,6 +79,7 @@ exports.signup = (req, res) => { email: newUser.email, handle: newUser.handle, createdAt: newUser.createdAt, + imageUrl: `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${noImg}?alt=media`, userId }; handle2Email.set(userCred.handle, userCred.email); @@ -207,7 +210,7 @@ exports.updateProfileInfo = (req, res) => { // Update the database entry for this user db.collection("users") .doc(req.user.handle) - .set(profileData, { merge: true }) + .set(profileData) .then(() => { console.log(`${req.user.handle}'s profile info has been updated.`); return res @@ -241,6 +244,7 @@ exports.getUserDetails = (req, res) => { }); }; +// Returns all data stored for a user exports.getAuthenticatedUser = (req, res) => { let credentials = {}; db.doc(`/users/${req.user.handle}`) @@ -258,4 +262,51 @@ exports.getAuthenticatedUser = (req, res) => { }); }; +// Uploads a profile image +exports.uploadProfileImage = (req, res) => { + const BusBoy = require("busboy"); + const path = require("path"); + const os = require("os"); + const fs = require("fs"); + const busboy = new BusBoy({ headers: req.headers }); + + let imageFileName; + let imageToBeUploaded = {}; + + busboy.on("file", (fieldname, file, filename, encoding, mimetype) => { + 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 filepath = path.join(os.tmpdir(), imageFileName); + imageToBeUploaded = { filepath, mimetype }; + file.pipe(fs.createWriteStream(filepath)); + }); + busboy.on("finish", () => { + admin.storage().bucket().upload(imageToBeUploaded.filepath, { + resumable: false, + metadata: { + metadata: { + contentType: imageToBeUploaded.mimetype + } + } + }) + .then(() => { + const imageUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}?alt=media`; + return db.doc(`/users/${req.user.handle}`).update({ imageUrl }); + }) + .then(() => { + return res.status(201).json({ message: "Image uploaded successfully"}); + }) + .catch((err) => { + console.error(err); + return res.status(500).json({ error: err.code}) + }) + }); + busboy.end(req.rawBody); +} diff --git a/functions/index.js b/functions/index.js index 737d44f..47dda28 100644 --- a/functions/index.js +++ b/functions/index.js @@ -16,7 +16,8 @@ const { login, signup, deleteUser, - updateProfileInfo + updateProfileInfo, + uploadProfileImage } = require("./handlers/users"); // Adds a user to the database and registers them in firebase with @@ -39,8 +40,13 @@ app.get("/getProfileInfo", fbAuth, getProfileInfo); // Updates the currently logged in user's profile information app.post("/updateProfileInfo", fbAuth, updateProfileInfo); +// Returns all user data for the logged in user. +// Used when setting the state in Redux. app.get("/user", fbAuth, getAuthenticatedUser); +// Uploads a profile image +app.post("/user/image", fbAuth, uploadProfileImage); + /*------------------------------------------------------------------* * handlers/post.js * *------------------------------------------------------------------*/ diff --git a/functions/package.json b/functions/package.json index 2e308b3..492ff05 100644 --- a/functions/package.json +++ b/functions/package.json @@ -14,6 +14,7 @@ }, "dependencies": { "axios": "^0.19.0", + "busboy": "^0.3.1", "firebase": "^6.6.2", "firebase-admin": "^8.6.0", "firebase-functions": "^3.1.0" diff --git a/functions/util/fbAuth.js b/functions/util/fbAuth.js index 35253e7..d440bb9 100644 --- a/functions/util/fbAuth.js +++ b/functions/util/fbAuth.js @@ -4,12 +4,12 @@ const { admin, db } = require('./admin'); // The function will only execute if the user is logged in, or rather, they have // a valid token module.exports = (req, res, next) => { - console.log(req); - console.log(req.body); - console.log(req.headers); - console.log(req.headers.authorization); - console.log(JSON.stringify(req.body)); - console.log(JSON.stringify(req.header)); + // console.log(req); + // console.log(req.body); + // console.log(req.headers); + // console.log(req.headers.authorization); + // console.log(JSON.stringify(req.body)); + // console.log(JSON.stringify(req.header)); let idToken; diff --git a/twistter-frontend/src/pages/editProfile.js b/twistter-frontend/src/pages/editProfile.js index ff6f3f7..39ad93f 100644 --- a/twistter-frontend/src/pages/editProfile.js +++ b/twistter-frontend/src/pages/editProfile.js @@ -4,13 +4,23 @@ import PropTypes from "prop-types"; // TODO: Add a read-only '@' in the left side of the handle input // TODO: Add a cancel button, that takes the user back to their profile page +import noImage from '../images/no-img.png'; + // Material-UI stuff import Button from "@material-ui/core/Button"; +import Box from "@material-ui/core/Box"; import CircularProgress from "@material-ui/core/CircularProgress"; import Grid from "@material-ui/core/Grid"; import TextField from "@material-ui/core/TextField"; import Typography from "@material-ui/core/Typography"; import withStyles from "@material-ui/core/styles/withStyles"; +import IconButton from "@material-ui/core/IconButton"; +import EditIcon from "@material-ui/icons/Edit"; +import Tooltip from "@material-ui/core/Tooltip"; + +// Redux stuff +import { connect } from "react-redux"; +import { uploadImage } from "../redux/actions/userActions"; const styles = { form: { @@ -27,25 +37,52 @@ const styles = { positon: "relative", marginBottom: 30 }, + box: { + position: "relative" + }, progress: { position: "absolute" + }, + uploadProgress: { + position: "absolute", + marginLeft: -155, + marginTop: 95 } }; export class edit extends Component { + // mapReduxToState = (credentials) => { + // this.setState({ + // imageUrl: credentials.imageUrl ? credentials.imageUrl : noImage, + // firstName: credentials.firstName ? credentials.firstName : '', + // lastName: credentials.lastName ? credentials.lastName : '', + // email: credentials.email ? credentials.email : 'error, email doesn\'t exist', + // handle: credentials.handle ? credentials.handle : 'error, handle doesn\'t exist', + // bio: credentials.bio ? credentials.bio : '' + // }); + // }; + + + // Runs as soon as the page loads. // Sets the default values of all the textboxes to the data // that is stored in the database for the user. componentDidMount() { + // const { credentials } = this.props; + // console.log(this.props.user); + // this.mapReduxToState(credentials); axios .get("/getProfileInfo") .then((res) => { + // Need to have the ternary if statements, because react throws an error if + // any of the res.data keys are undefined this.setState({ - firstName: res.data.firstName, - lastName: res.data.lastName, + imageUrl: res.data.imageUrl, + firstName: res.data.firstName ? res.data.firstName : "", + lastName: res.data.lastName ? res.data.lastName : "", email: res.data.email, handle: res.data.handle, - bio: res.data.bio + bio: res.data.bio ? res.data.bio : "" }); }) .catch((err) => { @@ -63,6 +100,7 @@ export class edit extends Component { constructor() { super(); this.state = { + imageUrl: "", firstName: "", lastName: "", email: "", @@ -108,6 +146,7 @@ export class edit extends Component { }) .catch((err) => { console.log(err); + // TODO: Should redirect to login page if they get a 403 this.setState({ errors: err.response.data, loading: false @@ -128,10 +167,65 @@ export class edit extends Component { }); }; + handleImageChange = (event) => { + const image = event.target.files[0]; + const formData = new FormData(); + formData.append('image', image, image.name); + this.props.uploadImage(formData); + } + + handleEditPicture = () => { + const fileInput = document.getElementById('imageUpload'); + fileInput.click(); + } + + // logging = () => { + // console.log(this.state); + // console.log(this.props); + // this.mapReduxToState(this.props.credentials); + // } + render() { const { classes } = this.props; + const uploading = this.props.UI.loading; const { errors, loading } = this.state; + // let imageMarkup = this.state.imageUrl ? ( + // + // ) : (); + + let imageMarkup = this.props.user.credentials.imageUrl ? ( + + + {uploading && ( + + )} + + ) : ( + + + {uploading && ( + + )} + + ) + return ( @@ -140,6 +234,13 @@ export class edit extends Component { Edit Profile
+ {imageMarkup} + + + + + + Submit {loading && ( @@ -234,8 +335,18 @@ export class edit extends Component { } } +const mapStateToProps = (state) => ({ + user: state.user, + UI: state.UI, + // credentials: state.user.credentials +}); + +const mapActionsToProps = { uploadImage } + edit.propTypes = { + uploadImage: PropTypes.func.isRequired, classes: PropTypes.object.isRequired }; -export default withStyles(styles)(edit); +// export default withStyles(styles)(edit); +export default connect(mapStateToProps, mapActionsToProps)(withStyles(styles)(edit)); \ No newline at end of file diff --git a/twistter-frontend/src/redux/actions/userActions.js b/twistter-frontend/src/redux/actions/userActions.js index 5993804..41bd4bb 100644 --- a/twistter-frontend/src/redux/actions/userActions.js +++ b/twistter-frontend/src/redux/actions/userActions.js @@ -1,8 +1,9 @@ -import {SET_USER, SET_ERRORS, CLEAR_ERRORS, LOADING_UI, SET_AUTHENTICATED, SET_UNAUTHENTICATED} from '../types'; +import {SET_USER, SET_ERRORS, CLEAR_ERRORS, LOADING_UI, SET_AUTHENTICATED, SET_UNAUTHENTICATED, LOADING_USER} from '../types'; import axios from 'axios'; - +// Gets Database info for the logged in user and sets it in Redux export const getUserData = () => (dispatch) => { + dispatch({ type: LOADING_USER }); axios.get('/user') .then((res) => { dispatch({ @@ -13,6 +14,7 @@ export const getUserData = () => (dispatch) => { .catch((err) => console.error(err)); } +// Sends login data to firebase and sets the user data in Redux export const loginUser = (loginData, history) => (dispatch) => { dispatch({ type: LOADING_UI }); axios @@ -33,6 +35,7 @@ export const loginUser = (loginData, history) => (dispatch) => { }); }; +// Sends signup data to firebase and sets the user data in Redux export const signupUser = (newUserData, history) => (dispatch) => { dispatch({ type: LOADING_UI }); axios @@ -55,12 +58,14 @@ export const signupUser = (newUserData, history) => (dispatch) => { }); }; +// Deletes the Authorization header and clears all user data from Redux export const logoutUser = () => (dispatch) => { localStorage.removeItem('FBIdToken'); delete axios.defaults.headers.common['Authorization']; dispatch({ type: SET_UNAUTHENTICATED }); } + export const deleteUser = () => (dispatch) => { axios .delete("/delete") @@ -81,8 +86,22 @@ export const deleteUser = () => (dispatch) => { dispatch({ type: SET_UNAUTHENTICATED }); } +// Saves Authorization in browser local storage and adds it as a header to axios const setAuthorizationHeader = (token) => { const FBIdToken = `Bearer ${token}`; localStorage.setItem('FBIdToken', FBIdToken); axios.defaults.headers.common['Authorization'] = FBIdToken; +} + +// Sends an image data form to firebase to be uploaded to the user profile +export const uploadImage = (formData) => (dispatch) => { + dispatch({ type: LOADING_UI }); + axios.post('/user/image', formData) + .then(() => { + dispatch(getUserData()); + dispatch({ type: CLEAR_ERRORS }); + }) + .catch(err => { + console.log(err); + }) } \ No newline at end of file diff --git a/twistter-frontend/src/redux/reducers/userReducer.js b/twistter-frontend/src/redux/reducers/userReducer.js index 7a29e90..e5081f2 100644 --- a/twistter-frontend/src/redux/reducers/userReducer.js +++ b/twistter-frontend/src/redux/reducers/userReducer.js @@ -1,4 +1,4 @@ -import {SET_USER, SET_ERRORS, CLEAR_ERRORS, LOADING_UI, SET_AUTHENTICATED, SET_UNAUTHENTICATED} from '../types'; +import {SET_USER, SET_ERRORS, CLEAR_ERRORS, LOADING_UI, SET_AUTHENTICATED, SET_UNAUTHENTICATED, LOADING_USER} from '../types'; const initialState = { authenticated: false, @@ -20,8 +20,14 @@ export default function(state = initialState, action) { case SET_USER: return { authenticated: true, + loading: false, ...action.payload, }; + case LOADING_USER: + return { + ...state, + loading: true + } default: return state; } From e8a403f575b009ef0794076e59abeeab2c074d36 Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Sun, 27 Oct 2019 23:43:35 -0400 Subject: [PATCH 02/31] Delete old profile image --- functions/handlers/users.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/functions/handlers/users.js b/functions/handlers/users.js index 5fc219c..71c8783 100644 --- a/functions/handlers/users.js +++ b/functions/handlers/users.js @@ -273,6 +273,8 @@ exports.uploadProfileImage = (req, res) => { let imageFileName; let imageToBeUploaded = {}; + let oldImageFileName = req.userData.imageUrl.split("/o/")[1].split("?alt")[0]; + console.log(`old file: ${oldImageFileName}`); busboy.on("file", (fieldname, file, filename, encoding, mimetype) => { if (mimetype !== 'image/jpeg' && mimetype !== 'image/png') { @@ -301,7 +303,19 @@ exports.uploadProfileImage = (req, res) => { return db.doc(`/users/${req.user.handle}`).update({ imageUrl }); }) .then(() => { - return res.status(201).json({ message: "Image uploaded successfully"}); + if (oldImageFileName !== "no-img.png") { + admin.storage().bucket().file(oldImageFileName).delete() + .then(() => { + return res.status(201).json({ message: "Image uploaded successfully"}); + }) + .catch((err) => { + console.log(err); + return res.status(201).json({ message: "Image uploaded successfully"}); + }) + } else { + return res.status(201).json({ message: "Image uploaded successfully"}); + } + }) .catch((err) => { console.error(err); From fb6c1e3d9864e28fa00fd5a91ca88bce57af34c4 Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Tue, 29 Oct 2019 12:40:38 -0400 Subject: [PATCH 03/31] Image upload edit some return messages --- functions/handlers/users.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/functions/handlers/users.js b/functions/handlers/users.js index d8429db..ec71b0f 100644 --- a/functions/handlers/users.js +++ b/functions/handlers/users.js @@ -1,4 +1,5 @@ /* eslint-disable promise/catch-or-return */ +/* eslint-disable promise/always-return */ const { admin, db } = require("../util/admin"); const config = require("../util/config"); @@ -307,14 +308,15 @@ exports.uploadProfileImage = (req, res) => { if (oldImageFileName !== "no-img.png") { admin.storage().bucket().file(oldImageFileName).delete() .then(() => { - return res.status(201).json({ message: "Image uploaded successfully"}); + return res.status(201).json({ message: "Image uploaded successfully1"}); }) .catch((err) => { console.log(err); - return res.status(201).json({ message: "Image uploaded successfully"}); + 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 successfully"}); + return res.status(201).json({ message: "Image uploaded successfully3"}); } }) From c96c77cd9f19932d580886019ed66f808bd0d4c2 Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Tue, 29 Oct 2019 15:00:21 -0400 Subject: [PATCH 04/31] Debugging upload issues --- functions/handlers/users.js | 147 +++++++++++++++++++++++++----------- 1 file changed, 102 insertions(+), 45 deletions(-) diff --git a/functions/handlers/users.js b/functions/handlers/users.js index ec71b0f..4138134 100644 --- a/functions/handlers/users.js +++ b/functions/handlers/users.js @@ -266,64 +266,121 @@ exports.getAuthenticatedUser = (req, res) => { // Uploads a profile image exports.uploadProfileImage = (req, res) => { - const BusBoy = require("busboy"); - const path = require("path"); - const os = require("os"); - const fs = require("fs"); + // const BusBoy = require("busboy"); + // const path = require("path"); + // const os = require("os"); + // const fs = require("fs"); + + // const busboy = new BusBoy({ headers: req.headers }); + + // let imageFileName; + // let imageToBeUploaded = {}; + // let oldImageFileName = req.userData.imageUrl.split("/o/")[1].split("?alt")[0]; + // console.log(`old file: ${oldImageFileName}`); + + // busboy.on("file", (fieldname, file, filename, encoding, mimetype) => { + // 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 filepath = path.join(os.tmpdir(), imageFileName); + // imageToBeUploaded = { filepath, mimetype }; + // file.pipe(fs.createWriteStream(filepath)); + // }); + // busboy.on("finish", () => { + // admin.storage().bucket().upload(imageToBeUploaded.filepath, { + // resumable: false, + // metadata: { + // metadata: { + // contentType: imageToBeUploaded.mimetype + // } + // } + // }) + // .then(() => { + // const imageUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}?alt=media`; + // return db.doc(`/users/${req.user.handle}`).update({ imageUrl }); + // }) + // .then(() => { + // if (oldImageFileName !== "no-img.png") { + // admin.storage().bucket().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}) + // }) + // }); + // busboy.end(req.rawBody); + + const BusBoy = require('busboy'); + const path = require('path'); + const os = require('os'); + const fs = require('fs'); const busboy = new BusBoy({ headers: req.headers }); - let imageFileName; let imageToBeUploaded = {}; - let oldImageFileName = req.userData.imageUrl.split("/o/")[1].split("?alt")[0]; - console.log(`old file: ${oldImageFileName}`); + let imageFileName; - busboy.on("file", (fieldname, file, filename, encoding, mimetype) => { + busboy.on('file', (fieldname, file, filename, encoding, mimetype) => { + // console.log(fieldname, file, filename, encoding, mimetype); if (mimetype !== 'image/jpeg' && mimetype !== 'image/png') { - return res.status(400).json({ error: "Wrong filetype submitted" }); + return res.status(400).json({ error: 'Wrong file type 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 + // my.image.png => ['my', 'image', 'png'] + const imageExtension = filename.split('.')[filename.split('.').length - 1]; + // 32756238461724837.png + imageFileName = `${Math.round( + Math.random() * 1000000000000 + ).toString()}.${imageExtension}`; const filepath = path.join(os.tmpdir(), imageFileName); imageToBeUploaded = { filepath, mimetype }; file.pipe(fs.createWriteStream(filepath)); }); - busboy.on("finish", () => { - admin.storage().bucket().upload(imageToBeUploaded.filepath, { - resumable: false, - metadata: { + busboy.on('finish', () => { + admin + .storage() + .bucket() + .upload(imageToBeUploaded.filepath, { + resumable: false, metadata: { - contentType: imageToBeUploaded.mimetype + metadata: { + contentType: imageToBeUploaded.mimetype + } } - } - }) - .then(() => { - const imageUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}?alt=media`; - return db.doc(`/users/${req.user.handle}`).update({ imageUrl }); - }) - .then(() => { - if (oldImageFileName !== "no-img.png") { - admin.storage().bucket().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}) - }) + }) + .then(() => { + const imageUrl = `https://firebasestorage.googleapis.com/v0/b/${ + config.storageBucket + }/o/${imageFileName}?alt=media`; + return db.doc(`/users/${req.user.handle}`).update({ imageUrl }); + }) + .then(() => { + return res.json({ message: 'image uploaded successfully' }); + }) + .catch((err) => { + console.error(err); + return res.status(500).json({ error: 'something went wrong' }); + }); }); + try { busboy.end(req.rawBody); + } catch (err) { + return res.status(500).json({error: err}); + } } From ab07d45205b62c368e8809f26739e6b084933ba6 Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Fri, 1 Nov 2019 10:12:54 -0400 Subject: [PATCH 05/31] Fix loading on image upload, so it waits for new image --- twistter-frontend/src/redux/actions/userActions.js | 5 +++-- twistter-frontend/src/redux/reducers/uiReducer.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/twistter-frontend/src/redux/actions/userActions.js b/twistter-frontend/src/redux/actions/userActions.js index 41bd4bb..5067258 100644 --- a/twistter-frontend/src/redux/actions/userActions.js +++ b/twistter-frontend/src/redux/actions/userActions.js @@ -9,7 +9,8 @@ export const getUserData = () => (dispatch) => { dispatch({ type: SET_USER, payload: res.data, - }) + }); + dispatch({type: CLEAR_ERRORS}); }) .catch((err) => console.error(err)); } @@ -99,7 +100,7 @@ export const uploadImage = (formData) => (dispatch) => { axios.post('/user/image', formData) .then(() => { dispatch(getUserData()); - dispatch({ type: CLEAR_ERRORS }); + // dispatch({ type: CLEAR_ERRORS }); }) .catch(err => { console.log(err); diff --git a/twistter-frontend/src/redux/reducers/uiReducer.js b/twistter-frontend/src/redux/reducers/uiReducer.js index 65e781d..491206e 100644 --- a/twistter-frontend/src/redux/reducers/uiReducer.js +++ b/twistter-frontend/src/redux/reducers/uiReducer.js @@ -23,7 +23,7 @@ export default function(state = initialState, action) { return { ...state, loading: true - } + }; default: return state; } From 3fa4cd70337cb7c96fded9ac25d8807a5643fb51 Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Fri, 1 Nov 2019 13:02:37 -0400 Subject: [PATCH 06/31] Changing writing microblogs to Material-UI --- twistter-frontend/src/Writing_Microblogs.js | 215 +++++++++++++++----- twistter-frontend/src/pages/Home.js | 9 +- twistter-frontend/src/pages/user.js | 7 +- 3 files changed, 173 insertions(+), 58 deletions(-) diff --git a/twistter-frontend/src/Writing_Microblogs.js b/twistter-frontend/src/Writing_Microblogs.js index 9cac7b7..e800d56 100644 --- a/twistter-frontend/src/Writing_Microblogs.js +++ b/twistter-frontend/src/Writing_Microblogs.js @@ -3,6 +3,29 @@ import { BrowserRouter as Router } from "react-router-dom"; import Route from "react-router-dom/Route"; import axios from "axios"; +// Material-UI +import TextField from '@material-ui/core/TextField'; +import Button from '@material-ui/core/Button'; +import withStyles from "@material-ui/styles/withStyles"; + +const styles = { + container: { + position: "fixed" + }, + form: { + width: "300px", + height: "50px", + marginTop: "180px", + marginLeft: "50px" + }, + textField: { + marginBottom: 20 + } + // TextField: { + // marginBottom: "30px" + // } +} + class Writing_Microblogs extends Component { constructor(props) { super(props); @@ -64,65 +87,147 @@ class Writing_Microblogs extends Component { } render() { + const { classes } = this.props; return ( -
-
- -