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 7조 영화는 조조] 집사를 위한 채팅 웹 서비스 'Cat Talk😸' 제출 #3

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

Conversation

TaePoong719
Copy link

Cat Talk


Cat Talk 배포 레포

Test ID : cat
Test PW : 00000

🧑🏻‍💻 프로젝트 소개

Cat Talk는 반려묘를 기르고 있는 집사들을 위한 채팅 웹 서비스 입니다.

[필수 구현 사항]

useState를 활용한 상태 관리 구현
tailwind CSS를 활용한 스타일 구현
react 상태를 통한 CRUD 구현 (Next.js 'use client')
✅ 상태에 따라 달라지는 스타일 구현
custom hook을 통한 비동기 처리 구현
✅ 유저인증 시스템(로그인, 회원가입) 구현
jwt등의 유저 인증 시스템 (로그인, 회원가입 기능)
✅ 소켓을 이용한 채팅 구현

[선택 구현 사항]

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


야놀자 테크 캠프 토이 프로젝트 2 요구 사항

🍋 소켓 기반 채팅앱

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

과제 수행 및 제출 방법

Y_FE_Toy2_{팀명}

E.g, Y_FE_Toy2_GYOHEON
  1. 현재 저장소를 로컬에 클론(Clone)합니다.
  2. 자신의 팀명으로 브랜치를 생성합니다.(구분 가능하도록 팀명을 꼭 파스칼케이스로 표시하세요, git branch Y_FE_Toy2_Team13)
  3. 자신의 팀명 브랜치에서 과제를 수행합니다.
  4. 과제 수행이 완료되면, 자신의 팀명 브랜치를 원격 저장소에 푸시(Push)합니다.(main 브랜치에 푸시하지 않도록 꼭 주의하세요, git push origin Y_FE_Toy2_Team13)
  5. 저장소에서 main 브랜치를 대상으로 Pull Request 생성하면, 과제 제출이 완료됩니다!(E.g, main <== Y_FE_Toy2_Team13)
  6. Pull Request 링크를 LMS로도 제출해 주셔야 합니다.
  7. main 혹은 다른 사람의 브랜치로 절대 병합하지 않도록 주의하세요!
  8. Pull Request에서 보이는 설명을 다른 사람들이 이해하기 쉽도록 꼼꼼하게 작성하세요!
  • 과제 수행 및 제출 과정에서 문제가 발생한 경우, 바로 담당 멘토나 강사에게 얘기하세요!

  • 백엔드 서버에 문제가 생겼을 경우, 바로 슬랙의 GyoHeon Lee에게 연락하세요!

필수 구현 사항

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

선택 구현 사항

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

추가 사항

  • api들의 응답 데이터들을 일부러 파편화 해두었습니다!
  • api들 간의 데이터를 조합하여 이상적인 구조를 만들어보세요.

예시 프로젝트

private-messaging-part-1-chat-ab610e9e03738ad37f7b0fb55c771087

API 사용법

  • 모든 network 요청(Request) headers에 아래 정보가 꼭 포함돼야 합니다!
  • serverId는 팀마다 개별 전달됩니다.
  • 확인할 수 없는 사용자나 팀의 DB 정보는 임의로 삭제될 수 있습니다!
{
	"content-type": "application/json",
	"serverId": "nREmPe9B"
}

기본 데이터 구조

user

interface User {
	id: string;
	password: string;
	name: string;
	picture: string;
	chats: string[]; // chat id만 속합니다.
}

chat

interface Chat {
	id: string;
	name: string;
	isPrivate: boolean;
	users: string[];
	messages: Message[]; // message 객체가 속합니다.

	updatedAt: Date;
}

message

interface Message {
	id: string;
	text: string;
	userId: string;

	createdAt: Date;
}

회원

회원가입

사용자가 id에 종속되어 회원가입합니다.

  • 사용자 비밀번호는 암호화해 저장합니다.
  • 프로필 이미지는 url or base64 형식이어야 합니다.
  • 프로필 이미지는 1MB 이하여야 합니다.
curl https://fastcampus-chat.net/signup
  \ -X 'POST'

요청 데이터 타입 및 예시:

