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주차] 김선영 미션 제출합니다. #20

Open
wants to merge 42 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
8d8b7b1
[Set] styled-components 설치 및 적용
seondal Sep 30, 2022
fa18c7d
[Feat] InputForm으로 사용자 입력값 받기
seondal Sep 30, 2022
33bc4f5
[Feat] 입력받은 값들 ChatList에서 보여주기
seondal Sep 30, 2022
eb2a4da
[Feat] UserList 구현
seondal Sep 30, 2022
6bc5c72
[Feat] 채팅에 유저 정보 포함시키기
seondal Sep 30, 2022
a1eb122
[Style] UserItem 디자인 적용
seondal Sep 30, 2022
fca94cf
[Style] ChatItem 디자인 적용중...
seondal Sep 30, 2022
c8b2bcf
[Feat] 각 채팅에 date 속성 추가
seondal Sep 30, 2022
8df779e
[Feat] 각 채팅에 전송자(유저) 정보 추가
seondal Sep 30, 2022
da075cf
[Style] UserList
seondal Sep 30, 2022
5196769
[Style] ChatList
seondal Sep 30, 2022
e380432
[Style] 현재유저의 말풍선만 스타일 다르게
seondal Sep 30, 2022
432a440
[Style] 전체적인 사이즈 변경
seondal Sep 30, 2022
8b7a67e
[Style] 말풍선 텍스트 줄바꿈 처리
seondal Sep 30, 2022
9c3a3e3
[Style] InputForm
seondal Sep 30, 2022
cd549c0
[Feat] 메세지 전송할때마다 맨 밑으로 스크롤 자동 이동
seondal Sep 30, 2022
ccacc5e
[Style] 스크롤바 커스텀
seondal Sep 30, 2022
c35a0ad
[Feat] 엔터로 전송, shift+엔터로 줄바꿈
seondal Sep 30, 2022
ed5dfeb
[Fix] 버튼으로 submit 할 시 새로고침되는 현상 수정
seondal Sep 30, 2022
571e82b
[Refact] 샘플 데이터 json 파일로 관리하기
seondal Sep 30, 2022
7a81211
[Fix] 한글 중복 입력 오류를 고치자 ! (기여 : @yjoonjang)
seondal Oct 2, 2022
570cb4e
Merge branch 'CEOS-Developers:master' into master
seondal Nov 4, 2022
ff0ac89
[Refact] Routing 설정
seondal Nov 4, 2022
6ace85b
[Del] 사용안하는 파일 삭제
seondal Nov 4, 2022
0a894b5
[Foldering] 라우팅을 위한 폴더링
seondal Nov 4, 2022
48b8e4f
[Feat] 라우팅을 이용한 페이지 이동 구현
seondal Nov 4, 2022
7b342fb
[Style] Layout NavLink
seondal Nov 4, 2022
bf1e6ad
[Add] ChatData 확장 및 유저데이터 추가
seondal Nov 4, 2022
0831d21
[Feat] 경로에 따라 해당 채팅방 보여지게하기
seondal Nov 4, 2022
b820b80
[Fix] 채팅방에 참여하는 유저만이 아닌 전체 유저가 보이는 오류 수정
seondal Nov 4, 2022
e590aac
[Feat] ChatroomPage 채팅방 리스트 띄우기
seondal Nov 5, 2022
32be316
[Feat] FriendPage 유저 리스트 띄우기
seondal Nov 5, 2022
f37cd87
[Feat] getRoomMembers: 채팅방에 참여하는 멤버들의 유저정보를 반환해주는 custom hooks
seondal Nov 5, 2022
79b63bb
[Feat] SettingPage
seondal Nov 5, 2022
23ea56e
💄 style : layout
seondal Sep 8, 2023
e55c5e8
💄 style : 친구 페이지
seondal Sep 8, 2023
1bef60c
🏗 folder : 폴더링
seondal Sep 8, 2023
9936ddb
💄 style : 채팅 페이지
seondal Sep 8, 2023
5ba033e
💄 style : 채팅방 디자인
seondal Sep 8, 2023
87fa56a
✨ feat : 채팅방 연속 챗 프로필 안보이게
seondal Sep 8, 2023
c9c8adb
✂️ edit : 더보기
seondal Sep 8, 2023
2f41407
🛠 fix : 빌드에러
seondal Sep 8, 2023
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
318 changes: 318 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"@types/react-dom": "^18.0.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.3",
"react-scripts": "5.0.1",
"styled-components": "^5.3.6",
"typescript": "^4.8.3",
"web-vitals": "^2.1.4"
},
Expand All @@ -39,5 +41,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/styled-components": "^5.1.26"
}
}
25 changes: 22 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
function App() {
return <div>화이팅!!</div>;
}
import { Route, Routes } from "react-router-dom";

