-
Notifications
You must be signed in to change notification settings - Fork 0
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
토이프로젝트2 12조 LANGCHAT #10
base: main
Are you sure you want to change the base?
Conversation
live server test
Feat: rating 및 mainboard 생성
Feat: rate 정렬
T1 14 feature/game/dictionary
Feat: login token 생성 및 localstorage 저장 기능
Feat: 메인 및 서브 레이아웃 적용
Style: 메인 및 서브 레이아웃 적용
T1 15 feature/game/check word
…-feature/game/design
Feat: 회원가입 폼 퍼블리싱
Feat: 게임페이지 접속 시 프록시 서버 1회 호출하여 최초 딜레이 해결, 함수에 주석 추가
Refactor: 함수에 주석 추가
Feat: 날짜별 채팅 정렬 기능 추가
Fix: searchWord 주석 추가
Fix: Game 컴포넌트 주석 추가
Feat: 날짜별 채팅 정렬 기능 추가
T1 61 feature/game/refactoring
Fix: README 수정
🚑Fix: fix way to insert query string
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
다양한 라이브러리를 활용해본 것도 보이고요!
map으로 노드를 그릴 때 key값 등 챙긴 것도 꼼꼼함이 돋보입니다.
메모이제이션관련해서 더 개선해보면 좋을 것 같아요!
영어끝말잇기와 같은 게임 기획아이템을 넣어서 더 재밌는 사이트가 된 것 같아요.
추후에 리스팅 부분에 무한 스크롤을 적용해보는 것도 좋을 것 같아요. (요즘 어떤 사이트에서든 너무너무 많이 쓰이는 요소라서, 과제에서도 많이 나옵니다.)
function App() { | ||
return ( | ||
<Routes> | ||
<Route element={<Layout />}> | ||
{/* 상원님 부분 */} | ||
<Route path="/game" element={<Game />} /> | ||
{/* 은지님 부분 */} | ||
<Route path="/home" element={<Home />} /> | ||
<Route path="/profile" element={<Profile />} /> | ||
{/* 홍규님 부분 */} | ||
<Route path="/chat" element={<ChatList />} /> | ||
<Route path="/chat/:chatId" element={<ChatRoom />} /> | ||
{/* 오픈 채팅 부분 */} | ||
<Route path="/open" element={<Openchat />} /> | ||
<Route path="/open/:chatId" element={<OpenchatRoom />} /> | ||
</Route> | ||
<Route element={<AuthLayout />}> | ||
{/* 성겸 부분 */} | ||
<Route index element={<SignIn />} /> | ||
<Route path="/signup" element={<SignUp />} /> | ||
</Route> | ||
</Routes> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
App 에서는 라우팅만 처리해놓은 게 깔끔하고 좋은 것 같아요~ 현업에서도 많이 쓰는 구조 입니다,
export const accessTokenState = atom({ | ||
key: 'accessTokenState', // unique ID (with respect to other atoms/selectors) | ||
default: localStorage.getItem('accessToken'), // default value (aka initial value) | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
토큰을 Recoil 이용해서 한번 더 상태관리를 감싼거죠? 이렇게 한 이유는 뭘까요?
로컬스토리지 만으로 했을 때 부족한 점이 있었나요?
const formik = useFormik({ | ||
initialValues: { | ||
id: '', | ||
password: '', | ||
confirmPassword: '', | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이런 submit해야 하는 데이터 등을 폼으로 관리할 수 있는 라이브러리들이 유용한 것 같아요
react-hook-form 도 유용한 편입니다~
type="submit" | ||
sx={{ mt: 3 }} | ||
> | ||
다음 단계로 ( 2 / 4 ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요런건 실제 스텝을 계산해 보여주도록 개선하면 좋을 것 같네요 step
이라는 값을 계산하고 있는 것 같아보여서요~
}; | ||
return newForm; | ||
}); | ||
// console.log(values); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
운영되는 서비스에서는 주석도 최대한 제거하고, 특히 console.log 는 남기지 않도록 습관을 들이면 좋습니다~
const handleSelectedUser = () => { | ||
if (selectedUser.id === user.id) { | ||
setSelectedUser({ id: '', name: '', picture: '' }); | ||
return; | ||
} | ||
|
||
setSelectedUser(user); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요런 걸 useCallback으로 정의해봐도 좋겠죠~
const handleSelectedUser = () => { | |
if (selectedUser.id === user.id) { | |
setSelectedUser({ id: '', name: '', picture: '' }); | |
return; | |
} | |
setSelectedUser(user); | |
}; | |
const handleSelectedUser = useCallback (() => { | |
if (selectedUser.id === user.id) { | |
setSelectedUser({ id: '', name: '', picture: '' }); | |
return; | |
} | |
setSelectedUser(user); | |
}, [user]} |
const inputValue = inputElement?.value; | ||
const existCheck = words?.find((e) => e === inputValue); | ||
// 시작 버튼을 눌렀는지 | ||
if (start) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
조건문 뎁스가 너무 깊어요! 이부분 리팩토링 고려해보면 좋을 것 같아요.
경우마다 플래그를 만들고 리턴해주는 방향으로 가는 게 더 좋아보입니다~
if(시작안함) 리턴
if(이미 입력한 단어) 리턴
if(끝말이 이어지지 않으면) 리턴
if(형식에 맞지 않으면 ) 리턴
if(사전 검색 가능한 단어) 어떤작업들~
// ..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
조언 감사드립니다! 해당 방법으로 리팩토링 해보겠습니다 ㅎㅎ
setUserData(exceptMe); | ||
}; | ||
|
||
useEffect(() => { | ||
fetchData(); | ||
}, [language]); | ||
|
||
return ( | ||
<List> | ||
{userData.length !== 0 | ||
? userData.map((data: UserData) => { | ||
const { id } = data; | ||
return <User key={id} data={data} onlineUser={onlineUser} />; | ||
}) | ||
: new Array(8) | ||
.fill(0) | ||
.map((_, index: React.Key) => <SkeletonUser key={index} />)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exceptMe 가 없으면 빈 array를 userData로 만들고
리턴하는 곳에서는
userData?.map(() => ... ) 이렇게 해도 될 것 같아요.
리턴하는 부분에서는 정말 UI를 "그리는" 관점의 코드만 있는 게 SPA 컴포넌트기반 웹화면 개발에 맞는 것 같습니다.
const hasUserDataExceptMe = data.some((data) => data.id !== user.id)
const userDataArray = hasUserDataExceptMe ? data.filter((data) => data.id !== user.id) : new Array(8).fill(0) ...
setUserData(userDataArray)
//
return
...
<List>
{userData?.map(() => ... }
</List>
{ReactDom.createPortal( | ||
<BackDrop userData={userData} onCloseModal={onCloseModal} />, | ||
document.getElementById('backdrop-root') as HTMLElement, | ||
)} | ||
</> | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
createPortal 로 뒷배경에 모달띄울 때는 제거되어야할 때는 없는지, 여러개 쌓이는 경우가 있진 않은지 등등 확인해보는 것도 좋을 것 같아요.
onClickSelectBtn, | ||
selectedIds, | ||
}: OpenchatInviteFriendItemProps) { | ||
const isSeleted = selectedIds.includes(user.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요런 값들을 메모이제이션 하는 거에요!
const isSelected = useMemo(() => selectedIds.includes(user.id), [selectedIds, user])
import convertBase64 from '../../utils/FileToBase64'; | ||
import Cropper from '../common/Cropper'; | ||
|
||
function SignUpForm2({ setStep }: SignUpFormProps) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
컴포넌트 명을 좀 더 명확히 하면 좋을 것 같습니다~
LANGCHAT: 언어 학습을 위한 채팅 앱
패스트캠퍼스 X 야놀자 프론트엔드 부트캠프 토이프로젝트2 12조
프로젝트 소개
제작기간 : 2023.11.06 ~ 2023.11.16
제작인원 : 4명
배포 주소
🌐 배포링크 : https://langchat-464b7.web.app/
🔒 테스트 계정 - ID: test0000 PW: 123123
팀원 소개
로그인/회원가입
채팅 로직 구현
기술 스택 및 라이브러리
사용 기술
협업툴
🎯 주요 구현 사항
useState
또는useReducer
를 활용한 상태 관리 구현Sass
,styled-component
,emotion
,Chakra UI
,tailwind CSS
등을 활용한 스타일 구현react
상태를 통한 CRUD 구현custom hook
을 통한 비동기 처리 구현jwt
등의 유저 인증 시스템 (로그인, 회원가입 기능)선택 구현 사항
Next.js
를 활용한 서버 사이드 렌더링 구현typescript
를 활용한 앱 구현storybook
을 활용한 디자인 시스템 구현jest
를 활용한 단위 테스트 구현😀 팀원별 상세 구현 사항
한은지 : 첫 화면, 프로필 페이지
주요 구현사항 설명
홈페이지
지홍규 : 메시지 페이지
주요 구현사항 설명
메시지 보내기 보달
채팅리스트
모든 채팅 가져오기
1대1채팅
로그아웃
localStorage
값과accessTokenState
값 초기화 후 로그인 페이지로 이동김성겸 : 인증관련, 오픈채팅 페이지
유저 인증 / 회원가입
회원가입
로그인
오픈 채팅
오픈채팅방 생성
오픈채팅방 초대
실시간 오픈채팅
오픈채팅 나가기
백상원 : 게임 페이지
주요 구현사항 설명
랭킹
끝말잇기 게임
➡️ 유저 흐름(flow) 이미지
📂 폴더 구조