interface RequestBody {
	id: string; // 사용자 아이디 (필수!, 영어와 숫자만)
	password: string; // 사용자 비밀번호, 5자 이상 (필수!)
	name: string; // 사용자 이름, 20자 이하 (필수!)
	picture?: string; // 사용자 이미지(url or base64, under 1MB)
}
{
	"id": "abcd",
	"password": "********",
	"name": "GyoHeon",
	"picture": "https://avatars.githubusercontent.com/u/66263916?v=4"
}

응답 데이터 타입 및 예시:

interface ResponseValue {
	message: title;
}
{
	"message": "User created"
}

id 중복 체크

id 중복 체크를 합니다.

curl https://fastcampus-chat.net/check/id
  \ -X 'POST'

요청 데이터 타입 및 예시:

interface RequestBody {
	id: string; // 사용자 아이디 (필수!, 영어와 숫자만)
}
{
	"id": "abcd"
}

응답 데이터 타입 및 예시:

interface ResponseValue {
	isDuplicated: boolean;
}
{
	"isDuplicated": false
}

로그인

  • 발급된 accessToken은 7일 후 만료됩니다.
curl https://fastcampus-chat.net/login
  \ -X 'POST'

요청 데이터 타입 및 예시:

interface RequestBody {
	id: string; // 사용자 아이디 (필수!)
	password: string; // 사용자 비밀번호 (필수!)
}
{
	"id": "abcd",
	"password": "********"
}

응답 데이터 타입 및 예시:

interface ResponseValue {
	accessToken: string; // 사용자 접근 토큰
	refreshToken: string; // access token 발급용 토큰
}
{
	"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjlQS3I...(생략)",
	"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjlQS3I...(생략)"
}

인증 확인

id 중복 체크를 합니다.

curl https://fastcampus-chat.net/auth/me
  \ -X 'GET'
  \ -H 'Authorization: Bearer <accessToken>'

요청 데이터 타입 및 예시:

  • 없음

응답 데이터 타입 및 예시:

interface ResponseValue {
	auth: boolean;
	user?: User;
}

interface User {
	id: string;
	name: string;
	picture: string;
}
{
	"auth": true,
	"user": {
		"id": "test1",
		"name": "abcde",
		"picture": "https://avatars.githubusercontent.com/u/42333366?v=4"
	}
}

토큰 재발급

curl https://fastcampus-chat.net/refresh
  \ -X 'POST'

요청 데이터 타입 및 예시:

interface RequestBody {
	refreshToken: string; // access token 발급용 토큰
}
{
	"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjlQS3I...(생략)"
}

응답 데이터 타입 및 예시:

interface ResponseValue {
	accessToken: string; // 사용자 접근 토큰
}
{
	"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjlQS3I...(생략)"
}

사용자 정보 수정

  • 프로필 이미지는 url or base64 형식이어야 합니다.
  • 프로필 이미지는 1MB 이하여야 합니다.
curl https://fastcampus-chat.net/user
  \ -X 'PATCH'
  \ -H 'Authorization: Bearer <accessToken>'

요청 데이터 타입 및 예시:

interface RequestBody {
	name?: string; // 새로운 표시 이름
	picture?: string; // 사용자 프로필 이미지(url or base64)
}
{
	"name": "abcde",
	"picture": "https://avatars.githubusercontent.com/u/42333366?v=4"
}

응답 데이터 타입 및 예시:

interface ResponseValue {
	messgae: string;
}
{
	"message": "User updated"
}

채팅

특정 유저 조회

  • 특정 유저를 조회합니다.
curl https://fastcampus-chat.net/user?userId=${userId}
  \ -X 'GET'
  \ -H 'Authorization: Bearer <accessToken>'

요청 데이터 타입 및 예시:

  • 없음
  • 조회하고 싶은 id는 query string으로 사용합니다.

응답 데이터 타입 및 예시:

type ResponseValue = {
	user: User;
};

interface User {
	id: string;
	name: string;
	picture: string;
}
{
	"user": {
		"id": "user1",
		"name": "lgh",
		"picture": "https://gravatar.com/avatar/c274467c5ef4fe381b154a20c5e7ce26?s=200&d=retro"
	}
}

모든 유저 조회

  • 현재 존재하는 모든 유저를 조회합니다.
curl https://fastcampus-chat.net/users
  \ -X 'GET'
  \ -H 'Authorization: Bearer <accessToken>'

요청 데이터 타입 및 예시:

  • 없음

응답 데이터 타입 및 예시:

type ResponseValue = User[];