import Layout from "./components/Layout";
import FriendPage from "./pages/FriendPage";
import ChatroomPage from "./pages/ChatroomPage";
import SettingPage from "./pages/SettingPage";
import Chatroom from "./pages/Chatroom";

const App = () => {
return (
<>
<Routes>
<Route element={<Layout />}>
<Route path="/" element={<FriendPage />} />
<Route path="/chatrooms" element={<ChatroomPage />} />
<Route path="/setting" element={<SettingPage />} />
</Route>
<Route path="/chatrooms/:id" element={<Chatroom />} />
</Routes>
</>
);
};

export default App;
1 change: 1 addition & 0 deletions src/asset/icon/chat.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/asset/icon/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import person from "./person.svg";
import chat from "./chat.svg";
import more from "./more.svg";

export const ICON = { person, chat, more };
1 change: 1 addition & 0 deletions src/asset/icon/more.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/asset/icon/person.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions src/common/getRoomMembers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { User } from "./interface";
import chatData from "../data/chatData.json";
import userData from "../data/userData.json";

const chatrooms = chatData.rooms;
const users = userData.users;

// 해당 채팅방 멤버들의 유저정보를 담은 배열을 반환
export const getRoomMembers = (roomId: number, includeCurUser: Boolean) => {
const roomMembers: User[] = [];
chatrooms[roomId].users.map((memberId) => roomMembers.push(users[memberId]));
if (!includeCurUser) {
roomMembers.shift();
}
return roomMembers;
};
30 changes: 30 additions & 0 deletions src/common/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
html{
display: flex;
justify-content: center;
align-items: center;
background-color: whitesmoke;
font-size: 0.8rem;
height: 100vh;
overflow: hidden;
}

body {
position: relative;
margin: 0;
width: 400px;
height: 90vh;
box-shadow: 0 0 16px lightgray;
background-color: white;
border-radius: 10px;
}

a {
text-decoration: none;
}

@media screen and (max-width: 400px) {
body {
width: 100%;
height: 100%;
}
}
13 changes: 13 additions & 0 deletions src/common/interface.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export interface User {
id: number;
name: string;
profileImage: string;
message: string;
}

export interface Chat {
id: number;
senderId: number;
text: string;
date: string;
}
34 changes: 34 additions & 0 deletions src/components/Item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import styled from "styled-components";

export const Item = styled.div`
display: flex;
align-items: center;
padding: 8px 20px;
gap: 8px;

:hover {
background-color: whitesmoke;
}

.title {
color: black;
}

.content {
color: gray;
font-size: 0.8rem;
}
`;

export const ProfileImage = styled.img<{
noImage?: boolean;
selected?: boolean;
}>`
width: 40px;
height: 40px;
border-radius: 15px;
object-fit: cover;
outline: ${({ selected }: { selected?: boolean }) =>
selected ? "1px solid black" : "none"};
opacity: ${(props) => (props.noImage ? 0 : 1)};
`;
65 changes: 65 additions & 0 deletions src/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { NavLink, Outlet, useLocation } from "react-router-dom";
import styled from "styled-components";
import { ICON } from "../asset/icon";

const MENUS = [
{ text: "친구", path: "/", icon: ICON.person },
{ text: "채팅", path: "/chatrooms", icon: ICON.chat },
{ text: "더보기", path: "/setting", icon: ICON.more },
];

export default function Layout() {
const { pathname } = useLocation();

return (
<Wrapper>
<Navigation>
{MENUS.map((menu) => (
<NavLink
key={menu.text}
to={menu.path}
style={({ isActive }) =>
isActive ? { opacity: 1.0 } : { opacity: 0.3 }
}>
<img src={menu.icon} alt="" />
</NavLink>
))}
</Navigation>
<Container>
<h2>{MENUS.find((menu) => menu.path === pathname)?.text}</h2>
<Outlet />
</Container>
</Wrapper>
);
}

