Skip to content

Commit

Permalink
Merge pull request #639 from sparcs-kaist/#638-bug-safari-chat-messag…
Browse files Browse the repository at this point in the history
…e-form

#638 [Bug] 사파리에서 채팅 MessageForm 에 한글 연달아 전송 시, 이전 입력이 같이 들어옴
  • Loading branch information
14KGun authored Sep 15, 2023
2 parents 71647ff + 976be7e commit aebb4b7
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 73 deletions.
177 changes: 111 additions & 66 deletions src/components/Chat/MessageForm/InputText/BodyText.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import {
ChangeEvent,
KeyboardEvent,
useCallback,
useEffect,
useRef,
useState,
} from "react";
import { css } from "@emotion/react";
import { useCallback, useEffect, useRef, useState } from "react";

import useSendMessage from "hooks/chat/useSendMessage";

Expand All @@ -20,44 +14,13 @@ type BodyTextProps = {

const BodyText = ({ sendMessage }: BodyTextProps) => {
const wrapRef = useRef<HTMLDivElement>(null);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const textareaRef = useRef<HTMLTextAreaElement>();
const [height, setHeight] = useState<CSS["height"]>("32px");
const [message, setMessage] = useState<string>("");
const [isSendingMessage, setIsSendingMessage] = useState<boolean>(false);

const isEnterPressed = useRef<boolean>(false);
const isShiftPressed = useRef<boolean>(false);

const isMessageValid: boolean =
regExpTest.chatMsg(message) && !isSendingMessage;

const onSend = async () => {
textareaRef.current?.focus();
if (isMessageValid) {
setIsSendingMessage(true);
const result = await sendMessage("text", { text: message });
if (result) setMessage("");
setIsSendingMessage(false);
}
};
const onKeyEvent = (e: KeyboardEvent<HTMLTextAreaElement>, v: boolean) => {
if (e.code === "ShiftLeft" || e.code === "ShiftRight")
isShiftPressed.current = v;
if (e.code === "Enter") isEnterPressed.current = v;
};
const onChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
if (isEnterPressed.current && !isShiftPressed.current) {
onSend();
return;
}
const msg = e.target.value;
if (!isSendingMessage) setMessage(msg);
};
const onKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) =>
onKeyEvent(e, true);
const onKeyUp = (e: KeyboardEvent<HTMLTextAreaElement>) =>
onKeyEvent(e, false);

