Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Y_FE_Toy1_Team8_wikinity #6

Open
wants to merge 258 commits into
base: main
Choose a base branch
from
Open

Y_FE_Toy1_Team8_wikinity #6

wants to merge 258 commits into from

Conversation

wowba
Copy link

@wowba wowba commented Sep 22, 2023

✨ Wikinity ✨

패스트캠퍼스 프론트엔트 부트캠프 1차 토이프로젝트
사이트 링크
깃헙 링크

👏 Contributors

avatar avatar avatar avatar
이영욱 김지민 지홍규 정진주

💻 커밋 컨벤션

명칭 의미
Feat 새로운 기능 추가
Fix 버그 수정
Docs 문서 수정
Style 코드 포맷팅, 세미콜론 누락
Refactor 코드 리팩토링
Test 테스트 코드, 리팩토링 테스트 코드 추가
Chore 빌드 업무 수정, 패키지 매니저 수정

📁 폴더 구조

📦
├─ public - static 파일
├─ src
│  ├─ assets - 이미지
│  ├─ components - 공통 컴포넌트 (nav, sidebar...)
│  ├─ pages - 페이지별 컴포넌트
│  │  └─ MainPage
│  │  └─ ...
│  ├─ recoil - 상태관리 파일 폴더
│  │  ├─ atoms
│  │  └─ selectors
│  ├─ styled - styled-components (CSS)
│  ├─ types - TS interface, type 등 타입 관련
│  └─ utils - 공통 함수
└─ ©generated by Project Tree Generator

🔨 Stack

UserFlow

Git Branches

  • main: 배포용 브랜치
  • feature: 개별 개발용 브랜치

개인별 작업 내역

이영욱

개발환경 설정

  • Firebase 프로젝트 생성 및 FireStore(DB), Storage, Auth 설정.
  • Github을 이용한 CI 및 Github Action, Firebase Hosting을 연계하여 CD 설정.

private, public router 설정

  • Route의 중첩 라우팅을 이용하여 publicRoute, PrivateRoute 컴포넌트를 생성하여
    로그인 여부에 따라 각 페이지별 접근 권한 판단할 수 있는 기능 추가.
로그인 시 publicRouter 이동 방지 로그아웃 시 privateRouter 이동 방지
privateRouter publicRouter

로그인 / 회원가입 페이지

  • Firebase의 Auth 기능을 이용하여 로그인 기능 구현.
  • Recoil을 이용하여 userState, isLoginState를 각각 생성하여
    router에서 로그인 판단 여부 및 유저 정보 저장.
로그인 실패시 시각적으로 확인할 수 있는 애니메이션 회원가입 중 잘못된 정보 기입시 alert 및 애니메이션
login createAccount

NavBar 공통 컴포넌트 작성 / 유저 프로필 모달

  • 여러 페이지로 이동할 수 있는 링크 및 모달 이미지를 가진 상단 NavBar 컴포넌트 작성
  • 유저 정보 확인 및 수정할 수 있는 ProfileModal 컴포넌트 작성
    • 로그아웃 시 유저 관련 state 초기화 및 publicRouter로 이동
NavBar Profile Modal
navBar profileModal

Firebase Auth / Recoil 이슈

Firebase의 Auth를 이용해 유저 로그인 정보를 받아올 시, Recoil을 이용해 해당 정보를 저장할 때
Auth에서 받아온 로그인 정보가 불변 객체가 되어 후에 로그아웃시 에러가 발생하는 이슈가 있었다.
검색해보니 해당 이슈는 상태관리 라이브러리 중 Recoil만 있는 듯 하였다.

이를 해결하기 위해 받아온 유저 정보를 그대로 저장하는 것이 아닌,
객체를 변경 가능하도록 깊은 복사하여 새로 생성한 뒤 저장하도록 하였다.
Recoil에 저장하기 전, 받아온 유저 정보 객체를 깊은복사를 한 뒤 State에 저장하여
후에 Firebase에서 해당 정보에 접근하여 정보를 수정할 수 있도록 변경했다.

signInWithEmailAndPassword(auth, email, password).then(
  async (userCredential) => {
    // Signed in
    const { user } = userCredential;
    const userId = userCredential.user.uid;
    const docRef = doc(db, 'user', userId);
    const docSnap = await getDoc(docRef);
    const userCopy = JSON.parse(JSON.stringify(user)); // 깊은복사 후 state 저장
    setUserState({
      userCredential: userCopy,
      userData: docSnap.data(),
    });
    setLoginState(true);
    navigate('/');
  }
);

