Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
565328b
[FE] feat: 메시지 영역 및 채팅 입력창 구현 (#69)
chysis Feb 23, 2025
6c4b76f
[FE] feat: 헤더를 포함한 채팅 영역 구현 (#69)
chysis Feb 23, 2025
57b0003
[FE] feat: friendsPage에 채팅 영역 임시 연결 (#69)
chysis Feb 23, 2025
a5fd737
[FE] feat: 메시지 아이템 컴포넌트 구현 (#69)
chysis Feb 24, 2025
47ce323
[FE] feat: 메시지 영역 구현 및 날짜 시각 변환 유틸함수 작성 (#69)
chysis Feb 24, 2025
74b972b
[FE] feat: 메시지 날짜 구분선 컴포넌트 껍데기 추가 (#69)
chysis Feb 24, 2025
f51cce6
[FE] design: 수정중 표시 디자인 추가 (#69)
chysis Feb 24, 2025
f37f8f3
[FE] setting: 웹소켓 및 stompjs 설치 (#69)
chysis Feb 25, 2025
31554cd
[FE] setting: 웹소켓 및 stompjs 설치 (#69)
chysis Feb 25, 2025
7683000
[FE] fix: 비어있는 guildId 값으로 단일 조회 요청되는 문제 수정 (#69)
chysis Feb 25, 2025
0702878
[FE] setting: mkcert 설치 및 vite config 설정 (#69)
chysis Feb 26, 2025
8cfd9f9
[FE] fix: 유저 프로필 컴포넌트에 TODO 추가 (#69)
chysis Feb 26, 2025
adfc85d
[FE] fix: zustand key camel case로 수정 (#69)
chysis Feb 27, 2025
08cf13c
[FE] feat: 현재 화면에서 선택한 채널 및 DM 채널 정보 store 작성 (#69)
chysis Feb 27, 2025
8728685
[FE] fix: input id camel case로 수정 (#69)
chysis Feb 27, 2025
1b10206
[FE] fix: 비어있는 guildId로 요청 보내지는 문제 수정 (#69)
chysis Feb 27, 2025
7cd376a
[FE] refactor: 카테고리 영역과 채팅 영역 분리 (#69)
chysis Feb 27, 2025
03c371f
[FE] feat: DM 페이지의 채팅 영역에 보여질 친구 관리 컴포넌트 구현 (#69)
chysis Feb 27, 2025
f411253
[FE] feat: DM 채팅방과 길드 채팅방 구분해서 작성 (#69)
chysis Feb 27, 2025
37a75b5
[FE] feat: DM 채널 목록 껍데기 컴포넌트 추가 (#69)
chysis Feb 27, 2025
caab2e9
[FE] feat: 채팅 웹소켓 연결 및 관련 함수를 정의하는 훅 구현 (#69)
chysis Feb 27, 2025
bccb84d
[FE] refactor: ChatTextarea 분리 및 훅 수정 (#69)
chysis Feb 27, 2025
567f869
[FE] feat: 채팅방 관련 컴포넌트 작성 (#69)
chysis Feb 27, 2025
d4398bb
[FE] refactor: 길드 채널 정보 인터페이스 export (#69)
chysis Feb 27, 2025
887bcdd
[FE] feat: 로그인 한 유저 정보를 저장하는 store 작성 (#69)
chysis Feb 27, 2025
79a8388
[FE] design: 현재 선택된 채널 표시 (#69)
chysis Feb 27, 2025
7888025
[FE] design: 길드 리스트에서 툴팁이 보이지 않는 현상 수정 (#69)
chysis Feb 27, 2025
842c04b
gitignore cert 추가
chysis Feb 27, 2025
9544e1b
[FE] design: UserProfile 탭의 z-index 수정 (#69)
chysis Feb 27, 2025
8f48e8e
[FE] design: dark 750 색상 추가 및 UserProfile 색상 조정 (#69)
chysis Feb 27, 2025
a1d6fa1
[FE] refactor: 친구 리스트 디자인 수정 및 명수 안내 (#69)
chysis Feb 27, 2025
75ddfb6
[FE] fix: useStompClient에 누락된 의존성 추가 (#69)
chysis Feb 27, 2025
3653579
[FE] refactor: ChattingSection 분기 처리 로직 리팩토링 (#69)
chysis Feb 27, 2025
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,6 @@ src/backend/**/generated/
src/backend/**/http/http-client.private.env.json

# docker-compose env
src/backend/.env
src/backend/.env

cert/*
3 changes: 3 additions & 0 deletions src/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"test": "jest"
},
"dependencies": {
"@stomp/stompjs": "^7.0.0",
"@tanstack/react-query": "^5.66.0",
"@tanstack/react-query-devtools": "^5.66.0",
"axios": "^1.7.9",
Expand All @@ -24,6 +25,8 @@
"react-icons": "^5.4.0",
"react-router-dom": "^7.1.5",
"styled-components": "^6.1.14",
"vite-plugin-mkcert": "^1.17.6",
"websocket": "^1.0.35",
"zustand": "^5.0.3"
},
"devDependencies": {
Expand Down
44 changes: 44 additions & 0 deletions src/frontend/src/components/friend/AddFriendForm/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useState } from 'react';

import * as S from './styles';

export type ResultMessageType = 'success' | 'fail';

interface ResultMessage {
type: ResultMessageType;
content: string;
}

const AddFriendForm = () => {
// TODO: 친구 검색 및 요청 보내기 로직 연동
// TODO: 요청 보내기 결과에 따라 resultMessage를 설정하고 표시
const [inputData, setInputData] = useState('');
const [resultMessage, setResultMessage] = useState<ResultMessage | null>(null);

const handleInputChange = (value: string) => {
setInputData(value);
};

const handleSendRequestButtonClick = () => {
console.log('친구 요청');
};

return (
<S.AddFriendFormContainer>
<S.FormTitle>친구 추가하기</S.FormTitle>
<S.FormSubtitle>AsyncGate 이메일을 사용하여 친구를 추가할 수 있어요</S.FormSubtitle>
<S.FriendSearchInputWrapper>
<S.FriendSearchInput
onChange={(e) => handleInputChange(e.target.value)}
placeholder="AsyncGate 이메일을 사용하여 친구를 추가할 수 있어요."
/>
<S.SendRequestButton $isDisabled={!inputData.trim()} onClick={handleSendRequestButtonClick}>
친구 요청 보내기
</S.SendRequestButton>
</S.FriendSearchInputWrapper>
{resultMessage && <S.ResultMessage $type={resultMessage.type}>{resultMessage.content}</S.ResultMessage>}
</S.AddFriendFormContainer>
);
};

export default AddFriendForm;
64 changes: 64 additions & 0 deletions src/frontend/src/components/friend/AddFriendForm/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import styled from 'styled-components';

import { BodyRegularText, ChipText, TitleText2 } from '@/styles/Typography';

import { ResultMessageType } from '.';

export const AddFriendFormContainer = styled.div`
display: flex;
flex-direction: column;
width: 100%;
padding: 2rem 3rem;
`;

export const FormTitle = styled(TitleText2)`
color: ${({ theme }) => theme.colors.white};
`;

export const FormSubtitle = styled(BodyRegularText)`
color: ${({ theme }) => theme.colors.dark[300]};
`;

export const FriendSearchInputWrapper = styled.div`
display: flex;
align-items: center;

width: 100%;
height: 5rem;
margin-top: 1.6rem;
padding: 0 1.2rem;
border-radius: 0.8rem;

background-color: ${({ theme }) => theme.colors.dark[800]};
`;

export const FriendSearchInput = styled.input`
display: flex;
flex-grow: 1;
align-items: center;

height: 4rem;
border: none;

color: ${({ theme }) => theme.colors.white};

background-color: ${({ theme }) => theme.colors.dark[800]};
outline: none;
`;

export const SendRequestButton = styled.button<{ $isDisabled: boolean }>`
cursor: ${({ $isDisabled }) => ($isDisabled ? 'not-allowed' : 'pointer')};

height: 3.2rem;
padding: 0.2rem 1.6rem;
border-radius: 0.4rem;

font-weight: 600;
color: ${({ theme }) => theme.colors.dark[300]};

background-color: ${({ theme }) => theme.colors.blue};
`;

export const ResultMessage = styled(BodyRegularText)<{ $type: ResultMessageType }>`
color: ${({ theme, $type }) => ($type === 'success' ? theme.colors.green : theme.colors.red)};
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as S from './styles';

const DirectMessageCategory = () => {
return (
<>
<S.FriendTitle>
<S.TitleName>다이렉트 메시지</S.TitleName>
</S.FriendTitle>
{/* TODO: 친구 채팅방 목록 */}
</>
);
};

export default DirectMessageCategory;
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import styled from 'styled-components';

import { TitleText2 } from '@/styles/Typography';

export const FriendTitle = styled.div`
display: flex;
align-items: center;

height: 4.8rem;
padding: 1.2rem 1.6rem;
border-bottom: 0.1rem solid ${({ theme }) => theme.colors.dark[500]};

color: ${({ theme }) => theme.colors.dark[300]};
`;

export const TitleName = styled(TitleText2)`
color: ${({ theme }) => theme.colors.dark[300]};
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { BiHash } from 'react-icons/bi';
import { FaInbox } from 'react-icons/fa';

import MessageSection from '@/pages/FriendsPage/components/ChattingSection/components/MessageSection';
import { useChannelInfoStore } from '@/stores/channelInfo';

import * as S from './styles';

// 디스코드에서는 채널 타입 아이콘 대신 상대방 프로필 사진이 뜸
// 우선은 프로필 사진 자리에 아이콘 배치
const DirectMessageChattingRoom = () => {
const { selectedDMChannel } = useChannelInfoStore();
if (!selectedDMChannel) return null;

return (
<>
<S.ChattingHeader>
<S.ChannelInfo>
<S.ChannelImage>
<BiHash size={28} />
</S.ChannelImage>
<S.ChannelTitle>{selectedDMChannel.name}</S.ChannelTitle>
</S.ChannelInfo>
<S.ToolBar>
<S.IconWrapper>
<FaInbox size={24} />
</S.IconWrapper>
</S.ToolBar>
</S.ChattingHeader>
<MessageSection channelId={selectedDMChannel.id} />
</>
);
};

export default DirectMessageChattingRoom;
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import styled from 'styled-components';

import { BodyMediumText } from '@/styles/Typography';

export const ChattingHeader = styled.div`
display: flex;
align-items: center;
justify-content: space-between;

height: 4.8rem;
padding: 0.8rem;
border-bottom: 0.2rem solid ${({ theme }) => theme.colors.dark[700]};

color: ${({ theme }) => theme.colors.dark[300]};
`;

export const ChannelInfo = styled.div`
display: flex;
align-items: center;
`;

export const ChannelImage = styled.div`
margin: 0 0.8rem;
`;

export const ChannelTitle = styled(BodyMediumText)`
color: ${({ theme }) => theme.colors.dark[300]};
`;

export const ToolBar = styled.div`
display: flex;
`;

export const IconWrapper = styled.div`
cursor: pointer;
margin: 0 0.8rem;
`;
45 changes: 45 additions & 0 deletions src/frontend/src/components/friend/FriendsList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as S from './styles';

// TODO: API 문서에 맞게 수정 및 types 폴더로 이동
export interface Friend {
name: string;
profileImageUrl: string;
isOnline: boolean;
}

// TODO: useQuery로 친구 리스트 요청
const friends: Friend[] = [
{
name: '친구1',
profileImageUrl: '',
isOnline: true,
},
{
name: '친구2',
profileImageUrl: '',
isOnline: true,
},
{
name: '친구3',
profileImageUrl: '',
isOnline: false,
},
];

const FriendsList = () => {
return (
<S.FriendsList>
<S.FriendCount>모든 친구 - {friends.length}명</S.FriendCount>
{friends.map((friend, index) => (
<S.FriendItem key={`${friend.name}_${index}`}>
<S.FriendProfileImage $imageUrl={friend.profileImageUrl}>
<S.FriendStatusMark $isOnline={friend.isOnline} />
</S.FriendProfileImage>
<S.FriendName>{friend.name}</S.FriendName>
</S.FriendItem>
))}
</S.FriendsList>
);
};

export default FriendsList;
72 changes: 72 additions & 0 deletions src/frontend/src/components/friend/FriendsList/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import styled from 'styled-components';

import { BodyMediumText, ChipText } from '@/styles/Typography';

export const FriendsList = styled.ul`
display: flex;
flex-direction: column;

width: 100%;
margin-top: 0.8rem;
padding: 0 2rem 0 3rem;

color: ${({ theme }) => theme.colors.dark[300]};
`;

export const FriendCount = styled(ChipText)`
margin: 1.6rem 0 1rem;
color: ${({ theme }) => theme.colors.dark[300]};
`;

export const FriendItem = styled.li`
cursor: pointer;

display: flex;
align-items: center;

height: 6.2rem;
border-top: 0.1rem solid ${({ theme }) => theme.colors.dark[500]};
border-radius: 0.4rem;

&:hover {
background-color: ${({ theme }) => theme.colors.dark[500]};
}
`;

export const FriendProfileImage = styled.div<{ $imageUrl: string }>`
position: relative;

width: 3.2rem;
height: 3.2rem;
border-radius: 50%;

background-color: ${({ theme }) => theme.colors.white};
background-image: url(${(props) => props.$imageUrl});
`;

export const FriendStatusMark = styled.div<{ $isOnline: boolean }>`
position: absolute;
right: 0;
bottom: 0;

width: 1rem;
height: 1rem;
border: 0.1rem solid ${({ theme }) => theme.colors.dark[400]};
border-radius: 50%;

background-color: ${({ $isOnline }) => ($isOnline ? 'green' : 'black')};
`;

export const FriendName = styled(BodyMediumText)`
overflow: hidden;

padding-left: 0.8rem;

color: ${({ theme }) => theme.colors.white};
text-overflow: ellipsis;
white-space: nowrap;
`;

export const FriendStatus = styled(ChipText)`
color: ${({ theme }) => theme.colors.dark[300]};
`;
Loading