굵직한 기능들은 이미 제작이 완료되었기 때문에, 자잘한 오류 등을 수정하고 발표 자료 제작을 돕는 시간을 가졌다.
점수:8/10점
데이터베이스를 사용해 리액트 협업을 함으로서 실무에서도 사용할 수 있는 기술을 배울 수 있어 상당히 좋았습니다만, 절대적인 시간이 많이 부족하여 추가적인 도전 과제를 시도해보지 못했기에 좀 더 시간이 있었다면 좋지 않았을까 하는 아쉬움이 남으면서도, 다음 프로젝트 때는 필수 구현 사항 외에도 추가적인 기능을 제작하고 싶다는 생각을 하게 된 프로젝트였습니다.
회원 가입 시 프로필 사진을 등록하지 않으면 프로필로 아무 사진도 뜨지 않는 오류가 있었고, 프로필 사진을 등록하기 위한 supabase update 기능이 제대로 동작하지 않는 문제점이 있는 등 여러 문제점이 있었습니다.
기본 프로필 사진을 설정하여, 회원 가입 시 프로필 사진을 등록하지 않을 경우 기본 프로필 사진을 사용할 수 있도록 수정하여 문제를 해결하였습니다. 또한 supabase update 기능이 되지 않은 이유는 해당 테이블을 SQL Editor를 사용해 만들었는데, 필요없는 코드를 삭제하는 바람에 생긴 문제였기에 SQL을 쓰지 않고 새로 테이블을 제작하여 해결했습니다.

프로필 사진을 등록하고 자기소개를 작성한 후 시작하기 버튼을 누르게 되면, profiles라는 supabase 테이블에 방금 가입한 아이디가 포함된 새로운 데이터 row를 생성합니다. 이 데이터에는 방금 등록한 이미지 경로 및 자기소개가 들어있어, 마이 페이지에 들어갔을 때나, 게시물 작성 시 프로필 사진 등, 여러 곳에서 사용됩니다.
프로필 사진의 경우 회원 가입 시 프로필 사진을 등록하지 않으면 프로필로 아무 사진도 뜨지 않는 오류가 있었고, 기본 프로필 사진을 설정하여, 회원 가입 시 프로필 사진을 등록하지 않을 경우 기본 프로필 사진을 사용할 수 있도록 수정하여 문제를 해결하였습니다.
마이페이지에서는 본인의 프로필 사진, 닉네임, 자기소개를 볼 수 있고, 프로필 사진을 변경할 수 있습니다. 프로필 사진 변경의 경우, 버튼을 클릭하고 사진을 선택하면 supabase 업로드 및 프로필 사진 변경 기능까지 한꺼번에 진행될 수 있도록 제작했습니다.
또한 페이지 하단에서는 내가 작성한 게시물을 볼 수 있고, 내가 작성한 게시물이 없을 경우 특정 문구가 나오게 제작했습니다.
본인의 게시물에는 수정 및 삭제를 할 수 있는 버튼이 나오도록 제작했습니다. 수정하기 버튼을 클릭하여 타이틀 및 내용을 변경한 후 버튼을 클릭하면 수정이 완료되어 해당 게시물 페이지로 이동하고, 삭제 버튼을 클릭하면 알럿 창이 뜬 다음 삭제가 완료되어 메인 페이지로 이동합니다. 해당 두 기능은 supabase에서 바로 수정 및 삭제를 하도록 제작했습니다.
{newsfeedList.length ? (
newsfeedList.map((list) => {
return <NewsfeedItem key={list.id} list={list} />;
})
) : (
<StyledNoPost>작성하신 게시물이 없습니다.</StyledNoPost>
)}
newsfeedList의 길이, 즉 게시물이 한 개라도 있을 경우 map을 통해 게시물을 화면에 추가하고, 만약 길이가 0, 즉 게시물이 하나도 없을 경우에는 작성한 게시물이 없다는 글귀가 나오도록 수정했다.
새로고침 시에는 제대로 유저 정보를 가져오지 못하는 걸 보고, 왜 그런 문제가 생기는 것일까 찬찬히 테스트해본 결과, useEffect를 사용하여 처음에 딱 한 번만 필요한 유저 정보를 가져와 넣어주기 때문에, 아직 유저 정보를 가져오지 못한 상황에서 벌써 가져올 경우 제대로 정보를 가져오지 못하는 문제가 발생하는 거였다.
때문에 useEffect 사용을 그만두고, useState를 사용해 currentUser가 있을 경우에만 해당 데이터들을 가져올 수 있도록 변경해주었다.
게시물 닉네임의 경우 본래 이메일에서 @ 앞의 아이디만 가져와 닉네임처럼 사용했는데, 우리 팀은 닉네임을 따로 설정하기로 했기 때문에 닉네임을 가져와서 넣어주는 방식으로 변경했다.
아래는 해당 문제를 해결한 최종 코드이다.
function WritingForm() {
const navigate = useNavigate();
const year = new Date().getFullYear();
const month = new Date().getMonth() + 1;
const day = new Date().getDate();
const currentUser = useSelector((state) => state.user.currentUserInfo);
const { email, id: userId, user_metadata } = currentUser;
const [userName, setUserName] = useState("");
const [profileUrl, setProfileUrl] = useState("");
const [userid, setUserid] = useState("");
async function getProfileImage() {
if (Object.keys(currentUser).length) {
const data = await profileByUserId(userId);
setProfileUrl(data[0].image_url);
setUserName(user_metadata.display_name);
setUserid(userId);
}
}
getProfileImage();
const [formData, setFormData] = useState({
id: uuidv4(),
date: `${year}/${month}/${day}`,
title: "",
content: "",
userName: "",
userid: "",
profileUrl: ""
});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData({
...formData,
[name]: value
});
};
async function addNewsfeed() {
await supabase
.from("newsfeed")
.insert({ ...formData, userName, profileUrl, userid })
.select();
}
const handleSubmit = (e) => {
e.preventDefault();
if (!formData.title.trim() || !formData.content.trim()) {
Swal.fire("제목과 내용을 모두 입력해야 합니다.");
return;
}
addNewsfeed();
navigate(-1);
};
return (
<div>
<div className="container">
<StyledForm onSubmit={handleSubmit}>
<StyledDiv>
<StyledTitleInput
type="text"
name="title"
placeholder="제목을 입력하세요"
value={formData.title}
onChange={handleChange}
/>
<div style={{ borderBottom: "5px solid #b4b9c9", padding: "15px" }}></div>
</StyledDiv>
<StyledDiv>
<StyledTextArea
name="content"
placeholder="내용을 입력해주세요..."
value={formData.content}
onChange={handleChange}
></StyledTextArea>
</StyledDiv>
<StyledButton type="submit">저장하기</StyledButton>
</StyledForm>
</div>
</div>
);
}
크게 어려웠던 점은 없었다. 아쉬운 점은 개별 평가에도 작성했듯이 추가 도전 과제를 하지 못 했다는 것... 내일 잘 마무리하고, 회고도 잘 작성하여 이번 프로젝트를 통해 다음 프로젝트 때는 더욱 완성도 높고 필수 사항은 당연히 구현하되 추가 기능까지 해볼 수 있으면 좋겠다!