interface User {
	id: string;
	name: string;
	picture: string;
}
[
	{
		"id": "user1",
		"name": "lgh",
		"picture": "https://gravatar.com/avatar/c274467c5ef4fe381b154a20c5e7ce26?s=200&d=retro"
	},
	{
		"id": "user2",
		"name": "ldj",
		"picture": "https://gravatar.com/avatar/d94869409b4e94903723612a4f93a6f9?s=200&d=retro"
	}
]

채팅 생성하기

curl https://fastcampus-chat.net/chat
  \ -X 'POST'
  \ -H 'Authorization: Bearer <accessToken>'

요청 데이터 타입 및 예시:

interface RequestBody {
	name: string; // chat 이름
	users: string[]; // 참가자들 id(자신 미포함)
	isPrivate?: boolean; // 공개 비공개
}
{
	"name": "test chat",
	"users": ["user1", "user2"]
}

응답 데이터 타입 및 예시:

interface ResponseValue {
	id: string;
	name: string;
	users: User[]; // 자신을 포함한 참가자들 정보
	isPrivate: boolean;
	updatedAt: Date;
}

interface User {
	id: string;
	name: string;
	picture: string;
}
{
	"id": "fasgadsfdsghssdlsdafasd",
	"name": "test chat",
	"users": [
		{
			"id": "user1",
			"name": "lgh",
			"picture": "https://gravatar.com/avatar/c274467c5ef4fe381b154a20c5e7ce26?s=200&d=retro"
		},
		{
			"id": "user2",
			"name": "ldj",
			"picture": "https://gravatar.com/avatar/d94869409b4e94903723612a4f93a6f9?s=200&d=retro"
		}
	],
	"isPrivate": false,
	"updatedAt": "2023-11-01T08:23:39.850Z"
}

특정 채팅 조회

  • 특정 id의 채팅을 조회합니다.
  • isPrivate: true인 채팅방은 해당 채팅방 참가자만 볼 수 있습니다.
curl https://fastcampus-chat.net/chat/only?chatId=${chatId}
  \ -X 'GET'
  \ -H 'Authorization: Bearer <accessToken>'

요청 데이터 타입 및 예시:

  • 없음

응답 데이터 타입 및 예시:

interface ResponseValue {
	chat: Chat;
}

interface Chat {
	id: string;
	name: string;
	users: User[]; // 속한 유저 정보
	isPrivate: boolean;
	latestMessage: Message | null;
	updatedAt: Date;
}

interface User {
	id: string;
	name: string;
	picture: string;
}

interface Message {
	id: string;
	text: string;
	userId: string;
	createAt: Date;
}
{
	"chat": {
		"id": "f189ab25-5644-4d72-bd7c-0170ee9c8ede",
		"name": "chat room 1",
		"users": [
			{
				"id": "user1",
				"name": "lgh",
				"picture": "https://gravatar.com/avatar/c274467c5ef4fe381b154a20c5e7ce26?s=200&d=retro"
			},
			{
				"id": "user2",
				"name": "ldj",
				"picture": "https://gravatar.com/avatar/d94869409b4e94903723612a4f93a6f9?s=200&d=retro"
			}
		],
		"isPrivate": false,
		"updatedAt": "2023-10-31T13:18:38.216Z",
		"latestMessage": null
	}
}

모든 채팅 조회

  • 현재 존재하는 모든 채팅을 조회합니다.
  • isPrivate: true인 채팅방은 보이지 않습니다.
curl https://fastcampus-chat.net/chat/all
  \ -X 'GET'
  \ -H 'Authorization: Bearer <accessToken>'

요청 데이터 타입 및 예시:

  • 없음

응답 데이터 타입 및 예시:

type ResponseValue = Chat[];

interface Chat {
	id: string;
	name: string;
	users: User[]; // 속한 유저 정보
	isPrivate: boolean;
	latestMessage: Message | null;
	updatedAt: Date;
}

interface User {
	id: string;
	name: string;
	picture: string;
}

