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

토이프로젝트2_9조_Talk #8

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

토이프로젝트2_9조_Talk #8

wants to merge 377 commits into from

Conversation

JeongMin83
Copy link

@JeongMin83 JeongMin83 commented Nov 17, 2023

YFE - Talk

일상 속 모든 대화를 편리하게 관리할 수 있는 채팅 앱입니다.


📌 배포 링크

Deploy Chat Badge


📌 팀 소개

진정민 프로필 정지오 프로필 신현진 프로필 진종수 프로필 노욱진 프로필
진정민
팀장 (FE)
정지오
팀원 (FE)
신현진
팀원 (FE)
진종수
팀원 (FE)
노욱진
팀원 (FE)

📌 Contributor

@JeongMin83 (진정민) : 채팅방

@jiohjung98 (정지오) : 채팅 생성

@xxxjinn (신현진) : 유저 목록 페이지, 유저 프로필 모달, css 수정

@jongsujin (진종수) : 내 채팅, 오픈 채팅 조회

@NohWookJin (노욱진) : 회원가입, 로그인, 마이페이지

📌 기술 스택

Environment

FrontEnd

Deploy

Communication

📌 주요 화면 및 기능

회원가입

  • 회원가입 진행시 각 입력폼마다 신규 유저가 넣고 있는 정보가 허용되는 값인지 검증하며 실시간으로 비교합니다.
  • 올바른 값들로 입력폼을 모두 채웠을 경우(사진은 선택) 회원가입 버튼이 활성화됩니다.
회원가입사진

로그인

  • 아이디나 비밀번호를 확인해 틀린 값이거나 없는 값일시 유저에게 메시지를 보냅니다.
  • 회원가입 페이지와 마찬가지로 입력폼을 모두 채웠을 경우 로그인 버튼이 활성화됩니다.
  • 로그인시 JWT 토큰은 모두 쿠키에 보관하며, 로컬 스토리지에 저장한 로그인 시간을 최상단 컴포넌트에서 실시간 날짜와 비교해 만료 날짜와 가까워지면 토큰을 재발급합니다.
로그인사진

회원정보 수정

  • 회원 정보 수정을 통해 유저의 프로필과 이름을 변경할 수 있습니다.
정보수정사진

유저 목록 페이지

  • 회원 가입한 모든 유저들의 이름과 실시간 접속상태를 보여줍니다.
  • 유저 검색이 가능하며, 해당하는 유저가 존재하지 않을 때에는 '해당 사용자가 존재하지 않습니다.'라는 문구가 나옵니다.
스크린샷 2023-11-16 182451
  • 목록에서 유저를 선택하면 해당 유저의 프로필 모달창이 나오고, 모달창에서 유저와의 1:1 채팅방으로 이동하는 것이 가능합니다.
스크린샷 2023-11-16 182554

채팅생성

  • 유저프로필 모달에서의 1:1 채팅 - 두 유저 간 1:1 채팅방이 있는지 확인하고 있으면 기존의 채팅방으로 이동, 없으면 새 채팅을 생성합니다.
스크린샷 2023-11-16 182554 스크린샷 2023-11-16 182554
  • 채팅페이지에서의 채팅
    • 유저 한 명 클릭 시 1:1 채팅 - 두 유저 간 1:1 채팅방이 있는지 확인하고 있으면 기존의 채팅방으로 이동, 없으면 새 채팅을 생성합니다.
    • 유저 여러 명 클릭 시 단체채팅 - 프라이빗한 채팅방과 오픈 채팅을 선택할 수 있고 채팅방 이름을 직접 입력해 단체 채팅을 선택합니다.
    • 프라이빗 채팅방의 경우, 내 채팅페이지에서만 채팅방이 나타납니다.
    • 오픈 채팅방의 경우, 내 채팅페이지와 모든채팅페이지에서 채팅방이 나타납니다.
스크린샷 2023-11-16 182554 스크린샷 2023-11-16 182554 스크린샷 2023-11-16 182554

스크린샷 2023-11-16 182554 스크린샷 2023-11-16 182554 스크린샷 2023-11-16 182554 스크린샷 2023-11-16 182554 스크린샷 2023-11-16 182554 스크린샷 2023-11-16 182554

하단 바

  • 하단바를 통해 각각 유저 목록/내 채팅/오픈 채팅/정보 수정 페이지로 이동할 수 있습니다.