후기

  • 처음으로 Firebase를 이용하여 개발 환경설정 및 기능구현을 진행하였는데, 토이 프로젝트로 사용하기에 매우 적합한 서비스를 경험해볼 수 있어서 좋았다.
  • 프론트엔드 프로젝트는 처음 협업을 해 보았는데, 코딩을 시작하기 전 UserFlow를 통해 페이지 및 사용될 컴포넌트 까지 사전에 대략적으로 구분해 놓으면 추후에 진행할 때 크게 도움이 될 것이다.
  • 개발하기에 급급해 공통된 컴포넌트 및 로직을 추상화 하는데 소흘하였다. 추후에는 화면 내 구조를 구상할 때 공통으로 사용될 컴포넌트들을 먼저 추상화 한 뒤,
    다른 구체적인 컴포넌트를 생각해 보아야 겠다.
  • 코드리뷰를 진행하지 않고 화면상으로만 리뷰를 진행했는데, 다음에는 적극적인 코드리뷰를 통해 더 좋은 코드를 작성하도록 노력해야겠다.
김지민

🔑 Wiki 페이지 주요 기능

글 작성하기 글 수정하기
write edit
Markdown Editor를 이용해 글 작성 가능,
실제 firestore에 업로드됨
Markdown Editor를 이용해 글 수정 가능,
firestore 데이터도 수정 됨

글 삭제하기 제목으로 검색하기
delete (1) search (2)
삭제 버튼 누르면 글 삭제가능
실제 firestore에서도 삭제됨
제목을 이용한 글 찾기 가능

카테고리 별 글 목록 변경 카테고리 추가
category cate_add
카테고리 별 선택된 카테고리에 해당하는 목록 보여주는 기능 구현 카테고리 명 추가 기능 구현

🔑 Main 페이지 모달 주요 기능

출퇴근 모달 투두리스트 모달
commute todo
출퇴근 버튼으로 출근 시간 측정하는 모달 구현,
Recoil의 state를 사용해 모달을 종료하고 다시 들어가도 출근 시간 기록하게 구현
투두 기능 구현,
Recoil로 구현하여 투두 모달을 종료하고 다시 들어가도 투두 리스트 상태가 변경되지 않게 구현

느낀점

React 초보라 상태 관리 라이브러리나 관련된 툴을 사용해 본적이 없었는데 이번에 Recoil을 사용해 보았다.
처음에는 잘 이해가 가지않아 코드를 짜는데 어려움을 겪었는데 시간이 지날수록 오히려 Recoil을 사용해 관리하는게 코드 가독성이 높아지고
여러모로 재사용할 수 있어서 좋았다. 다른 상태관리 라이브러리도 사용해 볼 수 있겠다는 자신감이 생겼다.
또한, firebase에서 auth기능이나 storage는 사용해 보았지만 firestore기능은 처음 사용해 보았는데
생각보다 접근성이 좋고 이렇게 간단한 데이터를 다루는데 사용이 편리하여서 좋았다
아쉬운 점은 firestore에서 addDoc을 하면 아이디가 자동으로 생성이 되는데 인덱스 값이 아닌 랜덤형식의 string값으로 배정이 되어
더 복잡한 테이블을 구성하기가 어려웠다는 점이다.
하지만 협업을 진행하면서 다양한 코드도 접하게 되고 또한 개발 관련해 시야가 넓어진 것 같아서 좋은 경험으로 남을 것 같다

지홍규

Notice 페이지

공지 등록하기 공지 수정하기
공지등록 공지수정
📌 공지 등록 시 firestore에 데이터 저장
📌 공백문자 submit 방어코드
📌 firebase Storage에 이미지 저장
(uuid로 storage에 저장 시 이미지 이름 중복 안도록 구현)
📌 등록할 때 저장한 비밀번호 검사
📌 공지 수정 시 firestore에 저장된 데이터 수정

공지 삭제하기 공지 상세보기
공지삭제 공지상세
📌 등록할 때 저장한 비밀번호 검사
📌 공지 삭제 시 firestore에 저장된 데이터 삭제
📌 해당 공지 클릭 시 공지 상세페이지로 이동

공지 검색하기 페이지네이션
공지검색 페이지네이션
📌 Enter키 or 검색하기 버튼 클릭 시 검색 동작
📌 검색어와 일치하는 공지 없다면 명시적으로 표시
📌 페이지버튼 클릭 시 페이지에 해당하는 공지 보여주기
📌 이전 or 다음 버튼 클릭 시 페이지 넘어가게 구현

Carousel

캐러셀

📌 캐러셀 클릭 시 해당 공지 상세페이지로 이동