interface Message {
	id: string;
	text: string;
	userId: string;
	createAt: Date;
}
[
	{
		"id": "f189ab25-5644-4d72-bd7c-0170ee9c8ede",
		"name": "chat room 1",
		"users": [
			{
				"id": "user1",
				"name": "lgh",
				"picture": "https://gravatar.com/avatar/c274467c5ef4fe381b154a20c5e7ce26?s=200&d=retro"
			},
			{
				"id": "user2",
				"name": "ldj",
				"picture": "https://gravatar.com/avatar/d94869409b4e94903723612a4f93a6f9?s=200&d=retro"
			}
		],
		"isPrivate": false,
		"updatedAt": "2023-10-31T13:18:38.216Z",
		"latestMessage": null
	},
	{
		"id": "f189ab25-5644-4d72-bd7c-0170ee9c8edj",
		"name": "chat room 2",
		"users": [
			{
				"id": "user1",
				"name": "lgh",
				"picture": "https://gravatar.com/avatar/c274467c5ef4fe381b154a20c5e7ce26?s=200&d=retro"
			},
			{
				"id": "user2",
				"name": "ldj",
				"picture": "https://gravatar.com/avatar/d94869409b4e94903723612a4f93a6f9?s=200&d=retro"
			}
		],
		"isPrivate": false,
		"updatedAt": "2023-10-31T15:18:38.216Z",
		"latestMessage": {
			"id": "8f7f67bb-f1ab-4792-9678-0b8546adcb6f",
			"text": "testtest444",
			"userId": "test:test6",
			"createdAt": "2023-11-06T11:15:50.588+00:00"
		}
	}
]

나의 채팅 조회

curl https://fastcampus-chat.net/chat
  \ -X 'GET'
  \ -H 'Authorization: Bearer <accessToken>'
  • 내가 속한 모든 채팅을 조회합니다.
  • isPrivate: true인 채팅방도 모두 보이게 됩니다.

요청 데이터 타입 및 예시:

  • 없음

응답 데이터 타입 및 예시:

type ResponseValue = Chat[];

interface Chat {
	id: string;
	name: string;
	users: User[]; // 속한 유저 id
	isPrivate: boolean;
	latestMessage: Message | null;
	updatedAt: Date;
}

interface User {
	id: string;
	name: string;
	picture: string;
}

interface Message {
	id: string;
	text: string;
	userId: string;
	createAt: Date;
}
[
	{
		"id": "f189ab25-5644-4d72-bd7c-0170ee9c8ede",
		"name": "chat room 1",
		"users": [
			{
				"id": "user1",
				"name": "lgh",
				"picture": "https://gravatar.com/avatar/c274467c5ef4fe381b154a20c5e7ce26?s=200&d=retro"
			},
			{
				"id": "user2",
				"name": "ldj",
				"picture": "https://gravatar.com/avatar/d94869409b4e94903723612a4f93a6f9?s=200&d=retro"
			}
		],
		"isPrivate": true,
		"updatedAt": "2023-10-31T13:18:38.216Z",
		"latestMessage": null
	},
	{
		"id": "f189ab25-5644-4d72-bd7c-0170ee9c8edj",
		"name": "chat room 2",
		"users": [
			{
				"id": "user1",
				"name": "lgh",
				"picture": "https://gravatar.com/avatar/c274467c5ef4fe381b154a20c5e7ce26?s=200&d=retro"
			},
			{
				"id": "user2",
				"name": "ldj",
				"picture": "https://gravatar.com/avatar/d94869409b4e94903723612a4f93a6f9?s=200&d=retro"
			}
		],
		"isPrivate": false,
		"updatedAt": "2023-10-31T15:18:38.216Z",
		"latestMessage": {
			"id": "8f7f67bb-f1ab-4792-9678-0b8546adcb6f",
			"text": "testtest444",
			"userId": "test:test6",
			"createdAt": "2023-11-06T11:15:50.588+00:00"
		}
	}
]

채팅 참여하기

curl https://fastcampus-chat.net/chat/participate
  \ -X 'PATCH'
  \ -H 'Authorization: Bearer <accessToken>'

요청 데이터 타입 및 예시:

interface RequestBody {
	chatId: string;
}
{
	"chatId": "f189ab25-5644-4d72-bd7c-0170ee9c8ede"
}

응답 데이터 타입 및 예시:

interface ResponseValue {
	id: string;
	name: string;
	users: User[]; // 속한 유저 id
	isPrivate: boolean;
	updatedAt: Date;
}

