Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: 댓글 폼 TextArea로 수정, 댓글/답글 관련 버그 수정 #210

Merged
merged 4 commits into from
Apr 14, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const commentContent = style({
fontWeight: 500,
lineHeight: 'normal',
letterSpacing: '-0.36px',
wordBreak: 'break-word',
});

export const deletedComment = style({
Expand Down
14 changes: 10 additions & 4 deletions src/app/list/[listId]/_components/ListDetailOuter/Comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import timeDiff from '@/lib/utils/time-diff';
import { QUERY_KEYS } from '@/lib/constants/queryKeys';
import { CommentType } from '@/lib/types/commentType';
import { UserType } from '@/lib/types/userProfileType';
import { useCommentId } from '@/store/useComment';
import { useCommentId, useCommentStatus } from '@/store/useComment';
import { commentLocale } from '@/app/list/[listId]/locale';

import * as styles from './Comment.css';
Expand All @@ -25,9 +25,10 @@ import { useLanguage } from '@/store/useLanguage';
*/
interface CommentProps {
comment?: CommentType;
onUpdate: (userName?: string) => void;
setActiveNickname: (userName?: string) => void;
activeNickname?: string | null;
handleSetCommentId: (id: number | undefined) => void;
handleSetComment: (comment: string) => void;
listId?: number;
commentId?: number;
currentUserInfo?: UserType;
Expand All @@ -36,17 +37,18 @@ interface CommentProps {

function Comment({
comment,
onUpdate,
setActiveNickname: onUpdate,
handleSetCommentId,
handleSetComment,
listId,
commentId,
currentUserInfo,

handleEdit,
}: CommentProps) {
const { language } = useLanguage();
const queryClient = useQueryClient();
const { setCommentId } = useCommentId();
const { setStatusCreateReply, setStatusEdit } = useCommentStatus();

//현재 작성중인 답글의 원댓글 정보를 업데이트 하는 로직
const handleActiveNicknameAndIdUpdate = () => {
Expand All @@ -55,11 +57,15 @@ function Comment({
if (!currentUserName && !currentCommentId) {
return null;
}
handleSetComment('');
setStatusCreateReply();
onUpdate(currentUserName);
handleSetCommentId(currentCommentId);
};

//수정하기 버튼을 누르면 실행되는 함수
const handleEditButtonClick = (comment: string) => {
setStatusEdit();
handleEdit(comment);
setCommentId(commentId as number);
};
Expand Down
103 changes: 88 additions & 15 deletions src/app/list/[listId]/_components/ListDetailOuter/CommentForm.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import { ChangeEvent } from 'react';
import { ChangeEvent, useEffect } from 'react';

import { useUser } from '@/store/useUser';
import { useIsEditing } from '@/store/useComment';
import * as styles from './Comments.css';
import CancelButton from '/public/icons/cancel_button.svg';
import { vars } from '@/styles/theme.css';
import Airplane from '/public/icons/airplane_send.svg';
import { useIsEditing, useCommentStatus } from '@/store/useComment';
import { useLanguage } from '@/store/useLanguage';
import useResizeTextarea from '@/hooks/useResizeTextarea';
import { commentPlaceholder } from '@/lib/constants/placeholder';
import { commentLocale } from '@/app/list/[listId]/locale';

import { vars } from '@/styles/theme.css';
import * as styles from './Comments.css';
import CancelButton from '/public/icons/cancel_button.svg';
import Airplane from '/public/icons/airplane_send.svg';

interface CommentFormProps {
comment?: string;
activeNickname?: string | null;
handleSubmit?: (e: React.FormEvent<HTMLFormElement>) => void;
handleSubmit: (e: React.FormEvent<HTMLFormElement> | React.KeyboardEvent<HTMLTextAreaElement>) => void;
handleUpdate?: () => void;
handleChange: (e: ChangeEvent<HTMLInputElement>) => void;
handleChange: (e: ChangeEvent<HTMLTextAreaElement>) => void;
imageSrc?: string;
isEditing?: boolean;
isPending: boolean;
Expand All @@ -31,16 +33,84 @@ function CommentForm({
handleUpdate,
handleCancel,
}: CommentFormProps) {
const { status } = useCommentStatus();
const { language } = useLanguage();
const { isEditing } = useIsEditing();
const { textareaRef, handleResizeHeight } = useResizeTextarea();

const handleResetTextArea = () => {
if (textareaRef.current !== null) {
textareaRef.current.style.height = '20px';
}
};

const handleTextareaChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
handleChange(e);
handleResizeHeight();
};

const handleSubmitForm = (e: React.FormEvent<HTMLFormElement>) => {
handleSubmit(e);
// handleResizeHeight();
handleResetTextArea();
};

const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === 'Enter' && !e.shiftKey && !isPending) {
// handleResizeHeight();
handleResetTextArea();
e.preventDefault();
handleSubmit(e);
}
Comment on lines +57 to +64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍👍

};

const handleCancelForm = () => {
handleCancel();
handleResizeHeight();
};

const textAreaHeight = () => {
if (textareaRef.current === null) {
return false;
}
if (textareaRef.current.scrollHeight >= 30) {
return true;
}
};

const { user } = useUser();
const userId = user.id;

useEffect(() => {
const textarea = textareaRef.current;

const handleBlur = () => {
handleResizeHeight();
};

const handleFocus = () => {
handleResizeHeight();
};

if (textarea) {
textarea.addEventListener('blur', handleBlur);
textarea.addEventListener('focus', handleFocus);
}

return () => {
if (textarea) {
textarea.removeEventListener('blur', handleBlur);
textarea.removeEventListener('focus', handleFocus);
}
};
}, [textareaRef, handleResizeHeight]);

return (
<div className={styles.formWrapperOuter}>
<div className={`${styles.formWrapperInner} ${!!activeNickname || isEditing ? styles.activeFormWrapper : ''}`}>
{activeNickname && (
<div
className={`${styles.formWrapperInner} ${!!activeNickname || isEditing || textAreaHeight() ? styles.activeFormWrapper : ''}`}
>
{status === 'createReply' && activeNickname && (
<div className={styles.activeReplyWrapper}>
<span className={styles.replyNickname}>
{language === 'ko'
Expand All @@ -57,28 +127,31 @@ function CommentForm({
/>
</div>
)}
{isEditing && (
{status === 'edit' && isEditing && (
<div className={styles.activeReplyWrapper}>
<span className={styles.replyNickname}>{commentLocale[language].editing}</span>
<CancelButton
className={styles.clearButton}
alt={commentLocale[language].cancelButtonAlt}
onClick={handleCancel}
onClick={handleCancelForm}
width={18}
height={18}
fill={vars.color.gray7}
/>
</div>
)}
<form className={styles.formContainer} onSubmit={handleSubmit}>
<input
<form className={styles.formContainer} onSubmit={handleSubmitForm}>
<textarea
rows={1}
className={styles.formInput}
value={comment}
onChange={handleChange}
onChange={handleTextareaChange}
disabled={!userId}
ref={textareaRef}
placeholder={
userId === null ? commentPlaceholder[language].requiredLogin : commentPlaceholder[language].comment
}
onKeyDown={handleKeyDown}
/>
{comment && (
<button type="submit" disabled={isPending} className={styles.formButton}>
Expand Down
14 changes: 11 additions & 3 deletions src/app/list/[listId]/_components/ListDetailOuter/Comments.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,25 @@ export const formContainer = style({
});

export const formInput = style({
width: 'inherit',
height: 'auto',
width: '100%',
height: '20px',
maxHeight: '60px',

flex: '1 0 0',

display: 'block',
overflow: 'hidden',
resize: 'none',
outline: 'none',
border: 'none',
fontSize: '1.6rem',
wordBreak: 'break-all',
wordWrap: 'break-word',
whiteSpace: 'pre-wrap',
resize: 'none',
backgroundColor: vars.color.gray3,
'::-webkit-scrollbar': {
display: 'none',
},
Comment on lines 70 to +73
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오! textarea에서 스크롤이 보이지 않게 하는 속성인가요? 🎨

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 네네..!! overflow scroll에서 hidden으로 바꾸면서 필요없는 코드가 되어버렸네요🤔 삭제해야하는 코드인데 발견해주셔서 감사합니다!! 🥹

});

export const replyNickname = style({
Expand Down
25 changes: 17 additions & 8 deletions src/app/list/[listId]/_components/ListDetailOuter/Comments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { QUERY_KEYS } from '@/lib/constants/queryKeys';
import { CommentType } from '@/lib/types/commentType';
import { UserType } from '@/lib/types/userProfileType';
import { useUser } from '@/store/useUser';
import { useReplyId, useCommentId, useCommentIdStore, useIsEditing } from '@/store/useComment';
import { useReplyId, useCommentId, useCommentIdStore, useIsEditing, useCommentStatus } from '@/store/useComment';
import Modal from '@/components/Modal/Modal';
import CommentForm from './CommentForm';
import LoginModal from '@/components/login/LoginModal';
Expand All @@ -39,8 +39,8 @@ function Comments() {
const { replyId, deleteReplyId } = useReplyId();
const { commentId, setCommentId, deleteCommentId } = useCommentId();
const { setIsEditing, setIsNotEditing, isEditing } = useIsEditing();
const { status, resetStatus } = useCommentStatus();
const bottomRef = useRef<HTMLDivElement>(null);
const replyBottomRef = useRef<HTMLDivElement>(null);

//zustand로 관리하는 user정보 불러오기
const { user } = useUser();
Expand Down Expand Up @@ -103,8 +103,12 @@ function Comments() {
}
};

const handleSetComment = (comment: string) => {
setComment(comment);
};

//댓글 폼 사용(추후 리액트 훅폼으로 수정해 볼 예정)
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
const handleInputChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
setComment(e.target.value);
};

Expand All @@ -121,6 +125,7 @@ function Comments() {
setComment('');
deleteCommentId();
deleteReplyId();
resetStatus();
};

//댓글 생성 리액트 쿼리 함수
Expand Down Expand Up @@ -154,6 +159,7 @@ function Comments() {
deleteCommentId();
setActiveNickname(null);
setIsPending(false);
resetStatus();
},
});

Expand All @@ -170,6 +176,7 @@ function Comments() {
setComment('');
deleteCommentId();
setIsNotEditing();
resetStatus();
setIsPending(false);
},
});
Expand All @@ -181,7 +188,7 @@ function Comments() {
setIsPending(true);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.getComments, commentId] });
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.getComments] });
addCommentId(commentId as number);
scrollToRef();
},
Expand All @@ -191,21 +198,22 @@ function Comments() {
deleteReplyId();
setIsNotEditing();
setIsPending(false);
resetStatus();
},
});

//댓글/답글 폼 submit 함수
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
const handleSubmit = (e: React.FormEvent<HTMLFormElement> | React.KeyboardEvent<HTMLTextAreaElement>) => {
e.preventDefault();
Comment on lines -198 to 207
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

명확한 타입지정 너무 좋네요!! 👍👍
+. 참고로 한 컴포넌트에 React로 바로 임포트 해온 타입이 있고, 아닌 경우도 있어서 나중에 컨벤션을 통일하는 것도 좋을 것 같다는 생각이 들었습니당🥰

if (!comment.trim()) {
return null;
}
if (comment.trim()) {
if (commentId && activeNickname) {
if (status === 'createReply' && commentId && activeNickname) {
createReplyMutation.mutate();
return;
}
if (isEditing) {
if (status === 'edit') {
if (replyId) {
editReplyMutation.mutate();
return;
Expand Down Expand Up @@ -276,9 +284,10 @@ function Comments() {
) : (
<Comment
comment={item}
onUpdate={setActiveNickname}
setActiveNickname={setActiveNickname}
activeNickname={activeNickname}
handleSetCommentId={handleSetCommentId}
handleSetComment={handleSetComment}
listId={Number(params?.listId)}
commentId={item.id}
currentUserInfo={userInformation}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';

import DeleteModalButton from '@/app/list/[listId]/_components/ListDetailOuter/DeleteModalButton';
import deleteReply from '@/app/_api/comment/deleteReply';
import { useCommentIdStore, useReplyId, useCommentId } from '@/store/useComment';
import { useCommentIdStore, useReplyId, useCommentId, useCommentStatus } from '@/store/useComment';
import { QUERY_KEYS } from '@/lib/constants/queryKeys';
import timeDiff from '@/lib/utils/time-diff';
import { ReplyType } from '@/lib/types/commentType';
Expand Down Expand Up @@ -78,6 +78,7 @@ interface ReplyProps {
function Reply({ reply, listId, currentUserInfo, handleEdit, commentId }: ReplyProps) {
const { language } = useLanguage();
const queryClient = useQueryClient();
const { setStatusEdit } = useCommentStatus();
const { setCommentId } = useCommentId();
const { setReplyId } = useReplyId();
const deleteReplyMutation = useMutation({
Expand All @@ -88,6 +89,7 @@ function Reply({ reply, listId, currentUserInfo, handleEdit, commentId }: ReplyP
});

const handleEditButtonClick = (content: string) => {
setStatusEdit();
handleEdit(content);
setCommentId(commentId as number);
setReplyId(reply?.id);
Expand Down
17 changes: 17 additions & 0 deletions src/hooks/useEnterKeyDown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
interface IProps {
handleSubmit: (e: React.FormEvent<HTMLFormElement> | React.KeyboardEvent<HTMLTextAreaElement>) => void;
isSubmitting: boolean;
}

function usePressEnterFetch({ handleSubmit, isSubmitting }: IProps) {
Comment on lines +1 to +6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

나현님 혹시 props 타입이름을 함수명+props로 변경하면 어떨까용??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 코드 고대로 복붙해온 거 깜빡했어용..머쓱 ㅎㅎㅎ 타입명 수정해두겠습니당!!👍 감사합니다 소현님 🙇‍♀️

const handlePressEnterFetch = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === 'Enter' && !e.shiftKey && !isSubmitting) {
e.preventDefault();
handleSubmit(e);
}
};

return { handlePressEnterFetch };
}

export default usePressEnterFetch;
Loading