Skip to content

Commit

Permalink
Merge pull request #214 from woowacourse-teams/feat/#210
Browse files Browse the repository at this point in the history
채팅 페이지 api 통합
  • Loading branch information
ss0526100 authored Aug 5, 2024
2 parents a4d4ff3 + e7e8e83 commit fcdf24e
Show file tree
Hide file tree
Showing 20 changed files with 325 additions and 252 deletions.
28 changes: 26 additions & 2 deletions frontend/src/apis/gets.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { MoimInfo, Participation } from '@_types/index';
import ApiClient from './apiClient';
import { Chat, MoimInfo, Participation } from '@_types/index';

import {
GetChamyoAll,
GetChamyoMine,
GetChat,
GetMoim,
GetMoims,
GetZzimMine,
} from './responseTypes';

import ApiClient from './apiClient';
import { checkStatus } from './apiconfig';
import { Filter } from '@_components/MyMoimListFilters/MyMoimListFilters';

Expand Down Expand Up @@ -44,6 +47,27 @@ export const getMoim = async (moimId: number): Promise<MoimInfo> => {
return json.data;
};

export const getChat = async (
moimId: number,
recentChatId?: number,
): Promise<Chat[]> => {
const response = await ApiClient.getWithAuth(
`chat?moimId=${moimId}&recentChatId=${recentChatId || 0}`,
);
checkStatus(response);

const json: GetChat = await response.json();
return json.data.chats;
};

export const getMyMoims = async (): Promise<MoimInfo[]> => {
const response = await ApiClient.getWithAuth(`moim/mine`);
checkStatus(response);

const json: GetMoims = await response.json();
return json.data.moims;
};

export const getChamyoMine = async (
moimId: number,
): Promise<'MOIMER' | 'MOIMEE' | 'NON_MOIMEE'> => {
Expand Down
10 changes: 9 additions & 1 deletion frontend/src/apis/posts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MoimInputInfo } from '@_types/index';
import ApiClient from './apiClient';
import { MoimInputInfo } from '@_types/index';
import { PostMoim } from './responseTypes';
import { checkStatus } from './apiconfig';

Expand Down Expand Up @@ -31,3 +31,11 @@ export const postWriteComment = async (moimId: number) => {
});
await checkStatus(response);
};

export const postChat = async (moimId: number, content: string) => {
const response = await ApiClient.postWithAuth('chat', {
moimId,
content,
});
await checkStatus(response);
};
14 changes: 9 additions & 5 deletions frontend/src/apis/responseTypes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MoimInfo, Participation } from '../types';
import { Chat, MoimInfo, Participation } from '../types';