interface User {
	id: string;
	name: string;
	picture: string;
}
{
	"id": "f189ab25-5644-4d72-bd7c-0170ee9c8ede",
	"name": "chat room 1",
	"users": [
		{
			"id": "user1",
			"name": "lgh",
			"picture": "https://gravatar.com/avatar/c274467c5ef4fe381b154a20c5e7ce26?s=200&d=retro"
		},
		{
			"id": "user2",
			"name": "ldj",
			"picture": "https://gravatar.com/avatar/d94869409b4e94903723612a4f93a6f9?s=200&d=retro"
		}
	],
	"isPrivate": true,
	"updatedAt": "2023-10-31T13:18:38.216Z"
}

채팅 나가기

curl https://fastcampus-chat.net/chat/leave
  \ -X 'PATCH'
  \ -H 'Authorization: Bearer <accessToken>'

요청 데이터 타입 및 예시:

interface RequestBody {
	chatId: string;
}
{
	"chatId": "f189ab25-5644-4d72-bd7c-0170ee9c8ede"
}

응답 데이터 타입 및 예시:

interface ResponseValue {
	message: string;
}
{
	"message": "Leave success"
}

채팅 초대하기

curl https://fastcampus-chat.net/chat/invite
  \ -X 'PATCH'
  \ -H 'Authorization: Bearer <accessToken>'

요청 데이터 타입 및 예시:

interface RequestBody {
	chatId: string;
	users: string[]; // 초대할 유저 id
}
{
	"chatId": "f189ab25-5644-4d72-bd7c-0170ee9c8ede",
	"users": ["user1", "user2"]
}

응답 데이터 타입 및 예시:

interface ResponseValue {
	id: string;
	name: string;
	users: User[]; // 속한 유저 정보
	isPrivate: boolean;
	updatedAt: Date;
}

interface User {
	id: string;
	name: string;
	picture: string;
}
{
	"id": "f189ab25-5644-4d72-bd7c-0170ee9c8ede",
	"name": "chat room 1",
	"users": [
		{
			"id": "user1",
			"name": "lgh",
			"picture": "https://gravatar.com/avatar/c274467c5ef4fe381b154a20c5e7ce26?s=200&d=retro"
		},
		{
			"id": "user2",
			"name": "ldj",
			"picture": "https://gravatar.com/avatar/d94869409b4e94903723612a4f93a6f9?s=200&d=retro"
		}
	],
	"isPrivate": true,
	"updatedAt": "2023-10-31T13:18:38.216Z"
}

Socket

  • socket.io 의 사용을 추천드립니다.
  • Socket 연결시에도 headers는 유지해야 합니다.

기본 연결

io(`https://fastcampus-chat.net/chat?chatId=${chatId}`, {
	extraHeaders: {
		Authorization: 'Bearer <accessToken>',
		serverId: 'test',
	},
});

emit Event(client -> server)

example

socket.emit('message-to-server', text);

message-to-server

  • 같은 방에 있는 사람들에게 메세지를 전달합니다.

요청 데이터

type RequestData: string;

fetch-messages

  • 이전 대화 목록을 불러옵니다.
  • messages-to-client로 데이터를 받을 수 있습니다.

요청 데이터

  • 없음

users

  • 접속 상태인 유저 목록을 불러옵니다.
  • users-to-client로 데이터를 받을 수 있습니다.

요청 데이터

  • 없음

on Event(server -> client)

example

socket.on('message-to-client', (messageObject) => {
	console.log(messageObject);
});

message-to-client

  • 같은 방에 있는 사람들에게 메세지를 전달합니다.

응답 데이터

interface ResponseData {
	id: string;
	text: string;
	userId: string; // 메세지를 보낸 사람의 id
	createdAt: Date;
}

messages-to-client

  • 이전 대화 목록을 불러옵니다.

응답 데이터

interface Message {
	id: string;
	text: string;
	userId: string; // 메세지를 보낸 사람의 id
	createdAt: Date;
}

interface ResponseData {
	messages: Message[];
}

join

  • 같은 방에 새로운 사람이 들어오면 모든 유저의 정보를 다시 받습니다.

응답 데이터

interface ResponseData {
	users: string[]; // 참여자들 id
	joiners: string[]; // 새로운 참여자 id
}

leave

  • 같은 방에 사람이 나가면 모든 유저의 정보를 다시 받습니다.

응답 데이터

interface ResponseData {
	users: string[]; // 참여자들 id
	leaver: string; // 나간 사용자 id
}

users-to-client

  • 접속 상태인 유저 목록을 불러옵니다.

응답 데이터

