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: 마이페이지 구현 #95

Merged
merged 30 commits into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
99b64c9
refactor: memberImage 컴포넌트 마이그레이션 및 props 수정
hae-on Apr 19, 2024
d694368
refactor: memberInfo 컴포넌트 마이그레이션 및 디자인 수정
hae-on Apr 19, 2024
06c2325
feat: postCounterBox 컴포넌트 구현
hae-on Apr 19, 2024
43247e3
refactor: memberPage 마이그레이션
hae-on Apr 19, 2024
380db1a
feat: memberPostPage 구현
hae-on Apr 19, 2024
c505f7b
feat: starRating 컴포넌트 구현
hae-on Apr 19, 2024
cb12916
refactor: memberReviewItem 컴포넌트 마이그레이션 및 수정
hae-on Apr 19, 2024
6a531fe
refactor: memberReviewList 컴포넌트 디자인 수정
hae-on Apr 19, 2024
acafa0f
refactor: 세부 디자인 수정
hae-on Apr 19, 2024
279e846
refactor: memberRecipeList 디자인 수정
hae-on Apr 19, 2024
a284eef
refactor: 세부 레이아웃 수정
hae-on Apr 19, 2024
d76cc7e
refactor: 필요없는 css 삭제
hae-on Apr 19, 2024
b079f35
refactor: 화살표 svg 위치 수정
hae-on Apr 19, 2024
3ac33fc
chore: 사용하지 않는 페이지 삭제
hae-on Apr 19, 2024
3388077
fix: webpack vanilla error hash 값 추가하여 해결
hae-on Apr 19, 2024
9acf263
refactor: review item 일부 컴포넌트로 분리
hae-on Apr 20, 2024
4761dfb
feat: 작성한 꿀조합/리뷰 클릭에 따른 페이지 이동 구현
hae-on Apr 20, 2024
943c4a4
chore: 사용하지 않는 css 삭제
hae-on Apr 20, 2024
bc69785
refactor: member에 recipeCount, reviewCount 추가
hae-on Apr 20, 2024
1410816
chore: v2 충돌 해결 후 병합
hae-on Apr 20, 2024
9ce3ca4
chore: v2 병합
hae-on Apr 23, 2024
d1d0ca9
refactor: 세부 디자인 반영
hae-on Apr 23, 2024
95f51e7
refactor: camera2 아이콘 교체
hae-on Apr 23, 2024
7d2544e
chore: svg 속성 카멜 케이스로 자동 변경
hae-on Apr 26, 2024
3e5de02
fix: css 순서 오류 방지
hae-on Apr 26, 2024
fe87ecd
chore: lint 적용
hae-on Apr 26, 2024
e70d98b
refactor: memberModifyInput 스타일 마이그레이션 및 수정
hae-on Apr 26, 2024
021eace
refactor: 레이아웃 변경
hae-on Apr 26, 2024
61a99ad
refactor: memberModifyPage 디자인 마이그레이션 및 수정
hae-on Apr 26, 2024
e3df96a
chore: 주석 추가
hae-on Apr 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified 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.
3 changes: 2 additions & 1 deletion src/components/Common/SectionHeader/SectionHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ interface SectionHeaderProps {
const SectionHeader = ({ name, link, state }: SectionHeaderProps) => {
return (
<div className={container}>
{/* Heading 컴포넌트로 교체 weight bold */}
<h1 className={title}>{name}</h1>
{link && (
<Link to={link} state={state}>
<SvgIcon variant="arrowRight" width={20} height={20} />
<SvgIcon variant="arrowRight" width={20} height={20} style={{ transform: 'translateY(2px)' }} />
Copy link
Contributor

Choose a reason for hiding this comment

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

오 👍

</Link>
)}
</div>
Expand Down
1 change: 0 additions & 1 deletion src/components/Common/SectionHeader/sectionHeader.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { style } from '@vanilla-extract/css';
export const container = style({
display: 'flex',
justifyContent: 'space-between',
padding: '0 20px',
});

export const title = style({
Expand Down
17 changes: 17 additions & 0 deletions src/components/Common/StarRating/StarRating.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { Meta, StoryObj } from '@storybook/react';

import StarRating from './StarRating';

const meta: Meta<typeof StarRating> = {
title: 'common/StarRating',
component: StarRating,
args: {
rating: 4.5,
createdAt: '2021-09-01T00:00:00.000Z',
},
};

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

export const Default: Story = {};
37 changes: 37 additions & 0 deletions src/components/Common/StarRating/StarRating.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { date, ratingInfo, ratingNumber, ratingWrapper } from './starRating.css';
import SvgIcon from '../Svg/SvgIcon';
import Text from '../Text/Text';

import { vars } from '@/styles/theme.css';
import { getRelativeDate } from '@/utils/date';

interface StarRatingProps {
rating: number;
createdAt: string;
}

const StarRating = ({ rating, createdAt }: StarRatingProps) => {
return (
<div className={ratingWrapper}>
<div className={ratingInfo}>
<Text as="span" size="caption3" weight="medium" className={ratingNumber}>
{rating.toFixed(1)}
</Text>
{Array.from({ length: 5 }, (_, index) => (
<SvgIcon
key={`rating-${index}`}
variant="star2"
fill={index < rating ? vars.colors.icon.fill : vars.colors.icon.light}
width={13}
height={13}
/>
))}
</div>
<Text as="span" size="caption4" color="disabled" className={date}>
{getRelativeDate(createdAt)}
</Text>
</div>
);
};

export default StarRating;
23 changes: 23 additions & 0 deletions src/components/Common/StarRating/starRating.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { vars } from '@/styles/theme.css';
import { style } from '@vanilla-extract/css';

export const ratingWrapper = style({
display: 'flex',
alignItems: 'center',
gap: 8,
});

export const ratingInfo = style({
display: 'flex',
alignItems: 'center',
gap: 4,
});

export const ratingNumber = style({
paddingTop: 4,
color: vars.colors.gray5,
});

export const date = style({
paddingTop: 2,
});
9 changes: 7 additions & 2 deletions src/components/Common/TopBar/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import LogoImage from '@/assets/logo.svg';
import { PATH } from '@/constants/path';
import { vars } from '@/styles/theme.css';


interface TopBarProps {
children?: React.ReactNode;
title?: string;
Expand All @@ -31,7 +30,13 @@ const Logo = () => {
const BackLink = ({ state }: TopBarProps) => {
return (
<Link to=".." relative="path" state={state}>
<SvgIcon variant="arrowLeft" stroke={vars.colors.gray5} width={20} height={20} />
<SvgIcon
variant="arrowLeft"
stroke={vars.colors.gray5}
width={20}
height={20}
style={{ transform: 'translateY(2px)' }}
/>
</Link>
);
};
Expand Down
1 change: 0 additions & 1 deletion src/components/Common/TopBar/topBar.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export const container = style({
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: '0 20px',
backgroundColor: vars.colors.white,
transform: 'translateX(-50%)',
zIndex: 1001,
Expand Down
2 changes: 2 additions & 0 deletions src/components/Common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ export { default as PageHeader } from './PageHeader/PageHeader';
export { default as Badge } from './Badge/Badge';
export { default as WriteButton } from './WriteButton/WriteButton';
export { default as Text } from './Text/Text';
export { default as TopBar } from './TopBar/TopBar';
export { default as StarRating } from './StarRating/StarRating';
22 changes: 6 additions & 16 deletions src/components/Members/MemberImage/MemberImage.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,32 @@
import { useState } from 'react';
import type { CSSProp } from 'styled-components';
import styled from 'styled-components';

import { container } from './memberImage.css';

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 MemberImage = ({ src, width = 48, height = 48 }: MemberImageProps) => {
const [isError, setIsError] = useState(false);

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

return (
<StyledMemberImage
<img
className={container}
src={isError ? DefaultMemberImage : src}
alt={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};
`;
6 changes: 6 additions & 0 deletions src/components/Members/MemberImage/memberImage.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { style } from '@vanilla-extract/css';

export const container = style({
borderRadius: '50%',
objectFit: 'cover',
});
91 changes: 23 additions & 68 deletions src/components/Members/MemberRecipeList/MemberRecipeList.tsx
Original file line number Diff line number Diff line change
@@ -1,90 +1,45 @@
import { Link, Spacing, Text, theme } from '@fun-eat/design-system';
import { useRef } from 'react';
import { Link as RouterLink } from 'react-router-dom';
import styled from 'styled-components';

import { PATH } from '@/constants/path';
import { useIntersectionObserver } from '@/hooks/common';
import { useInfiniteMemberRecipeQuery } from '@/hooks/queries/members';
import useDisplaySlice from '@/utils/displaySlice';
import { DefaultRecipeItem } from '@/components/Recipe';
import { container } from './memberRecipeList.css';

interface MemberRecipeListProps {
isPreview?: boolean;
}

const MemberRecipeList = ({ isPreview = false }: MemberRecipeListProps) => {
const MemberRecipeList = () => {
const scrollRef = useRef<HTMLDivElement>(null);

const { fetchNextPage, hasNextPage, data } = useInfiniteMemberRecipeQuery();
const memberRecipes = data?.pages.flatMap((page) => page.recipes);
const recipeToDisplay = useDisplaySlice(isPreview, memberRecipes);

useIntersectionObserver<HTMLDivElement>(fetchNextPage, scrollRef, hasNextPage);

const totalRecipeCount = data?.pages[0].page.totalDataCount;

if (totalRecipeCount === 0) {
return (
<ErrorContainer>
<Text size="lg" weight="bold">
앗, 작성한 꿀조합이 없네요 🥲
</Text>
<Spacing size={16} />
<RecipeLink as={RouterLink} to={`${PATH.RECIPE}`} block>
꿀조합 작성하러 가기
</RecipeLink>
</ErrorContainer>
);
}
// 추후 디자인 추가에 따라 변경 예정
// if (totalRecipeCount === 0) {
// return (
// <ErrorContainer>
// <Text size="lg" weight="bold">
// 앗, 작성한 꿀조합이 없네요 🥲
// </Text>
// <Spacing size={16} />
// <RecipeLink as={RouterLink} to={`${PATH.RECIPE}`} block>
// 꿀조합 작성하러 가기
// </RecipeLink>
// </ErrorContainer>
// );
// }

return (
<MemberRecipeListContainer>
{!isPreview && (
<TotalRecipeCount color={theme.colors.gray4}>
총 <strong>{totalRecipeCount}</strong>개의 꿀조합을 남겼어요!
</TotalRecipeCount>
)}
<Spacing size={20} />
<MemberRecipeListWrapper>
{recipeToDisplay?.map((recipe) => (
<>
<ul className={container}>
{memberRecipes.map((recipe) => (
<li key={recipe.id}>
<Link as={RouterLink} to={`${PATH.RECIPE}/${recipe.id}`}>
{/* <RecipeItem recipe={recipe} isMemberPage={isPreview} /> */}
</Link>
<DefaultRecipeItem recipe={recipe} />
</li>
))}
</MemberRecipeListWrapper>
</ul>
<div ref={scrollRef} aria-hidden />
</MemberRecipeListContainer>
</>
);
};

export default MemberRecipeList;

const MemberRecipeListContainer = styled.section`
display: flex;
flex-direction: column;
`;

const MemberRecipeListWrapper = styled.ul`
display: flex;
flex-direction: column;
gap: 20px;
`;

const TotalRecipeCount = styled(Text)`
text-align: right;
`;

const ErrorContainer = styled.div`
display: flex;
flex-direction: column;
align-items: center;
margin-top: 20px;
`;

const RecipeLink = styled(Link)`
padding: 12px 12px;
border: 1px solid ${({ theme }) => theme.colors.gray4};
border-radius: 8px;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { style } from '@vanilla-extract/css';

export const container = style({
display: 'grid',
gridTemplateColumns: 'repeat(2, 1fr)',
gridAutoRows: 'auto',
columnGap: 10,
rowGap: 20,
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,27 @@ const meta: Meta<typeof MemberReviewItem> = {
args: {
review: {
reviewId: 1,
productId: 5,
productName: '구운감자슬림명란마요',
productId: 1,
productName: '새우깡',
image:
'https://i.namu.wiki/i/9wnvUaEa1EkDqG-M0Pbwfdf19FJQQXV_-bnlU2SYaNcG05y2wbabiIrfrGES1M4xSgDjY39RwOvLNggDd3Huuw.webp',
content:
'할머니가 먹을 거 같은 맛입니다. 1960년 전쟁 때 맛 보고 싶었는데 그때는 너무 가난해서 먹을 수 없었는데요 이것보다 긴 리뷰도 잘려 보인답니다',
rating: 4.0,
favoriteCount: 1256,
categoryType: 'food',
createdAt: '2023-08-09T10:10:10',
tags: [
{
id: 5,
name: '단짠단짠',
tagType: 'TASTE',
},
{
id: 1,
name: '망고망고',
tagType: 'TASTE',
},
],
},
isPreview: true,
},
};

Expand Down
Loading
Loading