Skip to content

Commit

Permalink
[Feat] message content paging, 디자인 약간 수정 (#183)
Browse files Browse the repository at this point in the history
  • Loading branch information
wken5577 committed Dec 15, 2023
1 parent 87f44fa commit 65bf717
Show file tree
Hide file tree
Showing 12 changed files with 432 additions and 128 deletions.
26 changes: 12 additions & 14 deletions project/frontend/src/components/channel/ChannelMessageBox.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { unwrap } from '@/api/unwrap';
import { ApiContext } from '@/app/_internal/provider/ApiContext';
import { useCallback, useContext } from 'react';
import { useQuery } from 'react-query';
import { MessageContent, messageType } from '../dm/message/MessageContent';
import useChannelMessage from '@/hooks/chat/useChannel';
import { useContext } from 'react';
import {
MessageContent,
MessageContentInterface,
messageType,
} from '../dm/message/MessageContent';
import { MessageSendBox } from '../dm/message/MessageSendBox';
import { ChannelInfo } from './ChannelInfo';

Expand All @@ -11,21 +14,15 @@ export function ChannleMessageBox({
}: Readonly<{ channelId: string }>) {
const { api } = useContext(ApiContext);

const { isLoading, isError, data } = useQuery(
'channelInfo',
useCallback(
async () => unwrap(await api.channelControllerFindChannelInfo(channelId)),
[api, channelId],
),
);
const { channelInfo, isLoading, channelMessage } =
useChannelMessage(channelId);

if (isLoading) return <div>Loading...</div>;
if (isError || !data) return <p>알 수 없는 에러</p>;

const localMe = localStorage.getItem('me');
const me = localMe ? JSON.parse(localMe) : null;

const myAuthority: any = data.members.filter((mem: any) => {
const myAuthority: any = channelInfo?.members.filter((mem: any) => {
return mem.memberId === me?.id;
});
if (isLoading) return <div>Loading...</div>;
Expand All @@ -34,14 +31,15 @@ export function ChannleMessageBox({
<>
<ChannelInfo
channelId={channelId}
channelData={data}
channelData={channelInfo}
myAuthority={myAuthority[0]?.memberType}
myNickname={me?.nickname}
/>
<MessageContent
channelId={channelId}
type={messageType.CHANNEL}
myNickname={me?.nickname}
initData={channelMessage as MessageContentInterface[]}
/>
<MessageSendBox channelId={channelId} type={messageType.CHANNEL} />
</>
Expand Down
27 changes: 11 additions & 16 deletions project/frontend/src/components/dm/message/MessageBox.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { unwrap } from '@/api/unwrap';
import { ApiContext } from '@/app/_internal/provider/ApiContext';
import { useCallback, useContext } from 'react';
import { useQuery } from 'react-query';
import useDirectMessage from '@/hooks/chat/useDirectMessage';
import { useContext } from 'react';
import { MessageContent, messageType } from './MessageContent';
import { MessageSendBox } from './MessageSendBox';
import { UserInfo } from './UserInfo';
Expand All @@ -13,35 +12,31 @@ export function MessageBox({
readonly username: string;
readonly channelId: string;
}) {
const { api } = useContext(ApiContext);
const { isLoading, isError, data } = useQuery(
'userByNickanme',
useCallback(
async () => unwrap(await api.usersControllerGetUsetByNickname(username)),
[api, username],
),
const { isLoading, dmInfo, channelMessage } = useDirectMessage(
channelId,
username,
);

if (isLoading) return <div>로딩중... 👾</div>;
if (isError || !data) return <p>알 수 없는 에러</p>;
if (isLoading || !dmInfo) return <div>로딩중... 👾</div>;

const localMe = localStorage.getItem('me');
const me = localMe ? JSON.parse(localMe) : null;
return (
<>
<UserInfo
imageUri={data.profileImageUrl}
username={data.nickname}
imageUri={dmInfo.profileImageUrl}
username={dmInfo.nickname}
onActive={false}
targetId={data.id}
targetId={dmInfo.id}
/>
<MessageContent
type={messageType.DM}
myNickname={me?.nickname}
targetName={username}
channelId={channelId}
initData={channelMessage}
/>
<MessageSendBox type={messageType.DM} targetUserId={data.id} />
<MessageSendBox type={messageType.DM} targetUserId={dmInfo.id} />
</>
);
}
57 changes: 41 additions & 16 deletions project/frontend/src/components/dm/message/MessageContent.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useInitMessage } from '@/hooks/useInitMessage';
import { useSocket } from '@/hooks/useSocket';
import useInfScroll from '@/hooks/chat/useInfScroll';
import { useSocket } from '@/hooks/chat/useSocket';
import { useEffect, useRef, useState } from 'react';
import { MyChat } from './MyChat';
import { OtherChat } from './OtherChat';
Expand All @@ -26,41 +26,67 @@ export interface MessageContentInterface {

const isSystemMessage = (message: { type: string }) =>
['leave', 'join'].includes(message.type);
const isMySessage = (
const isMyMessage = (
msg1: { data: { member: { nickname: string } } },
msg2: { data: { member: { nickname: string } } },
) => msg1.data.member.nickname === msg2.data.member.nickname;
const calIsFirst = (
mesaageList: { type: string; data: { member: { nickname: string } } }[],
messageList: { type: string; data: { member: { nickname: string } } }[],
idx: number,
) =>
idx === 0 ||
isSystemMessage(mesaageList[idx - 1]) ||
!isMySessage(mesaageList[idx - 1], mesaageList[idx]);
): boolean => {
if (idx === 0) return true;
const targetIndex =
messageList[idx - 1].type === 'scroll-target' ? idx - 2 : idx - 1;

return (
isSystemMessage(messageList[targetIndex]) ||
!isMyMessage(messageList[targetIndex], messageList[idx])
);
};

let render = { isSocketRender: true };
export function MessageContent({
channelId,
type,
myNickname,
initData,
targetName,
}: Readonly<{
channelId: string;
type: messageType;
myNickname: string;
initData: MessageContentInterface[];
targetName?: string;
}>) {
const [messages, setMessages] = useState<MessageContentInterface[]>([]);
const messageEndRef = useRef<HTMLDivElement>(null);
useInitMessage(type, setMessages, channelId, targetName);
useSocket(type, setMessages, channelId, targetName);

const [messages, setMessages] = useState<MessageContentInterface[]>(initData);
const [isLastPage, setIsLastPage] = useState<boolean>(false);
const scrollTargetRef = useRef<HTMLDivElement>(null);
const messageStartRef = useRef<HTMLDivElement>(null);
useSocket(type, setMessages, channelId, targetName, render);
useInfScroll(
messageStartRef,
setMessages,
messages,
type,
channelId,
isLastPage,
setIsLastPage,
render,
targetName,
);
useEffect(() => {
setMessages(initData);
}, [initData]);
useEffect(() => {
messageEndRef.current?.scrollIntoView({ behavior: 'smooth' });
scrollTargetRef.current?.scrollIntoView({ behavior: 'auto' });
}, [messages]);

render.isSocketRender = false;
return (
<div className="w-[95%] h-[610px] pt-[20px] bg-chat-color2 rounded-[10px] flex flex-col overflow-y-scroll mt-sm">
<div ref={messageStartRef} />
{messages.map((message, idx) => {
if (message.type === 'scroll-target')
return <div key={crypto.randomUUID()} ref={scrollTargetRef} />;
if (message.type === 'leave' || message.type === 'join') {
return (
<UserStateAnnounce
Expand Down Expand Up @@ -91,7 +117,6 @@ export function MessageContent({
);
}
})}
<div ref={messageEndRef} />
</div>
);
}
4 changes: 2 additions & 2 deletions project/frontend/src/components/dm/message/MyChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export function MyChat({
return (
<div className=" pr-[3%] mb-[1.5%] flex flex-col">
<p
className="p-[2%] text-left inline-block max-w-[35%] rounded-[20px]
break-words bg-white self-end min-w-[10%]"
className="p-[2%] text-left inline-block max-w-[200px] rounded-[20px]
break-words bg-white self-end min-w-[30px]"
>
{message}
</p>
Expand Down
8 changes: 4 additions & 4 deletions project/frontend/src/components/dm/message/OtherChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ export function OtherChat({
setGameMode={toggleGameMode}
/>
</Portal>
<div className="flex flex-row pl-[3%] mb-[1.5%] items-center">
<div className="flex flex-row pl-[3%] mb-[1.5%]">
{isFirst === true ? (
<button
className="w-[50px] h-[50px] mb-[10px]"
className="w-[50px] h-[50px] mb-[10px] self-start"
onClick={handleModalOpen}
>
<Image
Expand All @@ -80,8 +80,8 @@ export function OtherChat({
''
)}
<p
className={`p-[2%] text-left text-white inline-block max-w-[35%] rounded-[20px]
break-words bg-chat-color1 self-start min-w-[10%]`}
className={`p-[2%] text-left text-white inline-block max-w-[200px] rounded-[20px]
break-words bg-chat-color1 self-start min-w-[30px]`}
>
{message}
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ export function UserStateAnnounce({
<>
{userState === UserState.LEAVE ? (
<p
className="w-[480px] h-[25px] bg-light-background rounded-md
className="w-[460px] h-[25px] bg-light-background rounded-md
text-dark-gray self-center text-center text-[15px] mb-[10px]"
>
{nickname} 님이 나갔습니다.
</p>
) : (
<p
className="w-[480px] h-[25px] bg-light-background rounded-md
className="w-[460px] h-[25px] bg-light-background rounded-md
text-dark-gray self-center text-center text-[15px] mb-[10px]"
>
{nickname} 님이 들어왔습니다.
Expand Down
35 changes: 35 additions & 0 deletions project/frontend/src/hooks/chat/useChannel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { unwrap } from '@/api/unwrap';
import { ApiContext } from '@/app/_internal/provider/ApiContext';
import { useCallback, useContext } from 'react';
import { useQueries } from 'react-query';

export default function useChannelMessage(channelId: string) {
const { api } = useContext(ApiContext);
const channelInfoFn = useCallback(
async () => unwrap(await api.channelControllerFindChannelInfo(channelId)),
[api, channelId],
);
const initialData = useCallback(
async () =>
unwrap(await api.channelControllerGetChannelMessages(channelId)),
[api, channelId],
);
const data = useQueries([
{ queryKey: 'channelInfo', queryFn: channelInfoFn },
{ queryKey: 'channelMessage', queryFn: initialData },
]);
const isLoading = data.some((d: any) => d.isLoading);
if (isLoading) return { isLoading: true };

const channelMessage: any = data[1].data;
if (channelMessage.length > 0) {
channelMessage.push({
type: 'scroll-target',
});
}
return {
isLoading: isLoading,
channelInfo: data[0].data,
channelMessage,
};
}
36 changes: 36 additions & 0 deletions project/frontend/src/hooks/chat/useDirectMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { unwrap } from '@/api/unwrap';
import { ApiContext } from '@/app/_internal/provider/ApiContext';
import { useCallback, useContext } from 'react';
import { useQueries } from 'react-query';

export default function useDirectMessage(
channelId: string,
targetName: string,
) {
const { api } = useContext(ApiContext);
const dmInfoFn = useCallback(
async () => unwrap(await api.usersControllerGetUsetByNickname(targetName)),
[api, targetName],
);
const initialData = useCallback(
async () => unwrap(await api.dmControllerGetDmChannelMessages(targetName)),
[api, targetName],
);
const data = useQueries([
{ queryKey: 'userByNickanme', queryFn: dmInfoFn },
{ queryKey: 'channelMessage', queryFn: initialData },
]);
const isLoading = data.some((d: any) => d.isLoading);
if (isLoading) return { isLoading: true };
const channelMessage: any = data[1].data;
if (channelMessage.length > 0) {
channelMessage.push({
type: 'scroll-target',
});
}
return {
isLoading: isLoading,
dmInfo: data[0].data,
channelMessage,
};
}
Loading

0 comments on commit 65bf717

Please sign in to comment.