μ΄μ chatboxλ₯Ό λ§λ€μμΌλ μ€μ λ‘ λ©μμ§κ° μΆλ ₯λλ μ°½μ λ§λ€μ΄λ³΄μ.
π μ¬μ©λλ κΈ°λ₯λ€
chatList
: λ©μμ§λ€μ΄ νλ©΄μ μΆλ ₯λλ κΈ°λ₯μ λ΄μ μ»΄ν¬λνΈcustom scrollbar
: μ±ν
μ°½ λ΄λΆμμ λμνλ μ€ν¬λ‘€λ°dayjs
: λ©μμ§ μμ± λ μ§λ₯Ό μνλ ννλ‘ μΆλ ₯ν΄μ£Όλ κΈ°λ₯image drag & drop
: μ΄λ―Έμ§λ₯Ό λλκ·Ένμ¬ μ±ν
μ°½μ λλνμ¬ κ°νΈνκ² μ
λ‘λν΄μ£Όλ κΈ°λ₯λ μ§λ³ κ·Έλ£Ή
: λ μ§λ³λ‘ λ©μμ§ κ·Έλ£ΉνμμΌ νμβοΈ client
|
βββ π pages
| βββ π Channel
| βββ π DirectMessage
|
βββ π components
βββ π ChatList
βββ π Chat
β Channel / Direct Message μ»΄ν¬λνΈ
<ChatList ... chatData={chatData} // μ
λ ₯ν λ©μμ§ λ°μ΄ν° ... />
β ChatList μ»΄ν¬λνΈ
const ChatList: FC<Props> = ({chatData}) => {
const textareaRef = useRef<HTMLTextAreaElement>(null);
...
return (
<ChatZone>
{chatData.map(chat => (
// μ μ μμ΄μ½, μ΄λ¦, λ©μμ§λ₯Ό μΆλ ₯ν΄μ£Όλ μ»΄ν¬λνΈ
<Chat key={chat.id} data={chat} />
))}
</ChatZone>
);
};
λΈλΌμ°μ μ체μμ μμ±λλ μ€ν¬λ‘€λ°κ° μλ μ±ν μ°½μμ μμ±λλ μ€ν¬λ‘€λ°λ‘, λμνμ§ μμ λλ 보μ΄μ§ μκ² νλ λ±μ 컀μ€ν μ΄ κ°λ₯ν μ€ν¬λ‘€λ°μ΄λ€.(μ°Έκ³ )
β Channel / Direct Message μ»΄ν¬λνΈ
<ChatList
scrollbarRef={scrollbarRef}
isReachingEnd={isReachingEnd}
/>
β ChatList μ»΄ν¬λνΈ
import { positionValues, Scrollbars } from 'react-custom-scrollbars-2';
const ChatList: FC<Props> = ({scrollbarRef, isReachingEnd}) => {
return <Scrollbars autoHide ref={scrollbarRef} onScrollFrame={onScroll}
...
</Scrollbars>
}
β Chat μ»΄ν¬λνΈ
π 2022.02-07T14:57:47.000Z
π 2:57 PM
const Chat: FC<Props> = memo(({ data }) => {
...
return <span>{dayjs(data.createdAt).format('h:mm A')}</span>
HTML5μμ μ 곡νλ onDragOver, onDropμ ν΅ν΄μ μμλ₯Ό λλκ·Ένμ¬ λ¨κ΅΄ μ μλ€.
β onDragOver : μμκ° λλ‘μ‘΄ μμ μμ λ λ°μ μ¦, dropμ΄ μΌλ£λ λκΉμ§ κ³μν΄μ μ΄λ²€νΈκ° λ°μλλ€.
β onDrop :μμκ° λλ‘μ‘΄μ λμΌ λ λ°μ μ¦, dropμ΄ μ€νλμμ λ μ€νλλ μ΄λ²€νΈμ΄λ€.
π‘ ν΄λΉ λ¬Έμμ μ μνλ©΄ λλ‘μ΄λ²€νΈλ‘ μ€νλλ μ΄λ―Έμ§ μ λ‘λ κ³Όμ μ κ°λ μ½λλ₯Ό κ°μ Έμ¬ μ μλ€.
π ondrop Event - W3Schools
const onDragOver = useCallback((e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
console.log(e);
setDragOver(true);
}, []);
const onDrop = useCallback(
(e: any) => {
e.preventDefault();
console.log(e);
const formData = new FormData();
// dataTransfer : λλκ·Έ μ€ λλ‘ μμ
μ€μ λλκ·Έλλ λ°μ΄ν°λ₯Ό 보μ νλ λ° μ¬μ©
if (e.dataTransfer.items) {
// DataTransferItemList μΈν°νμ΄μ€λ₯Ό μ¬μ©νμ¬ νμΌμ μ‘μΈμ€
for (let i = 0; i < e.dataTransfer.items.length; i++) {
// λ¨μ΄λ¨λ¦° νλͺ©μ΄ νμΌμ΄ μλ κ²½μ° κ±°λΆ
if (e.dataTransfer.items[i].kind === 'file') {
const file = e.dataTransfer.items[i].getAsFile();
console.log('... file[' + i + '].name = ' + file.name);
formData.append('image', file);
}
}
} else {
// DataTransfer μΈν°νμ΄μ€λ₯Ό μ¬μ©νμ¬ νμΌμ μ‘μΈμ€
for (let i = 0; i < e.dataTransfer.files.length; i++) {
console.log(
'... file[' + i + '].name = ' + e.dataTransfer.files[i].name
);
formData.append('image', e.dataTransfer.files[i]);
}
}
axios // μλ²μ μ΄λ―Έμ§ μ
λ‘λ λ° μ μ₯
.post(`/api/workspaces/${workspace}/dms/${id}/images`, formData)
.then(() => {
setDragOver(false);
localStorage.setItem( // λ©μμ§ μμ νμλ₯Ό μν λ‘컬μ€ν λ¦¬μ§ μ¬μ©
`${workspace}-${id}`,
new Date().getTime().toString()
);
mutateChat();
});
},
[workspace, id, mutateChat]
);
return (
<Container onDrop={onDrop} onDragOver={onDragOver}>
...
{dragOver && <DragOver>μ
λ‘λ!</DragOver>}
</Container>
)