내 채팅 / 오픈채팅 조회

  • 내가 속한 채팅만 보여주는 채팅 페이지와 현재 있는 Private 하지 않은 오픈 채팅을 볼 수 있습니다.
  • 내가 속해 있지 않은 채팅방을 입장할 땐 모달창으로 채팅에 참여 유무를 묻고 채팅에 참여할 수 있습니다. 이미 들어가 있는 방은 바로 접속 됩니다.
  • 내가 보낸 메시지 순으로 채팅방이 위로 정렬됩니다. 어느 채팅방에서 채팅을 친 후면 채팅 순서대로 채팅방이 정렬됩니다.
  • 채팅방에서 볼 수 있는 최근 메세지 길이가 20자를 넘어가면 ...로 처리 되어 보여집니다.
  • 1대1 채팅방일 땐 상대방의 이름과 사진이 채팅방 이름과 이미지로 보여지며 Private 및 그룹 채팅 유무에 따라 각기 다른 이미지로 채팅방을 구별할 수 있습니다
  • 또한 현재 있는 채팅방을 검색할 수 있으며 검색 결과에 맞는 것이 없다면 채팅방이 없음을 알려줍니다.
  • 내 채팅에 채팅 목록이 없을 땐 채팅방이 없음을 알려줍니다.
내 채팅 오픈 채팅

채팅방

  • 참여자들과 실시간으로 채팅을 주고 받을 수 있습니다.
  • 해당 채팅방에 속하지 않는 사용자는 메인 페이지로 돌아갑니다.
  • 동일한 유저의 연속적 채팅 시 유저의 프로필을 한 번만 보여줍니다.
  • 실시간으로 들어오고 나가는 참여자들을 공지해줍니다.
스크린샷 2023-11-16 23 29 03

📌 유저 플로우

유저플로우

📌 파일 구조

CHAT/
├── src/
│   ├── api/
│   │    └── socketIo.ts
│   │    
│   ├── app/
│   │    ├── head.tsx
│   │    ├── layout.tsx
│   │    ├── page.tsx 
│   │    ├── allchats/
│   │    ├── chatting/
|   |    ├── createAccount/
|   |    ├── login/
|   |    ├── mychats/
|   |    ├── mypage/
│   │    └── userSelect/
│   │    
│   ├── components/
│   │    ├── Move.tsx
│   │    ├── Navigation.tsx
│   │    ├── Chat/
│   │    ├── chats/
│   │    ├── chatting/ 
│   │    ├── Login/
│   │    ├── Mypage/
|   |    ├── Register/
|   |    ├── Users/
|   |    ├── mychats/
|   |    ├── mypage/
│   │    └── userSelect/
│   │                
│   ├── hooks/
│   │    └── AuthCheck.ts
│   │    └── createAccount/     
│   │    
│   ├── lib/           
│   │    ├── api.ts
│   │    ├── cookie.ts
│   │    └── registry.tsx
│   ├── store/        
│   │    └── atoms.ts
│   │
│   ├── style/        
│   │    └── theme.ts
│
├── public/
│   ├── assets/
│   ├── fonts/
│   └── Logo.png
│  
├── node_modules/
├── .babelrc
├── .gitignore
├── next-env.d.ts
├── next.config.js
├── package.json
├── tsconfig.json
├── README.md
└── ...

🍋 소켓 기반 채팅앱

주어진 API와 소켓을 분석해 어떤 프로젝트를 진행/완성할 것인지 팀 단위로 자유롭게 결정하고 만들어보세요.
과제 수행 및 리뷰 기간은 별도 공지를 참고하세요!

[필수 구현사항]

  • useState 또는 useReducer를 활용한 상태 관리 구현
  • Sass, styled-component, emotion, Chakra UI, tailwind CSS 등을 활용한 스타일 구현
  • react 상태를 통한 CRUD 구현
  • 상태에 따라 달라지는 스타일 구현
  • custom hook을 통한 비동기 처리 구현
  • 유저인증 시스템(로그인, 회원가입) 구현
  • jwt등의 유저 인증 시스템 (로그인, 회원가입 기능)
  • 소켓을 이용한 채팅 구현

[선택 구현사항]

  • Next.js를 활용한 서버 사이드 렌더링 구현
  • typescript를 활용한 앱 구현
  • storybook을 활용한 디자인 시스템 구현
  • jest를 활용한 단위 테스트 구현

📌 개발 기간 : 2주 23.11.06 ~ 23.11.16

NohWookJin and others added 30 commits November 12, 2023 07:20
Refactor: AuthCheck 유틸 및 회원가입 검증 수정
T29 14 - 내채팅페이지에서 1:1 채팅 기능 구현
feat: 내채팅페이지에서 채팅버튼 클릭 시 1:1 채팅 기능 구현
Feat: 유저 접속 상태 구현
Feat: 하단바 수정, 모달 css, send 버튼 수정
Feat: 채팅방 기본적 기능 구현(초대 제외)
jseo9732 added a commit that referenced this pull request Nov 18, 2023
Feat: 채팅방 목록 조회 기능 구현
Yamyam-code added a commit that referenced this pull request Nov 18, 2023
noSPkeepgoing added a commit that referenced this pull request Nov 18, 2023
LeHiHo added a commit that referenced this pull request Nov 18, 2023
 구현시작전 에러해결
