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

[Feat] 커뮤니티 카드 컴포넌트 구현 #79

Merged
merged 33 commits into from
Jun 14, 2024

Conversation

minjeong9919
Copy link
Contributor

🚀 작업 내용

  • 커뮤니티에 사용되는 포스트 글 컴포넌트를 구현했습니다.

📝 참고 사항

  • 작업에 사용되는 이미지는 임의로 제가 짱구 사진을 넣어서 추후에 API 연동 성공하면 public 파일에서 삭제하겠습니다.

🖼️ 스크린샷

image

🚨 관련 이슈 (이슈 번호)

✅ 체크리스트

  • Code Review 요청
  • Label 설정
  • PR 제목 규칙에 맞는지 확인

@minjeong9919 minjeong9919 added the ✨ Component 기능 개발 label Jun 12, 2024
@minjeong9919 minjeong9919 self-assigned this Jun 12, 2024
Copy link
Contributor

@bokeeeey bokeeeey left a comment

Choose a reason for hiding this comment

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

LGTM !

public/images/defaultProfile.png Outdated Show resolved Hide resolved
public/svgs/showMore.svg Outdated Show resolved Hide resolved
Comment on lines 23 to 43
export default function PostCard({ cardData }: PostCardProps) {
const [isPostModalOpen, setIsPostModalOpen] = useState(false);
const handleClickPostModal = () => {
setIsPostModalOpen(true);
};
const handleClosePostModal = () => {
setIsPostModalOpen(false);
};
const {
user_nickname: nickname,
created_at: createdAt,
title,
image,
good_count: goodCount,
comment_count: commentCount,
} = cardData;
const nowDate = new Date();
const createdDate = new Date(createdAt);
const timeToString = calculateTimeDifference(createdDate, nowDate);

return (
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
export default function PostCard({ cardData }: PostCardProps) {
const [isPostModalOpen, setIsPostModalOpen] = useState(false);
const handleClickPostModal = () => {
setIsPostModalOpen(true);
};
const handleClosePostModal = () => {
setIsPostModalOpen(false);
};
const {
user_nickname: nickname,
created_at: createdAt,
title,
image,
good_count: goodCount,
comment_count: commentCount,
} = cardData;
const nowDate = new Date();
const createdDate = new Date(createdAt);
const timeToString = calculateTimeDifference(createdDate, nowDate);
return (
export default function PostCard({ cardData }: PostCardProps) {
const [isPostModalOpen, setIsPostModalOpen] = useState(false);
const {
user_nickname: nickname,
created_at: createdAt,
title,
image,
good_count: goodCount,
comment_count: commentCount,
} = cardData;
const nowDate = new Date();
const createdDate = new Date(createdAt);
const timeToString = calculateTimeDifference(createdDate, nowDate);
const handleClickPostModal = () => {
setIsPostModalOpen(true);
};
const handleClosePostModal = () => {
setIsPostModalOpen(false);
};
return (

import 구문 정리해주신것처럼 함수 안에서도
이런식의 구분이 들어가면 더 읽기 좋을거같아요

Copy link
Contributor Author

Choose a reason for hiding this comment

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

훨씬 보기 편하군여,, 이런 부분도 신경써야겠어요 😃

<div className={cn('container')} onClick={handleContainerClick}>
<div className={cn('icon-and-count')}>
<LikeButton isChecked={isChecked} onClick={handleLikeButtonClick} />
<p id={cn('count')}>{goodCount > 99 ? '99+' : goodCount}</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

99라는 숫자는 상수로 선언해도 좋을거같네요

padding: 2rem 0;
border-radius: 0.8rem;
background-color: #111;
color: #fff;
Copy link
Contributor

Choose a reason for hiding this comment

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

변수로 사용 부탁드립니다

Copy link
Contributor Author

Choose a reason for hiding this comment

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

어멋 이 파일 삭제했는데 제 브랜치에 남아있었나봐요,, 좀 전에 만든거라,,

Copy link
Contributor

Choose a reason for hiding this comment

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

이건 여러곳에서 사용 가능할거같은데
회원정보 변경 부분에 들어갈 경우까지 고려해서 범용 컴포넌트로 만드시면 좋을거같아요

Copy link
Contributor Author

Choose a reason for hiding this comment

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

이 작업 완료했슴다 나중에 한번 더 pr 리뷰 부탁드려도 될까용가리

Comment on lines 14 to 20
<div className={cn('image-div')}>
{profile ? (
<Image src={profile} alt='프로필 이미지' width={64} height={64} />
) : (
<Image src={defaultImage} alt='기본 이미지' width={39} height={36} />
)}
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

https://velog.io/@yung315/nextimage-Error-handling
state와 onError을 사용하면 더 간결하게 사용 가능합니다

Copy link
Contributor Author

Choose a reason for hiding this comment

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

오 대박 Image 태그에 onError 속성이 있다니 맵소사
좋은 정보 증말 감사해요 😊

Comment on lines +12 to +17
type ProfileImageProp = {
profileImage: StaticImageData | string | null;
width?: number;
height?: number;
isEditable?: boolean;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

interface로 변경 부탁드려요

alt='프로필 이미지'
width={width}
height={height}
className={cn('profile-image')}
Copy link
Contributor

Choose a reason for hiding this comment

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

Image 태그에 className이 적용되나요..?
이건 컴포넌트로 만들어진 태그라 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.

오 신기하게 전 됐어요~!! border-radius 넣어줫는데 잘 적용됐어요!!!!

return (
<label htmlFor='profileInput' className={cn({ label: isEditable })}>
<div className={cn('profile-image-wrapper')}>
<Image
Copy link
Contributor

Choose a reason for hiding this comment

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

Image태그에서 layoutShift를 방지하고 싶으면 placeholder='blur'처리까지 넣어주시는게 좋아요
적용하시면 페이지 로딩시 이미지 요소가 있는 위치는 스켈레톤으로 처리 됩니다.
https://haruisshort.tistory.com/302

Copy link
Contributor Author

Choose a reason for hiding this comment

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

오오오 이미지에 아주 빠싹하시네여 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

저 이 부분 적용하려했는데 제가 사용하는 부분은 동적인 부분이라 추가적인 설정들이 많이 필요하더라구요,,, 하다가 포기,,,🥺 일단 이 부분 보류하고 추후에 설정해봐도 괜찮을까용?

Copy link
Contributor

Choose a reason for hiding this comment

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

넵넵 merge되면 제가 한번 살펴볼게요 동적 이미지에서의 스켈레톤처리가 최적화에서 가장 크게작용합니다

Copy link
Contributor Author

Choose a reason for hiding this comment

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

네네넹 감사합니도로도로~!

Copy link
Contributor

@Young2un Young2un left a comment

Choose a reason for hiding this comment

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

굿잡~~ 진행도 빠르고 수정도 빠르고 흡수력이 정말 좋으신거 같아용~! 고생하셨슴당~!~!

Comment on lines +21 to +22
<p id={cn('user-name')}>{nickname}</p>
<p id={cn('sub-info')}>{timeAgo}</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

지난번에도 보였던거 같은데 id를 사용하신이유가 무엇일까용??
그리고 id 는 그냥 id = 'user-name'으로 쓰는게 맞지 않을까용?(사실 모르는데 좀 이상하다고 느껴집니다!!) cn 자체가 classname의 줄임말이라서??

Copy link
Contributor Author

Choose a reason for hiding this comment

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

오옹오!!!! 구러네요오오오 좀 약간 속에 있는 요소들을 id로 쓰는데className이랑은 안어울리겠네욤,,수정하겠슴니다!!!

요즘은 영은님이 알려주신 그 단축키써서 클래스이름으로만 씁니동,, 그래도 id는 최대한 className으로 써보도록,, 명심하겠슴당

<AuthorCard nickname={nickname} timeAgo={timeToString} />
<div className={cn('keyboard-image-wrapper')}>
<Image src={ContentImage} className={cn('keyboard-image')} alt='키보드 이미지' />
{image.length > 1 && <p id={cn('image-count')}>{image.length}</p>}
Copy link
Contributor

Choose a reason for hiding this comment

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

진짜 굳이굳이 말하자면 1도 상수처리?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넹넹넹넹 !!!! 수정하겟슴니다다닷

Copy link
Contributor

Choose a reason for hiding this comment

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

수정안하셔도 됩니둥~~

src/components/ProfileImage/ProfileImage.module.scss Outdated Show resolved Hide resolved
@@ -44,7 +44,7 @@ export default function ImageInput() {
))}
{selectedImageFile.length < 4 && (
<label htmlFor='imageInput' className={cn('label-input')}>
<CarmeraIcon />
<CarmeraIcon fill='#999999' width={46} height={40} />
Copy link
Contributor

Choose a reason for hiding this comment

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

동적으로 바뀌는거 아니니까 파일에서 fill 설정해도 되지 않을까 싶습니다?!

Copy link
Contributor Author

@minjeong9919 minjeong9919 Jun 14, 2024

Choose a reason for hiding this comment

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

이거 ProfileImage 컴포넌트에서도 사용해서 이렇게 했어요오잇

Comment on lines +26 to +33
const {
user_nickname: nickname,
created_at: createdAt,
title,
image,
good_count: goodCount,
comment_count: commentCount,
} = cardData;
Copy link
Contributor

Choose a reason for hiding this comment

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

와아우~ 저도 써먹어야겠슴다~!!! 나이스하당!!!!!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

야하오 ~

Comment on lines 17 to 36
const [isChecked, setIsChecked] = useState(false);

const handleContainerClick = (e: MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
};

const handleLikeButtonClick = () => {
setIsChecked((prev) => !prev);
};
return (
<div className={cn('container')} onClick={handleContainerClick}>
<div className={cn('icon-and-count')}>
<LikeButton isChecked={isChecked} onClick={handleLikeButtonClick} />
<p id={cn('count')}>{goodCount > MAX_COUNT ? '99+' : goodCount}</p>
</div>
<div className={cn('icon-and-count')}>
<CommentIcon />
<p id={cn('count')}>{commentCount > MAX_COUNT ? '99+' : commentCount}</p>
</div>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

요기는 예진님 버튼 나오면 변경해야 할거 같아요!

Copy link
Contributor

@ggjiny ggjiny left a comment

Choose a reason for hiding this comment

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

깔끔하네용 고생하셨습니다!!👍buttons 폴더만 한번 확인 부탁드려요~~

Comment on lines +9 to +10
display: flex;
flex-direction: column;
Copy link
Contributor

Choose a reason for hiding this comment

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

여기도 mixin 써주셔도 좋을 것 같아용!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

오호옹 넹넹넹!!

Copy link
Contributor

Choose a reason for hiding this comment

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

오오오잉 이친구들 안지워졌을까용???

Copy link
Contributor Author

Choose a reason for hiding this comment

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

이게,,,제 컴퓨터가 아주 이상해여오,, 충돌인가 에러가 나서 지웠다가 다시 깔았더니 이렇게 소문자로 들어가부렸네요,, 방금도 대소문자랑 싸우고 왔슴니도,, 제 컴퓨터만 증말 왜이럴까요호,,

이 문제가 저인 것 같아서 일단 제가 해결하고 머지해보도록 하겟씁니더,,

Copy link
Contributor

@armd482 armd482 left a comment

Choose a reason for hiding this comment

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

수고하셨습니다!

import myProfileImage from '@/public/images/myProfile.jpeg';
import ShowMoreIcon from '@/public/svgs/verticalTripleDot.svg';

import ProfileImage from '../../../components/ProfileImage/ProfileImage';
Copy link
Contributor

Choose a reason for hiding this comment

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

이렇게 depth가 깊을 때는 @/로 하는 게 더 좋을 것 같습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

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

오오옹 넹넹!! 자동완성 import 가 저렇게 되었나보네여,, push 하기 전에 확인 꼭꼭 하도록 하겠슴니당!

Comment on lines 8 to 16
if (days > 0) {
return `${days}일 전`;
} else if (hours > 0) {
return `${hours}시간 전`;
} else if (minutes > 0) {
return `${minutes}분 전`;
} else {
return '방금 전';
}
Copy link
Contributor

Choose a reason for hiding this comment

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

return이 있어서 else는 안 붙여도 될 것 같습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

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

오오오 넹네엔ㅇ!

@minjeong9919 minjeong9919 merged commit a2c8f9b into develop Jun 14, 2024
@minjeong9919 minjeong9919 deleted the 29-feat-커뮤니티-카드-컴포넌트-구현 branch June 14, 2024 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ Component 기능 개발
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

[Feat] 커뮤니티 카드 컴포넌트 구현
5 participants