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주차] 안채연 미션 제출합니다 #18

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
384 changes: 370 additions & 14 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.11.60",
"@types/node": "^16.11.62",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.2",
"react-scripts": "5.0.1",
"typescript": "^4.8.3",
"recoil": "^0.7.5",
"styled-components": "^5.3.6",
"typescript": "^4.8.4",
"web-vitals": "^2.1.4"
},
"scripts": {
Expand All @@ -39,5 +42,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/styled-components": "^5.1.26"
}
}
Binary file removed public/favicon.ico
Binary file not shown.
Binary file added public/img/chat.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/img/full_chat.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/img/full_profile.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/img/full_setting.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/img/profile.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/img/search.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/img/setting.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/img/user0.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/img/user1.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/img/user2.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/img/user3.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/img/user4.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/img/user5.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 removed public/logo192.png
Binary file not shown.
Binary file removed public/logo512.png
Binary file not shown.
29 changes: 28 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
import styled from "styled-components";
import { Routes, Route } from "react-router-dom";
import FriendsList from "./pages/FriendsList";
import ChatList from "./pages/ChatList";
import Setting from "./pages/Setting";
import ChatRoom from "./pages/ChatRoom";
import InitialPage from "./pages/InitialPage";

function App() {
return <div>화이팅!!</div>;
return (
<Container>
<Routes>
<Route path="/*" element={<InitialPage />} />
<Route path="/FriendsList" element={<FriendsList />} />
<Route path="/Chat" element={<ChatList />} />
<Route path="/Setting" element={<Setting />} />
<Route path="/ChatRoom" element={<ChatRoom />} />
</Routes>
</Container>
);
}

const Container = styled.div`
box-shadow: 1px 1px 2px 2px lightgrey;
margin: 0 auto;
margin-top: 2rem;
border-radius: 0.5rem;
width: 24rem;
height: 43rem;
`;

export default App;
58 changes: 58 additions & 0 deletions src/components/ChattingRoom/ChatBody.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useRef, useEffect } from "react";
import { useRecoilState, useRecoilValue } from "recoil";
import styled from "styled-components";
import { chat } from "../../interface/interface";
import { chatList, roomId } from "../../store/recoil/recoil";
import ChatBubble from "./ChatBubble";

function ChatBody() {
const room = useRecoilValue(roomId);
const chatting = useRecoilValue(chatList);

const scrollRef = useRef<HTMLDivElement>(null);

const scrollBottom = () => {
if (scrollRef.current) {
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
}
};

useEffect(() => {
scrollBottom();
}, [chatting]);

return (
<ChatBodyContainer ref={scrollRef}>
{chatting[room - 1].chat.map((chat: chat) => (
<ChatBubble
key={chat.chatId}
chatId={chat.chatId}
senderId={chat.senderId}
receiverId={chat.receiverId}
text={chat.text}
time={chat.time}
/>
))}
</ChatBodyContainer>
);
}

const ChatBodyContainer = styled.div`
overflow-y: auto;
background: pink;
height: 30rem;
justify-content: flex-start;
display: flex;
flex-direction: column;
padding: 1rem;

&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-thumb {
border-radius: 2px;
background: #7d7d7d;
}
`;

export default ChatBody;
75 changes: 75 additions & 0 deletions src/components/ChattingRoom/ChatBubble.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { useRecoilState, useRecoilValue } from "recoil";
import styled from "styled-components";
import { chat } from "../../interface/interface";
import { currentId } from "../../store/recoil/recoil";
import UserData from "../../store/UserData.json";
import { UserProfileImage } from "../style";

interface bubbleStyle {
color?: string;
flexDirection?: string;
}

function ChatBubble({ chatId, senderId, receiverId, text, time }: chat) {
const currentUser = useRecoilValue(currentId);

return (
<>
{currentUser === senderId ? (
<BubbleList justifyContent="flex-end">
<TimeStyle>{time}</TimeStyle>
<div>
<UserName>{UserData.users[senderId].userName}</UserName>
<Bubble>{text}</Bubble>
</div>
</BubbleList>
) : (
<BubbleList>
<UserProfileImage
src={`img/user${senderId}.png`}
width={2}
height={2}
/>
<div style={{ marginLeft: "0.3rem" }}>
<UserName flex="row">{UserData.users[senderId].userName}</UserName>
<Bubble color="#fff" flexDirection="row">
{text}
</Bubble>
</div>
<TimeStyle>{time}</TimeStyle>
</BubbleList>
)}
</>
);
}

const BubbleList = styled.div<{ justifyContent?: string }>`
display: flex;
justify-content: ${((props) => props.justifyContent) || "flex-start"};
// justify-content: ${({ justifyContent }) => justifyContent || "flex-start"};
`;

const Bubble = styled.div<bubbleStyle>`
display: flex;
width: auto;
border-radius: 0.3rem;
background-color: ${(props) => props.color || "#dee2e6"};
font-size: 13px;
flex-direction: ${(props) => props.flexDirection || "row-reverse"};
padding: 8px;
`;

const UserName = styled.div<{ flex?: string }>`
font-size: 0.5rem;
margin-bottom: 0.1rem;
display: flex;
flex-direction: ${(props) => props.flex || "row-reverse"};
`;

const TimeStyle = styled.div`
font-size: 0.4rem;
margin-top: 2rem;
padding: 0.3rem;
`;

