Skip to content

Commit 325a6c9

Browse files
committed
feat: comments (#develop)
1 parent 149c459 commit 325a6c9

File tree

14 files changed

+140
-46
lines changed

14 files changed

+140
-46
lines changed

services/ahhachul.com/src/components/common/checkbox/Checkbox.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ const CheckboxControl = styled.div<{ checked?: boolean; disabled?: boolean }>`
7373
`;
7474

7575
const CheckboxLabel = styled.span<{ disabled?: boolean }>`
76-
color: ${props => (props.disabled ? '#33333E' : '#33333E')};
76+
color: ${props => (props.disabled ? '#95979F' : '#33333E')};
7777
font-size: 13px;
7878
cursor: pointer;
7979
`;

services/ahhachul.com/src/components/common/comment/CommentList.component.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ interface BaseCommentListProps {
1010
commentsMap: CommentList['comments'];
1111
servicePath: string;
1212
queryKey: readonly unknown[];
13+
isArticleAuthor: boolean;
1314
}
1415

1516
const BaseCommentList = React.memo(
16-
({ queryKey, servicePath, commentsMap }: BaseCommentListProps) => {
17+
({ queryKey, servicePath, commentsMap, isArticleAuthor }: BaseCommentListProps) => {
1718
const { setTempComment } = useTempComment();
1819

1920
useEffect(() => setTempComment(commentsMap), [commentsMap]);
@@ -24,14 +25,20 @@ const BaseCommentList = React.memo(
2425
<>
2526
{commentsMap.map(({ parentComment, childComments }) => (
2627
<React.Fragment key={parentComment.id}>
27-
<Comment comment={parentComment} queryKey={queryKey} servicePath={servicePath} />
28+
<Comment
29+
comment={parentComment}
30+
queryKey={queryKey}
31+
servicePath={servicePath}
32+
isArticleAuthor={isArticleAuthor}
33+
/>
2834
{childComments.map(childComment => (
2935
<Comment
3036
asChild
3137
key={childComment.id}
3238
comment={childComment}
3339
queryKey={queryKey}
3440
servicePath={servicePath}
41+
isArticleAuthor={isArticleAuthor}
3542
/>
3643
))}
3744
</React.Fragment>

services/ahhachul.com/src/components/common/comment/commentActions/CommentActions.component.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { Drawer } from 'vaul';
88

99
import { CloseIcon, DangerIcon, PhraseIcon, WarningIcon } from '@/assets/icons/jsx/icons';
1010
import { EllipsisIcon } from '@/assets/icons/system';
11-
import { useUser } from '@/hooks/domain';
1211
import { useDeleteComment } from '@/services/comment';
1312
import { useFlow } from '@/stackflow';
1413

@@ -17,24 +16,21 @@ import * as S from './CommentActions.styled';
1716
export interface CommentDropEllipsisProps {
1817
articleId: string;
1918
commentId: number;
20-
createdBy: number;
19+
isAuthor: boolean;
2120
queryKey: readonly unknown[];
2221
}
2322

2423
export const CommentDropEllipsis = ({
2524
articleId,
2625
commentId,
27-
createdBy,
26+
isAuthor,
2827
queryKey,
2928
}: CommentDropEllipsisProps): React.ReactElement => {
3029
const [isOpen, setIsOpen] = useState(false);
3130
const [view, setView] = useState('default');
3231
const [elementRef, bounds] = useMeasure();
3332
const previousHeightRef = useRef<number>(0);
3433

35-
const { user } = useUser();
36-
const isAuthor = user?.memberId === createdBy;
37-
3834
const handleOpen = () => {
3935
setView('default');
4036
setTimeout(() => {

services/ahhachul.com/src/components/common/comment/commentInput/CommentInput.component.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ interface CommentInputProps {
2323
shouldFocusOnMount?: boolean;
2424
showIsPrivateBtn?: boolean;
2525
actionLabel?: string;
26+
disablePrivateCheck?: boolean;
2627
onSubmit: ({ isPrivate, comment }: { isPrivate: boolean; comment: string }) => void;
2728
}
2829

@@ -35,6 +36,7 @@ const CommentInput = React.memo(
3536
onSubmit,
3637
actionLabel = '등록',
3738
disabled = false,
39+
disablePrivateCheck = false,
3840
}: CommentInputProps) => {
3941
const initialConfig = {
4042
namespace: 'commentEditor',
@@ -71,10 +73,11 @@ const CommentInput = React.memo(
7173
</S.EditorContainer>
7274
<SubmitComment
7375
comment={comment}
74-
isPrivate={isPrivate}
76+
isPrivate={disablePrivateCheck || isPrivate}
7577
setIsPrivate={setIsPrivate}
7678
showIsPrivateBtn={showIsPrivateBtn}
7779
actionLabel={actionLabel}
80+
disablePrivateCheck={disablePrivateCheck}
7881
onSubmit={onSubmit}
7982
/>
8083
</LexicalComposer>
@@ -89,12 +92,14 @@ const SubmitComment = ({
8992
setIsPrivate,
9093
showIsPrivateBtn,
9194
actionLabel,
95+
disablePrivateCheck,
9296
onSubmit,
9397
}: {
9498
comment: string;
9599
isPrivate: boolean;
96100
setIsPrivate: React.Dispatch<React.SetStateAction<boolean>>;
97101
showIsPrivateBtn?: boolean;
102+
disablePrivateCheck?: boolean;
98103
actionLabel?: string;
99104
onSubmit: ({ isPrivate, comment }: { isPrivate: boolean; comment: string }) => void;
100105
}) => {
@@ -135,8 +140,13 @@ const SubmitComment = ({
135140
{showIsPrivateBtn && (
136141
<UiComponent.Checkbox
137142
label="비공개 댓글"
143+
disabled={disablePrivateCheck}
138144
checked={isPrivate}
139145
onChange={e => {
146+
if (disablePrivateCheck) {
147+
return;
148+
}
149+
140150
setIsPrivate(e.target.checked);
141151
editor.focus();
142152
}}

services/ahhachul.com/src/components/common/comment/commentListItem/CommentListItem.component.tsx

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useActivity } from '@stackflow/react';
33
import { formatDateTime } from '@ahhachul/utils';
44

55
import { UiComponent } from '@/components';
6+
import { useUser } from '@/hooks/domain';
67
import { useFlow } from '@/stackflow';
78
import type { Comment } from '@/types';
89

@@ -15,36 +16,76 @@ interface CommentCardProps {
1516
asChild?: boolean;
1617
servicePath?: string;
1718
queryKey?: readonly unknown[];
19+
isArticleAuthor?: boolean;
1820
}
1921

20-
const Comment = ({ comment, asChild = false, servicePath, queryKey }: CommentCardProps) => {
22+
const Comment = ({
23+
comment,
24+
asChild = false,
25+
servicePath,
26+
queryKey,
27+
isArticleAuthor,
28+
}: CommentCardProps) => {
2129
const { push } = useFlow();
2230
const activity = useActivity();
2331

32+
const { user } = useUser();
33+
const isAuthor = user?.memberId === +comment.createdBy;
34+
const isSuper = (comment.isPrivate && isAuthor) || (comment.isPrivate && isArticleAuthor);
35+
2436
return (
2537
<S.CommentWrapper asChild={asChild} data-comment-id={comment.id}>
2638
<S.HeaderWrapper>
27-
<S.WriterName>{comment.writer}</S.WriterName>
28-
{queryKey && comment.status === 'CREATED' && (
39+
<S.WriterName>
40+
{comment.writer}
41+
{((comment.isPrivate && isAuthor) || (comment.isPrivate && isArticleAuthor)) && (
42+
<span css={{ marginLeft: '3px', color: '#95979F', fontWeight: 400 }}>(비공개)</span>
43+
)}
44+
</S.WriterName>
45+
{comment.isPrivate && isSuper && queryKey && comment.status === 'CREATED' && (
2946
<CommentDropEllipsis
47+
isAuthor={isAuthor}
48+
articleId={activity.params.id!}
49+
commentId={comment.id}
50+
queryKey={queryKey}
51+
/>
52+
)}
53+
{!comment.isPrivate && queryKey && comment.status === 'CREATED' && (
54+
<CommentDropEllipsis
55+
isAuthor={isAuthor}
3056
articleId={activity.params.id!}
31-
createdBy={+comment.createdBy!}
3257
commentId={comment.id}
3358
queryKey={queryKey}
3459
/>
3560
)}
3661
</S.HeaderWrapper>
3762
<S.ContentWrapper>
38-
{comment.isPrivate ? (
63+
{comment.isPrivate && !isAuthor && !isArticleAuthor ? (
3964
<S.DeletedComment>비공개 댓글입니다.</S.DeletedComment>
65+
) : isSuper ? (
66+
<UiComponent.ReadonlyEditor overrideCss={S.readonlyEditorCss} content={comment.content} />
4067
) : comment.status === 'CREATED' ? (
4168
<UiComponent.ReadonlyEditor overrideCss={S.readonlyEditorCss} content={comment.content} />
4269
) : (
4370
<S.DeletedComment>삭제된 댓글입니다.</S.DeletedComment>
4471
)}
4572
<S.DateText>{formatDateTime(comment.createdAt, { format: 'short' })}</S.DateText>
4673
</S.ContentWrapper>
47-
{queryKey && servicePath && !asChild && (
74+
{comment.isPrivate && isSuper && queryKey && servicePath && !asChild && (
75+
<S.ReplyButton
76+
onClick={() => {
77+
push('NewCommentReplyPage', {
78+
commentId: comment.id,
79+
id: +activity.params.id!,
80+
queryKey,
81+
servicePath,
82+
});
83+
}}
84+
>
85+
답글 달기
86+
</S.ReplyButton>
87+
)}
88+
{!comment.isPrivate && queryKey && servicePath && !asChild && (
4889
<S.ReplyButton
4990
onClick={() => {
5091
push('NewCommentReplyPage', {

services/ahhachul.com/src/components/common/editor/plugins/onChangePlugin/OnChangePlugin.component.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ export function OnChangePlugin({ readonly, initialState, shouldFocusOnMount, onC
4141

4242
if (shouldFocusOnMount) {
4343
setTimeout(() => {
44-
editor.focus();
44+
const editorElement = document.querySelector('[contenteditable="true"]');
45+
if (editorElement instanceof HTMLElement) {
46+
editorElement.click();
47+
}
4548
}, 550);
4649
}
4750
}, [readonly, initialState, shouldFocusOnMount]);

services/ahhachul.com/src/components/domain/community/postDetail/commentList/CommunityCommentList.component.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import * as S from './CommunityCommentList.styled';
77
interface CommunityCommentListProps {
88
id: number;
99
commentCnt: number;
10+
isArticleAuthor: boolean;
1011
}
1112

12-
const CommunityCommentList = ({ commentCnt, id }: CommunityCommentListProps) => {
13+
const CommunityCommentList = ({ commentCnt, id, isArticleAuthor }: CommunityCommentListProps) => {
1314
return (
1415
<S.Section>
1516
<S.HeaderWrapper>
@@ -24,20 +25,24 @@ const CommunityCommentList = ({ commentCnt, id }: CommunityCommentListProps) =>
2425
errorFallback={props => <UiComponent.ErrorCommentList {...props} />}
2526
suspenseFallback={<UiComponent.CommentListSkeleton />}
2627
>
27-
<CommentListInner id={id} />
28+
<CommentListInner id={id} isArticleAuthor={isArticleAuthor} />
2829
</UiComponent.SuspenseQueryBoundary>
2930
</S.Section>
3031
);
3132
};
3233

33-
const CommentListInner = ({ id }: Pick<CommunityCommentListProps, 'id'>) => {
34+
const CommentListInner = ({
35+
id,
36+
isArticleAuthor,
37+
}: Pick<CommunityCommentListProps, 'id' | 'isArticleAuthor'>) => {
3438
const { data } = useFetchCommunityCommentList(id);
3539

3640
return (
3741
<UiComponent.BaseCommentList
3842
commentsMap={data.comments}
3943
servicePath="community-posts"
4044
queryKey={communityKeys.comments(id)}
45+
isArticleAuthor={isArticleAuthor}
4146
/>
4247
);
4348
};

services/ahhachul.com/src/components/domain/community/postDetail/template/CommunityDetail.component.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { formatDateTime } from '@ahhachul/utils';
22

33
import { CommunityComponent, UiComponent } from '@/components';
44
import { subwayIconMap } from '@/constants';
5+
import { useUser } from '@/hooks/domain';
56
import { useFetchCommunityDetail } from '@/services/community';
67
import { isLexicalContent } from '@/utils/lexical';
78

@@ -14,6 +15,9 @@ interface CommunityDetailProps {
1415
const CommunityDetail = ({ id }: CommunityDetailProps) => {
1516
const { data: post } = useFetchCommunityDetail(id);
1617

18+
const { user } = useUser();
19+
const isArticleAuthor = +post.createdBy === user?.memberId;
20+
1721
return (
1822
<>
1923
<CommunityComponent.CommunityDetailHeaderActions id={id} createdBy={+post.createdBy} />
@@ -43,7 +47,11 @@ const CommunityDetail = ({ id }: CommunityDetailProps) => {
4347
</S.ContentContainer>
4448
</S.ArticleWrapper>
4549

46-
<CommunityComponent.CommunityCommentList id={id} commentCnt={post.commentCnt} />
50+
<CommunityComponent.CommunityCommentList
51+
id={id}
52+
commentCnt={post.commentCnt}
53+
isArticleAuthor={isArticleAuthor}
54+
/>
4755
<CommunityComponent.CommuntiyCommentInput id={id} />
4856
<S.Padding />
4957
</>

services/ahhachul.com/src/components/domain/complaint/postDetail/commentList/ComplaintCommentList.component.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import * as S from './ComplaintCommentList.styled';
77
interface ComplaintCommentListProps {
88
id: number;
99
commentCnt: number;
10+
isArticleAuthor: boolean;
1011
}
1112

12-
const ComplaintCommentList = ({ commentCnt, id }: ComplaintCommentListProps) => {
13+
const ComplaintCommentList = ({ commentCnt, id, isArticleAuthor }: ComplaintCommentListProps) => {
1314
return (
1415
<S.Section>
1516
<S.HeaderWrapper>
@@ -24,20 +25,24 @@ const ComplaintCommentList = ({ commentCnt, id }: ComplaintCommentListProps) =>
2425
errorFallback={props => <UiComponent.ErrorCommentList {...props} />}
2526
suspenseFallback={<UiComponent.CommentListSkeleton />}
2627
>
27-
<CommentListInner id={id} />
28+
<CommentListInner id={id} isArticleAuthor={isArticleAuthor} />
2829
</UiComponent.SuspenseQueryBoundary>
2930
</S.Section>
3031
);
3132
};
3233

33-
const CommentListInner = ({ id }: Pick<ComplaintCommentListProps, 'id'>) => {
34+
const CommentListInner = ({
35+
id,
36+
isArticleAuthor,
37+
}: Pick<ComplaintCommentListProps, 'id' | 'isArticleAuthor'>) => {
3438
const { data } = useFetchComplaintCommentList(id);
3539

3640
return (
3741
<UiComponent.BaseCommentList
3842
commentsMap={data.comments}
3943
servicePath="complaint-posts"
4044
queryKey={complaintKeys.comments(id)}
45+
isArticleAuthor={isArticleAuthor}
4146
/>
4247
);
4348
};

services/ahhachul.com/src/components/domain/complaint/postDetail/template/ComplaintDetail.component.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { formatDateTime } from '@ahhachul/utils';
22

33
import { ComplaintComponent, UiComponent } from '@/components';
44
import { subwayIconMap } from '@/constants';
5+
import { useUser } from '@/hooks/domain';
56
import { useFetchComplaintDetail } from '@/services/complaint';
67
import { isLexicalContent } from '@/utils/lexical';
78

@@ -14,6 +15,9 @@ interface ComplaintDetailProps {
1415
const ComplaintDetail = ({ id }: ComplaintDetailProps) => {
1516
const { data: post } = useFetchComplaintDetail(id);
1617

18+
const { user } = useUser();
19+
const isArticleAuthor = +post.createdBy === user?.memberId;
20+
1721
return (
1822
<>
1923
<ComplaintComponent.SendComplaintMessage
@@ -50,7 +54,11 @@ const ComplaintDetail = ({ id }: ComplaintDetailProps) => {
5054
</S.ContentContainer>
5155
</S.ArticleWrapper>
5256

53-
<ComplaintComponent.ComplaintCommentList id={id} commentCnt={post.commentCnt} />
57+
<ComplaintComponent.ComplaintCommentList
58+
id={id}
59+
commentCnt={post.commentCnt}
60+
isArticleAuthor={isArticleAuthor}
61+
/>
5462
<ComplaintComponent.ComplaintCommentInput id={id} />
5563
<S.Padding />
5664
</>

0 commit comments

Comments
 (0)