Skip to content
26 changes: 23 additions & 3 deletions src/components/Chat/ChatContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,27 @@ const WorkSpaceChat = (): JSX.Element => {

// TODO: 메세지를 받으면 재렌더링 한다.
useEffect(() => {
socket?.on('sendMessage', ({ text, writer, room, project, createdAt }: ChatDataType) => {
setChatBucket([...chatBucket, { text, writer, room, project, createdAt }]);
socket?.on('sendMessage', ({ id, text, writer, room, project, createdAt }: ChatDataType) => {
setChatBucket([...chatBucket, { id, text, writer, room, project, createdAt }]);
});

// TODO: 채팅 수정
socket?.on('editMessage', (foundChat: ChatDataType) => {
console.log('서버에서 받아오는 값', foundChat);
setChatBucket([...chatBucket, foundChat]);
});

// TODO: 채팅 삭제
socket?.on('deleteMessage', ({ id }) => {
const copyChatBucket = [...chatBucket];
const findChat = (copyChatBucket: ChatDataType): true | undefined => {
if (copyChatBucket.id === id) {
return true;
}
};
const findChatIndex = copyChatBucket.findIndex(findChat);
copyChatBucket.splice(findChatIndex, 1);
setChatBucket([...copyChatBucket]);
});
}, [chatBucket]);

Expand All @@ -74,6 +93,7 @@ const WorkSpaceChat = (): JSX.Element => {
message: chat,
};
const newChat: ChatDataType = {
id: null,
text: chat,
room: room,
createdAt: newChatDate.toString(),
Expand Down Expand Up @@ -110,7 +130,7 @@ const WorkSpaceChat = (): JSX.Element => {

return (
<WorkSpaceFrame>
<ChatZone scrollbarRef={scrollbarRef} chatSections={chatSections} />
<ChatZone scrollbarRef={scrollbarRef} chatSections={chatSections} chatBucket={chatBucket} />
<Textarea
onSubmitForm={onSubmitForm}
onChangeChat={onChangeChatValue}
Expand Down
169 changes: 165 additions & 4 deletions src/components/Chat/ChatItem/index.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,133 @@
import React, { memo } from 'react';
import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
import ProfileImage from '../../Common/ProfileImage';
import ChatProfileModal from '../ChatProfileModal';
import Modal from '../../Common/Modal';
import useSocket from '../../../hooks/useSocket';

import dayjs from 'dayjs';
import autosize from 'autosize';
import { useParams } from 'react-router';

import {
AlertButtonWrapper,
AlertChatContent,
AlertChatDeleteButton,
AlertChatItem,
AlertChatItemUserInfoWrapper,
ChatContent,
ChatCreatedAt,
ChatDeleteAlert,
ChatDeleteButton,
ChatEditbutton,
ChatEditButtonWrapper,
ChatEditTextArea,
ChatNowDateHover,
ChatProfileImageWrapper,
ChatUpdateModal,
ChatUserId,
ChatUserInfoWrapper,
ChatWrapper,
} from './styles';

import { ChatDataType } from '../../../types/types';
import Button from '../../Common/Button';
import useInput from '../../../hooks/useInput';

interface Props {
data: ChatDataType;
isSameSender: boolean;
chatBucket: ChatDataType[];
}

const ChatItem = ({ data, isSameSender }: Props): JSX.Element => {
const ChatItem = ({ data, isSameSender, chatBucket }: Props): JSX.Element => {
const { projectUrl, part: room } = useParams<{ projectUrl: string; part: string }>();
const [socket] = useSocket(projectUrl);
const textareaRef = useRef<HTMLTextAreaElement>(null);

const [showChatProfileModal, setShowChatProfileModal] = useState<boolean>(false);
const [showChatDeleteAlert, setShowChatDeleteAlert] = useState<boolean>(false);
const [showChatEditForm, setShowChatEditForm] = useState<boolean>(false);
const [editChat, onChangeChat, setEditChat] = useInput<string>(data.text);

const { uploadImage, profileColor, name } = data.writer;
let date = dayjs(data.createdAt);
date = date.add(9, 'hour');

useEffect(() => {
if (textareaRef.current) {
autosize(textareaRef.current);
}
}, [textareaRef.current]);

// TODO: 채팅 프로필 모달
const onShowChatProfileModal = useCallback(e => {
e.preventDefault();
if (editChat.trim() === '') {
return;
}
e.stopPropagation();
setShowChatProfileModal(true);
}, []);

// TODO: 채팅 수정 엔터
const onChatEditEnter = useCallback((): void => {
if (editChat.trim() === '') {
return;
}

const getChatEditData = {
room: room,
id: data.id,
message: editChat,
};

socket?.emit('editMessage', getChatEditData);
setShowChatEditForm(false);
}, [editChat]);

// TODO: 채팅 수정 버튼
const onChatEditButton = useCallback(
(e: React.MouseEvent<HTMLButtonElement, MouseEvent>): void => {
e.preventDefault();
e.stopPropagation();

const getChatEditData = {
room: room,
id: data.id,
message: editChat,
};

socket?.emit('editMessage', getChatEditData);
setShowChatEditForm(false);
},
[editChat],
);
// TODO: 채팅 수정 실행 취소
const onChatEditCancel = useCallback((e: React.MouseEvent<HTMLButtonElement, MouseEvent>): void => {
e.preventDefault();
setEditChat(data.text);
setShowChatEditForm(false);
}, []);

// TODO: 채팅 삭제 버튼
const onChatDeleteButton = useCallback(
(e: React.MouseEvent<HTMLButtonElement, MouseEvent>): void => {
e.preventDefault();
e.stopPropagation();
setShowChatDeleteAlert(false);

const getChatDeleteData = {
room: room,
id: data.id,
};
socket?.emit('deleteMessage', getChatDeleteData);
},
[data],
);

return (
<ChatWrapper isSameSender={isSameSender}>
<ChatProfileImageWrapper isSameSender={isSameSender}>
<ChatProfileImageWrapper isSameSender={isSameSender} onClick={e => onShowChatProfileModal(e)}>
<ProfileImage
width="40px"
height="40px"
Expand All @@ -35,13 +136,73 @@ const ChatItem = ({ data, isSameSender }: Props): JSX.Element => {
userName={name}
/>
</ChatProfileImageWrapper>
{showChatProfileModal && (
<Modal backgroundColor={false} setShowModal={setShowChatProfileModal}>
<ChatProfileModal data={data} />
</Modal>
)}
<div>
<ChatUserInfoWrapper isSameSender={isSameSender}>
<ChatUserId>{name}</ChatUserId>
<ChatCreatedAt>{dayjs(date).format('A h:mm')}</ChatCreatedAt>
</ChatUserInfoWrapper>
<ChatContent isSameSender={isSameSender}>{data.text}</ChatContent>
<ChatContent isSameSender={isSameSender}>
{showChatEditForm ? (
<div>
<ChatEditTextArea
value={editChat}
onChange={onChangeChat}
ref={textareaRef}
onKeyPress={e => e.key === 'Enter' && onChatEditEnter()}
onBlur={onChatEditEnter}
/>
<ChatEditButtonWrapper>
<button onClick={onChatEditCancel}>취소</button>
<button onClick={onChatEditButton}>저장</button>
</ChatEditButtonWrapper>
</div>
) : (
<>{data.text}</>
)}
</ChatContent>
</div>
<ChatUpdateModal>
<ChatEditbutton onClick={() => setShowChatEditForm(true)} />
<ChatDeleteButton onClick={() => setShowChatDeleteAlert(true)} />
</ChatUpdateModal>
<ChatNowDateHover isSameSender={isSameSender}>{dayjs(date).format('A h:mm')}</ChatNowDateHover>
{showChatDeleteAlert && (
<Modal setShowModal={setShowChatDeleteAlert}>
<ChatDeleteAlert>
<div>메세지 삭제</div>
<p>이 메시지를 삭제하시겠습니까? 이 작업은 실행 취소할 수 없습니다.</p>
<AlertChatItem>
<div>
<ProfileImage
width="40px"
height="40px"
profileImage={uploadImage}
profileColor={profileColor}
userName={name}
/>
</div>
<AlertChatItemUserInfoWrapper>
<div>
<ChatUserId>{name}</ChatUserId>
<ChatCreatedAt>{dayjs(date).format('A h:mm')}</ChatCreatedAt>
</div>
<AlertChatContent>{data.text}</AlertChatContent>
</AlertChatItemUserInfoWrapper>
</AlertChatItem>
<AlertButtonWrapper>
<Button size="small" buttonType="cancel" clickEvent={() => setShowChatDeleteAlert(false)}>
취소
</Button>
<AlertChatDeleteButton onClick={onChatDeleteButton}>삭제</AlertChatDeleteButton>
</AlertButtonWrapper>
</ChatDeleteAlert>
</Modal>
)}
</ChatWrapper>
);
};
Expand Down
Loading