export interface GetMoims {
data: { moims: MoimInfo[] };
Expand All @@ -8,6 +8,14 @@ export interface GetMoim {
data: MoimInfo;
}

export interface PostMoim {
data: number;
}

export interface GetChat {
data: { chats: Chat[] };
}

export interface GetChamyoMine {
data: {
role: 'MOIMER' | 'MOIMEE' | 'NON_MOIMEE';
Expand All @@ -25,7 +33,3 @@ export interface GetZzimMine {
isZzimed: boolean;
};
}

export interface PostMoim {
data: number;
}
13 changes: 8 additions & 5 deletions frontend/src/components/Chat/Chat.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ type Story = StoryObj<typeof Chat>;

export const Default: Story = {
args: {
sender: '테바',
time: '12:12',
imageUrl: '',
message: '여러분~ 싸우지 마세요',
isMyMessage: false,
chat: {
chatId: 11,
content: '여러분~ 싸우지 마세요',
nickname: '테바',
date: '2024-08-01',
time: '12:12',
isMyMessage: false,
},
},
};
17 changes: 8 additions & 9 deletions frontend/src/components/Chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,26 @@ import {
timeStyle,
} from './Chatstyle';

import { Chat } from '@_types/index';
import UserPreview from '@_components/UserPreview/UserPreview';
import { formatHhmmToKoreanWithPrefix } from '@_utils/formatters';
import { useTheme } from '@emotion/react';

export interface ChatMessageProps {
sender: string;
message: string;
isMyMessage: boolean;
time: string;
imageUrl?: string;
chat: Chat;
}

export default function Chat(props: ChatMessageProps) {
const { sender, message, isMyMessage, time, imageUrl } = props;
const { chat } = props;
const { content, nickname, time, isMyMessage } = chat;
const theme = useTheme();
return (
<div css={chatMessageStyle({ isMyMessage })}>
<UserPreview imageUrl={imageUrl} />
{/* TODO: 추후 프로필 사진 추가시 변경해야함 */}
<UserPreview imageUrl={''} />
<div css={messageContainer({ isMyMessage })}>
<span css={senderStyle({ theme })}>{sender}</span>
<div css={messageStyle({ theme, isMyMessage })}>{message}</div>
<span css={senderStyle({ theme })}>{nickname}</span>
<div css={messageStyle({ theme, isMyMessage })}>{content}</div>
<span css={timeStyle({ theme })}>
{formatHhmmToKoreanWithPrefix(time)}
</span>
Expand Down
110 changes: 59 additions & 51 deletions frontend/src/components/ChatList/ChatList.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,83 +13,91 @@ export const Default: Story = {
args: {
chats: [
{
sender: '상돌',
time: '14:00',
message: '안나야 공은 찰 줄 아냐',
chatId: 1,
content: '안녕하세요! 오늘 날씨 어때요?',
nickname: '홍길동',
date: '2024-08-01',
time: '10:00',
isMyMessage: false,
},
{
sender: '안나',
time: '14:04',
message: '시비걸꺼면 나가라',
chatId: 2,
content: '안녕하세요! 저는 괜찮아요.',
nickname: '김철수',
date: '2024-08-01',
time: '10:01',
isMyMessage: true,
},
{
sender: '안나',
time: '14:04',
message: '지하돌아',
isMyMessage: true,
},
{
sender: '테바',
time: '14:06',
message: '여러분~ 싸우지 마세요',
chatId: 3,
content: '요즘 어떤 일 하고 계세요?',
nickname: '홍길동',
date: '2024-08-01',
time: '10:02',
isMyMessage: false,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: false,
chatId: 4,
content: '프로젝트 작업 중이에요.',
nickname: '김철수',
date: '2024-08-01',
time: '10:03',
isMyMessage: true,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
chatId: 5,
content: '주말에 만나서 이야기해요.',
nickname: '홍길동',
date: '2024-08-01',
time: '10:04',
isMyMessage: false,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: false,
chatId: 6,
content: '좋아요! 그때 봅시다.',
nickname: '김철수',
date: '2024-08-01',
time: '10:05',
isMyMessage: true,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
chatId: 7,
content: '다음 주에 발표 준비 잘 하고 있나요?',
nickname: '홍길동',
date: '2024-08-01',
time: '10:06',
isMyMessage: false,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: false,
chatId: 8,
content: '네, 열심히 하고 있어요.',
nickname: '김철수',
date: '2024-08-01',
time: '10:07',
isMyMessage: true,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
chatId: 9,
content: '도움 필요하면 언제든지 말해요.',
nickname: '홍길동',
date: '2024-08-01',
time: '10:08',
isMyMessage: false,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
isMyMessage: false,
chatId: 10,
content: '감사합니다! 도움 요청할게요.',
nickname: '김철수',
date: '2024-08-01',
time: '10:09',
isMyMessage: true,
},
{
sender: '테바',
time: '14:07',
message:
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!',
chatId: 11,
content: '여러분~ 싸우지 마세요',
nickname: '테바',
date: '2024-08-01',
time: '12:12',
isMyMessage: false,
},
],
Expand Down
33 changes: 9 additions & 24 deletions frontend/src/components/ChatList/ChatList.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,30 @@
import Chat, { ChatMessageProps } from '@_components/Chat/Chat';
import { useEffect, useRef, useState } from 'react';
import { useEffect, useRef } from 'react';

import Chat from '@_components/Chat/Chat';
import { Chat as ChatType } from '@_types/index';
import { list } from './ChatList.style';
import { useTheme } from '@emotion/react';

interface ChatListProps {
chats: ChatMessageProps[];
chats: ChatType[];
}

export default function ChatList(props: ChatListProps) {
const { chats } = props;
const [lastChats, setLastChats] = useState<ChatMessageProps[]>([]);
const messageEndRef = useRef<HTMLDivElement | null>(null);
const observer = useRef<IntersectionObserver | null>();
const theme = useTheme();

useEffect(() => {
observer.current = new IntersectionObserver(() => {
if (lastChats.length === chats.length) return;
if (messageEndRef) messageEndRef.current?.focus();
});
if (messageEndRef.current) observer.current.observe(messageEndRef.current);
}, [messageEndRef, lastChats, chats]);
const theme = useTheme();

useEffect(() => {
if (lastChats.length === chats.length) return;
const latestMyMessageIndex = chats.findLastIndex(
(chat) => chat.isMyMessage,
);
if (latestMyMessageIndex >= lastChats.length)
messageEndRef?.current?.focus();

setLastChats(chats);
}, [lastChats, chats]);
messageEndRef.current?.scrollIntoView();
}, [chats]);

return (
<div css={list({ theme })}>
{chats.map((chat) => (
<Chat key={chat.message + chat.time} {...chat} />
<Chat key={chat.chatId} chat={chat} />
))}
<div ref={messageEndRef}></div>
<div ref={messageEndRef} tabIndex={1}></div>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,5 @@ export default meta;
type Story = StoryObj<typeof ChattingPreview>;

export const Default: Story = {
args: {
title: '축구 하실 사람?',
lastChat: '아니 시간 안 정하냐 방장아;',
participants: [
{ imageUrl: '' },
{ imageUrl: '' },
{ imageUrl: '' },
{ imageUrl: '' },
],
},
args: {},
};
Loading

0 comments on commit fcdf24e

Please sign in to comment.