스파르타코딩클럽 내일배움캠프 77일차
오늘 일과 간단 요약
- 디자이너님과 전체 회의 (기획 확정)
- 닉네임 추가
- 닉네임/프로필 사진 수정 기능 구현
디자이너님과 전체 회의
한 이틀은 걸린 것 같은 기획의 큰 틀을 확정지었다. 디자이너님이 디자인 해주시고 기능 구현만 남았다. 이제서야 기획의 큰 틀이 끝나다니...정말 길고 험난한 여정이었다 ㅋㅋㅋ
초반에 구상했던 와이어프레임과는 정말 거리가 멀다. UI도 바뀌고 우리 웹페이지의 타켓층에 대해 생각해보면서 카테고리를 새로 추가하고, 메인 페이지에 어떤 것들이 오는 것이 좋을까 고민해보기도 하면서 바뀐 부분이 제법 된다.
그리고 그에 따라 기능이 추가되기도 하고 삭제되기도 하는 중이다.
그래도 오전에 디자이너님과 함께 전체 회의를 하면서 디자이너님의 생각도 들어보고 우리의 의견도 각자 피력하면서 나름대로 평화롭게 마무리되었다. 혹시나 했는데 우리 조원들 모두 적극적으로 의견을 이야기해주고 다양한 의견이 나와서 오히려 정하기 쉬웠다. 다행이다...ㅋㅋㅋㅋㅋ
메인 페이지에서 나오는 부분이 처음보다 많이 바뀌었다.
여행전/여행후 카테고리를 나눈 것도 있고 그리고 좋아요 순이든 최신순이든 이런 사소한 걸 오늘에서야 명확하게 확정지었다.
디자이너님이 모든 페이지를 디자인해주시면 이제 그대로 css를 수정해야지. 지금은 기능 구현을 먼저 하느라 처음에 대충 틀만 만들었던 UI를 그대로 쓰고 있는데 이것도 기능 구현이 끝나면 바로바로 바뀔 듯 싶다. 3주가 길다면 길고 짧다면 짧은데 아무래도....약간 짧다고 느껴진다 ㅋㅋ
닉네임 기능 추가
처음에 로그인 기능을 구현하면서 우선은 username이 이메일 앞부분으로 해놓았었다.
그러다가 닉네임 수정 기능을 넣게 되면서 username을 따로 정해줘야 이메일이 손상되지(?) 않기 때문에 회원가입하면서 닉네임 input창을 새로 만들었다.
firebase에서는 친절하게도 updateProfile이라는 기능이 있기 때문에 콘솔로 찍어가면서 구현할 수 있었다.
createUserWithEmailAndPassword(authService, email, pw)
.then((data) => {
// alert("회원가입 성공");
// setModal(false);
updateProfile(data.user, {
displayName: userName,
photoURL:
"https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png",
});
return data.user;
})
.then((item) => {
console.log(item);
const userData = {
photoURL:
"https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png",
uid: item.uid,
displayName: userName,
email: item.email,
};
console.log(userData);
localStorage.setItem("User", JSON.stringify(userData));
setModal(false);
})
.catch((error) => {
if (error.code === "auth/email-already-in-use") {
setError("이미 사용중인 이메일입니다.");
}
});
회원가입 파일에서 일부를 가져온 것인데, 원래는 그냥 data만 가져왔었는데 updateProfile을 이용해서 displayName을 설정하고 기본 프로필을 설정해주었다.
프로필 사진은 구현할까 조원들과 고민하다가 오후에 결정된 거라서 우선은 displayName만.
이러고 input창이랑 새로 추가해서 회원강비하고 콘솔로 찍어보니까 제대로 잘 나왔다.
그러고 보니 이걸 구현하고 merge까지 했는데 콘솔 찍는 걸 지우지 않았다. 나중에 수정해야 겠다.
아무튼 이런 식으로 닉네임을 받아온 뒤에 header에서 닉네임을 새로 추가해주었다.
// header.tsx
const auth = getAuth();
const user = auth.currentUser;
const userName = user?.displayName;
콘솔로 찍어보니 displayName이 제대로 잘 나왔다. 이것도 역시 헤더에는 아직 프로필을 포함하지 않았다.
처음에는 닉네임 변경만 구현하기로 했어서 그냥 input창이 토글되면 나오는 걸로 구현했었다.
// userEdit.tsx
const [nickname, setNickName] = useState<any>(userName);
const editNameBtn = () => {
updateProfile(authService.currentUser as any, {
displayName: nickname,
})
.then(() => {
localStorage.setItem("User", JSON.stringify(authService.currentUser));
alert("닉네임 변경했습니다");
setToggle(false);
navigate("/user/:id");
})
.catch((error) => {
console.log("error: ", error);
});
};
const editNameHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
setNickName(event.target.value);
};
이 부분이 닉네임 수정한느 부분이다. localStorage에서 잠시 닉네임 변경한 걸 저징했다가 updateProfile을 이용해서 바꾸었다. 그리고 바꾼 걸 알 수 있게 alert를 추가하고 헤더에서도 바뀌기 위해 새로고침되는 것처럼 보이려고 navigate를 다시 했다. 원래는 여기에도 콘솔로 수정전, 수정후를 찍어봤는데 제대로 잘 바뀌었었다.
여기까지가 닉네임만 수정하는 기능 구현이다.
프로필 수정 기능 구현
여기까지 구현한 뒤에 디자이너님이 디자인해주신 댓글 창을 보니까 닉네임이 있어서 조원들과 프로필 수정을 넣을까 말까 고민했었다. 고민 뒤에 구현을 할 수 있다면 프로필도 넣으면 좋을 것 같아서 프로필 수정까지 구현 완료했다. 시간이 너무 오래 걸리면 어쩌나 고민했는데 이미 구현해놓은 닉네임 수정 기능이 있어서 거기에서 프로필 수정을 추가하면 되는 거라서 다행히 오늘 안에는 끝낼 수 있었다.
대신에 토글이었던 부분을 모달창으로 리팩토링을 해야 했지만, 아무렴 프로필까지 구현해서 다행이다.
사실은 닉네임 변경만 있는 것보다는 프로필도 있는데 좋아보이기 때문에...ㅋㅋㅋ (개인적 생각이다)
토글이었던 버튼을 모달창 오픈하는 버튼으로 바꾸고 모달창으로 프로필 수정을 구현했다.
// ProfileEdit.tsx
const auth = getAuth();
const user = auth.currentUser;
const userName = user?.displayName;
const userImg: any = user?.photoURL;
const [img, setImg] = useState(userImg);
const [nickname, setNickname] = useState<any>(userName);
const imgRef = useRef<HTMLInputElement>(null);
const nameRef = useRef<HTMLInputElement>(null);
const navigate = useNavigate();
const changeImgFile = () => {
if (imgRef.current?.files) {
const file = imgRef.current.files[0];
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = () => {
const changeImg = reader.result;
localStorage.setItem("imgURL", changeImg as any);
setImg(changeImg as any);
};
}
};
const profileEdit = async () => {
const imgRef = ref(storage, `${authService.currentUser?.uid}${Date.now()}`);
const imgDataUrl = localStorage.getItem("imgURL");
let downloadUrl;
if (imgDataUrl) {
const response = await uploadString(imgRef, imgDataUrl, "data_url");
downloadUrl = await getDownloadURL(response.ref);
}
updateProfile(authService.currentUser as any, {
displayName: nickname,
photoURL: downloadUrl ? downloadUrl : null,
})
.then(() => {
localStorage.setItem("User", JSON.stringify(authService.currentUser));
localStorage.removeItem("imgURL");
alert("프로필 수정을 완료했습니다");
setModal(false);
navigate("/user/:id");
})
.catch((error) => {
console.log("error: ", error);
});
};
const editNameHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
setNickname(event.target.value);
};
const cancleBtn = () => {
setImg(userImg);
setNickname(userName);
setModal(false);
};
프로필 수정과 닉네임 수정까지 합친 기능이다. 이것도 마찬가지로 localstorage에 저장했다가 firebase storage에 저장하고 그 저장한 이미지 url를 불러오는 형식인데, 나중에 선형님이 말해주신 오류(?)가 있어서 수정해야 한다.
localstorage에 저장할 수 있는 용량이 정해져 있어서 그 이상 크기를 가진 이미지를 업로드 하려면 오류가 있다는 것이다.
분명 이전 프로젝트 같이 진행할 때 그런 오류가 있었는데 왜 구현할 때는 생각이 나지 않았는가....ㅋㅋㅋㅋ
아무튼 그래서 그걸 사전에 공지를 하던지 alert 창을 띄워야 겠다.
테스트로 이미지를 올릴 때는 이미지 용량이 그렇게 크지 않아서 잘 바뀌었던 것 같다.
여기까지 하고 또 닉네임 글자수 제한을 두자는 디자이너님의 의견이 있어서 닉네임 유효성 검사도 추가했다.
const nameRegex = /^(?=.*[a-z0-9가-힣])[a-z0-9가-힣]{2,8}$/;
if (!nameRegex.test(userName)) {
setNameError(
"닉네임은 2~8자로 영어 또는 숫자 또는 한글이 조합되어야 합니다."
);
return;
}
닉네임은 2~8글자로 이루어저야 하며 영어, 숫자, 한글 조합으로 이루어져야 한다는 것이다.
정규 표현식을 쓰는게 어렵지만 구글링도 해보고 직접 다른 사람이 구현한 걸 뜯어보면서 공부하는 중이다.
그런데 생으로 구현하기에는 아직 좀 무리인것 같다....ㅋㅋㅋ 좀 더 공부해야지...
아무튼 여기까지 구현한 뒤에 PR 날리고 dev에 머지까지 완료했다.
짧은 일기
일단 오늘의 가장 큰 수확(?)은 디자이너님과 의견을 통일했다는 점이다. 이전까지는 선형님이 소통을 맡아서 하시면서 중간에서 고생을 많이 하셨는데 오늘 다같이 전체 회의를 하면서 서로의 의견을 들어보고 설득하고 설득 당하기도 하면서 최종적으로 기획을 완료하게 되었다. 디자인 피드백이 남아있지만 가장 중요한 기능에 대한 합의를 완료했다는 점이 아주 다행이고 기쁜 점이다.
확실히 디자이너님과 협업을 하면서 소통의 중요성을 더 절실히 느끼는 것 같다. 그래도 같은 개발자라고 그렇게 자세히 말하지 않아도 서로 이해는 했는데 디자이너님의 관점이 다르다는 걸 깨달았다. 나중에 회사가서도 소통을 정말 열심히 해야겠다는 생각이 든다.
여튼 오전까지 회의를 하고 남은 시간은 다행히 거의 기능 개발에 쏟을 수 있었다. 어제는 정말 기능 구현을 거의 하지 못했었는데 오늘은 오후에는 사전 멘토링 작성하고 스크럼하는 시간을 제외하고는 각자 기능 개발을 할 수 있었다.
그래서 프로필 수정 기능을 완료했는데, 오늘 회원가입 유효성 검사를 수정하다가 유효성 검사의 허점(?)을 발견하게 되어서 그 버그를 내일 바로 해결해야 한다. 내가 경우의 수를 잘못 생각한건지 아니면 제대로 조건을 걸지 못한 건지 모르겠지만, 아무튼 최대한 빨리 해결해야겠다. 그리고 이미지 용량 관련도 고민해봐야지.
역시 기능 구현을 시작하면 다 한 것 같지만 버그가 생긴다. 내일은 그 버그가 해결되길 바란다...ㅎ