interface ResponseData {
	user: string[]; // 참가자들 id
}

server 연결

io(`https://fastcampus-chat.net/server`, {
	extraHeaders: {
		Authorization: 'Bearer <accessToken>',
		serverId: 'test',
	},
});

emit Event(client -> server)

example

socket.emit('users-server');

users-server

  • 같은 serverId를 사용하는 online 사용자를 불러옵니다.
  • users-server-to-client로 데이터를 받을 수 있습니다.

요청 데이터

  • 없음

on Event(server -> client)

example

socket.on('message-to-client', (messageObject) => {
	console.log(messageObject);
});

users-server-to-client

  • 같은 serverId를 사용하는 접속 상태인 유저 목록을 불러옵니다.

응답 데이터

interface ResponseData {
	user: string[]; // 참가자들 id
}

invite

  • 새로운 채팅방 생성시 해당 채팅방 유저에게 채팅방 정보를 전송합니다.
  • 기존 채팅방에 유저 초대시 초대된 유저에게 채팅방 정보를 전송합니다.

응답 데이터

interface ResponseData {
	id: string;
	name: string;
	users: string[]; // 참여자들 id
	isPrivate: boolean;
	updatedAt: Date;
}

new-chat

  • 새로운 대화방이 생긴 경우 (not private) 서버(팀에서 사용하는 serverId)의 참여자들에게 이를 전달합니다.

응답 데이터

interface ResponseData {
	id: string;
	name: string;
	users: string[]; // 참여자들 id
	isPrivate: boolean;
	updatedAt: Date;
}

🧑🏻‍💻 Contributor

@TaePoong719 (최우혁) : 유저 목록, 참여한 채팅 및 유저 검색
@LikeFireAndSky (김민섭) : 채팅 목록 구현, 클라우디너리 연동, 퍼블리싱
@hhjs2 (정효주) : 로그인, 회원가입, 채팅 기능 구현
@JitHoon (최지훈) : 채팅 검색, 채팅 기능 구현
@syb0127 (서예빈) : 로그아웃, 푸터 구현 및 디자인 작업


🧑🏻‍💻 Stack

Stack


🧑🏻‍💻 디자인

Userflow

유저플로우1 유저플로우2
유저플로우3 유저플로우4
유저플로우5

디자인 프로토타입

image

🧑🏻‍💻 주요 기능 구현

로그인, 회원가입

유저 목록 조회, 검색, 채팅

채팅방 검색 및 채팅

드래그 & 드롭


🧑🏻‍💻 Script

Development Mode

$ git clone https://github.com/MOVIEJOJO7/cat-talk.git
$ npm i
$ npm run dev

🧑🏻‍💻 팀 소개

최우혁 프로필 김민섭 프로필 정효주 프로필 최지훈 프로필 서예빈 프로필 김민수 멘토님
최우혁
Frontend
김민섭
Frontend
정효주
Frontend
최지훈
Frontend
서예빈
Frontend
김민수 멘토님

🧑🏻‍💻 개발 기간 : 11일 23.11.06 월 ~ 23.11.16 목

TaePoong719 and others added 30 commits November 10, 2023 10:33
Feat : 오픈 채팅방 목록 검색 세부 기능 추가
Feat : 로그인 & 회원가입 구현
Feat : 유저 친구 페이지 완성 및 모달 작업 pr
Feat : 오픈채팅방 데이터 받아와서 리스트에 뿌려주기 pr
Feat : 환경변수 사용 X, 쿠키로 대체 pr
Feat : 유저/채팅방 검색 기능 추가 pr
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 added a commit that referenced this pull request Nov 17, 2023
2YH02 added a commit that referenced this pull request Nov 17, 2023
Feature/#3 랜덤 키워드, 라이어 지정
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
This reverts commit 8f8f8b3, reversing
changes made to d0431c0.
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 added a commit that referenced this pull request Nov 17, 2023
Feature/#3 게임 시작 소켓 연결 진행중
2YH02 added a commit that referenced this pull request Nov 17, 2023
Feat/#3: 게임 시작 소켓 연결
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
2YH02 pushed a commit that referenced this pull request Nov 17, 2023
seungjun222 pushed a commit that referenced this pull request Nov 17, 2023
gahyuun pushed a commit that referenced this pull request Nov 17, 2023
Feature: 사이드바 레이아웃 구현
dbstjrals pushed a commit that referenced this pull request Nov 17, 2023
JeongMin83 added a commit that referenced this pull request Nov 17, 2023
styled component, layout, api 적용
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
Copy link

