Skip to content
Merged
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
2 changes: 1 addition & 1 deletion frontend/src/apis/channel/dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ interface Reaction {
users: string[];
}

interface Message {
export interface Message {
messageId: string;
user: User;
content: string;
Expand Down
18 changes: 11 additions & 7 deletions frontend/src/apis/dm/dto.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
interface DMParticipant {
userId: string;
username: string;
profileImage: string;
}
import { User } from '@/types/user';
import { Message } from '../channel/dto';

interface DMLastMessage {
senderId: string;
content: string;
createdAt: string;
}

export interface DMItem {
interface DMItem {
dmId: string;
participants: DMParticipant[];
participants: User[];
lastMessage: DMLastMessage;
unreadCount: number;
}
Expand All @@ -21,3 +18,10 @@ export interface DMListResponseDto {
userId: string;
dms: DMItem[];
}

export interface DMResponseDto {
dmId: string;
participants: User[];
isGroup: boolean;
messages: Record<string, Message[]>;
}
7 changes: 6 additions & 1 deletion frontend/src/apis/dm/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { DMListResponseDto } from '@/apis/dm/dto';
import { DMListResponseDto, DMResponseDto } from '@/apis/dm/dto';
import https from '@/lib/https';

export const getDMList = async (): Promise<DMListResponseDto> => {
const { data } = await https.get('/api/dms');
return data;
};

export const getDMMessage = async (dmId: string): Promise<DMResponseDto> => {
const { data } = await https.get(`api/dms/${dmId}`);
return data;
};
40 changes: 40 additions & 0 deletions frontend/src/components/dm/DMContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useParams } from 'react-router';
import Message from '../common/Message';
import DMInfo from './DMInfo';
import { useGetDMMessages } from '@/hooks/dm/useGetDMMessages';
import DateBadge from '../common/DateBadge';

const DMContent = () => {
const { dmId } = useParams();
const { data, isLoading, isError } = useGetDMMessages(dmId!);

if (isLoading) return <p>로딩중입니다.</p>;
if (isError) return <p>에러</p>;

return (
<div>
{data && data?.participants.length > 0 && (
<DMInfo {...data.participants[0]} />
)}
{data?.messages ? (
Object.entries(data.messages).map(([date, messages]) => (
<div key={date}>
<DateBadge date={date} />
{messages.map(msg => (
<Message
key={msg.messageId}
user={msg.user}
content={msg.content}
createdAt={msg.createdAt}
/>
))}
</div>
))
) : (
<p>메시지 없음</p>
)}
</div>
);
};

export default DMContent;
50 changes: 26 additions & 24 deletions frontend/src/components/dm/sideBar/DMList.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { User } from '@/types/user';
import { DMItem } from '@/types/dm';
import clsx from 'clsx';
import { useNavigate, useParams } from 'react-router';

interface DMListProps {
participants: User;
senderId: string;
content: string;
createdAt: string;
unreadCount: number;
}
//@TODO 단체 채팅일 경우 고려해야함

const DMList = ({
participants,
senderId,
content,
createdAt,
unreadCount,
}: DMListProps) => {
const date = new Date(createdAt);
const DMList = ({ dmId, participants, lastMessage, unreadCount }: DMItem) => {
const date = new Date(lastMessage.createdAt);
const { workspaceId, dmId: currentDMId } = useParams();
const navigate = useNavigate();

const month = date.getMonth() + 1;
const day = date.getDate();

return (
<div className="flex gap-2 w-full hover:bg-amber-300 py-4 px-4 border-b-white border-b">
<Avatar className="rounded-lg w-12 h-12">
<div
className={clsx(
'flex w-full gap-2 px-4 py-4 border-b hover:bg-amber-300 border-b-white',
String(currentDMId) === String(dmId) && 'bg-amber-300'
)}
onClick={() => {
navigate(`/workspace/${workspaceId}/dm/${dmId}`);
}}
>
<Avatar className="w-12 h-12 rounded-lg">
<AvatarImage
src={participants.profileImage}
src={participants[0].profileImage}
alt="유저의 프로필이미지"
/>
<AvatarFallback>{participants.username}</AvatarFallback>
<AvatarFallback>{participants[0].username}</AvatarFallback>
</Avatar>
<div className="flex flex-col w-full">
<div className="flex justify-between items-center">
<div className="flex items-center justify-between">
<span className="text-base font-bold text-white">
{participants.displayName}
{participants[0].displayName}
</span>
<div className="flex gap-2 items-center">
<div className="flex items-center gap-2">
<p className="text-sm text-white">{`${month}월 ${day}일`}</p>
{unreadCount > 0 && (
<div className="rounded-full bg-amber-300 px-2 py-[1px] text-sm text-white">
Expand All @@ -45,7 +45,9 @@ const DMList = ({
</div>
</div>
<p className="text-sm text-white">
{participants.userId === senderId ? `나 : ${content}` : content}
{participants[0].userId === lastMessage.senderId
? `나 : ${lastMessage.content}`
: lastMessage.content}
</p>
</div>
</div>
Expand Down
44 changes: 10 additions & 34 deletions frontend/src/components/dm/sideBar/SideBar.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,20 @@
import { useParams } from 'react-router';
import DMList from './DMList';
import SideBarHeader from './SideBarHeader';

//여기는 나중에 API 연결하면 바뀔 부분!
const DM_DATA = [
{
participants: {
userId: '1',
username: '안연아',
displayName: '안연아(웹FE)',
profileImage: 'https://github.com/shadcn.png',
isActive: true,
},
senderId: '1',
content: '안녕하세요! 채팅 테스트입니다.',
createdAt: '2025-01-25T12:34:56Z',
unreadCount: 0,
},
{
participants: {
userId: '1',
username: '안연아',
displayName: '안연아(웹FE)',
profileImage: 'https://github.com/shadcn.png',
isActive: true,
},
senderId: '3',
content: '안녕하세요! 채팅 테스트입니다.',
createdAt: '2025-01-25T12:34:56Z',
unreadCount: 2,
},
];
import useGetDMListQuery from '@/hooks/dm/useGetDMListQuery';

const SideBar = () => {
const { workspaceId } = useParams();
const { data, isLoading, isError } = useGetDMListQuery(workspaceId!);

if (isLoading) return <p>로딩중입니다.</p>;
if (isError) return <p>로딩중입니다.</p>;

return (
<div className="flex flex-col h-screen bg-amber-200 gap-2">
<div className="flex flex-col h-screen gap-2 bg-amber-200">
<SideBarHeader />
<div className="flex flex-col">
{DM_DATA.map((dm, index) => (
<DMList key={index} {...dm} />
))}
{data?.dms.map((dm, index) => <DMList key={index} {...dm} />)}
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const MainNavigationSidebar = () => {
const { channelList } = useWorkspaceChannelListQuery(workspaceId!);

return (
<div className=" min-w-16 bg-yellow-200 text-white flex py-3 flex-col items-center border-r-2">
<div className="flex flex-col items-center py-3 text-white bg-yellow-200 border-r-2 min-w-16">
{icons.map((item, index) => {
return (
<WorkspaceIconButton
Expand All @@ -27,7 +27,7 @@ const MainNavigationSidebar = () => {
}
}
if (item.type === 'DM') {
navigate(`/workspace/${workspaceId}/dm`);
navigate(`/workspace/${workspaceId}/dm/1`);
}
if (item.type === 'ETC') console.log('더보기 클릭');
}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DMItem } from '@/apis/dm/dto';
import { Button } from '@/components/ui/button';
import WorkspaceAccordionSection from '@/components/workspace/WorkspaceAccordionList';
import WorkspaceDirectMessageListItem from '@/components/workspace/WorkspaceChannelPanel/WorkspaceDirectMessageListItem';
import { DMItem } from '@/types/dm';
import { MdOutlineAddBox } from 'react-icons/md';

interface WorkspaceDMsProps {
Expand All @@ -16,7 +16,7 @@ const WorkspaceDMs = ({ dmList, onAddColleauge }: WorkspaceDMsProps) => {
<WorkspaceDirectMessageListItem dm={dm} key={index} />
))}
<Button
className=" w-full bg-transparent shadow-none hover:bg-gray-50 flex justify-start text-xs py-0"
className="flex justify-start w-full py-0 text-xs bg-transparent shadow-none hover:bg-gray-50"
onClick={onAddColleauge}
>
{<MdOutlineAddBox className="text-2xl" />}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,55 +1,37 @@
import { Button } from '@/components/ui/button';

interface DMParticipant {
userId: string;
username: string;
profileImage: string;
}

interface LastMessage {
senderId: string;
content: string;
createdAt: string;
}

interface DirectMessage {
dmId: string;
participants: DMParticipant[];
lastMessage: LastMessage;
unreadCount: number;
}
import { DMItem } from '@/types/dm';

interface WorkspaceDirectMessageListItemProps {
dm: DirectMessage;
dm: DMItem;
}

const WorkspaceDirectMessageListItem = ({
dm,
}: WorkspaceDirectMessageListItemProps) => {
return (
<Button className="w-full shadow-none flex items-center justify-start text-xs rounded-lg bg-transparent hover:bg-transparent">
<div className="relative w-6 h-6 flex-shrink-0 ">
<Button className="flex items-center justify-start w-full text-xs bg-transparent rounded-lg shadow-none hover:bg-transparent">
<div className="relative flex-shrink-0 w-6 h-6 ">
<img
src={dm.participants[0]?.profileImage}
className="w-5 h-5 rounded-full"
/>
{dm.participants.length > 1 ? (
<span className="absolute -bottom-1 -right-1 w-6 h-6 flex items-center justify-center text-xs text-white rounded-full">
<span className="absolute flex items-center justify-center w-6 h-6 text-xs text-white rounded-full -bottom-1 -right-1">
{dm.participants.length}
</span>
) : (
<div className="absolute -bottom-1 -right-0 w-3 h-3 flex items-center justify-center text-xs bg-green-400 text-white rounded-full"></div>
<div className="absolute flex items-center justify-center w-3 h-3 text-xs text-white bg-green-400 rounded-full -bottom-1 -right-0"></div>
)}
</div>

<div className="flex-1 min-w-0">
<span className="text-start block overflow-hidden whitespace-nowrap text-ellipsis truncate">
<span className="block overflow-hidden truncate text-start whitespace-nowrap text-ellipsis">
{dm.participants.map(participant => participant.username).join(', ')}
</span>
</div>

{dm.unreadCount > 0 && (
<div className="w-6 h-6 bg-purple-300 text-white flex items-center justify-center rounded-full">
<div className="flex items-center justify-center w-6 h-6 text-white bg-purple-300 rounded-full">
{dm.unreadCount}
</div>
)}
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/hooks/dm/useGetDMMessages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useQuery } from '@tanstack/react-query';
import { getDMMessage } from '@/apis/dm';

export const useGetDMMessages = (dmId: string) => {
return useQuery({
queryKey: ['dmMessage', dmId],
queryFn: () => getDMMessage(dmId),
enabled: !!dmId,
});
};
Loading