From c9628f383a1d5988620cc066dc4f1c699e876cd5 Mon Sep 17 00:00:00 2001 From: wynter24 Date: Tue, 10 Dec 2024 17:42:28 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=92=84[Design]=20WrittenReview,=20Rat?= =?UTF-8?q?ingIcon=20=EB=B3=80=EA=B2=BD=EB=90=9C=20=EB=94=94=EC=9E=90?= =?UTF-8?q?=EC=9D=B8=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95=20#100?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/icons/RatingIcon.tsx | 2 +- src/components/written-review/WrittenReview.tsx | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/public/icons/RatingIcon.tsx b/public/icons/RatingIcon.tsx index 4582487b..14ae97b0 100644 --- a/public/icons/RatingIcon.tsx +++ b/public/icons/RatingIcon.tsx @@ -12,7 +12,7 @@ function RatingIcon({ checked = false, ...props }: RatingIconProps) { - const heartColor = checked ? '#EA580C' : '#D1D5DB'; + const heartColor = checked ? '#00a991' : '#d8d9db'; return ( +
-

+

{comment}

-
+
{`${userName}'s -

+

{userName}

-

{createdAt}

+

{createdAt}

-
+
); } From 4633dc587238557ded0fa603849265be2d36c309 Mon Sep 17 00:00:00 2001 From: wynter24 Date: Tue, 10 Dec 2024 18:18:11 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=E2=99=BB=EF=B8=8F[Refactor]=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EC=97=90=EB=9F=AC=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B0=84=EC=86=8C=ED=99=94=20=EB=B0=8F=20?= =?UTF-8?q?=EC=83=81=EC=9C=84=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8?= =?UTF-8?q?=EB=A1=9C=20=EC=B1=85=EC=9E=84=20=EB=B6=84=EB=A6=AC=20#100?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/written-review/WrittenReview.tsx | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/components/written-review/WrittenReview.tsx b/src/components/written-review/WrittenReview.tsx index b8e65c52..a26a7d95 100644 --- a/src/components/written-review/WrittenReview.tsx +++ b/src/components/written-review/WrittenReview.tsx @@ -1,8 +1,5 @@ -'use client'; - import Image from 'next/image'; import RatingDisplay from '../rating-display/RatingDisplay'; -import { useState, useEffect } from 'react'; // 디자인 확정시, 기본 이미지 변경 const defaultProfileImage = '/images/profile.png'; @@ -22,16 +19,6 @@ export default function WrittenReview({ userName, createdAt, }: WrittenReviewProps) { - const [imgSrc, setImgSrc] = useState(profileImage || defaultProfileImage); - - useEffect(() => { - setImgSrc(profileImage || defaultProfileImage); - }, [profileImage]); - - const handleImageError = () => { - setImgSrc(defaultProfileImage); - }; - return (
@@ -42,10 +29,10 @@ export default function WrittenReview({ {`${userName}'s (e.currentTarget.src = defaultProfileImage)} />

{userName} From a5c9520d9c505d1d88c7bbb3c3d2b78617744d00 Mon Sep 17 00:00:00 2001 From: wynter24 Date: Wed, 11 Dec 2024 10:51:33 +0900 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=92=84=E2=99=BB=EF=B8=8F[Design,=20Re?= =?UTF-8?q?factor]=20UI=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=20=EB=B0=8F=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=BB=B4?= =?UTF-8?q?=ED=8C=8C=EC=9A=B4=EB=93=9C=20=ED=8C=A8=ED=84=B4=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20#100?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../written-review/WrittenReview.tsx | 108 ++++++++++++++---- .../written-review/types/writtenReview.ts | 24 ++++ 2 files changed, 109 insertions(+), 23 deletions(-) create mode 100644 src/components/written-review/types/writtenReview.ts diff --git a/src/components/written-review/WrittenReview.tsx b/src/components/written-review/WrittenReview.tsx index a26a7d95..c77a5231 100644 --- a/src/components/written-review/WrittenReview.tsx +++ b/src/components/written-review/WrittenReview.tsx @@ -1,45 +1,107 @@ import Image from 'next/image'; import RatingDisplay from '../rating-display/RatingDisplay'; +import { LocationIcon } from '../../../public/icons'; +import { + ClubImageProps, + ClubInfoProps, + CommentProps, + RatingProps, + UserProfileProps, +} from './types/writtenReview'; -// 디자인 확정시, 기본 이미지 변경 +// 기본 이미지 (변경될 수 있음) const defaultProfileImage = '/images/profile.png'; +const defaultClubImage = '/images/profile.png'; -interface WrittenReviewProps { - ratingCount: number; - comment: string; - profileImage?: string; - userName: string; - createdAt: string; +function handleImageError( + event: React.SyntheticEvent, + defaultSrc: string, +) { + event.currentTarget.src = defaultSrc; } export default function WrittenReview({ - ratingCount, - comment, + children, +}: { + children: React.ReactNode; +}) { + return ( +

+ {children} +
+
+ ); +} + +function Rating({ ratingCount }: RatingProps) { + return ; +} + +function Comment({ text }: CommentProps) { + return ( +

+ {text} +

+ ); +} + +function UserProfile({ profileImage, userName, createdAt, -}: WrittenReviewProps) { + className, +}: UserProfileProps) { return ( -
- -

- {comment} -

-
+
+ {profileImage && ( {`${userName}'s (e.currentTarget.src = defaultProfileImage)} + onError={(e) => handleImageError(e, defaultProfileImage)} /> -

- {userName} -

-

{createdAt}

+ )} +

+ {userName} +

+

{createdAt}

+
+ ); +} + +function ClubImage({ src, alt }: ClubImageProps) { + return ( + {alt handleImageError(e, defaultClubImage)} + /> + ); +} + +function ClubInfo({ clubName, location }: ClubInfoProps) { + return ( +
+

{clubName}

+
+ + + {location} +
-
-
+
); } + +// WrittenReview의 자식 컴포넌트 연결 +WrittenReview.Rating = Rating; +WrittenReview.Comment = Comment; +WrittenReview.UserProfile = UserProfile; +WrittenReview.ClubInfo = ClubInfo; +WrittenReview.ClubImage = ClubImage; diff --git a/src/components/written-review/types/writtenReview.ts b/src/components/written-review/types/writtenReview.ts new file mode 100644 index 00000000..0f22dacc --- /dev/null +++ b/src/components/written-review/types/writtenReview.ts @@ -0,0 +1,24 @@ +export interface UserProfileProps { + profileImage?: string; + userName?: string; + createdAt: string; + className?: string; +} + +export interface ClubImageProps { + src: string; + alt?: string; +} + +export interface ClubInfoProps { + clubName: string; + location: string; +} + +export interface CommentProps { + text: string; +} + +export interface RatingProps { + ratingCount: number; +} From f0558fd5755d745c593236b0154d2e4cb8f72d0b Mon Sep 17 00:00:00 2001 From: wynter24 Date: Wed, 11 Dec 2024 10:53:20 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=E2=9C=85[Test]=20=EC=8A=A4=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=EB=B6=81=20=EC=88=98=EC=A0=95=20#100?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../written-review/WrittenReview.stories.tsx | 78 ++++++++++++++++++- 1 file changed, 74 insertions(+), 4 deletions(-) diff --git a/src/components/written-review/WrittenReview.stories.tsx b/src/components/written-review/WrittenReview.stories.tsx index 3fa22bfb..b80fe80d 100644 --- a/src/components/written-review/WrittenReview.stories.tsx +++ b/src/components/written-review/WrittenReview.stories.tsx @@ -1,22 +1,92 @@ import type { Meta, StoryObj } from '@storybook/react'; import WrittenReview from './WrittenReview'; +// 컴파운드 컴포넌트의 모든 props를 포함하는 타입 정의 +interface StoryProps { + ratingCount: number; + comment: string; + profileImage: string; + userName: string; + createdAt: string; + clubImage: string; + clubName: string; + clubImageAlt: string; + location: string; +} + const meta = { title: 'Components/WrittenReview', component: WrittenReview, + parameters: { + layout: 'centered', + }, } satisfies Meta; export default meta; -type Story = StoryObj; +type Story = StoryObj; -export const CreatedReview: Story = { +export const FindClubReview: Story = { + render: (args) => ( + +
+ + + +
+
+ ), args: { ratingCount: 4, comment: - '따듯하게 느껴지는 공간이에요 :) 평소에 달램 이용해보고 싶었는데 이렇게 같이 달램 생기니까 너무 좋아요! 프로그램이 더 많이 늘어났으면 좋겠어요.', + '아침부터 자기발전을 위한 시간을 가져서 좋았어요. 각자의 길 위에서 달려가는 생생한 순간을 공유해주셔서 감사합니다!', + profileImage: + 'https://cdn.pixabay.com/photo/2024/02/17/00/18/cat-8578562_1280.jpg', + userName: '다람쥐', + createdAt: '2024.01.25', + }, +}; + +export const MypageReview: Story = { + render: (args) => ( +
+ +
+ +
+ + + + +
+
+
+
+ ), + args: { profileImage: 'https://cdn.pixabay.com/photo/2024/02/17/00/18/cat-8578562_1280.jpg', - userName: '럽윈즈올', + userName: '다람쥐', + ratingCount: 4, + comment: + '아침부터 자기발전을 위한 시간을 가져서 좋았어요. 각자의 길 위에서 달려가는 생생한 순간을 공유해주셔서 감사합니다!', createdAt: '2024.01.25', + clubImage: + 'https://cdn.pixabay.com/photo/2024/02/17/00/18/cat-8578562_1280.jpg', + clubName: '달램핏 오피스 스트레칭', + clubImageAlt: '달램핏 이미지', + location: '을지로 3가', }, }; From 557e304f5cfc641a1c2381db17a894062dd81e13 Mon Sep 17 00:00:00 2001 From: wynter24 Date: Wed, 11 Dec 2024 10:54:32 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=94=A5[Remove]=20WrittenReview=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20#100?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../written-review/WrittenReview.test.tsx | 55 ------------------- 1 file changed, 55 deletions(-) delete mode 100644 src/components/written-review/WrittenReview.test.tsx diff --git a/src/components/written-review/WrittenReview.test.tsx b/src/components/written-review/WrittenReview.test.tsx deleted file mode 100644 index 35a40d3e..00000000 --- a/src/components/written-review/WrittenReview.test.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import '@testing-library/jest-dom'; -import WrittenReview from './WrittenReview'; -import { act } from 'react'; - -describe('WrittenReview Component', () => { - const defaultProfileImage = - 'https://cdn.pixabay.com/photo/2018/02/12/10/45/heart-3147976_1280.jpg'; - const validProfileImage = - 'https://cdn.pixabay.com/photo/2024/02/17/00/18/cat-8578562_1280.jpg'; - const brokenProfileImage = 'https://broken-url.com/image.jpg'; - - it('유효한 이미지 경우 정상적으로 렌더링', () => { - render( - , - ); - const imgElement = screen.getByAltText("Test User's profile picture"); - - expect(imgElement.getAttribute('src')).toContain( - encodeURIComponent(validProfileImage), - ); - }); - - it('유효하지 않은 이미지 경우 기본 이미지로 대체', async () => { - render( - , - ); - - const imgElement = screen.getByAltText("Test User's profile picture"); - - expect(imgElement.getAttribute('src')).toContain( - encodeURIComponent(brokenProfileImage), - ); - - await act(async () => { - imgElement.dispatchEvent(new Event('error')); - }); - - expect(imgElement.getAttribute('src')).toContain( - encodeURIComponent(defaultProfileImage), - ); - }); -});