export default ChatBubble;
57 changes: 57 additions & 0 deletions src/components/ChattingRoom/ChatRoomHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Link } from "react-router-dom";
import { useRecoilState, useRecoilValue } from "recoil";
import styled from "styled-components";
import { currentId, roomId } from "../../store/recoil/recoil";
import UserData from "../../store/UserData.json";
import UserProfile from "../profile/HedaerProfile";

function ChatRoomHeader() {
let userData = UserData.users;
let room = useRecoilValue(roomId);
const [userId, setUserId] = useRecoilState(currentId);

// const newUserData = UserData.users.filter((user) => {
// user.userId === 0 || user.userId === room;
// });

return (
<Header>
{userData.map((user) =>
user.userId === 0 || user.userId === room ? (
<UserProfile
key={user.userId}
userImage={user.profileImage}
userName={user.userName}
userId={user.userId}
/>
) : (
<></>
)
)}
<Link to="/Chat" onClick={() => setUserId(0)}>
Copy link

Choose a reason for hiding this comment

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

앗 채연님 코드 리뷰하다가 닫기 버튼을 안 만든 걸 깨달았네요 ... !! !! 이 방법은 생각해보지 못했는데 저도 적용해봐야겠어요!

<CloseBtn />
</Link>
</Header>
);
}

const Header = styled.div`
position: relative;
margin: 0 auto;
background: #ffffff;
height: 6rem;
border-radius: 0.5rem 0.5rem 0rem 0rem;
display: flex;
flex-direction: row;
`;
const CloseBtn = styled.div`
position: absolute;
right: 1rem;
top: 1rem;
width: 1rem;
height: 1rem;
background: #fa5858;
border-radius: 1rem;
`;

export default ChatRoomHeader;
79 changes: 79 additions & 0 deletions src/components/ChattingRoom/SendMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { useRecoilState, useRecoilValue } from "recoil";
import styled from "styled-components";
import useInput from "../../hooks/useInput";
import { chat, chatRoom } from "../../interface/interface";
import {
chatList,
chattingRoom,
currentId,
roomId,
} from "../../store/recoil/recoil";

function SendMessage() {
const { text, handleChange, resetText } = useInput("");
const room = useRecoilValue(roomId);
const [chatting, setChatting] = useRecoilState(chatList);
const getChatting = useRecoilValue(chattingRoom);
const sender = useRecoilValue(currentId);
const time = new Date();

const newChat: chat = {
chatId: Date.now(),
senderId: sender,
receiverId: sender === 0 ? room : 0,
text: text,
time: ("0" + time.getHours()).slice(-2) + ":" + time.getMinutes(),
Copy link

Choose a reason for hiding this comment

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

디테일 ...😍

};

const newChatting: chatRoom = {
roomId: room,
chat: [...getChatting[0].chat, newChat],
};

function AddText(text: string) {
if (text.trim()) {
setChatting(
Copy link

Choose a reason for hiding this comment

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

이번 과제 채팅 저장하는 부분에서 엄청 힘들었는데 채연님은 깔끔하게 잘 작성하셨네요 🤩 저도 삼항연산자를 사용해서 작성해봐야겠어요!

chatting.map((chat) => (chat.roomId === room ? newChatting : chat))
);
}
}

function onSend(e: any) {
e.preventDefault();
AddText(text);
resetText();
}

return (
<InputContainer onSubmit={onSend}>
<Input onChange={handleChange} value={text} />
<SendButton type="submit">전송</SendButton>
</InputContainer>
);
}

const InputContainer = styled.form`
margin: 0 auto;
background: #ffffff;
height: 5rem;
border-radius: 0rem 0rem 0.5rem 0.5rem;
display: flex;
flex-direction: "row";
`;

const Input = styled.input`
width: 18rem;
margin: 0.5rem;
height: 3.5rem;
border: none;
`;

const SendButton = styled.button`
width: 4rem;
height: 3.7rem;
margin-top: 0.5rem;
background-color: #f9eb54;
border: none;
`;

export default SendMessage;
61 changes: 61 additions & 0 deletions src/components/Navi.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Link, useLocation } from "react-router-dom";
import styled from "styled-components";

const Navigation = () => {
const { pathname } = useLocation();

return (
<Nav>
<IconWrap>
<Link to="/FriendsList">
{pathname === "/FriendsList" ? (
<Icon src="img/full_profile.png" />
) : (
<Icon src="img/profile.png" />
)}
</Link>
<Link to="/Chat">
{pathname === "/Chat" ? (
<Icon src="img/full_chat.png" />
) : (
<Icon src="img/chat.png" />
)}
</Link>
<Link to="/Setting">
{pathname === "/Setting" ? (
<Icon src="img/full_setting.png" />
) : (
<Icon src="img/setting.png" />
)}
</Link>
</IconWrap>
</Nav>
);
};

const Nav = styled.div`
width: 5rem;
height: 42.9rem;
border-radius: 0.5rem 0 0 0.5rem;
background-color: rgb(230, 230, 230);
//border-right: 1px solid rgb(230, 230, 230);
border: 0.05rem solid #fff;
`;

const IconWrap = styled.div`
width: 1.7rem;
margin: auto;
height: auto;
display: flex;
flex-direction: column;
padding: 2rem 0;
`;

const Icon = styled.img`
width: 1.7rem;
height: 1.7rem;
margin: auto;
padding: 1rem 0;
`;

export default Navigation;
Loading