Skip to content

Commit

Permalink
refactor: MemberImage 컴포넌트 추가 (#15)
Browse files Browse the repository at this point in the history
* feat: MemberImage 컴포넌트 추가

* refactor: 기존의 프로필 이미지 컴포넌트들을 MemberImage 컴포넌트로 교체

* feat: 프로필 이미지에 오류 발생 시 기본 이미지로 대체

* feat: 상태를 boolean값으로 변경
  • Loading branch information
xodms0309 authored Jan 29, 2024
1 parent 2779283 commit 158a142
Show file tree
Hide file tree
Showing 12 changed files with 113 additions and 60 deletions.
Binary file added src/assets/defaultProfile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions src/components/Members/MemberImage/MemberImage.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Meta, StoryObj } from '@storybook/react';

import MemberImage from './MemberImage';
import DefaultMemberImage from '../../../assets/defaultProfile.png';

const meta: Meta<typeof MemberImage> = {
title: 'members/MemberImage',
component: MemberImage,
args: {
src: 'https://github.com/woowacourse-teams/2023-fun-eat/assets/78616893/1f0fd418-131c-4cf8-b540-112d762b7c34',
alt: '펀잇님의 프로필 사진',
},
};

export default meta;
type Story = StoryObj<typeof MemberImage>;

export const Default: Story = {};

export const Error: Story = {
args: {
src: DefaultMemberImage,
},
};
42 changes: 42 additions & 0 deletions src/components/Members/MemberImage/MemberImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useState } from 'react';
import type { CSSProp } from 'styled-components';
import styled from 'styled-components';

import DefaultMemberImage from '@/assets/defaultProfile.png';

interface MemberImageProps {
src: string;
alt: string;
width?: number;
height?: number;
css?: CSSProp;
}

const MemberImage = ({ src, alt, width = 45, height = 45, css }: MemberImageProps) => {
const [isError, setIsError] = useState(false);

const handleImageError = () => {
setIsError(true);
};

return (
<StyledMemberImage
src={isError ? DefaultMemberImage : src}
alt={alt}
width={width}
height={height}
css={css}
onError={handleImageError}
/>
);
};

export default MemberImage;

const StyledMemberImage = styled.img`
border: 2px solid ${({ theme }) => theme.colors.primary};
border-radius: 50%;
background: ${({ theme }) => theme.backgroundColors.default};
object-fit: cover;
${({ css }) => css};
`;
20 changes: 12 additions & 8 deletions src/components/Members/MembersInfo/MembersInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Button, Heading, Link, theme } from '@fun-eat/design-system';
import { Link as RouterLink } from 'react-router-dom';
import styled from 'styled-components';

import MemberImage from '../MemberImage/MemberImage';

