Skip to content

Commit

Permalink
Merge pull request #160 from Quad8/150-feat-다른-유저-프로필-보기
Browse files Browse the repository at this point in the history
[Feat] 다른 유저 프로필 보기
  • Loading branch information
minjeong9919 committed Aug 5, 2024
2 parents a9c5419 + 4504451 commit 8cfff52
Show file tree
Hide file tree
Showing 35 changed files with 771 additions and 163 deletions.
14 changes: 14 additions & 0 deletions src/api/usersAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,17 @@ export const checkNickname = async (nickname: string) => {
throw error;
}
};

/**
* 클릭한 사용자의 정보를 반환합니다.
*/

export const getOthersInfo = async (userId: number) => {
try {
const res = await fetch(`${BASE_URL}/api/v1/users/${userId}`);
const { data } = await res.json();
return data;
} catch (error) {
throw error;
}
};
5 changes: 3 additions & 2 deletions src/app/(test)/mj/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import classNames from 'classnames/bind';
// import ProfileImage from '@/components/ProfileImage/ProfileImage';
import styles from './page.module.scss';
import ReviewModalTest from './test/ReviewModalTest';
// import ReviewModalTest from './test/ReviewModalTest';
// import OrderListModalTest from './OrderListModatTest';
// import ImageZoomText from './test/ImageZoomText';

const cn = classNames.bind(styles);

Expand All @@ -13,7 +14,7 @@ export default function Page() {
<div className={cn('container')}>
{/* <ProfileImage isEditable width={139} height={139} profileImage={null} /> */}
{/* <OrderListModalTest /> */}
<ReviewModalTest />
{/* <ImageZoomText /> */}
</div>
);
}
10 changes: 10 additions & 0 deletions src/app/(test)/mj/test/ImageZoomText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import ImageZoom from '@/components/ImageZoom/ImageZoom';

export default function ImageZoomText() {
const imageUrl = 'https://cdn.imweb.me/thumbnail/20220404/12007f769b366.jpg';
return (
<div style={{ marginLeft: 130 }}>
<ImageZoom image={imageUrl} alt='테스트용' width={500} height={500} />
</div>
);
}
7 changes: 7 additions & 0 deletions src/app/community/_components/AuthorCard.module.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.container {
@include flex-center;

position: relative;
width: 100%;
height: 6.4rem;
}
Expand All @@ -16,6 +17,12 @@

& > .user-name {
@include pretendard-18-500;

cursor: pointer;

&:hover {
text-decoration: underline;
}
}

& > .sub-info {
Expand Down
59 changes: 46 additions & 13 deletions src/app/community/_components/AuthorCard.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import classNames from 'classnames/bind';
import { MouseEvent } from 'react';
import { useRef, useState } from 'react';

import ProfileImage from '@/components/ProfileImage/ProfileImage';
import { PopOver } from '@/components';
import UserProfileCard from './UserProfileCard';

import styles from './AuthorCard.module.scss';

Expand All @@ -12,39 +13,71 @@ interface AuthorCardProps {
nickname: string;
dateText: string;
userImage: string | null;
userId: number;
onClickPopOver: () => void;
onClosePopOver: () => void;
isOpenPopOver: boolean;
popOverOptions: {
label: string;
onClick: (e: React.MouseEvent<HTMLDivElement>) => void;
onClick?: () => void;
}[];
}

export default function AuthorCard({
nickname,
dateText,
userImage,
userId,
onClickPopOver,
onClosePopOver,
isOpenPopOver,
popOverOptions,
}: AuthorCardProps) {
const userProfileCardRef = useRef<HTMLDivElement>(null);
const [isOpenUserCard, setIsOpenUserCard] = useState(false);
const [isHovering, setIsHovering] = useState(false);

const handleOpenProfile = () => {
setIsOpenUserCard(true);
};

const handleCloseProfile = () => {
setIsOpenUserCard(false);
};

return (
<div className={cn('container')}>
<ProfileImage profileImage={userImage} />
<div
className={cn('container')}
onClick={(e) => e.stopPropagation()}
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}
>
<div
onMouseEnter={handleOpenProfile}
onMouseLeave={handleCloseProfile}
className={cn('user-profile')}
ref={userProfileCardRef}
>
<ProfileImage profileImage={userImage} />
<UserProfileCard isOpenProfileCard={isOpenUserCard} userId={userId} />
</div>
<div className={cn('info-textbox')}>
<p className={cn('user-name')}>{nickname}</p>
<p className={cn('user-name')} onMouseEnter={handleOpenProfile} onMouseLeave={handleCloseProfile}>
{nickname}
</p>
<p className={cn('sub-info')}>{dateText}</p>
</div>
<div className={cn('show-more-icon')}>
<PopOver
optionsData={popOverOptions}
onHandleClose={onClosePopOver}
isOpenPopOver={isOpenPopOver}
onHandleOpen={onClickPopOver}
/>
</div>
{isHovering && (
<div className={cn('show-more-icon')}>
<PopOver
optionsData={popOverOptions}
onHandleClose={onClosePopOver}
isOpenPopOver={isOpenPopOver}
onHandleOpen={onClickPopOver}
position={{ left: -30, top: -20 }}
/>
</div>
)}
</div>
);
}
15 changes: 15 additions & 0 deletions src/app/community/_components/Comment.module.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
.container {
display: flex;
position: relative;
width: 100%;
gap: 1.2rem;

&:hover {
background-color: $gray-5;
}
}

.user-profile {
position: relative;
}