@minsoo-web minsoo-web left a comment

Choose a reason for hiding this comment

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

짧은 기간동안 멋진 결과물을 만드셨네요!! 고생 많으셨습니다.

좋았던 점

  • 낯설 수 있는 신기술들을 도입해보면서 모던한 스택으로 개발을 시도한 점 멋졌습니다.
  • 폴더구조를 잘 분리해서 유지보수성을 높이고자 노력한 점이 좋았습니다.
  • 제네릭 등을 활용해 typed하게 작업하려고 시도한 점들이 인상 깊었습니다.
  • vercel 자동배포, preview 등을 활용한 점

아쉬웠던 점

  • 반복되어 사용되는 fetch 함수의 옵션들을 매번 작성한 점
  • 전반적으로 지켜지지 않아보이는 컨벤션 (변수명 케이스, 파일관리 등)
  • 사용되지 않는 파일 또는 주석들을 삭제하지 않아, 깔끔하지 못했던 마무리

리뷰 남긴 내용들을 기반으로 리팩토링해보는 시간도 꼭 가져보면 좋을 것 같습니다!
고생 많으셨습니다!!

Choose a reason for hiding this comment

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

Choose a reason for hiding this comment

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

preview까지 적용... 멋집니다!!!

Comment on lines +18 to +20
const handleBackChat = () => {
router.back();
};

Choose a reason for hiding this comment

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

함수를 한 번 더 감싸준 이유가 있으신가요?! 🤔

};

const handleLeaveChat = async () => {
await fetch('https://fastcampus-chat.net/chat/leave', {

Choose a reason for hiding this comment

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

URL은 고정이니까, 상수로 관리했어도 좋았을 것 같습니다. (오타의 위험성) 아니면 nextjs의 rewrite를 활용해서 유사 프록시 전략을 사용하는 것도 방법입니다.

Choose a reason for hiding this comment

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

페이지 라우팅에서만 사용할 수 있는 줄 알았었는데 next js의 rewrite를 API URL에 적용할 수 있는 지 몰랐습니다!! 감사합니다.

Comment on lines +25 to +29
headers: {
'content-type': 'application/json',
serverId: process.env.NEXT_PUBLIC_SERVER_ID as string,
Authorization: `Bearer ${accessToken}`,
},

Choose a reason for hiding this comment

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

매번 똑같이 header를 호출하는 코드가 반복될텐데, header를 뱉어주는 함수를 만들어서 호출했으면 어땠을까? 하는 의견 남겨봅니다.

}
};

const invalidImageType = ['svg', 'png', 'jpg', 'jpeg'];

Choose a reason for hiding this comment

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

이 리뷰를 마지막으로 생애주기와 관련이 없는 상수들을 컴포넌트 외부로 선언하도록 변경해보세요!

Comment on lines +48 to +54
onClick={() => {
if (isShowMore) {
setIsShowMore(false);
} else {
router.back();
}
}}

Choose a reason for hiding this comment

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

인라인으로 선언하는 익명함수와 함수를 선언해서 콜백으로 전달하는 방식이 혼재되어있는 것 같습니다. 따로 기준이 있으신가요?

Choose a reason for hiding this comment

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

api를 모아두는 파일이름은 utils 보다는 apis.ts 가 더 좋았을 것 같아요!! 그리고, 어떤 곳에서는 인라인으로 직접 호출하고 어떤 곳에서는 파일로 관리하는 것은 컨벤션이 잘 안 지켜진 게 아닐까 의견 드리고 싶었습니다.

import { User } from '@/types';

export type UserHasOnline = User & {
isOnline: boolean;

Choose a reason for hiding this comment

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

online이 혹시 로그인 여부를 표시하는 변수명인가요? 온라인은 네트워크 연결이 되어있는지의 여부를 나타내는 용어 같습니다

const { data, isLoading, isError } = useQuery({
queryKey: ['fetchAllUsers'],
queryFn: () => fetchAllUsers(token),
staleTime: 1000 * 60 * 5,

Choose a reason for hiding this comment

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

staleTime은 조심해서 써야합니다. 새로고침하기 전까지는 5분동안 데이터가 항상 똑같은 데이터를 받기 때문입니다.

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