SENTENCE U | Day 27 (설정페이지)

블로그 이사 완료·2023년 1월 31일
0
post-thumbnail

유저명/타이틀 변경, 계정 삭제 기능 추가

수정 버튼 클릭 시 flag State 변경으로 수정모드로 변경한다.

const onEditHandler = useCallback(() => {
  setIsEditing((prev) => !prev);
}, []);

<UserForm onSubmit={onEditUserSubmit}>
  {isEditing ? (
    <>
      <Label htmlFor='editName-label'>
        <NameInput
          autoComplete='off'
          type='text'
          name='editName'
          id='editName-label'
          value={editName}
          onChange={onChangeEditName}
          />
      </Label>
      <Label htmlFor='editTitle-label'>
        <TitleInput
          autoFocus
          autoComplete='off'
          type='text'
          name='editTitle'
          id='editTitle-label'
          value={editTitle}
          onChange={onChangeEditTitle}
          />
      </Label>
      </>
  ) : (
    <>
      <Name>{userName}</Name>
      <Title>{userTitle}</Title>
      </>
  )}
  {isEditing ? (
    <Edit onClick={onEditUserSubmit}>저장</Edit>
  ) : (
    <Edit onClick={onEditHandler}>수정</Edit>
  )}
</UserForm>

포스트 변경과 동일한 구조로 유저명과 유저타이틀도 변경된 내용을 POST로 서버로 보낸다.

const onEditUserSubmit = useCallback(
    (e) => {
      e.preventDefault();
      const regexp = /^[가-힣.,?;^_!%\s]+$/g;
      if (editName) {
        if (editName.length > 5 || editName.length < 2 || !regexp.test(editName)) {
          toast.error('유저명은 최소 2자, 최대 5자의 한글만 가능합니다.');
        } else {
          axios
            .put(
              `/api/users/${userId}`,
              {
                userName: userName,
                editName: editName,
                editTitle: editTitle,
              },
              { withCredentials: true },
            )
            .then(() => {
              refetch();
              setIsEditing(false);
            })
            .catch((error) => {
              console.log(error);
              toast.error('오류가 발생했습니다.');
            });
        }
      }
    },
    [userName, editName, editTitle, userId, refetch],
  );
router.put('/users/:id', async (req, res) => {
  await User.updateOne(
    { _id: req.params.id },
    { $set: { userName: req.body.editName, userTitle: req.body.editTitle } },
  )
    .then((user) => {
      if (!user) return res.status(404).json({ message: 'User not found' });
      Post.updateOne({ postUser: req.body.userName }, { $set: { postUser: req.body.editName } })
        .then(() => {
          return res.status(200).json(user);
        })
        .catch((error) => {
          console.log(error);
          return res.status(403).json(error);
        });
    })
    .catch((error) => {
      console.log(error);
      return res.status(403).json(error);
    });
});

계정 삭제 기능은 포스트와 댓글 삭제와 동일하지만, 해당 이름의 모든 포스트를 삭제하는 과정을 추가함.

router.delete('/users/:id', async (req, res) => {
  await User.findOne({ _id: req.params.id })
    .then((user) => {
      // 해당 유저의 모든 포스트 삭제
      Post.deleteMany({ postUser: user.userName })
        .then(() => {})
        .catch((error) => {
          console.log(error);
          return res.status(403).json(error);
        });
      // 계정 삭제
      User.deleteOne({ _id: req.params.id })
        .then(() => {
          return res.status(200).json({ WithdrawalSuccess: true });
        })
        .catch((error) => {
          console.log(error);
          return res.status(403).json(error);
        });
    })
    .catch((error) => {
      console.log(error);
      return res.status(403).json(error);
    });
});

모바일 화면 메뉴 나누기

기존 모바일크기 홈페이지는 인기포스트와 최근포스트가 일렬로 배치되었고, 최근 포스트를 보기 위해서는 꽤나 많은 스크롤이 필요했음.

벨로그의 홈페이지를 벤치마킹해 홈에서 인기포스트와 최근포스트를 선택해서 바로 볼 수 있도록 나눴다.

디바이스 크기에 따라 CSS(emotion)에서 display:none; 을 설정할 수 있겠지만, 그럼 컴포넌트를 불러오고 스타일에서 보이지 않게 설정하는 것이다.

그래서 애초에 렌더링 되지 않도록 아래와 같이 코드를 적용했다.

<Main>
  <LeftWrap>
    <Intro />
    {innerWidth > 768 ? <TopPosts /> : <PostMenu />}
  </LeftWrap>
  {innerWidth > 768 ? (
    <>
      <CenterWrap>
        <RecentPosts />
      </CenterWrap>
      <RightWrap>
        <Time />
        <UserLists />
      </RightWrap>
      </>
  ) : (
    ''
  )}
</Main>

PostMenu는 메뉴를 클릭 할 때마다 해당 메뉴에 맞는 컴포넌트를 렌더링 하도록 설정했다.

const PostMenu = () => {
  const ref = useRef();
  const [isPostMenu, setIsPostMenu] = useState(true);

  const onTopPostClick = useCallback(() => {
    ref.current.classList.remove('recent');
    setIsPostMenu(true);
  }, []);

  const onRecentPostClick = useCallback(() => {
    ref.current.classList.add('recent');
    setIsPostMenu(false);
  }, []);

  return (
    <Container>
      <TopPostTitle ref={ref} onClick={onTopPostClick}>
        인기 포스트
      </TopPostTitle>
      <RecentPostTitle onClick={onRecentPostClick}>최신 포스트</RecentPostTitle>
      <DotMenu>
        <BsThreeDots />
      </DotMenu>
      <PostWrap>{isPostMenu ? <TopPosts /> : <RecentPosts />}</PostWrap>
    </Container>
  );
};


기타 스타일 변경

전체적으로 한글 적용

한국 유저들을 대상으로 기획한 프로젝트인데 영어가 많아서 뭐하겠는가.. 하고 왠만한 영어는 한글로 변경했다.

max-width 변경

4K 모니터로 작업하다보니 너무 큰 화면에 맞게 UI구성이 된 것 같아 홈페이지의 max-width:1920px로 지정했고, 기타 페이지는 max-width: 768px로 지정했다.

내용이 과하게 퍼져있지 않고 넘치지 않으니 시각적으로 보기 좋았다.

포스트 유저 아바타 추가

포스트에 내용, 날짜, 이름만 있어서 너무 기본적인 스타일인 것 같아 해당 포스트의 유저 아바타를 불러와 적용했다.

useEffect(() => {
  axios
    .get(`/api/users/${postUser}`)
    .then((res) => {
    if (res.data.userAvatar) {
      setPostAvatar(res.data.userAvatar);
    }
  })
    .catch((error) => {
    console.log(error.response);
  });
}, [postUser]);
profile
https://kyledev.tistory.com/

0개의 댓글