.profile-image {
Expand Down Expand Up @@ -34,6 +43,12 @@

& > .nickname {
@include pretendard-16-400;

cursor: pointer;

&:hover {
text-decoration: underline;
}
}

& > .time-ago {
Expand Down
99 changes: 63 additions & 36 deletions src/app/community/_components/Comment.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
'use client';

import classNames from 'classnames/bind';
import { useState, forwardRef } from 'react';
import { forwardRef, useState, MouseEvent } from 'react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { toast } from 'react-toastify';

import ProfileImage from '@/components/ProfileImage/ProfileImage';
import { calculateTimeDifference } from '@/libs/calculateDate';
import type { Users } from '@/types/userType';
import type { UserDataResponseType } from '@/types/userType';
import { PopOver } from '@/components';
import { deleteComment } from '@/api/communityAPI';

import { communityPopOverOption } from '@/libs/communityPopOverOption';

import styles from './Comment.module.scss';
import UserProfileCard from './UserProfileCard';

const cn = classNames.bind(styles);

Expand All @@ -27,16 +28,17 @@ interface CommentDataType {

interface CommentProps {
cardId: number;
onOpenPopOver: (commentId: number) => void;
onClosePopOver: () => void;
commentData: CommentDataType;
isOpenedPopOver: boolean;
onOpenProfileCard: () => void;
}

interface UserDataType {
data: Users;
status: string;
message: string;
}

export default forwardRef<HTMLDivElement, CommentProps>(function Comment({ cardId, commentData }, ref) {
export default forwardRef<HTMLDivElement, CommentProps>(function Comment(
{ cardId, commentData, onOpenPopOver, onClosePopOver, isOpenedPopOver, onOpenProfileCard },
ref,
) {
const queryClient = useQueryClient();

const {
Expand All @@ -47,12 +49,17 @@ export default forwardRef<HTMLDivElement, CommentProps>(function Comment({ cardI
content: comment,
createdAt: createdTime,
} = commentData;
const createdTimeToDate = new Date(createdTime);

const createdTimeToDate = new Date(createdTime);
const [isOpenPopOver, setIsOpenPopOver] = useState(false);
const [showIcon, setShowIcon] = useState(false);
const [isOpenProfileCard, setIsOpenProfileCard] = useState(false);
const [commentPositionTop, setCommentPositionTop] = useState(0);

const userData = queryClient.getQueryData<UserDataResponseType>(['userData']);

const userData = queryClient.getQueryData<UserDataType>(['userData']);
const userID = userData?.data?.id;
const timeAgo = calculateTimeDifference(createdTimeToDate);

const { mutate: deleteCommentMutation } = useMutation({
mutationFn: deleteComment,
Expand All @@ -68,44 +75,64 @@ export default forwardRef<HTMLDivElement, CommentProps>(function Comment({ cardI
},
});

const handleClickPopOver = () => {
setIsOpenPopOver(!isOpenPopOver);
const handleOpenProfile = (e: MouseEvent<HTMLDivElement>) => {
onOpenProfileCard();
const { top } = e.currentTarget.getBoundingClientRect();
setCommentPositionTop(top);
setIsOpenProfileCard(true);
};

const handleClosePopOver = () => {
setIsOpenPopOver(false);
const handleCloseProfile = () => {
setIsOpenProfileCard(false);
};

const handleClickPopOver = () => {
if (isOpenPopOver) {
onClosePopOver();
setIsOpenPopOver(false);
} else {
onOpenPopOver(commentId);
setIsOpenPopOver(true);
}
};

const handleClickDelete = () => {
deleteCommentMutation(commentId);
};

const handleClickEdit = () => {};

const handleClickReport = () => {};

const timeAgo = calculateTimeDifference(createdTimeToDate);

return (
<div className={cn('container')} ref={ref}>
<ProfileImage profileImage={profile && profile} />
<div
className={cn('container')}
ref={ref}
onMouseEnter={() => setShowIcon(true)}
onMouseLeave={() => (isOpenedPopOver ? setShowIcon(true) : setShowIcon(false))}
>
<div onMouseEnter={handleOpenProfile} onMouseLeave={handleCloseProfile}>
<ProfileImage profileImage={profile && profile} />
<UserProfileCard
isOpenProfileCard={isOpenProfileCard}
userId={commentUserId}
positionTop={commentPositionTop}
/>
</div>
<div className={cn('content-wrapper')}>
<div className={cn('user-info-wrapper')}>
<div className={cn('user-info')}>
<div className={cn('user-info')} onMouseEnter={handleOpenProfile} onMouseLeave={handleCloseProfile}>
<p className={cn('nickname')}>{nickname}</p>
<p className={cn('time-ago')}>{timeAgo}</p>
</div>
<PopOver
optionsData={communityPopOverOption({
isMine: userID === commentUserId,
onClickDelete: handleClickDelete,
onClickEdit: handleClickEdit,
onClickReport: handleClickReport,
})}
isOpenPopOver={isOpenPopOver}
onHandleOpen={handleClickPopOver}
onHandleClose={handleClosePopOver}
/>
{showIcon && (
<PopOver
optionsData={communityPopOverOption({
isMine: userID === commentUserId,
onClickDelete: handleClickDelete,
})}
isOpenPopOver={isOpenPopOver && isOpenedPopOver}
onHandleOpen={handleClickPopOver}
onHandleClose={onClosePopOver}
position={{ left: 415, top: 15 }}
/>
)}
</div>
<div className={cn('content')}>{comment}</div>
</div>
Expand Down
Loading

0 comments on commit 8cfff52

Please sign in to comment.