Mern Social Network الجزء السابع

imadbelasri Nodejs
NS

فهاد الجزء السابع من Mern Social Network غادي نكملوا الجزء الخاص بالمستخدم وغادي نزيدو ل component لي غادي يمكن من عرض المستخدمين كاملين ولي غادي تكون عندي إمكانية متابعتهم وغادي نزيدو ل component لي غادي يمكن المستخدم باش يشوف البروفيل ديالو وأيضا تعديل المعلومات الخاصة به.


نظرة سريعة بالفيديو


1- إضافة ل component Users

دائما ف dossier pages زيد fichier Users.js لي فيه غادي نعرضوا المستخدمين كاملين ولي غادي تكون عندي إمكانية متابعتهم وهاد الخاصية غادي نزيدو الكود ديالها فالأجزاء القادمة.

الكود ديال الملف هو :

                                                    
                                                        import React from "react";
import { Link } from "react-router-dom";
import { useDispatch, connect } from "react-redux";
import { getAllUsers } from "../redux/actions/userActions";
import { isLogged } from "../helpers/auth";

function Users({ users, userError }) {
  const dispatch = useDispatch();
  const [error, setError] = React.useState(null);
  const jwt = isLogged();

  React.useEffect(() => {
    if (userError && userError !== null) {
      setError(userError);
    }

    dispatch(getAllUsers(jwt && jwt.token));
  }, [dispatch, jwt, userError]);

  function showError() {
    return error && <div className="alert alert-danger">{error}</div>;
  }

  if (!jwt) {
    return (
      <div className="container">
        <div className="row my-5">
          <div className="col-md-8 mx-auto">
            <div className="alert alert-info">
              <Link to="/login">Connectez vous pour voir les profiles</Link>
            </div>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="container">
      <div className="row my-4">
        <div className="col-md-8 mx-auto">
          {showError()}
          <div className="card p-2">
            <div className="card-header bg-white">
              <h3 className="card-title">Profiles</h3>
            </div>
            <div className="card-body">
              <ul className="list-group">
                {users &&
                  users.map((user, index) => (
                    <Link
                      to={`/user/${user._id}`}
                      key={index}
                      style={{ textDecoration: "none" }}
                    >
                      <li className="list-group-item d-flex flex-row justify-content-between align-items-center">
                        <div className="d-flex flex-row justify-content-between align-items-center">
                          <img
                            src={`http://localhost:8888/api/user/photo/${user._id}`}
                            width="50"
                            height="50"
                            className="img-fluid rounded pr-2"
                            alt={user && user.name}
                          />
                          <h4 className="mt-3">{user.name}</h4>
                        </div>
                        <i className="fa fa-arrow-right"></i>
                      </li>
                    </Link>
                  ))}{" "}
              </ul>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

const mapStateToProps = ({ user: { users, userError } }) => ({
  users,
  userError,
});

export default connect(mapStateToProps, null)(Users);
                                                    
                                                

2- إضافة ل component Profile

دائما ف dossier pages زيد fichier Profile.js لي فيه غادي يمكن للمستخدم باش يشوف البروفيل ديالو والناس لي متبعهم ولي متبعينوا بالإضافة ل tweets لي زاد وروابط تعديل وحذف الحساب ديالو.

الكود ديال الملف هو :

                                                        
                                                            import React from "react";
import { useParams, Link, useHistory } from "react-router-dom";
import { isLogged, checkAuth, logout } from "../helpers/auth";
import { getUser, deleteUser } from "../redux/actions/userActions";
import FollowButton from "../components/FollowButton";
import FollowComponent from "../components/FollowComponent";
import { useDispatch, connect } from "react-redux";
import PostList from "../components/PostList";
import { getUserPosts } from "../redux/actions/postActions";

function Profile({ userSuccess, userError, userPosts }) {
  const { userId } = useParams();
  const [error, setError] = React.useState("");
  const [following, setFollowing] = React.useState(false);
  const [user, setUser] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const jwt = isLogged();
  const dispatch = useDispatch();
  const history = useHistory();
  const date = user && user.createdAt ? new Date(user.createdAt) : null;

  React.useEffect(() => {
    async function getProfile() {
      const userData = await getUser(userId, jwt && jwt.token);
      if (userData.error) {
        setError(userData.error);
      } else {
        setUser(userData.data);
        setFollowing(checkFollow(userData.data));
      }
    }
    function checkFollow(user) {
      const match = user.followers.find((follower) => {
        return follower._id === jwt.user._id;
      });
      return match;
    }
    if (loading) {
      getProfile();
    }
    return () => {
      setLoading(false);
    };
  }, [userId, jwt, loading]);

  React.useEffect(() => {
    if (userSuccess) {
      logout(() => {
        history.push("/");
      });
      dispatch({ type: "TOGGLE_SUCCESS" });
    }
    if (userError) {
      setError(userError);
    }
    function loadUserPosts() {
      dispatch(getUserPosts(jwt.token, userId));
    }
    loadUserPosts();
  }, [userError, userSuccess, dispatch, userId]);

  function showError() {
    return error && <div className="alert alert-danger">{error}</div>;
  }

  function hanldeButtonClick(user) {
    setUser(user);
    setFollowing(!following);
  }

  if (!jwt) {
    return (
      <div className="container">
        <div className="row my-5">
          <div className="col-md-8 mx-auto">
            <div className="alert alert-info">
              <Link to="/login">Connectez vous pour voir le profile</Link>
            </div>
          </div>
        </div>
      </div>
    );
  }
  return (
    <div className="container">
      <div className="row my-5">
        <div className="col-md-8 mx-auto">
          {error ? (
            showError()
          ) : (
            <div className="card p-2">
              <div className="d-flex flex-row justify-content-start align-items-center">
                <img
                  src={`http://localhost:8888/api/user/photo/${userId}?${new Date().getTime()}`}
                  width="50"
                  height="50"
                  className="img-fluid rounded pr-2"
                  alt={user && user.name}
                />
                <h4 className="mt-3">{user && user.name}</h4>
              </div>
              <span className="font-weight-bold mt-3">
                {user && user.email}
              </span>
              <p className="lead">{user && user.about}</p>
              <hr />
              <span className="badge badge-danger col-4">
                Inscrit le : {date && date.toLocaleDateString()}
              </span>
              <hr />
              {checkAuth(userId) ? (
                <div className="d-flex flex-row justify-content-end align-items-center">
                  <Link to={`/user/edit/${userId}`}>
                    <i className="fa fa-edit btn mr-2 btn-warning btn-sm"></i>
                  </Link>
                  <Link
                    to="#"
                    onClick={() => dispatch(deleteUser(userId, jwt.token))}
                  >
                    <i className="fa fa-trash btn btn-danger btn-sm"></i>
                  </Link>
                </div>
              ) : (
                <FollowButton
                  following={following}
                  hanldeButtonClick={hanldeButtonClick}
                  token={jwt && jwt.token}
                  followId={user && user._id}
                  userId={jwt && jwt.user._id}
                />
              )}
              <hr />
              <h3 className="text-primary">Abonnés</h3>
              <hr />
              <FollowComponent data={user && user.followers} />
              <h3 className="text-primary">Abonnements</h3>
              <hr />
              <FollowComponent data={user && user.following} />
              <hr />
              <h3 className="text-primary">Publications</h3>
              <PostList posts={userPosts} />
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

const mapStateToProps = ({
  user: { userError, userSuccess },
  post: { userPosts },
}) => ({
  userError,
  userSuccess,
  userPosts,
});

export default connect(mapStateToProps, null)(Profile);
                                                        
                                                    

3- إضافة ل component EditProfile

دائما ف dossier pages زيد fichier EditProfile.js لي فيه غادي يمكن للمستخدم باش يدير تعديل للمعلومات الخاصة به.

الكود ديال الملف هو :

                                                        
                                                            import React from "react";
import { useDispatch, connect } from "react-redux";
import { useParams, useHistory } from "react-router-dom";
import { isLogged, checkAuth } from "../helpers/auth";
import { getUser } from "../redux/actions/userActions";
import { updateUser } from "../redux/actions/userActions";
// import { createUser } from "../redux/actions/userActions";

function EditProfile({ userError, userSuccess }) {
  const [user, setUser] = React.useState({
    name: "",
    email: "",
    password: "",
    about: "",
    image: "",
  });
  const [error, setError] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const dispatch = useDispatch();
  const history = useHistory();
  const jwt = isLogged();
  const { userId } = useParams();
  const userData = new FormData();

  React.useEffect(() => {
    async function getProfile() {
      const userData = await getUser(userId, jwt && jwt.token);
      if (userData.error) {
        setError(userData.error);
      } else {
        setUser(userData.data);
      }
    }
    if (loading) {
      getProfile();
    }
    return () => {
      setLoading(false);
    };
  }, [userId, jwt, loading]);

  React.useEffect(() => {
    if (userSuccess) {
      history.push(`/user/${user && user._id}`);
      dispatch({ type: "TOGGLE_SUCCESS" });
    }
    if (userError) {
      setError(userError);
    }
  }, [userError, userSuccess, history,user, dispatch]);

  function handleInputChange(event) {
    const value =
      event.target.name === "image"
        ? event.target.files[0]
        : event.target.value;
    setUser({ ...user, [event.target.name]: value });
  }

  function showError() {
    return error && <div className="alert alert-danger">{error}</div>;
  }

  function handleFormSubmit(event) {
    event.preventDefault();
    user.name && userData.append("name", user.name);
    user.email && userData.append("email", user.email);
    user.password && userData.append("password", user.password);
    user.about && userData.append("about", user.about);
    user.image && userData.append("image", user.image);
    dispatch(updateUser(userData, jwt.token, userId));
  }

  if (!checkAuth(userId)) {
    history.push(`/user/${userId}`);
  }

  return (
    <div className="container">
      <div className="row my-5">
        <div className="col-md-6 mx-auto">
          {showError()}
          <h3 className="card-title">Modifier mon profile</h3>
          <form
            onSubmit={(event) => handleFormSubmit(event)}
            className="card p-2"
          >
            <div className="form-group">
              <img
                width="200"
                height="200"
                src={`http://localhost:8888/api/user/photo/${userId}`}
                alt={user && user.name}
                className="img-fluid rounded"
              />
            </div>
            <div className="form-group">
              <input
                type="file"
                accept="image/*"
                name="image"
                onChange={(event) => handleInputChange(event)}
                className="form-control"
              />
            </div>
            <div className="form-group">
              <input
                type="text"
                name="name"
                placeholder="Nom & Prénom"
                value={user.name}
                required
                onChange={(event) => handleInputChange(event)}
                className="form-control"
              />
            </div>
            <div className="form-group">
              <input
                type="email"
                name="email"
                placeholder="Email"
                required
                value={user.email}
                onChange={(event) => handleInputChange(event)}
                className="form-control"
              />
            </div>
            <div className="form-group">
              <input
                type="password"
                name="password"
                placeholder="Mot de passe"
                required
                value={user.password || ""}
                onChange={(event) => handleInputChange(event)}
                className="form-control"
              />
            </div>
            <div className="form-group">
              <textarea
                row="5"
                cols="30"
                name="about"
                placeholder="Bio"
                required
                value={user.about}
                onChange={(event) => handleInputChange(event)}
                className="form-control"
              />
            </div>
            <div className="form-group">
              <button type="submit" className="btn btn-outline-primary">
                Valider
              </button>
            </div>
          </form>
        </div>
      </div>
    </div>
  );
}
const mapStateToProps = ({ user: { userError, userSuccess } }) => ({
  userError,
  userSuccess,
});

export default connect(mapStateToProps, null)(EditProfile);
                                                        
                                                    

4- إضافة الصفحة الرئيسية

دائما ف dossier pages زيد fichier Home.js لي فيه غادي يتعرضوا les tweets ديال المستخدمين لي متبعهم الشخص لي connecté وأيضا غادي تكون عندو إمكانية ديال إضافة tweet ويزيد تعليقات على tweets.

الكود ديال الملف هو :

                                                        
                                                            import React from "react";
import { useDispatch, connect } from "react-redux";
import { Link } from "react-router-dom";
import { isLogged } from "../helpers/auth";
import { getAllPosts } from "../redux/actions/postActions";
import PostList from "../components/PostList";
import AddPost from "../components/AddPost";

function Home({ posts }) {
  const jwt = isLogged();
  const dispatch = useDispatch();

  React.useEffect(() => {
    if (jwt) {
      function loadPosts() {
        dispatch(getAllPosts(jwt.token, jwt.user._id));
      }
      loadPosts();
    }
  }, []);

  if (!jwt) {
    return (
      <div className="container">
        <div className="row my-5">
          <div className="col-md-8 mx-auto">
            <div className="alert alert-info">
              <Link to="/login">Connectez vous pour voir les tweets</Link>
            </div>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="container">
      <AddPost />
      <PostList posts={posts && posts} />
    </div>
  );
}

const mapStateToProps = ({ post: { posts } }) => ({
  posts,
});

export default connect(mapStateToProps, null)(Home);
                                                        
                                                    

5- إضافة ل component PostList

ف dossier components زيد fichier PostList.js لي فيه غادي يتعرضوا les tweets لي كنرسلوهم من ل component Home.

الكود ديال الملف هو :

                                                        
                                                            import React from "react";
import Post from "./Post";

export default function PostList({ posts }) {
  const [data, setData] = React.useState([]);

  React.useEffect(() => {
    setData(posts);
  }, [posts]);

  return (
    <div className="row my-5">
      <div className="col-md-8 mx-auto">
        {data &&
          data.map((item, i) => {
            return <Post post={item} key={item._id} />;
          })}
      </div>
    </div>
  );
}
                                                        
                                                    

دروس ذات صلة

NS

Mern Social Network الجزء الاول

فهاد ال projet غادي نشوفوا كيفاش نقادو social network ب react js express nodejs & mongodb هاد ل proj...


NS

Mern Social Network الجزء الثاني

فهاد الجزء الثاني من Mern Social Network من بعد ما زدنا فالجزء السابق ل models ديالنا دبا غادي ندوزو...


NS

Mern Social Network الجزء الثالت

فهاد الجزء الثالت من Mern Social Network من بعد ما زدنا فالجزء السابق ل controllers ديالنا دبا...


NS

Mern Social Network الجزء الرابع

فهاد الجزء الرابع من MERN social network غادي ندوزو ل frontend منبعد مازدنا ل backend فالأجزاء الساب...


NS

Mern Social Network الجزء الخامس

فهاد الجزء الخامس من MERN social network غادي نكملوا الجزء الخاص ب redux من بعد مازدنا types و actio...


NS

Mern Social Network الجزء السادس

فهاد الجزء السادس من MERN social network غادي نكملوا ل projet ديالنا وندوزوا للجزء الخاص بإضافة rout...


NS

Mern Social Network الجزء الثامن

فهاد الجزء الثامن من Mern Social Network غادي نزيدوا نكملوا الجزء الخاص بعرض وإضافة tweets ومنبعد غا...


NS

Mern Social Network الجزء التاسع والأخير

فهاد الجزء التاسع والاخير من Mern Social Network غادي نزيدو الإمكانية ديال متابعة وإلغاء م...