느낀점

  • 구현은 어렵지 않았지만 TypeScript나 ESLint가 너무 까다로워서 진을 뺏던 것 같다. 그러나 이러한 도구들을 사용하면서 확실히 코드의 품질이 향상되는 것을 느낄 수 있었다.

  • Firebase를 처음 사용해봤는데, 정말 간편하게 백엔드 서비스를 구축할 수 있어서 놀랐다. 앞으로 혼자 프로젝트를 진행할 때 Firebase를 애용할 것 같다.

  • 이번 프로젝트가 처음 해보는 협업 프로젝트였는데 혼자 프로젝트를 진행할 때보다 신경써야할 게 훨씬 많다는 것을 깨달았다.

    그래도 이번 프로젝트를 통해 어떻게 협업을 진행해야하는지 어느정도 감이 잡힌 것 같다.

  • 아쉬운 점이 있다면, 코드리뷰를 해보지 못한 것이다. 코드리뷰를 통해 피드백을 주고 받으면서 코드 품질을 높일 수 있었을 텐데 못해본 것이 너무 아쉽다. 다음 프로젝트에서는 꼭 코드리뷰 해보고싶다.

정진주

🌟ProjectPage 주요 기능

프로젝트 리스트 페이지 프로젝트 작성 페이지
스크린샷 2023-09-22 오후 3 52 34 스크린샷 2023-09-22 오후 3 52 42
프로젝트의 리스트
미리보기에는 주제, 마감일, 인원 표시
팀명, 프로젝트 주제, 프로젝트 설명,
프로젝트 마감일, 참여인원을 작성할 수 있는 페이지 ,
상단의 진행중/완료를 클릭을 통해서 변경 가능
프로젝트 상세 글 페이지 프로젝트 수정 페이지
스크린샷 2023-09-22 오후 3 53 08 스크린샷 2023-09-22 오후 3 53 16
작성한 프로젝트 상세 페이지
삭제 버튼을 통해 삭제 가능
수정 페이지를 통해 글 수정 가능,
진행중/완료 변경 가능

진행중/ 완료 표시

스크린샷 2023-09-22 오후 2 35 46 스크린샷 2023-09-22 오후 3 22 06

firestore에서도 project 컬렉션을 통해 데이터 crud가 가능하도록 구현하였다.

캘린더 기능

  • react-calendar 라이브러리를 이용한 캘린더
  • styled-component를 통해 디자인 변경
    스크린샷 2023-09-22 오후 3 50 32

구현 영상:

  • 프로젝트 페이지 crud 구현 영상
2023-09-22.3.26.00.mov

아쉬운 점 & 배운점

  • react와 typescript를 사용하여 만든 첫 토이프로젝트였기 때문에 react+ts의 문법을 익히는데 시간이 오래걸렸던 것 같아 아쉬웠다.
  • 또한 상태관리를 위한 recoil을 처음 접했어서 더 공부한 뒤에 잘 사용하고 싶다.
  • firebase를 처음 사용해봤지만 문서나 블로그를 보며 사용했는데 생각보다 접근성이 좋고 익숙해지는데 얼마 걸리지 않아
    사용하기 편리하다고 느꼈다.

CRA - typescript && libraries

  • npx create-react-app <프로젝트 명 or ./ > --template typescript
  • npm install recoil styled-components react-router-dom
  • prettier & eslint setting

Firebase setting

  1. firebase 프로젝트 생성 및 앱 등록
  2. curl -sL https://firebase.tools | bash (firebase mac설치)
  3. npm install firebase
  4. firebase login
  5. firebase init (storage, hosting, firestore)

wowba and others added 30 commits September 12, 2023 10:25
Feat: 로그인 페이지 라우터 추가
Feat: 회원가입, 계정생성 페이지 컴포넌트 추가 및 라우터 등록
공지사항 등록하기 페이지 기초 틀 잡기, firestore 연결하기
공지사항 등록하기 페이지 기초 틀 잡기, firestore 연결하기
Feat: 공지사항 등록하기 페이지 기초 구현 & firestore 연결
Feat: 회원가입 기능 구현
Refactor: CreateAccount.tsx 리팩토링
공지사항 리스트 페이지 기초구현, firestore 데이터 가져와서 화면에 출력하기, 공지사항 등록페이지 css작성
Feat: 공지사항 리스트 페이지 기초 구현 & firestore 데이터 가져오기
Eojoonhyuk added a commit that referenced this pull request Sep 22, 2023
Change to commute button component in header
NamgungJongMin added a commit that referenced this pull request Sep 22, 2023
Sinary00 pushed a commit that referenced this pull request Sep 22, 2023
유저 정보 연결 컨텍스트를 작성한다.
im-na0 pushed a commit that referenced this pull request Sep 22, 2023
im-na0 pushed a commit that referenced this pull request Sep 22, 2023
Feature: 로그인, 회원가입 페이지 마크업
@wowba wowba changed the title Y fe toy1 team8 제출 Y fe toy1 team8 wikinity Sep 23, 2023
@moana16 moana16 changed the title Y fe toy1 team8 wikinity Y_FE_Toy1_Team8_wikinity Sep 24, 2023
Copy link

