Hi Lauren,
I removed ‘background: “#dcdcdc”,’ in line 1 for the code but the error still shows that points to background in line 3. I don’t know which one is important for me to keep. Should I remove background in line 3 or in line 2?=
style={{
background: “#dcdcdc”,
background: “-webkit-linear-gradient(to left, #dcdcdc, #ee82ee
)”,
background: “linear-gradient(to left, #dcdcdc, #ee82ee
)”,
}}
Do I remove both import React, { Component } from “react”; & import { withRouter } from “react-router-dom”;?
Here is my MongoDB Compass database=
User.js=
const mongoose = require('mongoose');
const { v1: uuidv1 } = require('uuid');
const crypto = require('crypto');
const { ObjectId } = mongoose.Schema;
const userSchema = new mongoose.Schema({
name: {
type: String,
trim: true,
required: true
},
email: {
type: String,
trim: true,
required: true
},
hashed_password: {
type: String,
required: true
},
salt: String,
created: {
type: Date,
default: Date.now
},
updated: Date,
photo: {
data: Buffer,
contentType: String
},
about: {
type: String,
trim: true
},
phone: {
type: String,
trim: true
},
notificationToken: {
type: String
},
following: [{
type: ObjectId,
ref: "User"
}],
followers: [{
type: ObjectId,
ref: "User"
}],
resetPasswordLink: {
data: String,
default: ""
}
});
//virtual field
userSchema.virtual('password')
.set(function(password){
//create temp var _password
this._password = password;
//generate a timestamp
this.salt = uuidv1();
// encrypt password
this.hashed_password = this.encryptPassword(password);
})
.get(function(){
return this._password;
})
//methods
userSchema.methods = {
authenticate: function(plainText){
return this.encryptPassword(plainText) === this.hashed_password;
},
encryptPassword: function(password){
if(!password) return "";
try{
return crypto.createHmac('sha1',this.salt)
.update(password)
.digest('hex')
} catch(err){
return ""
}
}
}
module.exports = mongoose.model("User", userSchema);
Profile.js=
import React, { Component } from 'react';
import { isAuthenticated } from "../auth";
import { Redirect, Link } from 'react-router-dom';
import { read } from "./apiUser";
import DefaultProfile from '../images/avatar.jpg';
import DeleteUser from './DeleteUser';
import FollowProfileButton from './FollowProfileButton';
import { listByUser } from '../post/apiPost';
import '../css/Profile.css';
import { Tabs, Tab } from 'react-bootstrap-tabs';
import Loading from '../loading/Loading';
class Profile extends Component {
constructor() {
super();
this.state = {
// user: "",
user: { following: [], followers: [] },
redirectToSignin: false,
following: false,
error: "",
posts: [],
loading: false
}
}
// check follow
checkFollow = (user) => {
const jwt = isAuthenticated();
const match = user.followers.find(follower => {
return follower._id === jwt.user._id
})
return match
}
clickFollowButton = callApi => {
this.setState({ loading: true })
const userId = isAuthenticated().user._id;
const token = isAuthenticated().token;
callApi(userId, token, this.state.user._id)
.then(data => {
if (data.error) {
this.setState({ error: data.error })
} else {
this.setState({ user: data, following: !this.state.following, loading: false })
}
})
}
// profileUnfollow = (unfollowId) => {
// const userId = isAuthenticated().user._id;
// const token = isAuthenticated().token;
// unfollow(userId, token, unfollowId)
// .then(data => {
// if (data.error) {
// this.setState({ error: data.error })
// } else {
// this.setState({ user: data })
// }
// })
// }
// unfollowClick = (e) => {
// const unfollowId = e.target.getAttribute("data-index");
// this.profileUnfollow(unfollowId);
// }
init = (userId) => {
this.setState({ loading: true })
const token = isAuthenticated().token;
read(userId, token)
.then(data => {
if (data.error) {
this.setState({ redirectToSignin: true });
} else {
let following = this.checkFollow(data);
this.setState({ user: data, following });
this.loadPosts(data._id);
}
});
};
loadPosts = (userId) => {
const token = isAuthenticated().token;
listByUser(userId, token)
.then(data => {
if (data.error) {
console.log(data.error)
} else {
this.setState({ posts: data, loading: false });
}
})
}
componentDidMount() {
const userId = this.props.match.params.userId;
this.init(userId);
}
componentWillReceiveProps(props) {
const userId = props.match.params.userId;
this.init(userId);
}
renderProfile = () => {
const { user, following, posts } = this.state;
const photoUrl = user._id ? `${process.env.REACT_APP_API_URL}/user/photo/${user._id}?${new Date().getTime()}` : DefaultProfile;
let followingBadge = <p style={{ marginBottom: "0" }}><span className="badge badge-pill badge-primary">{user.following.length}</span> Following</p>
let followersBadge = <p style={{ marginBottom: "0" }}><span className="badge badge-pill badge-success">{user.followers.length}</span> Followers</p>
let postsBadge = <p style={{ marginBottom: "0" }}><span className="badge badge-pill badge-warning">{posts.length}</span> Posts</p>
return <div className="user-profile">
<div className="row">
<div className="col-md-4">
<div className="profile-info-left">
<div className="text-center">
<img
height="300"
width="300"
src={photoUrl}
alt={user.name}
onError={i => (i.target.src = DefaultProfile)}
className="avatar img-circle"
/>
<h2 className="mt-2" >{user.name}</h2>
</div>
<div className="action-buttons">
{isAuthenticated().user && isAuthenticated().user._id === user._id ? (
<>
<div className="row">
<div className="col-md-4 col-xs-6">
<Link
className="btn btn-sm btn-raised btn-primary"
to={`/post/create`}
>
Create Post
</Link>
</div>
<div className="col-md-4 col-xs-6">
<Link
className="btn btn-sm btn-raised btn-dark"
to={`/user/edit/${user._id}`}
>
Edit Profile
</Link>
</div>
</div>
<div className="mt-2">
<DeleteUser userId={user._id} />
</div>
</>
): (
<div className="row">
<div className="col-md-6 col-xs-6">
<Link
className="btn btn-sm btn-raised btn-success ml-3"
to={`/chat/${isAuthenticated().user._id}/${user._id}`}
>
Message
</Link>
</div>
<div className="col-md-6 col-xs-6">
<FollowProfileButton following={following} onButtonClick={this.clickFollowButton} />
</div>
</div>
)}
</div>
<div className="section">
<h3>About Me</h3>
<p>{user.about}</p>
</div>
<div className="section">
<h3>Phone Number</h3>
<p>{user.phone}</p>
</div>
<div className="section">
<h3>Statistics</h3>
<p><span className="badge badge-pill badge-primary">{user.following.length}</span> Following</p>
<p><span className="badge badge-pill badge-success">{user.followers.length}</span> Followers</p>
<p><span className="badge badge-pill badge-warning">{posts.length}</span> Posts</p>
</div>
</div>
</div>
<div className="col-md-8">
<div className="profile-info-right">
<Tabs onSelect={(index, label) => console.log(label + ' selected')}>
<Tab label={postsBadge} className="tab-title-name">
<div className="row">
{posts.map((post, i) => (
<div key={i} style={{ paddingBottom: "15px" }} className="col-md-4">
<Link to={`/post/${post._id}`} >
<figure className="snip1205 red">
<img
style={{ objectFit: "cover", padding: "0" }}
height="200"
width="200"
src={`${process.env.REACT_APP_API_URL}/post/photo/${post._id}`}
alt={post.title}
/>
<i className="fas fa-heart">
<br />
<span style={{ color: "white", fontSize: "20px" }} >{post.likes.length}</span>
</i>
</figure>
</Link>
</div>
))}
</div>
</Tab>
<Tab label={followersBadge} className="tab-title-name">
{user.followers.map((person, i) => (
<div key={i} className="media user-follower">
<img
src={`${process.env.REACT_APP_API_URL}/user/photo/${person._id}`}
onError={i => (i.target.src = DefaultProfile)}
alt={person.name}
className="media-object pull-left mr-2"
/>
<div className="media-body">
<Link to={`/user/${person._id}`} >
{person.name}<br /><span className="text-muted username">@{person.name}</span>
</Link>
{/* <button type="button" className="btn btn-sm btn-toggle-following pull-right"><i className="fa fa-checkmark-round"></i> <span>Following</span></button> */}
</div>
</div>
))}
</Tab>
<Tab label={followingBadge} className="tab-title-name">
{user.following.map((person, i) => (
<div key={i} className="media user-following">
<img
src={`${process.env.REACT_APP_API_URL}/user/photo/${person._id}`}
onError={i => (i.target.src = DefaultProfile)}
alt={person.name}
className="media-object pull-left mr-2"
/>
<div className="media-body">
<Link to={`/user/${person._id}`} >
{ person.name }<br /><span className="text-muted username">@{person.name}</span>
</Link>
{/* <button data-index = {person._id} onClick={this.unfollowClick} type="button" className="btn btn-sm btn-toggle-following pull-right"><i className="fa fa-checkmark-round"></i> <span>Unfollow</span></button> */}
</div>
</div>
))}
</Tab>
</Tabs>
</div>
</div>
</div>
</div>
}
render() {
const { redirectToSignin, user, loading } = this.state;
console.log("state user", user);
if (redirectToSignin) {
return <Redirect to='/signin' />
}
return (
<div className="container">
{ loading ? (
<Loading />
) : (
this.renderProfile()
) }
</div>
);
}
}
export default Profile;
EditProfile.js=
import React, { Component } from 'react';
import Loading from '../loading/Loading';
import { read, update, updateUser } from "./apiUser";
import { isAuthenticated } from "../auth";
import { Redirect } from 'react-router-dom';
import DefaultProfile from '../images/avatar.jpg';
class EditProfle extends Component {
constructor() {
super();
this.state = {
id: "",
name: "",
email: "",
about: "",
phone: "",
password: "",
loading: false,
redirectToProfile: false,
error: "",
fileSize: 0
}
}
init = (userId) => {
const token = isAuthenticated().token;
read(userId, token)
.then(data => {
if (data.error) {
this.setState({ redirectToProfile: true })
} else {
this.setState({
id: data._id,
name: data.name,
email: data.email,
error: "" ,
about: data.about,
phone: data.phone
});
}
})
}
componentDidMount() {
this.userData = new FormData()
const userId = this.props.match.params.userId;
this.init(userId);
}
isValid = () => {
const { name, email, password, fileSize } = this.state;
const userId = this.props.match.params.userId;
if(userId !== isAuthenticated().user._id){
this.setState({ error: "You are not authorized to do this !!", loading: false });
return false;
}
if (fileSize > 1000000) {
this.setState({ error: "File size should be less than 1 MB", loading: false });
return false;
}
if (name.length === 0) {
this.setState({ error: "Name is required", loading: false });
return false;
}
//test regular expression with 'test' keyword
if (!/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(email)) {
this.setState({ error: "Please enter a valid email address.", loading: false });
return false;
}
if (password.length >= 1 && password.length <= 5) {
this.setState({ error: "Password must be at least 6 characters long", loading: false });
return false;
}
return true;
}
handleChange = e => {
const value = e.target.name === 'photo' ? e.target.files[0] : e.target.value;
const fileSize = e.target.name === 'photo' ? e.target.files[0].size : 0;
this.userData.set(e.target.name, value);
this.setState({
error: "",
[e.target.name]: value,
fileSize
});
};
clickSubmit = e => {
e.preventDefault();
this.setState({ loading: true })
if (this.isValid()) {
//const { name, email, password } = this.state;
//const user = { name, email, password: password || undefined };
// console.log(user);
const userId = this.props.match.params.userId;
const token = isAuthenticated().token;
update(userId, token, this.userData)
.then(data => {
if (data.error) {
this.setState({ error: data.error, loading: false });
} else {
updateUser(data, () => {
this.setState({
redirectToProfile: true
});
})
}
});
}
};
signupForm = (name, email, password, loading, about, phone) => (
<form>
<div className="form-group">
<label className="text-muted">Profile Photo</label>
<input
onChange={this.handleChange}
name="photo"
type="file"
accept="image/*"
className="form-control"
/>
</div>
<div className="form-group">
<label className="text-muted">Name</label>
<input
onChange={this.handleChange}
name="name"
type="text"
className="form-control"
value={name}
/>
</div>
<div className="form-group">
<label className="text-muted">Email</label>
<input
onChange={this.handleChange}
type="email"
name="email"
className="form-control"
value={email}
/>
</div>
<div className="form-group">
<label className="text-muted">About</label>
<textarea
onChange={this.handleChange}
type="text"
name="about"
className="form-control"
value={about}
/>
</div>
<div className="form-group">
<label className="text-muted">Phone</label>
<textarea
onChange={this.handleChange}
type="string"
name="phone"
className="form-control"
value={phone}
/>
</div>
<div className="form-group">
<label className="text-muted">Password</label>
<input
onChange={this.handleChange}
type="password"
name="password"
className="form-control"
value={password}
/>
</div>
<button onClick={this.clickSubmit} className="btn btn-raised btn-primary">Update</button>
</form>
);
render() {
const { id, name, email, password, loading, redirectToProfile, error, about, phone } = this.state;
if (redirectToProfile) {
return <Redirect to={`/user/${isAuthenticated().user._id}`}></Redirect>
}
const photoUrl = id ? `${process.env.REACT_APP_API_URL}/user/photo/${id}?${new Date().getTime()}` : DefaultProfile ;
return (
<div className="container">
<h2 className="mt-5 mb-5">Edit Profile</h2>
<div className="alert alert-danger" style={{ display: error ? "" : "none" }}>
{error}
</div>
<img
style={{ display: loading ? "none" : "" , height: "200px", width: "auto" }}
className="img-thumbnail"
src={photoUrl}
onError={i => (i.target.src = DefaultProfile)}
alt={name}
/>
{loading ? (
<Loading />
) : (
this.signupForm(name, email, password, loading, about, phone)
)}
</div>
);
}
}
export default EditProfle;
Thank you!