diff --git a/src/assets/defaultProfile.png b/src/assets/defaultProfile.png new file mode 100644 index 000000000..76a16709c Binary files /dev/null and b/src/assets/defaultProfile.png differ diff --git a/src/components/Members/MemberImage/MemberImage.stories.tsx b/src/components/Members/MemberImage/MemberImage.stories.tsx new file mode 100644 index 000000000..e644e9390 --- /dev/null +++ b/src/components/Members/MemberImage/MemberImage.stories.tsx @@ -0,0 +1,24 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import MemberImage from './MemberImage'; +import DefaultMemberImage from '../../../assets/defaultProfile.png'; + +const meta: Meta = { + 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; + +export const Default: Story = {}; + +export const Error: Story = { + args: { + src: DefaultMemberImage, + }, +}; diff --git a/src/components/Members/MemberImage/MemberImage.tsx b/src/components/Members/MemberImage/MemberImage.tsx new file mode 100644 index 000000000..c3dd9f98e --- /dev/null +++ b/src/components/Members/MemberImage/MemberImage.tsx @@ -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 ( + + ); +}; + +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}; +`; diff --git a/src/components/Members/MembersInfo/MembersInfo.tsx b/src/components/Members/MembersInfo/MembersInfo.tsx index 1b2e94839..55e0ea8c0 100644 --- a/src/components/Members/MembersInfo/MembersInfo.tsx +++ b/src/components/Members/MembersInfo/MembersInfo.tsx @@ -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'; @@ -23,7 +25,16 @@ const MembersInfo = () => { return ( - + {nickname} 님 @@ -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; -`; diff --git a/src/components/Members/index.ts b/src/components/Members/index.ts index 4e31460ee..2080b25c6 100644 --- a/src/components/Members/index.ts +++ b/src/components/Members/index.ts @@ -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'; diff --git a/src/components/Rank/RecipeRankingItem/RecipeRankingItem.tsx b/src/components/Rank/RecipeRankingItem/RecipeRankingItem.tsx index 308f2d3fd..26362d02e 100644 --- a/src/components/Rank/RecipeRankingItem/RecipeRankingItem.tsx +++ b/src/components/Rank/RecipeRankingItem/RecipeRankingItem.tsx @@ -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'; @@ -59,7 +60,7 @@ const RecipeRankingItem = ({ rank, recipe }: RecipeRankingItemProps) => { - + {nickname} 님 @@ -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; -`; diff --git a/src/components/Recipe/CommentItem/CommentItem.tsx b/src/components/Recipe/CommentItem/CommentItem.tsx index 847194b75..121af50c6 100644 --- a/src/components/Recipe/CommentItem/CommentItem.tsx +++ b/src/components/Recipe/CommentItem/CommentItem.tsx @@ -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'; @@ -15,7 +16,7 @@ const CommentItem = ({ recipeComment }: CommentItemProps) => { return ( <> - +
{author.nickname} 님 @@ -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; `; diff --git a/src/components/Recipe/RecipeItem/RecipeItem.tsx b/src/components/Recipe/RecipeItem/RecipeItem.tsx index f7e7f229f..8a226070a 100644 --- a/src/components/Recipe/RecipeItem/RecipeItem.tsx +++ b/src/components/Recipe/RecipeItem/RecipeItem.tsx @@ -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'; @@ -30,7 +31,15 @@ const RecipeItem = ({ recipe, isMemberPage = false }: RecipeItemProps) => { ) : ( )} - {author && } + {author && ( + + )} )} @@ -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; diff --git a/src/components/Review/BestReviewItem/BestReviewItem.tsx b/src/components/Review/BestReviewItem/BestReviewItem.tsx index 5e66dcbbb..6fa84835a 100644 --- a/src/components/Review/BestReviewItem/BestReviewItem.tsx +++ b/src/components/Review/BestReviewItem/BestReviewItem.tsx @@ -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 { @@ -29,7 +30,7 @@ const BestReviewItem = ({ productId }: BestReviewItemProps) => { - +
{userName} 님 @@ -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; diff --git a/src/components/Review/ReviewItem/ReviewItem.tsx b/src/components/Review/ReviewItem/ReviewItem.tsx index bbd38647e..5b9ef5e8d 100644 --- a/src/components/Review/ReviewItem/ReviewItem.tsx +++ b/src/components/Review/ReviewItem/ReviewItem.tsx @@ -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'; @@ -23,7 +24,13 @@ const ReviewItem = ({ productId, review }: ReviewItemProps) => { - +
{userName} @@ -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; diff --git a/src/pages/RecipeDetailPage.tsx b/src/pages/RecipeDetailPage.tsx index 4b4fbb666..2388eca26 100644 --- a/src/pages/RecipeDetailPage.tsx +++ b/src/pages/RecipeDetailPage.tsx @@ -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'; @@ -40,7 +41,7 @@ export const RecipeDetailPage = () => { - +
{author.nickname} 님 {getFormattedDate(createdAt)} @@ -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; diff --git a/src/pages/ReviewDetailPage.tsx b/src/pages/ReviewDetailPage.tsx index 9cc209bf5..5681e5b12 100644 --- a/src/pages/ReviewDetailPage.tsx +++ b/src/pages/ReviewDetailPage.tsx @@ -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'; @@ -35,7 +36,13 @@ export const ReviewDetailPage = () => { - +
{userName} @@ -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;