@LEEJAEHYUB LEEJAEHYUB left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2주 짧은 기간동안 다양한 기능 과 페이지 구현하시느라 고생하셨습니다.
이번 토이프로젝트를 바탕으로 프로젝트의 협업을 위해 준비해야하는 것들, 그리고 기술을 사용했을 때 그 기술(library같은것들)을 왜 사용했는지에 대해 한번더 생각해보시면 좋을것 같습니다.
리뷰드린 내용은 정답이라기보다는 좀 더 나은 코드를 위한 저의 의견입니다. 참고하시어 리팩토링 및 추후 같은 로직 작성 시 참고해주시면 좋을 것 같습니다.
모두 고생많으셨습니다 :)

"jsx-a11y/label-has-associated-control": [
2,
{
"labelAttributes": ["htmlFor"]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

label요소가 반드시 연결되는 린트 설정을 하셨는데, 만약 프로젝트 내에서 label을 그렇게 사용하시면 설정하시는 게 맞습니다. 하지만 label이 그냥 단독으로 사용되거나 꼭 다른 요소와 연결되지 않은 경우가 있다면 해당 린트 옵션을 끄는것을 추천드려요!

@@ -0,0 +1,8 @@
{
"singleQuote": true,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

프리티어에 작은따옴표를 사용하는 설정을 했는데 어떤 파일에는 singleQuote이고 어떤 파일은 doubleQuote입니다. 린트와 잘 연계해서 따옴표 통일성을 유지하는 것을 권장드립니다.

<title>WIKINITY</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추후 프로젝트에서는 index.html에도 불필요한 코드 및 주석을 정리해보세요 ㅎㅎ
그리고 구글애널리틱스를 사용해서 웹페이지의 통계를 받아올 수도 있는데 이때 index.html에 cdn방식으로 사용하는 경우도 있습니다. 나중에 이런 insight도 검색해보세요!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용하지 않는 테스트 컴포넌트라면 삭제를 권장합니다.

<Route path='/wiki/write' element={<WikiWrite />} />
<Route path='/wiki/content' element={<WikiItem />} />
<Route path='/wiki/edit' element={<WikiEdit />} />
</Route>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

에러가 발생했을 때 라우팅도 추가하면 좋을 것 같아요.
흔히 보는 404 에러 페이지 같은것입니다!

<Route path="*" element={<NotFoundComponent />} />

이런식으로 만들수 있겠죠!

const [currentPage, setCurrentPage] = useState(1);

const handlePageClick = (pageNumber: number) => {
if (pageNumber > totalPages) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 조건문 처리방식은 if else문이 아니여서 오히려 가독성도 좋고 로직 파악도 좋아서 주로 사용하는 방식입니다.

const setUserState = useSetRecoilState(userState)
const setLoginState = useSetRecoilState(loginState)

const handleButtonClick = () => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

async / await 를 사용하여 비동기처리를 해보는것도 권장드립니다.

try {
 const credentialResult = await signInWithEmailAndPassword(auth,...);
 /* 이후 로직... */
} catch (error) {
  /* error 처리 */
}

const userProfileRef = ref(storage, `user/${userId}`)
await uploadBytes(userProfileRef, uploadFile)
imageUrl = await getDownloadURL(userProfileRef)
initialValue.profile = imageUrl

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

세미콜론은 왠만하면 작성하시는 것을 권장합니다.

</WriteDiv>

<div>
<WriteInput

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

input과 textarea가 번갈아가면서 반복적으로 사용되고 있습니다.
데이터셋을 어떻게 만들면 해당 마크업을 반복문을 사용하여 코드를 줄일수 있는지 생각해보세요

ex...

const inputList = [
  {
   id: "projectTeamName",
   type: "text",
   required: true,
  },
  ...
]

}, [projectId]);

const handleDelete = async (): Promise<void> => {
try {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

삭제할때는 모달이나 alert창을 띄워서 진짜 삭제할것인지 허들을 한번 두면 좋을것 같아요 UX적으로요!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants