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

[4주차] 이현영 미션 제출합니다. #19

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
fd3af98
style: 기본 마크업
hamo-o Sep 29, 2022
489440a
refactor: Header 컴포넌트 분리
hamo-o Sep 29, 2022
73388d2
feat: handleSubmit() 추가 && refactor: InputBox 컴포넌트 분리
hamo-o Sep 30, 2022
9142feb
refactor: ChatBoxList 컴포넌트 분리
hamo-o Sep 30, 2022
47fd40f
feat: useContext로 chats 배열 공급
hamo-o Sep 30, 2022
bc5bbe1
fix: 배열 prop으로 내려주기
hamo-o Sep 30, 2022
be858ce
fix: ChatBox 컴포넌트에 prop 전달
hamo-o Sep 30, 2022
0e3f9e2
fix: User배열 위치 변경
hamo-o Sep 30, 2022
051acf7
feat: enterKey, shiftKey 처리
hamo-o Sep 30, 2022
bfb4d50
fix: setChats user_id값 수정 && ChatBoxList 렌더링 내용 수정
hamo-o Sep 30, 2022
3d37248
feat: scrollTo() 구현
hamo-o Sep 30, 2022
bbb1deb
fix: json 파일 변경 && design: ChatBox css 수정
hamo-o Oct 1, 2022
4a7d4a0
fix: anytype 수정
hamo-o Oct 2, 2022
7036d54
refactor: interface 분리
hamo-o Oct 4, 2022
ba84517
refactor: React.FC 대체 && chore: 사용하지 않는 hook 정리
hamo-o Oct 5, 2022
e00d00b
feat: json 파일 추가
hamo-o Nov 2, 2022
c9b60b7
refactor: context > recoil 사용
hamo-o Nov 2, 2022
3de2c14
feat: page routing
hamo-o Nov 2, 2022
9bd10a9
feat: Header 추가
hamo-o Nov 3, 2022
c110bee
feat: 친구 목록 페이지 구현
hamo-o Nov 3, 2022
4f14b31
feat: navbar 구현
hamo-o Nov 3, 2022
6c75c53
feat: 채팅 페이지 구현
hamo-o Nov 3, 2022
600c678
chore: components 폴더 정리
hamo-o Nov 3, 2022
2156387
feat: chatRoom navigate 처리
hamo-o Nov 3, 2022
635e28a
feat: useInput 구현
hamo-o Nov 4, 2022
27f77b3
feat: 검색 기능 구현
hamo-o Nov 4, 2022
8f0e12d
fix: ChatRoom 유저 설정
hamo-o Nov 4, 2022
0c65cb3
feat: 선택된 유저 구현
hamo-o Nov 4, 2022
b9373b9
fix: 친구목록 curUser 수정
hamo-o Nov 4, 2022
7d40c42
refactor: useInput ChatInput에 활용
hamo-o Nov 4, 2022
d9a7387
chore: 프로필 변경
hamo-o Nov 4, 2022
4136723
feat: 상태메시지 추가
hamo-o Nov 4, 2022
fba91c7
design: font 저장
hamo-o Nov 4, 2022
989892f
fix: img 깨짐 수정
hamo-o Nov 5, 2022
e3a8b9a
fix: key값 오류 수정
hamo-o Nov 5, 2022
0a5f2b7
fix: ChatBox key값 중복 해결
hamo-o Nov 5, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": true
}
4,816 changes: 1,123 additions & 3,693 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,25 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.2.0",
"@fortawesome/free-brands-svg-icons": "^6.2.0",
"@fortawesome/free-regular-svg-icons": "^6.2.0",
"@fortawesome/free-solid-svg-icons": "^6.2.0",
"@fortawesome/react-fontawesome": "^0.2.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.11.60",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"@types/react-router-dom": "^5.3.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.3",
"react-scripts": "5.0.1",
"recoil": "^0.7.6",
"styled-components": "^5.3.6",
"typescript": "^4.8.3",
"web-vitals": "^2.1.4"
},
Expand All @@ -39,5 +48,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/styled-components": "^5.1.26"
}
}
Binary file added public/assets/default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/라떼.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/마리.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/뭉치.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/보통이.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 19 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
import GlobalStyle from './styles/GlobalStyle';
import { BrowserRouter, Route, Routes } from 'react-router-dom';

import Friends from './pages/Friends';
import Chatting from './pages/Chatting';
import ChatRoom from './pages/ChatRoom';
import Setting from './pages/Setting';

function App() {
return <div>화이팅!!</div>;
return (
<BrowserRouter>
<GlobalStyle />
<Routes>
<Route path="/" element={<Friends />} />
<Route path="/chatList" element={<Chatting />} />
<Route path="/setting" element={<Setting />} />
<Route path="/chatRoom/:id" element={<ChatRoom />} />
</Routes>
</BrowserRouter>
);
}

export default App;
94 changes: 94 additions & 0 deletions src/components/chatRoom/ChatBoxItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { useRecoilValue } from 'recoil';
import styled from 'styled-components';

import { curUserState } from '../../recoil/recoil';
import { User } from '../../interfaces/interfaces';

const ChatBox = ({
user,
chat_content,
}: {
user: User;
chat_content: string;
}) => {
const curUser = useRecoilValue(curUserState);

return (
<ChatBoxItem isSelected={user.user_id === curUser}>
{user.user_id === curUser ? (
<></>
) : (
<UserImgWrapper>
<UserImg src={user.user_img} />
</UserImgWrapper>
)}
<ChatWrapper>
{user.user_id === curUser ? (
<></>
) : (
<ChatUserName>{user.user_name}</ChatUserName>
)}
<ChatItem>
<ChatText isSelected={user.user_id === curUser}>
{chat_content}
</ChatText>
<ChatTime />
</ChatItem>
</ChatWrapper>
</ChatBoxItem>
);
};

const ChatBoxItem = styled.div<{ isSelected: boolean }>`
display: flex;
gap: 0.8rem;

justify-content: ${(props) => (props.isSelected ? 'right' : 'left')};
`;

const UserImgWrapper = styled.div`
width: 2.2rem;
height: 2.2rem;
border-radius: 40%;
overflow: hidden;
`;

const UserImg = styled.img`
width: 100%;
height: 100%;
object-fit: cover;
`;

const ChatWrapper = styled.div``;

const ChatUserName = styled.div`
padding-bottom: 0.4rem;

font-size: 0.75rem;
`;

const ChatItem = styled.div`
display: flex;
gap: 0.5rem;
`;

const ChatText = styled.div<{ isSelected: boolean }>`
padding: 0.6rem 0.8rem 0.5rem;

border-radius: 5px;

font-size: 0.9rem;
font-weight: 500;

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
word-break: break-all;

image
image

채림님한테 배운 건데... 이렇게 하면 영어로 길게 쳤을 때도 말풍선이 깨지지 않아용!!

background-color: ${(props) =>
props.isSelected ? 'rgb(255, 234, 0)' : 'white'};
`;

const ChatTime = styled.div`
align-self: flex-end;

font-size: 0.5rem;
font-weight: 500;
`;

export default ChatBox;
56 changes: 56 additions & 0 deletions src/components/chatRoom/ChatBoxList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { useRef, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
import styled from 'styled-components';

import { userState, chatState } from '../../recoil/recoil';
import ChatBoxItem from './ChatBoxItem';

const ChatBoxList = () => {
const { id } = useParams();
Copy link
Member

Choose a reason for hiding this comment

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

오 useParams쓰셨군요..! 저도 처음에 파람스로 쓰려고 하다가
recoil로 받아오는 게 더 편해서 바꿨었는데 현영님은 두개 중 어떤게 더 편하셨나용

const roomId = Number(id);

const chatList = useRecoilValue(chatState);
const userList = useRecoilValue(userState);

const chatBoxRef = useRef<HTMLDivElement>(null);

const scrollTo = () => {
if (chatBoxRef.current) {
chatBoxRef.current.scrollTo(0, chatBoxRef.current.scrollHeight);
}
};

useEffect(() => {
scrollTo();
}, [chatList]);

return (
<ChatBoxWrapper ref={chatBoxRef}>
{chatList
.filter((chat) => chat.chat_room === roomId)
.map((chat) => (
<ChatBoxItem
key={chat.chat_id}
{...chat}
user={userList.find((user) => user.user_id === chat.user_id)!}
/>
))}
</ChatBoxWrapper>
);
};

const ChatBoxWrapper = styled.div`
height: 26rem;
padding: 1.5rem;

display: flex;
flex-direction: column;
gap: 1rem;

overflow-y: auto;

background-color: rgb(180, 213, 226);
`;

export default ChatBoxList;
34 changes: 34 additions & 0 deletions src/components/chatRoom/ChatHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useRecoilValue } from 'recoil';
import { useParams } from 'react-router-dom';

import HeaderItem from './HeaderItem';
import { userState } from '../../recoil/recoil';
import styled from 'styled-components';

const ChatHeader = () => {
const { id } = useParams();
const roomId = Number(id);

const users = useRecoilValue(userState);

return (
<HeaderWrapper>
{users
.filter((user) => user.user_id === 1 || user.user_id === roomId)
.map((user) => (
<HeaderItem key={user.user_id} {...user} />
))}
</HeaderWrapper>
);
};

const HeaderWrapper = styled.div`
height: 6rem;
padding-left: 1.5rem;

display: flex;
align-items: center;
gap: 1rem;
`;

export default ChatHeader;
93 changes: 93 additions & 0 deletions src/components/chatRoom/ChatInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { useRef } from 'react';
import { useParams } from 'react-router-dom';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { Chat } from '../../interfaces/interfaces';

import useInput from '../../hooks/useInput';
import { chatState, curUserState } from '../../recoil/recoil';

import styled from 'styled-components';

const InputBox = () => {
const { id } = useParams();
const roomId = Number(id);

const [chat, handleChangeInput, reset] = useInput('');

const setChats = useSetRecoilState(chatState);

const chatId = useRef<number>(11);

const curUser = useRecoilValue(curUserState);

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();

if (chat.trim()) {
const newChat: Chat = {
user_id: curUser,
chat_id: chatId.current,
chat_room: roomId,
chat_content: chat,
};

chatId.current += 1;

setChats((prevChats) => [...prevChats, newChat]);
}

reset();
};

const handleEnter = (e: React.KeyboardEvent<HTMLFormElement>) => {
if (e.keyCode === 13) {
if (!e.shiftKey) handleSubmit(e);
}
};

return (
<InputWrapper onSubmit={handleSubmit} onKeyDown={handleEnter}>
<Input value={chat} onChange={handleChangeInput} />
<Button>전송</Button>
</InputWrapper>
);
};

const InputWrapper = styled.form`
height: 8rem;

display: flex;
`;

const Input = styled.input`
padding: 1rem;
flex-grow: 8;

border: none;
resize: none;
word-break: break-word;

font-family: sans-serif;
`;

const Button = styled.button`
padding: 0.5rem 1rem 0.5rem;
margin: 0.5rem;
height: 2rem;

align-self: end;

border-radius: 10px;

background-color: rgb(237, 237, 237);
font-weight: 500;
color: rgb(144, 144, 144);
`;

/*
.input-box__btn--default:hover {
background-color: rgb(255, 234, 0);
color: black;
} */

export default InputBox;
Loading