import { SvgIcon } from '@/components/Common';
import { PATH } from '@/constants/path';
import { useLogoutMutation, useMemberQuery } from '@/hooks/queries/members';
Expand All @@ -23,7 +25,16 @@ const MembersInfo = () => {
return (
<MembersInfoContainer>
<MemberInfoWrapper>
<MembersImage src={profileImage} width={45} height={45} alt={`${nickname}의 프로필`} />
<MemberImage
src={profileImage}
width={45}
height={45}
alt={`${nickname}의 프로필`}
css={{
marginRight: `16px`,
objectFit: `cover`,
}}
/>
<Heading size="xl" weight="bold">
{nickname}
</Heading>
Expand Down Expand Up @@ -55,10 +66,3 @@ const MemberModifyLink = styled(Link)`
margin-left: 5px;
transform: translateY(1px);
`;

const MembersImage = styled.img`
margin-right: 16px;
border: 2px solid ${({ theme }) => theme.colors.primary};
border-radius: 50%;
object-fit: cover;
`;
1 change: 1 addition & 0 deletions src/components/Members/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export { default as MemberReviewList } from './MemberReviewList/MemberReviewList
export { default as MemberRecipeList } from './MemberRecipeList/MemberRecipeList';
export { default as MemberModifyInput } from './MemberModifyInput/MemberModifyInput';
export { default as MemberReviewItem } from './MemberReviewItem/MemberReviewItem';
export { default as MemberImage } from './MemberImage/MemberImage';
9 changes: 2 additions & 7 deletions src/components/Rank/RecipeRankingItem/RecipeRankingItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import styled from 'styled-components';

import RecipePreviewImage from '@/assets/plate.svg';
import { SvgIcon } from '@/components/Common';
import { MemberImage } from '@/components/Members';
import type { RecipeRanking } from '@/types/ranking';
import { getRelativeDate } from '@/utils/date';

Expand Down Expand Up @@ -59,7 +60,7 @@ const RecipeRankingItem = ({ rank, recipe }: RecipeRankingItemProps) => {
</TitleFavoriteWrapper>
</RankingRecipeWrapper>
<AuthorWrapper>
<AuthorImage src={profileImage} alt={`${nickname} 님의 프로필`} width={40} height={40} />
<MemberImage src={profileImage} alt={`${nickname} 님의 프로필`} width={40} height={40} />
<Text size="sm" color={theme.textColors.sub}>
{nickname}
</Text>
Expand Down Expand Up @@ -114,9 +115,3 @@ const AuthorWrapper = styled.div`
align-items: center;
height: 100%;
`;

const AuthorImage = styled.img`
border: 2px solid ${({ theme }) => theme.colors.primary};
border-radius: 50%;
object-fit: cover;
`;
8 changes: 2 additions & 6 deletions src/components/Recipe/CommentItem/CommentItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Divider, Spacing, Text, useTheme } from '@fun-eat/design-system';
import styled from 'styled-components';

import { MemberImage } from '@/components/Members';
import type { Comment } from '@/types/recipe';
import { getFormattedDate } from '@/utils/date';

Expand All @@ -15,7 +16,7 @@ const CommentItem = ({ recipeComment }: CommentItemProps) => {
return (
<>
<AuthorWrapper>
<AuthorProfileImage src={author.profileImage} alt={`${author.nickname}님의 프로필`} width={32} height={32} />
<MemberImage src={author.profileImage} alt={`${author.nickname}님의 프로필`} width={32} height={32} />
<div>
<Text size="xs" color={theme.textColors.info}>
{author.nickname}
Expand All @@ -40,11 +41,6 @@ const AuthorWrapper = styled.div`
align-items: center;
`;

const AuthorProfileImage = styled.img`
border: 1px solid ${({ theme }) => theme.colors.primary};
border-radius: 50%;
`;

const CommentContent = styled(Text)`
margin: 16px 0;
`;
22 changes: 10 additions & 12 deletions src/components/Recipe/RecipeItem/RecipeItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import styled from 'styled-components';

import PreviewImage from '@/assets/plate.svg';
import { SvgIcon } from '@/components/Common';
import { MemberImage } from '@/components/Members';
import type { MemberRecipe, Recipe } from '@/types/recipe';
import { getFormattedDate } from '@/utils/date';

Expand All @@ -30,7 +31,15 @@ const RecipeItem = ({ recipe, isMemberPage = false }: RecipeItemProps) => {
) : (
<PreviewImage width={160} height={160} />
)}
{author && <ProfileImage src={author.profileImage} alt={`${author.nickname}의 프로필`} />}
{author && (
<MemberImage
src={author.profileImage}
alt={`${author.nickname}의 프로필`}
width={60}
height={60}
css={{ position: `absolute`, bottom: `-20px`, right: `16px` }}
/>
)}
</ImageWrapper>
)}
<RecipeInfoWrapper>
Expand Down Expand Up @@ -76,17 +85,6 @@ const RecipeImage = styled.img`
object-fit: cover;
`;

const ProfileImage = styled.img`
position: absolute;
bottom: -20px;
right: 16px;
width: 60px;
height: 60px;
border: 2px solid ${({ theme }) => theme.colors.primary};
border-radius: 50%;
background-color: ${({ theme }) => theme.backgroundColors.default};
`;

const RecipeInfoWrapper = styled.div`
position: relative;
display: flex;
Expand Down
9 changes: 2 additions & 7 deletions src/components/Review/BestReviewItem/BestReviewItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Spacing, Text, useTheme } from '@fun-eat/design-system';
import styled from 'styled-components';

import { SvgIcon } from '@/components/Common';
import { MemberImage } from '@/components/Members';
import { useBestReviewQuery } from '@/hooks/queries/rank';

interface BestReviewItemProps {
Expand Down Expand Up @@ -29,7 +30,7 @@ const BestReviewItem = ({ productId }: BestReviewItemProps) => {
<BestReviewItemContainer>
<ReviewRateFavoriteWrapper>
<ReviewerInfoWrapper>
<ReviewerImage src={profileImage} width={32} height={32} alt={`${userName}의 프로필`} />
<MemberImage src={profileImage} width={32} height={32} alt={`${userName}의 프로필`} />
<div>
<Text size="sm" weight="bold">
{userName}
Expand Down Expand Up @@ -82,12 +83,6 @@ const ReviewerInfoWrapper = styled.div`
column-gap: 10px;
`;

const ReviewerImage = styled.img`
border: 2px solid ${({ theme }) => theme.colors.primary};
border-radius: 50%;
object-fit: cover;
`;

const FavoriteWrapper = styled.div`
display: flex;
gap: 8px;
Expand Down
15 changes: 8 additions & 7 deletions src/components/Review/ReviewItem/ReviewItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import styled from 'styled-components';
import ReviewFavoriteButton from '../ReviewFavoriteButton/ReviewFavoriteButton';

import { SvgIcon, TagList } from '@/components/Common';
import { MemberImage } from '@/components/Members';
import type { Review } from '@/types/review';
import { getRelativeDate } from '@/utils/date';

Expand All @@ -23,7 +24,13 @@ const ReviewItem = ({ productId, review }: ReviewItemProps) => {
<ReviewItemContainer>
<ReviewerWrapper>
<ReviewerInfoWrapper>
<ReviewerImage src={profileImage} width={40} height={40} alt={`${userName}의 프로필`} />
<MemberImage
src={profileImage}
width={40}
height={40}
alt={`${userName}의 프로필`}
css={{ objectFit: `cover` }}
/>
<div>
<Text weight="bold">{userName}</Text>
<RatingIconWrapper>
Expand Down Expand Up @@ -80,12 +87,6 @@ const RebuyBadge = styled(Badge)`
font-weight: ${({ theme }) => theme.fontWeights.bold};
`;

const ReviewerImage = styled.img`
border: 2px solid ${({ theme }) => theme.colors.primary};
border-radius: 50%;
object-fit: cover;
`;

const RatingIconWrapper = styled.div`
display: flex;
align-items: center;
Expand Down
8 changes: 2 additions & 6 deletions src/pages/RecipeDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import styled from 'styled-components';

import RecipePreviewImage from '@/assets/plate.svg';
import { ErrorBoundary, ErrorComponent, Loading, SectionTitle } from '@/components/Common';
import { MemberImage } from '@/components/Members';
import { CommentForm, CommentList, RecipeFavoriteButton } from '@/components/Recipe';
import { useRecipeDetailQuery } from '@/hooks/queries/recipe';
import { getFormattedDate } from '@/utils/date';
Expand Down Expand Up @@ -40,7 +41,7 @@ export const RecipeDetailPage = () => {
<Spacing size={24} />
<AuthorFavoriteWrapper>
<AuthorWrapper>
<AuthorProfileImage src={author.profileImage} alt={`${author.nickname}님의 프로필`} width={45} height={45} />
<MemberImage src={author.profileImage} alt={`${author.nickname}님의 프로필`} width={45} height={45} />
<div>
<Text color={theme.textColors.info}>{author.nickname}</Text>
<Text color={theme.textColors.info}> {getFormattedDate(createdAt)}</Text>
Expand Down Expand Up @@ -124,11 +125,6 @@ const AuthorWrapper = styled.div`
align-items: center;
`;

const AuthorProfileImage = styled.img`
border: 1px solid ${({ theme }) => theme.colors.primary};
border-radius: 50%;
`;

const RecipeUsedProductsWrapper = styled.div`
padding: 20px;
border-radius: 8px;
Expand Down
15 changes: 8 additions & 7 deletions src/pages/ReviewDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useParams } from 'react-router-dom';
import styled from 'styled-components';

import { SectionTitle, SvgIcon, TagList } from '@/components/Common';
import { MemberImage } from '@/components/Members';
import { PATH } from '@/constants/path';
import { useReviewDetailQuery } from '@/hooks/queries/review';
import { getRelativeDate } from '@/utils/date';
Expand Down Expand Up @@ -35,7 +36,13 @@ export const ReviewDetailPage = () => {
<ReviewItemContainer>
<ReviewerWrapper>
<ReviewerInfoWrapper>
<ReviewerImage src={profileImage} width={40} height={40} alt={`${userName}의 프로필`} />
<MemberImage
src={profileImage}
width={40}
height={40}
alt={`${userName}의 프로필`}
css={{ objectFit: `cover` }}
/>
<div>
<Text weight="bold">{userName}</Text>
<RatingIconWrapper>
Expand Down Expand Up @@ -100,12 +107,6 @@ const RebuyBadge = styled(Badge)`
font-weight: ${({ theme }) => theme.fontWeights.bold};
`;

const ReviewerImage = styled.img`
border: 2px solid ${({ theme }) => theme.colors.primary};
border-radius: 50%;
object-fit: cover;
`;

const RatingIconWrapper = styled.div`
display: flex;
align-items: center;
Expand Down

0 comments on commit 158a142

Please sign in to comment.