/* form height handler */
const resizeEvent = useCallback(() => {
if (!wrapRef.current) return;
const cacheHeight = wrapRef.current.style.height;
Expand All @@ -71,41 +34,123 @@ const BodyText = ({ sendMessage }: BodyTextProps) => {
)}px`;
wrapRef.current.style.height = cacheHeight;
setHeight(newHeight);
}, [setHeight]);

}, []);
useEffect(() => {
resizeEvent();
window.addEventListener("resize", resizeEvent);
return () => window.removeEventListener("resize", resizeEvent);
}, []);
useEffect(resizeEvent, [message]);

/* message validation handler */
const [isMessageValidState, setIsMessageValidState] =
useState<boolean>(false);
const getIsMessageValid = useCallback(
(message: string): boolean =>
regExpTest.chatMsg(message) && !isSendingMessage,
[isSendingMessage]
);
useEffect(
() =>
setIsMessageValidState(
getIsMessageValid(textareaRef.current?.value || "")
),
[getIsMessageValid]
);

/* send message handler */
const onSend = async () => {
if (!textareaRef.current) return;

const message = textareaRef.current.value;
const isMessageValid = getIsMessageValid(message);
refreshTextArea();
textareaRef.current.focus();
resizeEvent();

if (isMessageValid) {
setIsSendingMessage(true);
const result = await sendMessage("text", { text: message });
if (!result) textareaRef.current.value = message;
setIsSendingMessage(false);
}
};

/* textarea event handler */
const onChange = useCallback(
(e: Event) => {
if (!textareaRef.current) return;
if (isSendingMessage) refreshTextArea();
setIsMessageValidState(getIsMessageValid(textareaRef.current.value));

if (isEnterPressed.current && !isShiftPressed.current) {
onSend();
return;
}
resizeEvent();
},
[isSendingMessage, getIsMessageValid, onSend]
);
const onKeyEvent = (e: KeyboardEvent, v: boolean) => {
if (e.code === "ShiftLeft" || e.code === "ShiftRight")
isShiftPressed.current = v;
if (e.code === "Enter") {
if (textareaRef.current && !v && !isShiftPressed.current) {
refreshTextArea();
textareaRef.current.focus();
}
isEnterPressed.current = v;
}
};
const onKeyDown = (e: KeyboardEvent) => onKeyEvent(e, true);
const onKeyUp = (e: KeyboardEvent) => onKeyEvent(e, false);

/* textarea refresh handler */
const refreshTextArea = () => {
if (!wrapRef.current) return;
if (textareaRef.current) wrapRef.current.removeChild(textareaRef.current);
const textarea = document.createElement("textarea");
textarea.oninput = onChange;
textarea.addEventListener("keydown", onKeyDown);
textarea.addEventListener("keyup", onKeyUp);
textarea.placeholder = "채팅을 입력해주세요";
textarea.value = "";
textareaRef.current = textarea;
wrapRef.current.prepend(textarea);
resizeEvent();
};
useEffect(refreshTextArea, [sendMessage]);

return (
<div ref={wrapRef} css={{ height: height }}>
<textarea
ref={textareaRef}
value={message}
placeholder="채팅을 입력해주세요"
onChange={onChange}
onKeyDown={onKeyDown}
onKeyUp={onKeyUp}
css={{
width: "calc(100% - 30px)",
height: "100%",
background: "none",
border: "none",
resize: "none",
outline: "none",
...theme.font14,
color: theme.black,
padding: "8px 12px",
boxSizing: "border-box",
}}
/>
<div
ref={wrapRef}
css={css`
height: ${height};
& > textarea {
${[
css`
width: calc(100% - 30px);
height: 100%;
background: none;
border: none;
resize: none;
outline: none;
color: ${theme.black};
padding: 8px 12px;
box-sizing: border-box;
`,
theme.font14,
]}
}
`}
>
<ButtonSend
onClick={onSend}
status={
isSendingMessage ? "pending" : isMessageValid ? "active" : "inactive"
isSendingMessage
? "pending"
: isMessageValidState
? "active"
: "inactive"
}
/>
</div>
Expand Down
8 changes: 3 additions & 5 deletions src/components/Loading.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { css } from "@emotion/react";
import { css, keyframes } from "@emotion/react";

import theme, { Font } from "tools/theme";

Expand All @@ -18,9 +18,7 @@ const Loading = ({
${font}
color: ${color};
content: "Loading 🚕";
animation: loading 1.5s linear infinite;
}
@keyframes loading {
animation: ${keyframes`
25% {
content: "Loading. 🚕";
}
Expand All @@ -29,7 +27,7 @@ const Loading = ({
}
75% {
content: "Loading... 🚕";
}
}`} 1.5s linear infinite;
}
`;
const positionCenter = css`
Expand Down
3 changes: 1 addition & 2 deletions src/pages/Event/Event2023FallStore/PublicNoticeContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ const PublicNoticeContainer = () => {
width: 0,
overflow: "hidden",
whiteSpace: "nowrap",
...theme.font14,
}}
>
<div
Expand Down Expand Up @@ -81,7 +80,7 @@ const PublicNoticeContainer = () => {
`}
>
{[...notices, ...notices].map((text, index) => (
<span key={index} css={{ padding: "0 20px" }}>
<span key={index} css={{ padding: "0 20px", ...theme.font14 }}>
{text}
</span>
))}
Expand Down

0 comments on commit aebb4b7

Please sign in to comment.