const Wrapper = styled.div`
display: flex;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
`;

const Navigation = styled.div`
display: flex;
align-items: center;
flex-direction: column;
gap: 20px;
background-color: #e6e6e6;
padding: 20px;
border-bottom-left-radius: 10px;
border-top-left-radius: 10px;
`;

const Container = styled.div`
display: flex;
flex: 1;
flex-direction: column;

h2 {
margin: 0px;
padding: 20px;
}
`;
81 changes: 81 additions & 0 deletions src/components/chatroom/ChatItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import styled from "styled-components";
import { Chat, User } from "../../common/interface";
import { ProfileImage } from "../Item";

interface ChatItemProps {
chat: Chat;
isCurUser: boolean;
noProfile: boolean;
sender: User;
}

const ChatItem = ({ chat, isCurUser, sender, noProfile }: ChatItemProps) => {
const time = String(new Date(chat.date).getHours()).padStart(2, "0");
const minute = String(new Date(chat.date).getMinutes()).padStart(2, "0");

return (
<Wrapper isCurUser={isCurUser} isMargin={!noProfile}>
{isCurUser ? (
<>
<ChatWrapper>
<div className="time">
{time}:{minute}
</div>
<ChatBalloon isCurUser={true}>{chat.text}</ChatBalloon>
</ChatWrapper>
</>
) : (
<>
{noProfile ? (
<ProfileImage src={sender.profileImage} noImage={true} />
) : (
<ProfileImage src={sender.profileImage} />
)}
<ContentWrapper>
{!noProfile && <div className="name">{sender.name}</div>}
<ChatWrapper>
<ChatBalloon isCurUser={false}>{chat.text}</ChatBalloon>
<div className="time">
{time}:{minute}
</div>
</ChatWrapper>
</ContentWrapper>
</>
)}
</Wrapper>
);
};

const Wrapper = styled.div<{ isCurUser: boolean; isMargin: boolean }>`
display: flex;
gap: 10px;
justify-content: ${({ isCurUser }: { isCurUser: boolean }) =>
isCurUser ? "flex-end" : "flex-start"};
width: 100%;
margin-top: ${({ isMargin }: { isMargin: boolean }) =>
isMargin ? "20px" : "0px"};
`;

const ContentWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 5px;
`;
const ChatWrapper = styled.div`
display: flex;
align-items: flex-end;
gap: 5px;
.time {
font-size: 8px;
color: grey;
}
`;
const ChatBalloon = styled.div`
background-color: ${({ isCurUser }: { isCurUser: boolean }) =>
isCurUser ? "yellow" : "white"};
padding: 10px;
border-radius: 5px;
word-break: break-all;
`;

export default ChatItem;
56 changes: 56 additions & 0 deletions src/components/chatroom/ChatList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { useEffect, useRef } from "react";
import styled from "styled-components";
import { Chat, User } from "../../common/interface";
import ChatItem from "./ChatItem";

interface ChatListProps {
curUser: number;
chats: Chat[];
users: User[];
}

Choose a reason for hiding this comment

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

interface선언 파일이 따로 있는데 여기다가 인터페이스를 선언한 이유가 따로 있으신가요???


const ChatList = ({ curUser, chats, users }: ChatListProps) => {
// 채팅이 업데이트될 때마다 아래로 스크롤
const chatListRef = useRef<HTMLDivElement>(null);
useEffect(() => {
chatListRef.current?.scrollTo(0, chatListRef.current.scrollHeight);
console.log("스크롤!");
}, [chats]);

return (
<Wrapper ref={chatListRef}>
{chats.map((chat, idx) => (
<ChatItem
key={chat.id}
noProfile={idx !== 0 && chats[idx - 1].senderId === chat.senderId}
isCurUser={curUser === chat.senderId}
chat={chat}
sender={users[chat.senderId]}
/>
))}
</Wrapper>
);
};

const Wrapper = styled.div`
display: flex;
flex-direction: column;
padding: 15px;
gap: 10px;
height: 65%;
overflow: auto;
background-color: powderblue;

/* 스크롤바 커스텀*/
::-webkit-scrollbar {
width: 3px;
}
::-webkit-scrollbar-thumb {
background-color: white;
border-radius: 10px;
}
::-webkit-scrollbar-track {
}
`;

export default ChatList;
Loading