LeHiHo added a commit that referenced this pull request Nov 18, 2023
LeHiHo added a commit that referenced this pull request Nov 18, 2023
토큰 관리, 토큰재발급 구현
Copy link

@JungHyeonSeo-GGQ JungHyeonSeo-GGQ left a comment

Choose a reason for hiding this comment

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

토이프로젝트 진행하시느라 정말로 고생많으셨습니다~


if (!isRightWay) {
return null;
} else {

Choose a reason for hiding this comment

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

해당 부분에 else 는 불필요해 보입니다

password: '',
});
const [loginFail, setLoginFail] = useState<string>('');
const FAIL_MESSAGE = '* 아이디 또는 비밀번호가 일치하지 않습니다.';

Choose a reason for hiding this comment

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

해당 부분은 상수값인거같은데 상수값은 LoginForm 이 렌더링될때마다 생성될 필요가 없기에 컴포넌트 밖에다가 선언해주시면 좋을꺼같습니다

Comment on lines +83 to +88
{formData.id === '' || formData.password === '' ? (
<button className="submitEmptyButton">로그인</button>
) : (
<button className="submitFullButton">로그인</button>
)}
</div>

Choose a reason for hiding this comment

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

해당 부분을 보면 input 에 값이 입력되어 있지 않을때는 로그인 버튼이 비활성 되어있도록 구현해주신거같습니다
input이 비어있으니 실제로 로그인은 되지 않지만 불필요하게 api를 호출하고 있는거같습니다

input 이 비어있다면 아예 로그인 api를 호출하지 않도록 코드를 작성하는게 서버에 리소스를 줄이는 방법중에 하나 입니다

setLoginFail('');

try {
const res: ResponseBody = await instance.post('login', formData);

Choose a reason for hiding this comment

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

우선 해당 코드 부분은 별도의 파일로 분리해주시는걸 추천드리고 만약 분리를 한다고해도 useMutation을 적극 활용해주시는게 좋을꺼같습니다

Comment on lines +13 to +21
useEffect(() => {
const isUserAccess = getCookie('accessToken');

if (isUserAccess) {
setIsRightWay(true);
} else {
setIsRightWay(false);
}
}, []);

Choose a reason for hiding this comment

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

코드를 계속 살펴보면 이코드가 계속 반복되는거같습니다 로그인한 유저인지 아닌지를 판단하는 코드인거같습니다
이러한 부분은 HOC 로 뺴주시거나 nextjs 를 사용하셨으니 SSR로 처리해주시면 좋을꺼같습니다

const [selectedChat, setSelectedChat] = useState<Chat | null>(null);

const router = useRouter();
const userId = typeof window !== 'undefined' ? localStorage.getItem('userId') : null;

Choose a reason for hiding this comment

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

userId는 이미 recoil를 사용하고 계시니 recoil에서 가져오는게 더 호율적입니다

import { EnterChatRoomModalProps } from './chatsStore';
import { textModalData } from './ModalTextData';

const EnterChatRoomModal = ({ isOpen, onEnterClick, onCancelClick, selectedChat }: EnterChatRoomModalProps) => {

Choose a reason for hiding this comment

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

컴포넌트에 props는 별도의 파일로 빼기보다는 해당 컴포넌트에 선언해주시는게 유지보수할때 더 간편합니다

};

// 입장하기 버튼 눌렀을 때 채팅에 참여시키는 함수
const onEnterHandler = async () => {

Choose a reason for hiding this comment

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

해당 함수를 보니깐 props로 함수가 넘겨지는거 같습니다 props로 함수가 넘겨질때는 useCallback으로 묶어주시는게 렌더링 성능 향상에 도움이됩니다

Comment on lines +87 to +92
for (let i = 0; i < users.length; i++) {
if (userId == users[i].id) {
return users[i].username;
}
}
return undefined;

Choose a reason for hiding this comment

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

어.. 이부분은 사실 array.find()의 코드라서 아래처럼 개선할수있을꺼같습니다

const user = users.find(user => user.id === userId);
return user ? user.username : undefined;

}, []);

useEffect(() => {
const FetchMessagesInterval = setInterval(() => {

Choose a reason for hiding this comment

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

emit을 반복적으로 interval로 보내고 있으신거같습니다 그리고 특정 소켓이벤트가 오면 clear 해주시고 계신데
만약 서버가 이슈가 생겨서 소켓을 못보내는 상황이라면 계속 무한정 인터벌이 돌아갈꺼같습니다
이럴때를 대비해 특정 시간까지만 인터벌이 돌도록 타임아웃 코드를 작성해주시면 좋을꺼같습니다

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.

6 participants