From cfa3c1c2764aaf0cd60e81ce7f59b9b6180a4823 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 26 Dec 2023 02:02:13 +0900 Subject: [PATCH 01/67] modify useGetMemberProfileQuery and add initialData --- src/apis/member/data.ts | 10 ++++++++++ src/apis/member/queries.ts | 14 ++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/apis/member/data.ts b/src/apis/member/data.ts index 23228f64..3a3ca95d 100644 --- a/src/apis/member/data.ts +++ b/src/apis/member/data.ts @@ -8,3 +8,13 @@ export const initialMyProfile = { reviewCount: 0, likeProductCount: 0 } + +export const initialMemberProfile = { + id: 0, + nickname: '', + profileImageUrl: '', + offerLevel: 0, + sellingProductCount: 0, + soldProductCount: 0, + reviewCount: 0 +} diff --git a/src/apis/member/queries.ts b/src/apis/member/queries.ts index 68621d57..13668357 100644 --- a/src/apis/member/queries.ts +++ b/src/apis/member/queries.ts @@ -1,6 +1,10 @@ -import { useQuery, useSuspenseQuery } from '@tanstack/react-query' +import { useQuery } from '@tanstack/react-query' import { getMemberProfile, getMyProfile } from './apis' -import { initialMyProfile } from './data' +import { initialMemberProfile, initialMyProfile } from './data' + +export type ProfileQueryResult = + | ReturnType + | ReturnType export const useGetMyProfileQuery = (accessToken?: string) => useQuery({ @@ -11,7 +15,9 @@ export const useGetMyProfileQuery = (accessToken?: string) => }) export const useGetMemberProfileQuery = (memberId = '') => - useSuspenseQuery({ + useQuery({ queryKey: ['memberProfile', memberId], - queryFn: () => getMemberProfile(Number(memberId)) + queryFn: () => getMemberProfile(Number(memberId)), + enabled: Boolean(memberId), + initialData: initialMemberProfile }) From 0b17bcd2ea5be678b9bf65f68f0f764706f6188c Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 26 Dec 2023 02:03:15 +0900 Subject: [PATCH 02/67] fix updateTradeStatus request type --- src/apis/post/types.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/apis/post/types.ts b/src/apis/post/types.ts index 7146837c..07bc7cf5 100644 --- a/src/apis/post/types.ts +++ b/src/apis/post/types.ts @@ -3,8 +3,7 @@ import type { OptionShape, PostDetail, PostSummaries, - SortOptionsShape, - TradeStatusType + SortOptionsShape } from '@types' export type GetPostRes = PostDetail @@ -30,10 +29,9 @@ export type DeletePostRes = { // TODO: 정확한 타입 BE 확인 필요 } -// TODO: 정확한 타입 BE 확인 필요 export type UpdateTradeStatusReq = { postId: number - request: TradeStatusType + tradeStatus: string } export type UpdateTradeStatusRes = number From 20aefd95cb2fec0e6f2d42cb08439c5e3bc78117 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 26 Dec 2023 02:05:01 +0900 Subject: [PATCH 03/67] update post summary scheme and apply modified scheme to ReviewButton component --- .../shop/Post/BuyTabPost/BuyTabPost.stories.tsx | 3 ++- src/components/shop/Post/SaleTabPost/index.tsx | 10 ++++------ src/components/shop/Post/SaleTabPost/styled.ts | 6 +++--- .../PostList/BuyTabPostList/BuyTabPostList.stories.tsx | 3 ++- src/types/scheme.ts | 1 + 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/components/shop/Post/BuyTabPost/BuyTabPost.stories.tsx b/src/components/shop/Post/BuyTabPost/BuyTabPost.stories.tsx index a775d529..d499b2c5 100644 --- a/src/components/shop/Post/BuyTabPost/BuyTabPost.stories.tsx +++ b/src/components/shop/Post/BuyTabPost/BuyTabPost.stories.tsx @@ -23,7 +23,8 @@ export const Primary: StoryObj = { liked: true, tradeStatus: 'SELLING', likeCount: 0, - createdAt: '' + createdAt: '', + hasReview: false }, render: args => { const post = args as OfferSummary diff --git a/src/components/shop/Post/SaleTabPost/index.tsx b/src/components/shop/Post/SaleTabPost/index.tsx index 81d16f61..d7aba2a4 100644 --- a/src/components/shop/Post/SaleTabPost/index.tsx +++ b/src/components/shop/Post/SaleTabPost/index.tsx @@ -18,7 +18,8 @@ const SaleTabPost = (props: SaleTabPostProps): ReactElement => { likeCount, createdAt, hasToken, - onChangeTradeStatus + onChangeTradeStatus, + hasReview } = props const isSoldOut = tradeStatus === 'SOLD' @@ -28,9 +29,6 @@ const SaleTabPost = (props: SaleTabPostProps): ReactElement => { onChangeTradeStatus?.(id, item) } - // Sample Value - const isReviewed = false - return ( @@ -64,10 +62,10 @@ const SaleTabPost = (props: SaleTabPostProps): ReactElement => { {hasToken && isSoldOut && ( - {isReviewed ? '보낸 후기 보기' : '후기 보내기'} + {hasReview ? '보낸 후기 보기' : '후기 보내기'} )} diff --git a/src/components/shop/Post/SaleTabPost/styled.ts b/src/components/shop/Post/SaleTabPost/styled.ts index d8aa07ce..65e00276 100644 --- a/src/components/shop/Post/SaleTabPost/styled.ts +++ b/src/components/shop/Post/SaleTabPost/styled.ts @@ -160,9 +160,9 @@ const ReviewButtonWrapper = styled.div` } `} ` -const ReviewButton = styled(Button)<{ isReviewed: boolean }>` - ${({ theme, isReviewed }): string => ` - color: ${isReviewed ? theme.colors.grayScale70 : theme.colors.brandPrimary}; +const ReviewButton = styled(Button)<{ hasReview: boolean }>` + ${({ theme, hasReview }): string => ` + color: ${hasReview ? theme.colors.grayScale70 : theme.colors.brandPrimary}; margin-right: 20px; ${theme.mediaQuery.tablet} { diff --git a/src/components/shop/PostList/BuyTabPostList/BuyTabPostList.stories.tsx b/src/components/shop/PostList/BuyTabPostList/BuyTabPostList.stories.tsx index 34a5209d..325b57c3 100644 --- a/src/components/shop/PostList/BuyTabPostList/BuyTabPostList.stories.tsx +++ b/src/components/shop/PostList/BuyTabPostList/BuyTabPostList.stories.tsx @@ -25,7 +25,8 @@ const posts: PostSummary[] = Array.from({ length: 10 }, () => 0).map( liked: true, tradeStatus: 'SELLING', likeCount: 0, - createdAt: '' + createdAt: '', + hasReview: false }) ) diff --git a/src/types/scheme.ts b/src/types/scheme.ts index d6a21fa3..5c3cf6d6 100644 --- a/src/types/scheme.ts +++ b/src/types/scheme.ts @@ -38,6 +38,7 @@ export type PostSummary = { tradeStatus: TradeStatusCodes likeCount: number createdAt: string + hasReview: boolean } export type PostSummaries = { posts: PostSummary[] From 9d4eb9b7eaeda7bf80efc7d3435d54b0666b538d Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 26 Dec 2023 02:06:18 +0900 Subject: [PATCH 04/67] fix not sync user isLogin and isSuccess --- src/hooks/useAuth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts index 976bbe21..46bbbd3f 100644 --- a/src/hooks/useAuth.ts +++ b/src/hooks/useAuth.ts @@ -8,7 +8,7 @@ export const useAuth = () => { const router = useRouter() const accessToken = getCookie(env.AUTH_TOKEN_KEY) const user = useGetMyProfileQuery(accessToken) - const [isLogin, setIsLogin] = useState(false) + const [isLogin, setIsLogin] = useState(user.isSuccess) const handleLogout = () => { deleteCookie(env.AUTH_TOKEN_KEY) From 39984f41d5074274eb71a52741a5204b646913b5 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 26 Dec 2023 02:06:49 +0900 Subject: [PATCH 05/67] remove unnecessary hook --- src/hooks/index.ts | 1 - src/hooks/useProfile.ts | 18 ------------------ 2 files changed, 19 deletions(-) delete mode 100644 src/hooks/useProfile.ts diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 0bbe63da..e106687c 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -1,4 +1,3 @@ export * from './useResponsive' export * from './useAuth' export * from './useModal' -export * from './useProfile' diff --git a/src/hooks/useProfile.ts b/src/hooks/useProfile.ts deleted file mode 100644 index 10fcdd73..00000000 --- a/src/hooks/useProfile.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { getCookie } from 'cookies-next' -import { useGetMyProfileQuery, useGetMemberProfileQuery } from '@apis' -import type { GetMyProfileRes, GetMemberProfileRes } from '@apis' -import { env } from '@constants' - -type UseProfileReturns = { profile: GetMyProfileRes | GetMemberProfileRes } - -export const useProfile = (memberId = ''): UseProfileReturns => { - const token = getCookie(env.AUTH_TOKEN_KEY) - - const myProfile = useGetMyProfileQuery(token) - const memberProfile = useGetMemberProfileQuery(memberId) - - const isMyProfile = myProfile && memberId === String(myProfile.data?.id) - const profile = isMyProfile ? myProfile.data : memberProfile.data - - return { profile } -} From 42ce732d1828c5a4e600f638f506db96d31efd65 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 26 Dec 2023 02:08:16 +0900 Subject: [PATCH 06/67] add updatePostTradeStatus api and query --- src/apis/post/apis.ts | 14 +++++++++++++- src/apis/post/queries.ts | 25 ++++++++++++++++++------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/apis/post/apis.ts b/src/apis/post/apis.ts index 0cb086a1..c6878218 100644 --- a/src/apis/post/apis.ts +++ b/src/apis/post/apis.ts @@ -1,4 +1,10 @@ -import type { GetCategoriesRes, GetPostsReq, GetPostsRes } from './types' +import type { + GetCategoriesRes, + GetPostsReq, + GetPostsRes, + UpdateTradeStatusReq, + UpdateTradeStatusRes +} from './types' import { http } from '@utils/http' export const getCategories = () => @@ -6,3 +12,9 @@ export const getCategories = () => export const getPosts = (params: GetPostsReq) => http.get('/posts', params) + +export const updatePostTradeStatus = (params: UpdateTradeStatusReq) => + http.put( + `/posts/trade-status/${params.postId}`, + params + ) diff --git a/src/apis/post/queries.ts b/src/apis/post/queries.ts index 213b50b8..09dd0b90 100644 --- a/src/apis/post/queries.ts +++ b/src/apis/post/queries.ts @@ -1,6 +1,12 @@ -import { useInfiniteQuery, useQuery } from '@tanstack/react-query' -import { getCategories, getPosts } from './apis' -import type { GetPostsReq, GetPostsRes } from './types' +import type { DefaultError } from '@tanstack/react-query' +import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/react-query' +import { getCategories, getPosts, updatePostTradeStatus } from './apis' +import type { + GetPostsReq, + GetPostsRes, + UpdateTradeStatusReq, + UpdateTradeStatusRes +} from './types' export const useGetCategoriesQuery = () => useQuery({ @@ -8,15 +14,15 @@ export const useGetCategoriesQuery = () => queryFn: getCategories }) -export const useGetPostsQuery = (params: GetPostsReq) => +export const useGetPostsQuery = (searchOptions: GetPostsReq) => useQuery({ - queryKey: ['getPosts'], - queryFn: () => getPosts(params) + queryKey: ['posts', searchOptions], + queryFn: () => getPosts(searchOptions) }) export const useGetInfinitePostsQuery = (params: GetPostsReq) => useInfiniteQuery({ - queryKey: ['getPosts'], + queryKey: ['infinitePosts'], queryFn: () => getPosts(params), initialPageParam: null, getNextPageParam: lastPage => @@ -24,3 +30,8 @@ export const useGetInfinitePostsQuery = (params: GetPostsReq) => ? lastPage.posts[lastPage.posts.length - 1].id : undefined }) + +export const usePostTradeStatusMutation = () => + useMutation({ + mutationFn: params => updatePostTradeStatus(params) + }) From 3dc4b2419d3c2912b15a6ed9c648a6287cefaaeb Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 26 Dec 2023 02:08:41 +0900 Subject: [PATCH 07/67] apply mediaquery on profilebox --- src/components/shop/ProfileBox/index.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/shop/ProfileBox/index.tsx b/src/components/shop/ProfileBox/index.tsx index a963e1ca..55830ab6 100644 --- a/src/components/shop/ProfileBox/index.tsx +++ b/src/components/shop/ProfileBox/index.tsx @@ -1,4 +1,4 @@ -import { Badge, Text, Icon } from '@offer-ui/react' +import { Badge, Text, Icon, useMedia } from '@offer-ui/react' import type { ReactElement } from 'react' import { Styled } from './styled' import type { ProfileBoxProps } from './types' @@ -13,6 +13,8 @@ const ProfileBox = ({ soldProductCount, className }: ProfileBoxProps): ReactElement => { + const { desktop } = useMedia() + return ( @@ -20,7 +22,11 @@ const ProfileBox = ({ - + {nickname} Lv.{offerLevel} From 73fe177352c9704114fd42f16563e375b8beb10f Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 26 Dec 2023 02:09:33 +0900 Subject: [PATCH 08/67] replace import path to alias --- src/pages/shop/view/buy/styled.ts | 2 +- src/pages/shop/view/review/styled.ts | 2 +- src/pages/shop/view/sale/styled.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/shop/view/buy/styled.ts b/src/pages/shop/view/buy/styled.ts index 599a038f..b92be3d6 100644 --- a/src/pages/shop/view/buy/styled.ts +++ b/src/pages/shop/view/buy/styled.ts @@ -1,7 +1,7 @@ import styled from '@emotion/styled' import type { ColorKeys } from '@offer-ui/react' import { Divider as DividerComponent } from '@offer-ui/react' -import { Tabs, Tab as TabComponent } from '@components/common' +import { Tabs, Tab as TabComponent } from '@components' const SearchOptionsWrapper = styled.div` ${({ theme }): string => ` diff --git a/src/pages/shop/view/review/styled.ts b/src/pages/shop/view/review/styled.ts index acd7f726..7c0fea9c 100644 --- a/src/pages/shop/view/review/styled.ts +++ b/src/pages/shop/view/review/styled.ts @@ -1,7 +1,7 @@ import styled from '@emotion/styled' import type { ColorKeys } from '@offer-ui/react' import { Divider as DividerComponent } from '@offer-ui/react' -import { Tabs, Tab as TabComponent } from '@components/common' +import { Tabs, Tab as TabComponent } from '@components' const SearchOptionsWrapper = styled.div` ${({ theme }): string => ` diff --git a/src/pages/shop/view/sale/styled.ts b/src/pages/shop/view/sale/styled.ts index 599a038f..b92be3d6 100644 --- a/src/pages/shop/view/sale/styled.ts +++ b/src/pages/shop/view/sale/styled.ts @@ -1,7 +1,7 @@ import styled from '@emotion/styled' import type { ColorKeys } from '@offer-ui/react' import { Divider as DividerComponent } from '@offer-ui/react' -import { Tabs, Tab as TabComponent } from '@components/common' +import { Tabs, Tab as TabComponent } from '@components' const SearchOptionsWrapper = styled.div` ${({ theme }): string => ` From a9858cbaa216a5815bc4b0ee1422f9e1b7533807 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 26 Dec 2023 02:10:51 +0900 Subject: [PATCH 09/67] modify shop main page some props --- src/pages/shop/[id].tsx | 6 +++--- src/pages/shop/index.tsx | 9 ++++++--- src/pages/shop/view/main/index.tsx | 18 +++++++++++------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/pages/shop/[id].tsx b/src/pages/shop/[id].tsx index bf9095b1..24291277 100644 --- a/src/pages/shop/[id].tsx +++ b/src/pages/shop/[id].tsx @@ -1,7 +1,7 @@ import type { GetServerSidePropsContext } from 'next' import type { ReactElement } from 'react' import { ShopPageMainView } from './view/main' -import { useProfile } from '@hooks' +import { useGetMemberProfileQuery } from '@apis/member' export const getServerSideProps = (context: GetServerSidePropsContext) => { return { @@ -15,9 +15,9 @@ type ShopPageProps = { memberId: string } const ShopPage = ({ memberId }: ShopPageProps): ReactElement => { - const { profile } = useProfile(memberId) + const memberProfile = useGetMemberProfileQuery(memberId) - return + return } export default ShopPage diff --git a/src/pages/shop/index.tsx b/src/pages/shop/index.tsx index 5e83d435..d1f222c4 100644 --- a/src/pages/shop/index.tsx +++ b/src/pages/shop/index.tsx @@ -1,10 +1,13 @@ +import { getCookie } from 'cookies-next' import { ShopPageMainView } from './view/main' -import { useAuth } from '@hooks/useAuth' +import { useGetMyProfileQuery } from '@apis/member' +import { env } from '@constants' const MyShopPage = () => { - const { user } = useAuth() + const accessToken = getCookie(env.AUTH_TOKEN_KEY) + const myProfile = useGetMyProfileQuery(accessToken) - return + return } export default MyShopPage diff --git a/src/pages/shop/view/main/index.tsx b/src/pages/shop/view/main/index.tsx index e4d878fe..2cfbe185 100644 --- a/src/pages/shop/view/main/index.tsx +++ b/src/pages/shop/view/main/index.tsx @@ -3,17 +3,21 @@ import type { MouseEvent } from 'react' import { useState } from 'react' import { Styled } from './styled' import { pageTabs } from '../../pageTabs' +import type { ProfileQueryResult } from '@apis' import { ProfileBox, Tabs } from '@components' -import type { MyProfile, MemberProfile } from '@types' type ShopPageMainViewProps = { - profile: MyProfile | MemberProfile + hasToken: boolean + profile: ProfileQueryResult } -export const ShopPageMainView = ({ profile }: ShopPageMainViewProps) => { +export const ShopPageMainView = ({ + profile, + hasToken +}: ShopPageMainViewProps) => { const [pageIndex, setPageIndex] = useState(0) const handleTabClick = ( - e: MouseEvent, + _: MouseEvent, index: number ): void => { setPageIndex(index) @@ -21,7 +25,7 @@ export const ShopPageMainView = ({ profile }: ShopPageMainViewProps) => { return (
- {profile.nickname}님의 거래 활동 + {profile.data.nickname}님의 거래 활동 @@ -42,8 +46,8 @@ export const ShopPageMainView = ({ profile }: ShopPageMainViewProps) => { {pageTabs.map(({ tab, panel }) => ( - - {panel({ memberId: profile.id })} + + {panel({ profile, hasToken })} ))} From a207a377cae133429d6ecd98d453c0ae6ddc06f7 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 26 Dec 2023 02:11:58 +0900 Subject: [PATCH 10/67] implement shop page - sale api --- src/pages/shop/view/sale/index.tsx | 94 +++++++++++++++++------------- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/src/pages/shop/view/sale/index.tsx b/src/pages/shop/view/sale/index.tsx index d7e0e755..61b1c230 100644 --- a/src/pages/shop/view/sale/index.tsx +++ b/src/pages/shop/view/sale/index.tsx @@ -2,34 +2,46 @@ import { SelectBox } from '@offer-ui/react' import type { ReactElement } from 'react' import { useState } from 'react' import { Styled } from './styled' -import type { GetPostsReq } from '@apis/post' -import { useGetPostsQuery } from '@apis/post' -import { Tabs } from '@components/common' -import { SaleTabPostList } from '@components/shop/PostList' +import type { GetPostsReq, ProfileQueryResult } from '@apis' +import { usePostTradeStatusMutation, useGetPostsQuery } from '@apis' +import type { SaleTabPostProps } from '@components' +import { Tabs, SaleTabPostList } from '@components' import { SORT_OPTIONS, TRADE_STATUS } from '@constants' -import type { TradeStatusCodes } from '@types' -import { noop } from '@utils' +import type { SortOption } from '@types' export type ShopPageSaleViewProps = { - memberId: number + hasToken: boolean + profile: ProfileQueryResult } export const ShopPageSaleView = ({ - memberId + hasToken, + profile }: ShopPageSaleViewProps): ReactElement => { - const hasToken = true - const [tradeStatusCode, setTradeStatusCode] = - useState('SELLING') + const [searchOptions, setSearchOptions] = useState({ + sellerId: profile.data.id, + tradeStatus: 'SELLING', + sort: 'CREATED_DATE_DESC' + }) - const searchOptions = { - sellerId: memberId, - tradeStatus: tradeStatusCode - } as GetPostsReq + const posts = useGetPostsQuery(searchOptions) + const postTradeStatus = usePostTradeStatusMutation() - const { data: postsInfo } = useGetPostsQuery(searchOptions) + const handleChangeSearchOptions = (newOption: GetPostsReq) => + setSearchOptions({ + ...searchOptions, + ...newOption + }) - const handleTabClick = (newTradeStatusCode: TradeStatusCodes) => () => { - setTradeStatusCode(newTradeStatusCode) - } + const handleChangeProductTradeStatus: SaleTabPostProps['onChangeTradeStatus'] = + async (postId, tradeStatus) => { + await postTradeStatus.mutateAsync({ + postId, + tradeStatus: tradeStatus.code + }) + + await posts.refetch() + profile.refetch() + } return (
@@ -39,12 +51,16 @@ export const ShopPageSaleView = ({ {TRADE_STATUS.map(tradeStatus => { - const isCurrent = tradeStatus.code === tradeStatusCode + const isCurrent = tradeStatus.code === searchOptions.tradeStatus return ( + onClick={() => + handleChangeSearchOptions({ + tradeStatus: tradeStatus.code + }) + }> @@ -53,8 +69,9 @@ export const ShopPageSaleView = ({ - {/* MEMO: 거래 상태 갯수 */} - {postsInfo?.posts.length} + {tradeStatus.code === 'SELLING' + ? profile.data.sellingProductCount + : profile.data.soldProductCount} @@ -64,27 +81,22 @@ export const ShopPageSaleView = ({ + handleChangeSearchOptions({ sort: option.code }) + } /> - - - - - - + {TRADE_STATUS.map(tradeStatus => ( + + + + ))} From 60c06b34deb185776e757f5d7c9187d4b93afe8f Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 28 Dec 2023 19:05:36 +0900 Subject: [PATCH 11/67] implement my liked posts in shop page --- src/apis/like/apis.ts | 9 ++- src/apis/like/index.ts | 1 + src/apis/like/queries.ts | 11 ++- .../Post/BuyTabPost/likeTabPanel/index.tsx | 40 ++++----- src/pages/shop/pageTabs.ts | 3 +- src/pages/shop/view/buy/index.tsx | 81 +++++++++---------- src/pages/shop/view/buy/types.ts | 6 -- 7 files changed, 74 insertions(+), 77 deletions(-) delete mode 100644 src/pages/shop/view/buy/types.ts diff --git a/src/apis/like/apis.ts b/src/apis/like/apis.ts index 3c05fd82..85f54553 100644 --- a/src/apis/like/apis.ts +++ b/src/apis/like/apis.ts @@ -1,5 +1,12 @@ -import type { UpdateLikeStatusReq } from './types' +import type { + GetLikedPostsReq, + GetLikedPostsRes, + UpdateLikeStatusReq +} from './types' import { http } from '@utils/http' export const updateLikeStatus = (postId: number) => http.put('/posts/likes', { postId }) + +export const getLikedPosts = (params: GetLikedPostsReq) => + http.get('/posts/likes', params) diff --git a/src/apis/like/index.ts b/src/apis/like/index.ts index d2186f10..7fece7cc 100644 --- a/src/apis/like/index.ts +++ b/src/apis/like/index.ts @@ -1,2 +1,3 @@ export * from './types' +export * from './apis' export * from './queries' diff --git a/src/apis/like/queries.ts b/src/apis/like/queries.ts index fe236e0e..3a73118e 100644 --- a/src/apis/like/queries.ts +++ b/src/apis/like/queries.ts @@ -1,5 +1,12 @@ -import { useMutation } from '@tanstack/react-query' -import { updateLikeStatus } from './apis' +import { useQuery, useMutation } from '@tanstack/react-query' +import { getLikedPosts, updateLikeStatus } from './apis' +import type { GetLikedPostsReq } from './types' + +export const useGetLikedPostsQuery = (searchOptions: GetLikedPostsReq) => + useQuery({ + queryKey: ['likedPosts', searchOptions], + queryFn: () => getLikedPosts(searchOptions) + }) export const useUpdateLikeStatusMutation = () => useMutation({ diff --git a/src/components/shop/Post/BuyTabPost/likeTabPanel/index.tsx b/src/components/shop/Post/BuyTabPost/likeTabPanel/index.tsx index 2ec7d77c..fe27499b 100644 --- a/src/components/shop/Post/BuyTabPost/likeTabPanel/index.tsx +++ b/src/components/shop/Post/BuyTabPost/likeTabPanel/index.tsx @@ -1,25 +1,19 @@ import type { ReactElement } from 'react' import type { LikeTabPanelProps } from './types' import { Styled } from '../styled' -import { toLocaleCurrency } from '@utils' - -const LikeTabPanel = (props: LikeTabPanelProps): ReactElement => { - const { - className, - // sellerNickName, - id: postId, - thumbnailImageUrl, - title = '', - // startPrice, - tradeStatus, - createdAt, - likeCount - } = props - - // TODO: API Scheme 변경 필요 - const sellerNickName = '' - const startPrice = 0 +import { toLocaleCurrency, getTimeDiffText } from '@utils' +const LikeTabPanel = ({ + className, + seller, + id: postId, + thumbnailImageUrl, + title = '', + price, + tradeStatus, + createdAt, + likeCount +}: LikeTabPanelProps): ReactElement => { return ( @@ -29,17 +23,17 @@ const LikeTabPanel = (props: LikeTabPanelProps): ReactElement => { /> - {sellerNickName} + {seller.nickname} {title} - - 시작가: {startPrice ? toLocaleCurrency(startPrice) : ''}원 - + 시작가: {toLocaleCurrency(price)}원 {tradeStatus.name} - {createdAt} + + {getTimeDiffText(createdAt)} + diff --git a/src/pages/shop/pageTabs.ts b/src/pages/shop/pageTabs.ts index 2e59a8b1..d5c2e691 100644 --- a/src/pages/shop/pageTabs.ts +++ b/src/pages/shop/pageTabs.ts @@ -1,5 +1,4 @@ import type { ReactElement } from 'react' -import type { ShopPageBuyViewProps } from './view/buy' import { ShopPageBuyView } from './view/buy' import type { ShopPageReviewViewProps } from './view/review' import { ShopPageReviewView } from './view/review' @@ -28,7 +27,7 @@ export const pageTabs: PageTab[] = [ code: 'buy', name: '구매' }, - panel: (props: ShopPageBuyViewProps) => ShopPageBuyView(props) + panel: ShopPageBuyView }, { tab: { diff --git a/src/pages/shop/view/buy/index.tsx b/src/pages/shop/view/buy/index.tsx index 6977ec22..58204809 100644 --- a/src/pages/shop/view/buy/index.tsx +++ b/src/pages/shop/view/buy/index.tsx @@ -1,42 +1,43 @@ import { SelectBox } from '@offer-ui/react' -import type { ReactElement, MouseEvent } from 'react' +import type { ReactElement } from 'react' import { useState } from 'react' import { Styled } from './styled' -import { sortItems } from './types' +import { useGetLikedPostsQuery } from '@apis/like' +import { useGetMyOffersQuery } from '@apis/offer' import { Tabs } from '@components/common' import { BuyTabPostList } from '@components/shop/PostList' -import { TRADE_ACTIVITY_TYPES } from '@constants' -import type { TradeBuyActivityCodes, TradeBuyActivityNames } from '@types' -import { noop } from '@utils' +import { TRADE_ACTIVITY_TYPES, SORT_OPTIONS } from '@constants' +import type { + SortOption, + SortOptionCodes, + TradeBuyActivityCodes, + TradeBuyActivityNames +} from '@types' const tradeBuyActivityList = Object.entries< TradeBuyActivityCodes, TradeBuyActivityNames >(TRADE_ACTIVITY_TYPES.buy) -const getArticles = () => { - return [] -} - -export type ShopPageBuyViewProps = { - memberId: number -} - -export const ShopPageBuyView = ({ - memberId -}: ShopPageBuyViewProps): ReactElement => { - const [tabIndex, setTabIndex] = useState(0) - const [articles] = useState(getArticles()) +export const ShopPageBuyView = (): ReactElement => { + const [sortOptionCode, setSortOptionCode] = + useState('CREATED_DATE_DESC') + const [activityType, setActivityType] = + useState('like') - // eslint-disable-next-line no-console - console.log(memberId) + const offers = useGetMyOffersQuery({ sort: sortOptionCode }) + const likedPosts = useGetLikedPostsQuery({ + sort: sortOptionCode, + lastId: 0, + limit: 100 + }) - const handleTabClick = ( - e: MouseEvent, - index: number - ): void => { - setTabIndex(index) + const handleChangeSortOption = (newSortOption: SortOption) => { + setSortOptionCode(newSortOption.code) } + const handleChangeActivityType = + (newActivityType: TradeBuyActivityCodes) => (): void => + setActivityType(newActivityType) return (
@@ -45,19 +46,17 @@ export const ShopPageBuyView = ({ - {tradeBuyActivityList.map((tradeBuyActivity, index) => { - const isCurrent = tabIndex === index + {tradeBuyActivityList.map(([code, name]) => { + const isCurrent = code === activityType return ( + key={`${code}-tab`} + onClick={handleChangeActivityType(code)}> - - {tradeBuyActivity[1]} - + {name} 1 @@ -67,26 +66,22 @@ export const ShopPageBuyView = ({ diff --git a/src/pages/shop/view/buy/types.ts b/src/pages/shop/view/buy/types.ts deleted file mode 100644 index 60574f5c..00000000 --- a/src/pages/shop/view/buy/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const sortItems = [ - { - code: 'recently', - name: '최신순' - } -] From dfb2c9195a690b0258ab24564b5bb2b5577da704 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 28 Dec 2023 19:07:26 +0900 Subject: [PATCH 12/67] remove unnecessary search option on getting liked posts --- src/apis/like/types.ts | 4 ++-- src/pages/shop/view/buy/index.tsx | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/apis/like/types.ts b/src/apis/like/types.ts index 737aeb96..05ce8f37 100644 --- a/src/apis/like/types.ts +++ b/src/apis/like/types.ts @@ -2,8 +2,8 @@ import type { PostSummaries } from '@types' export type GetLikedPostsReq = { sort: string - lastId: number - limit: number + lastId?: number + limit?: number } export type GetLikedPostsRes = PostSummaries diff --git a/src/pages/shop/view/buy/index.tsx b/src/pages/shop/view/buy/index.tsx index 58204809..1e5d44ea 100644 --- a/src/pages/shop/view/buy/index.tsx +++ b/src/pages/shop/view/buy/index.tsx @@ -26,11 +26,7 @@ export const ShopPageBuyView = (): ReactElement => { useState('like') const offers = useGetMyOffersQuery({ sort: sortOptionCode }) - const likedPosts = useGetLikedPostsQuery({ - sort: sortOptionCode, - lastId: 0, - limit: 100 - }) + const likedPosts = useGetLikedPostsQuery({ sort: sortOptionCode }) const handleChangeSortOption = (newSortOption: SortOption) => { setSortOptionCode(newSortOption.code) From 481ef4f10419358ec91646b6964391b5a8cb120a Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 28 Dec 2023 19:08:13 +0900 Subject: [PATCH 13/67] apply getTimeDiffText util on shop > sale --- src/components/shop/Post/SaleTabPost/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/shop/Post/SaleTabPost/index.tsx b/src/components/shop/Post/SaleTabPost/index.tsx index f4ed3577..fda9e5fc 100644 --- a/src/components/shop/Post/SaleTabPost/index.tsx +++ b/src/components/shop/Post/SaleTabPost/index.tsx @@ -5,7 +5,7 @@ import { Styled } from './styled' import type { SaleTabPostProps } from './types' import { TRADE_STATUS } from '@constants' import type { TradeStatusType } from '@types' -import { toLocaleCurrency } from '@utils' +import { toLocaleCurrency, getTimeDiffText } from '@utils' const SaleTabPost = (props: SaleTabPostProps): ReactElement => { const { @@ -54,7 +54,7 @@ const SaleTabPost = (props: SaleTabPostProps): ReactElement => { {likeCount} - {createdAt} + {getTimeDiffText(createdAt)} From bdee1d13de73a0f56aa1e61582ec23287f6ef0f3 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 28 Dec 2023 19:08:52 +0900 Subject: [PATCH 14/67] fix layout of shop page user name --- src/pages/shop/view/main/styled.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/pages/shop/view/main/styled.tsx b/src/pages/shop/view/main/styled.tsx index 62442481..c7529735 100644 --- a/src/pages/shop/view/main/styled.tsx +++ b/src/pages/shop/view/main/styled.tsx @@ -12,11 +12,7 @@ const UserName = styled.p` ${theme.mediaQuery.tablet} { ${theme.fonts.body01B}; - margin: 16px auto; - } - - ${theme.mediaQuery.mobile} { - margin-left: 16px; + margin: 16px; } `} ` From 8fd1f8e4783139e5aaf3bf1683764753644230ea Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 28 Dec 2023 19:37:39 +0900 Subject: [PATCH 15/67] apply offers and liked posts length --- src/pages/shop/view/buy/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pages/shop/view/buy/index.tsx b/src/pages/shop/view/buy/index.tsx index 1e5d44ea..2aed546b 100644 --- a/src/pages/shop/view/buy/index.tsx +++ b/src/pages/shop/view/buy/index.tsx @@ -54,7 +54,11 @@ export const ShopPageBuyView = (): ReactElement => { {name} - 1 + + {code === 'like' + ? likedPosts.data?.posts.length + : offers.data?.offers.length} + ) From 3d3fb9a95ecd7cd4f508564e37dd8483de2ee42e Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 28 Dec 2023 22:29:47 +0900 Subject: [PATCH 16/67] fix calling always memberId 0's posts --- src/apis/post/queries.ts | 3 ++- src/pages/shop/view/sale/index.tsx | 26 ++++++++++++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/apis/post/queries.ts b/src/apis/post/queries.ts index c70a6b8e..d4961d9d 100644 --- a/src/apis/post/queries.ts +++ b/src/apis/post/queries.ts @@ -35,7 +35,8 @@ export const useGetCategoriesQuery = () => export const useGetPostsQuery = (searchOptions: GetPostsReq) => useQuery({ queryKey: ['posts', searchOptions], - queryFn: () => getPosts(searchOptions) + queryFn: () => getPosts(searchOptions), + enabled: typeof searchOptions.sellerId === 'number' }) export const useGetInfinitePostsQuery = (params: GetPostsReq) => diff --git a/src/pages/shop/view/sale/index.tsx b/src/pages/shop/view/sale/index.tsx index 61b1c230..6bf230d2 100644 --- a/src/pages/shop/view/sale/index.tsx +++ b/src/pages/shop/view/sale/index.tsx @@ -1,6 +1,6 @@ import { SelectBox } from '@offer-ui/react' import type { ReactElement } from 'react' -import { useState } from 'react' +import { useEffect, useState, useCallback } from 'react' import { Styled } from './styled' import type { GetPostsReq, ProfileQueryResult } from '@apis' import { usePostTradeStatusMutation, useGetPostsQuery } from '@apis' @@ -18,7 +18,7 @@ export const ShopPageSaleView = ({ profile }: ShopPageSaleViewProps): ReactElement => { const [searchOptions, setSearchOptions] = useState({ - sellerId: profile.data.id, + sellerId: profile.data.nickname ? profile.data.id : undefined, tradeStatus: 'SELLING', sort: 'CREATED_DATE_DESC' }) @@ -26,12 +26,15 @@ export const ShopPageSaleView = ({ const posts = useGetPostsQuery(searchOptions) const postTradeStatus = usePostTradeStatusMutation() - const handleChangeSearchOptions = (newOption: GetPostsReq) => - setSearchOptions({ - ...searchOptions, - ...newOption - }) - + const handleChangeSearchOptions = useCallback( + (newOption: GetPostsReq) => { + setSearchOptions({ + ...searchOptions, + ...newOption + }) + }, + [searchOptions] + ) const handleChangeProductTradeStatus: SaleTabPostProps['onChangeTradeStatus'] = async (postId, tradeStatus) => { await postTradeStatus.mutateAsync({ @@ -43,6 +46,13 @@ export const ShopPageSaleView = ({ profile.refetch() } + useEffect( + function fetchProfileOnMount() { + handleChangeSearchOptions({ sellerId: profile.data.id }) + }, + [handleChangeSearchOptions, profile.data.id] + ) + return (
From 9b9a69396d1230e89beb80e83b3de46d4945d594 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 28 Dec 2023 22:42:30 +0900 Subject: [PATCH 17/67] fix profileBox layout when other profile --- src/components/shop/ProfileBox/index.tsx | 15 +++--- src/components/shop/ProfileBox/styled.ts | 60 ++++++++++++++++++++---- src/components/shop/ProfileBox/types.ts | 1 + src/pages/shop/view/main/index.tsx | 36 +++++++------- 4 files changed, 81 insertions(+), 31 deletions(-) diff --git a/src/components/shop/ProfileBox/index.tsx b/src/components/shop/ProfileBox/index.tsx index 55830ab6..fcaf3e57 100644 --- a/src/components/shop/ProfileBox/index.tsx +++ b/src/components/shop/ProfileBox/index.tsx @@ -6,12 +6,13 @@ import type { ProfileBoxProps } from './types' const ProfileBox = ({ nickname, profileImageUrl, - likeProductCount, + likeProductCount = 0, offerLevel, reviewCount, sellingProductCount, soldProductCount, - className + className, + hasToken }: ProfileBoxProps): ReactElement => { const { desktop } = useMedia() @@ -32,29 +33,29 @@ const ProfileBox = ({ Lv.{offerLevel} - - + + 판매중 {sellingProductCount}개 - + 거래완료 {soldProductCount}개 - + 거래후기 {reviewCount}개 - + 관심상품 diff --git a/src/components/shop/ProfileBox/styled.ts b/src/components/shop/ProfileBox/styled.ts index de98971b..81ac4c6c 100644 --- a/src/components/shop/ProfileBox/styled.ts +++ b/src/components/shop/ProfileBox/styled.ts @@ -1,3 +1,4 @@ +import type { Theme } from '@emotion/react' import styled from '@emotion/styled' import { Avatar as AvatarComponent } from '@offer-ui/react' @@ -103,15 +104,20 @@ const NickName = styled.span` } `} ` -const UserProductWrapper = styled.div` - ${({ theme }): string => ` +const UserProductWrapper = styled.div<{ hasToken: boolean }>` + ${({ theme, hasToken }): string => ` display: grid; background-color: ${theme.colors.bgGray01}; gap: 16px; padding: 16px 20px; ${theme.mediaQuery.tablet} { - grid-template-columns: 1fr 1fr 1fr 1fr; + ${ + hasToken + ? 'grid-template-columns: 1fr 1fr 1fr 1fr;' + : 'grid-template-areas: ". sell sold review .";' + } + gap: 93px; padding: 24px 40px; min-width: 684px; @@ -119,14 +125,54 @@ const UserProductWrapper = styled.div` ${theme.mediaQuery.mobile} { grid-template-columns: 1fr 1fr; + grid-template-areas: none; gap: 44px; min-width: 300px; padding: 20px 36px; } `} ` -const UserProductRow = styled.div` - ${({ theme }): string => ` + +const setStyleByToken = (theme: Theme, hasToken: boolean) => { + if (hasToken) { + return ` + ${theme.mediaQuery.mobile} { + min-width: 90px; + } + ` + } + + return ` + :nth-of-type(1) { + grid-area: sold; + } + :nth-of-type(2) { + grid-area: sell; + } + :nth-of-type(3) { + grid-area: review; + } + :nth-of-type(4) { + display: none; + } + + ${theme.mediaQuery.mobile} { + min-width: 90px; + :nth-of-type(1) { + grid-area: auto; + } + :nth-of-type(2) { + grid-area: auto; + } + :nth-of-type(3) { + grid-area: auto; + } + } + } + ` +} +const UserProductRow = styled.div<{ hasToken: boolean }>` + ${({ theme, hasToken }) => ` display: flex; align-items: center; justify-content: space-between; @@ -135,9 +181,7 @@ const UserProductRow = styled.div` min-width: 85px; } - ${theme.mediaQuery.mobile} { - min-width: 90px; - } + ${setStyleByToken(theme, hasToken)} `} ` const UserProductTitleWrapper = styled.p` diff --git a/src/components/shop/ProfileBox/types.ts b/src/components/shop/ProfileBox/types.ts index e132d18b..b0778965 100644 --- a/src/components/shop/ProfileBox/types.ts +++ b/src/components/shop/ProfileBox/types.ts @@ -3,4 +3,5 @@ import type { MyProfile } from '@types' export type ProfileBoxProps = { className?: string likeProductCount?: number + hasToken: boolean } & Omit diff --git a/src/pages/shop/view/main/index.tsx b/src/pages/shop/view/main/index.tsx index 2cfbe185..26a54071 100644 --- a/src/pages/shop/view/main/index.tsx +++ b/src/pages/shop/view/main/index.tsx @@ -30,27 +30,31 @@ export const ShopPageMainView = ({ - {pageTabs.map(({ tab }, index) => ( - - {tab.name} - - ))} + {pageTabs + .filter(pageTab => (hasToken ? true : pageTab.tab.code !== 'buy')) + .map(({ tab }, index) => ( + + {tab.name} + + ))} - {pageTabs.map(({ tab, panel }) => ( - - - - {panel({ profile, hasToken })} - - - ))} + {pageTabs + .filter(pageTab => (hasToken ? true : pageTab.tab.code !== 'buy')) + .map(({ tab, panel }) => ( + + + + {panel({ profile, hasToken })} + + + ))} From b839d241d4fe1382b7e7b72c819dde34929f6b20 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 28 Dec 2023 22:58:19 +0900 Subject: [PATCH 18/67] implement shop page > buy - offer --- src/apis/offer/apis.ts | 5 +++++ src/apis/offer/index.ts | 1 + src/apis/offer/queries.ts | 10 +++++++-- src/apis/offer/types.ts | 4 ++-- .../Post/BuyTabPost/offerTabPanel/index.tsx | 22 ++++++++++--------- src/components/shop/Post/BuyTabPost/styled.ts | 6 ++--- 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/apis/offer/apis.ts b/src/apis/offer/apis.ts index 34ee66f9..cc440a5a 100644 --- a/src/apis/offer/apis.ts +++ b/src/apis/offer/apis.ts @@ -1,10 +1,15 @@ import type { + GetMyOffersReq, + GetMyOffersRes, GetPostOffersReq, CreateOfferReq, GetPostOffersRes } from './types' import { http } from '@utils/http' +export const getMyOffers = (params: GetMyOffersReq) => + http.get('/posts/offers', params) + export const getPostOffers = (params: GetPostOffersReq) => http.get( `/posts/${params.postId}/offers`, diff --git a/src/apis/offer/index.ts b/src/apis/offer/index.ts index d2186f10..7fece7cc 100644 --- a/src/apis/offer/index.ts +++ b/src/apis/offer/index.ts @@ -1,2 +1,3 @@ export * from './types' +export * from './apis' export * from './queries' diff --git a/src/apis/offer/queries.ts b/src/apis/offer/queries.ts index 60db6510..393771cc 100644 --- a/src/apis/offer/queries.ts +++ b/src/apis/offer/queries.ts @@ -1,6 +1,12 @@ import { useMutation, useQuery } from '@tanstack/react-query' -import { getPostOffers, createOffer } from './apis' -import type { CreateOfferReq, GetPostOffersReq } from './types' +import { getPostOffers, createOffer, getMyOffers } from './apis' +import type { CreateOfferReq, GetPostOffersReq, GetMyOffersReq } from './types' + +export const useGetMyOffersQuery = (searchOptions: GetMyOffersReq) => + useQuery({ + queryKey: ['myOffers', searchOptions], + queryFn: () => getMyOffers(searchOptions) + }) export const useGetPostOffersQuery = (params: GetPostOffersReq) => useQuery({ diff --git a/src/apis/offer/types.ts b/src/apis/offer/types.ts index 189cf928..556f85a0 100644 --- a/src/apis/offer/types.ts +++ b/src/apis/offer/types.ts @@ -21,7 +21,7 @@ export type CreateOfferRes = CommonCreation export type GetMyOffersReq = { sort: string - lastId: number - limit: number + lastId?: number + limit?: number } export type GetMyOffersRes = OfferSummaries diff --git a/src/components/shop/Post/BuyTabPost/offerTabPanel/index.tsx b/src/components/shop/Post/BuyTabPost/offerTabPanel/index.tsx index 792b4eff..d889eef3 100644 --- a/src/components/shop/Post/BuyTabPost/offerTabPanel/index.tsx +++ b/src/components/shop/Post/BuyTabPost/offerTabPanel/index.tsx @@ -1,25 +1,25 @@ import type { ReactElement } from 'react' import type { OfferTabPanelProps } from './types' import { Styled } from '../styled' -import { toLocaleCurrency } from '@utils' +import { toLocaleCurrency, getTimeDiffText } from '@utils' const OfferTabPanel = (props: OfferTabPanelProps): ReactElement => { const { className, - // sellerNickName, postId, thumbnailImageUrl, // title = '', offerPrice, tradeStatus, - createdAt - // isReviewed + createdAt, + hasReview } = props // TODO: API Scheme 변경 필요 - const sellerNickName = '' + const seller = { + nickName: '' + } const title = '' - const isReviewed = false return ( @@ -30,7 +30,7 @@ const OfferTabPanel = (props: OfferTabPanelProps): ReactElement => { /> - {sellerNickName} + {seller.nickName} {title} @@ -40,16 +40,18 @@ const OfferTabPanel = (props: OfferTabPanelProps): ReactElement => { {tradeStatus.name} - {createdAt} + + {getTimeDiffText(createdAt)} + - {isReviewed ? '보낸 후기 보기' : '후기 보내기'} + {hasReview ? '보낸 후기 보기' : '후기 보내기'} diff --git a/src/components/shop/Post/BuyTabPost/styled.ts b/src/components/shop/Post/BuyTabPost/styled.ts index da0a8601..ca9f8720 100644 --- a/src/components/shop/Post/BuyTabPost/styled.ts +++ b/src/components/shop/Post/BuyTabPost/styled.ts @@ -156,9 +156,9 @@ export const ReviewButtonWrapper = styled.div` } `} ` -export const ReviewButton = styled(Button)<{ isReviewed: boolean }>` - ${({ theme, isReviewed }): string => ` - color: ${isReviewed ? theme.colors.grayScale70 : theme.colors.brandPrimary}; +export const ReviewButton = styled(Button)<{ hasReview: boolean }>` + ${({ theme, hasReview }): string => ` + color: ${hasReview ? theme.colors.grayScale70 : theme.colors.brandPrimary}; margin-right: 20px; ${theme.mediaQuery.tablet} { From 986a284ca32186a2d6d575339dd9c63ef3ca48ec Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 28 Dec 2023 23:21:14 +0900 Subject: [PATCH 19/67] fix infinite rendering --- src/pages/shop/view/sale/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/shop/view/sale/index.tsx b/src/pages/shop/view/sale/index.tsx index 6bf230d2..05be7c50 100644 --- a/src/pages/shop/view/sale/index.tsx +++ b/src/pages/shop/view/sale/index.tsx @@ -50,7 +50,7 @@ export const ShopPageSaleView = ({ function fetchProfileOnMount() { handleChangeSearchOptions({ sellerId: profile.data.id }) }, - [handleChangeSearchOptions, profile.data.id] + [profile.data.id] ) return ( From 9ee1e65b989061b4e5ef1ab364a667e929951ace Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 28 Dec 2023 23:31:26 +0900 Subject: [PATCH 20/67] implement shop > review page --- src/apis/review/apis.ts | 5 ++ src/apis/review/index.ts | 2 + src/apis/review/queries.ts | 41 +++++++++++++ .../shop/Post/ReviewTabPost/index.tsx | 3 +- src/constants/app.ts | 6 +- src/pages/shop/view/review/index.tsx | 57 +++++++++---------- 6 files changed, 80 insertions(+), 34 deletions(-) create mode 100644 src/apis/review/apis.ts create mode 100644 src/apis/review/queries.ts diff --git a/src/apis/review/apis.ts b/src/apis/review/apis.ts new file mode 100644 index 00000000..7508bc12 --- /dev/null +++ b/src/apis/review/apis.ts @@ -0,0 +1,5 @@ +import type { GetReviewsReq, GetReviewsRes } from './types' +import { http } from '@utils/http' + +export const getReviews = (params: GetReviewsReq) => + http.get('/reviews', params) diff --git a/src/apis/review/index.ts b/src/apis/review/index.ts index c9f6f047..7fece7cc 100644 --- a/src/apis/review/index.ts +++ b/src/apis/review/index.ts @@ -1 +1,3 @@ export * from './types' +export * from './apis' +export * from './queries' diff --git a/src/apis/review/queries.ts b/src/apis/review/queries.ts new file mode 100644 index 00000000..ce4bca52 --- /dev/null +++ b/src/apis/review/queries.ts @@ -0,0 +1,41 @@ +import { useQuery } from '@tanstack/react-query' +// import { getReviews } from './apis' +import type { GetReviewsReq } from './types' +import type { ReviewInfo } from '@types' + +export const useGetReviewsQuery = (searchOptions: GetReviewsReq) => + useQuery({ + queryKey: ['reviews', searchOptions], + queryFn: () => { + const getMockScore = () => { + if (searchOptions.role === 'ALL') { + return 0 + } else if (searchOptions.role === 'SELLER') { + return 1 + } + + return 2 + } + + const mockData: ReviewInfo = [ + { + id: 0, + reviewer: { + id: 0, + profileImageUrl: 'string', + nickname: 'string' + }, + score: getMockScore(), + post: { + id: 0, + title: 'string' + }, + content: 'string', + createdDate: '2023-12-28T14:15:45.027Z' + } + ] + + return mockData + // getReviews(searchOptions) + } + }) diff --git a/src/components/shop/Post/ReviewTabPost/index.tsx b/src/components/shop/Post/ReviewTabPost/index.tsx index 33573050..82e19dbe 100644 --- a/src/components/shop/Post/ReviewTabPost/index.tsx +++ b/src/components/shop/Post/ReviewTabPost/index.tsx @@ -4,6 +4,7 @@ import React from 'react' import { Styled } from './styled' import type { ReviewTabPostProps } from './types' import { ICON_META } from './types' +import { getTimeDiffText } from '@utils/format' const ReviewTabPost = ({ reviewer, @@ -31,7 +32,7 @@ const ReviewTabPost = ({ - {createdDate} + {getTimeDiffText(createdDate)} diff --git a/src/constants/app.ts b/src/constants/app.ts index 40fff3d3..229ff9cf 100644 --- a/src/constants/app.ts +++ b/src/constants/app.ts @@ -63,9 +63,9 @@ export const TRADE_ACTIVITY_TYPES = { offer: '가격제안' }, review: { - all: '전체후기', - buyer: '구매자 후기', - seller: '판매자 후기' + ALL: '전체후기', + BUYER: '구매자 후기', + SELLER: '판매자 후기' } } as const diff --git a/src/pages/shop/view/review/index.tsx b/src/pages/shop/view/review/index.tsx index 754088cf..87c97a7e 100644 --- a/src/pages/shop/view/review/index.tsx +++ b/src/pages/shop/view/review/index.tsx @@ -1,8 +1,9 @@ -import type { ReactElement, MouseEvent } from 'react' +import type { ReactElement } from 'react' import { useState } from 'react' import { Styled } from './styled' -import { Tabs } from '@components/common' -import { ReviewTabPostList } from '@components/shop/PostList' +import type { ProfileQueryResult } from '@apis' +import { useGetReviewsQuery } from '@apis' +import { Tabs, ReviewTabPostList } from '@components' import { TRADE_ACTIVITY_TYPES } from '@constants' import type { TradeReviewActivityCodes, TradeReviewActivityNames } from '@types' @@ -11,29 +12,25 @@ const tradeReviewActivityList = Object.entries< TradeReviewActivityNames >(TRADE_ACTIVITY_TYPES.review) -const getReviews = () => { - return [] -} - export type ShopPageReviewViewProps = { - memberId: number + profile: ProfileQueryResult } export const ShopPageReviewView = ({ - memberId + profile }: ShopPageReviewViewProps): ReactElement => { - const [tabIndex, setTabIndex] = useState(0) - const [reviews] = useState(getReviews()) + const [reviewType, setReviewType] = useState('ALL') - // eslint-disable-next-line no-console - console.log(memberId) + const reviews = useGetReviewsQuery({ + memberId: profile.data.id, + page: 1, + role: reviewType + }) - const handleTabClick = ( - e: MouseEvent, - index: number - ): void => { - setTabIndex(index) - } + const handleChangeReviewType = + (newReviewType: TradeReviewActivityCodes) => () => { + setReviewType(newReviewType) + } return (
@@ -42,21 +39,21 @@ export const ShopPageReviewView = ({ - {tradeReviewActivityList.map((tradeReviewActivity, index) => { - const isCurrent = tabIndex === index + {tradeReviewActivityList.map(([code, name]) => { + const isCurrent = code === reviewType return ( + key={`${code}-tab`} + onClick={handleChangeReviewType(code)}> - - {tradeReviewActivity[1]} - + {name} - 1 + + {reviews.data?.length} + ) @@ -65,13 +62,13 @@ export const ShopPageReviewView = ({ - + - + - + From 17c72de90af3220cb7ebcc9b3d4e505a3ddcfd94 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 28 Dec 2023 23:42:04 +0900 Subject: [PATCH 21/67] apply changed get reviews api dto --- src/pages/shop/view/review/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/shop/view/review/index.tsx b/src/pages/shop/view/review/index.tsx index 87c97a7e..e9bb62e3 100644 --- a/src/pages/shop/view/review/index.tsx +++ b/src/pages/shop/view/review/index.tsx @@ -23,7 +23,8 @@ export const ShopPageReviewView = ({ const reviews = useGetReviewsQuery({ memberId: profile.data.id, - page: 1, + lastId: 0, + limit: 100, role: reviewType }) From 9e669dc7ce09c831932a2eadeb7b0f43ad73d838 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 28 Dec 2023 23:46:53 +0900 Subject: [PATCH 22/67] fix layout of profile box --- src/components/shop/ProfileBox/styled.ts | 34 +++++++++++++++++------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/components/shop/ProfileBox/styled.ts b/src/components/shop/ProfileBox/styled.ts index 81ac4c6c..bc7a82da 100644 --- a/src/components/shop/ProfileBox/styled.ts +++ b/src/components/shop/ProfileBox/styled.ts @@ -143,17 +143,31 @@ const setStyleByToken = (theme: Theme, hasToken: boolean) => { } return ` - :nth-of-type(1) { - grid-area: sold; - } - :nth-of-type(2) { - grid-area: sell; - } - :nth-of-type(3) { - grid-area: review; + ${theme.mediaQuery.desktop} { + :nth-of-type(1) { + grid-area: auto; + } + :nth-of-type(2) { + grid-area: auto; + } + :nth-of-type(3) { + grid-area: auto; + } } - :nth-of-type(4) { - display: none; + + ${theme.mediaQuery.tablet} { + :nth-of-type(1) { + grid-area: sold; + } + :nth-of-type(2) { + grid-area: sell; + } + :nth-of-type(3) { + grid-area: review; + } + :nth-of-type(4) { + display: none; + } } ${theme.mediaQuery.mobile} { From a6aabededfc3209db74625f02a09c2238c118482 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 28 Dec 2023 23:51:40 +0900 Subject: [PATCH 23/67] remove setting button and last product row when other profile --- src/components/shop/ProfileBox/index.tsx | 24 ++++++++++++++---------- src/components/shop/ProfileBox/styled.ts | 19 ++++--------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/components/shop/ProfileBox/index.tsx b/src/components/shop/ProfileBox/index.tsx index fcaf3e57..aa01ccf3 100644 --- a/src/components/shop/ProfileBox/index.tsx +++ b/src/components/shop/ProfileBox/index.tsx @@ -18,9 +18,11 @@ const ProfileBox = ({ return ( - - - + {hasToken && ( + + + + )} {reviewCount}개 - - - - 관심상품 - - {likeProductCount}개 - + {hasToken && ( + + + + 관심상품 + + {likeProductCount}개 + + )} diff --git a/src/components/shop/ProfileBox/styled.ts b/src/components/shop/ProfileBox/styled.ts index bc7a82da..79f64ad5 100644 --- a/src/components/shop/ProfileBox/styled.ts +++ b/src/components/shop/ProfileBox/styled.ts @@ -144,12 +144,8 @@ const setStyleByToken = (theme: Theme, hasToken: boolean) => { return ` ${theme.mediaQuery.desktop} { - :nth-of-type(1) { - grid-area: auto; - } - :nth-of-type(2) { - grid-area: auto; - } + :nth-of-type(1), + :nth-of-type(2), :nth-of-type(3) { grid-area: auto; } @@ -165,19 +161,12 @@ const setStyleByToken = (theme: Theme, hasToken: boolean) => { :nth-of-type(3) { grid-area: review; } - :nth-of-type(4) { - display: none; - } } ${theme.mediaQuery.mobile} { min-width: 90px; - :nth-of-type(1) { - grid-area: auto; - } - :nth-of-type(2) { - grid-area: auto; - } + :nth-of-type(1), + :nth-of-type(2), :nth-of-type(3) { grid-area: auto; } From bbd7cb4d83dac9fe55ae75f58e1bc002ecba3696 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 29 Dec 2023 13:33:26 +0900 Subject: [PATCH 24/67] implement mutate like status in shop page --- src/components/shop/Post/BuyTabPost/index.tsx | 9 ++++++++- .../shop/Post/BuyTabPost/likeTabPanel/index.tsx | 13 +++++++++++-- .../shop/Post/BuyTabPost/likeTabPanel/types.ts | 5 ++++- src/components/shop/Post/BuyTabPost/types.ts | 2 ++ .../BuyTabPostList/BuyTabPostList.stories.tsx | 11 ++++++++++- .../shop/PostList/BuyTabPostList/index.tsx | 13 +++++++++++-- .../shop/PostList/BuyTabPostList/types.ts | 2 ++ src/pages/shop/view/buy/index.tsx | 17 +++++++++++++---- 8 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/components/shop/Post/BuyTabPost/index.tsx b/src/components/shop/Post/BuyTabPost/index.tsx index 349ed6fd..0c3407a6 100644 --- a/src/components/shop/Post/BuyTabPost/index.tsx +++ b/src/components/shop/Post/BuyTabPost/index.tsx @@ -9,7 +9,14 @@ const BuyTabPost = (props: BuyTabPostProps): ReactElement => { return ( <> - {isOfferType ? : } + {isOfferType ? ( + + ) : ( + + )} ) } diff --git a/src/components/shop/Post/BuyTabPost/likeTabPanel/index.tsx b/src/components/shop/Post/BuyTabPost/likeTabPanel/index.tsx index fe27499b..f95f41f8 100644 --- a/src/components/shop/Post/BuyTabPost/likeTabPanel/index.tsx +++ b/src/components/shop/Post/BuyTabPost/likeTabPanel/index.tsx @@ -12,8 +12,13 @@ const LikeTabPanel = ({ price, tradeStatus, createdAt, - likeCount + likeCount, + onChangeLikeStatus }: LikeTabPanelProps): ReactElement => { + const handleChangeLikeStatus = () => { + onChangeLikeStatus(postId) + } + return ( @@ -37,7 +42,11 @@ const LikeTabPanel = ({ - + 관심 {likeCount} diff --git a/src/components/shop/Post/BuyTabPost/likeTabPanel/types.ts b/src/components/shop/Post/BuyTabPost/likeTabPanel/types.ts index d4e96ed3..0b45caf3 100644 --- a/src/components/shop/Post/BuyTabPost/likeTabPanel/types.ts +++ b/src/components/shop/Post/BuyTabPost/likeTabPanel/types.ts @@ -1,3 +1,6 @@ import type { PostSummary } from '@types' -export type LikeTabPanelProps = PostSummary & { className?: string } +export type LikeTabPanelProps = PostSummary & { + className?: string + onChangeLikeStatus(postId: number): void +} diff --git a/src/components/shop/Post/BuyTabPost/types.ts b/src/components/shop/Post/BuyTabPost/types.ts index 73bfff7e..bd535fce 100644 --- a/src/components/shop/Post/BuyTabPost/types.ts +++ b/src/components/shop/Post/BuyTabPost/types.ts @@ -1,3 +1,4 @@ +import type { LikeTabPanelProps } from './likeTabPanel' import type { OfferSummary, PostSummary, TradeBuyActivityCodes } from '@types' export type BuyTabPostProps = { className?: string } & ( @@ -7,6 +8,7 @@ export type BuyTabPostProps = { className?: string } & ( export type LikeActivityProps = { activityType: Extract + onChangeProductLikeStatus: LikeTabPanelProps['onChangeLikeStatus'] } & PostSummary export type OfferActivityProps = { activityType: Extract diff --git a/src/components/shop/PostList/BuyTabPostList/BuyTabPostList.stories.tsx b/src/components/shop/PostList/BuyTabPostList/BuyTabPostList.stories.tsx index 87d37b86..7f882dcb 100644 --- a/src/components/shop/PostList/BuyTabPostList/BuyTabPostList.stories.tsx +++ b/src/components/shop/PostList/BuyTabPostList/BuyTabPostList.stories.tsx @@ -1,4 +1,5 @@ import { Text } from '@offer-ui/react' +import { action } from '@storybook/addon-actions' import type { Meta, StoryObj } from '@storybook/react' import { useState } from 'react' import { BuyTabPostList as BuyTabPostListComponent } from './index' @@ -18,6 +19,10 @@ const PrimaryWithHooks = () => { const [activityType, setActivityType] = useState('offer') + const handleChangeLikeStatus = (postId: number) => { + action('change like status')(postId) + } + return ( <>
- + ) } diff --git a/src/components/shop/PostList/BuyTabPostList/index.tsx b/src/components/shop/PostList/BuyTabPostList/index.tsx index dcff7690..44fdbdfe 100644 --- a/src/components/shop/PostList/BuyTabPostList/index.tsx +++ b/src/components/shop/PostList/BuyTabPostList/index.tsx @@ -1,10 +1,13 @@ import { Divider } from '@offer-ui/react' import type { ReactElement } from 'react' import { Fragment } from 'react' -import type { BuyTabPostListProps, PostType } from './types' +import type { BuyTabPostListProps, LikePostListProps, PostType } from './types' import { BuyTabPost } from '@components/shop/Post' import type { OfferSummary } from '@types' +import { noop } from '@utils' +const isLikedProps = (props: BuyTabPostListProps): props is LikePostListProps => + props.activityType === 'like' const isOfferPost = (post: PostType): post is OfferSummary => 'postId' in post const BuyTabPostList = (props: BuyTabPostListProps): ReactElement => { @@ -18,7 +21,13 @@ const BuyTabPostList = (props: BuyTabPostListProps): ReactElement => { {isOfferPost(post) ? ( ) : ( - + )} {index !== props.posts.length - 1 && } diff --git a/src/components/shop/PostList/BuyTabPostList/types.ts b/src/components/shop/PostList/BuyTabPostList/types.ts index 5a5d6701..d33700c3 100644 --- a/src/components/shop/PostList/BuyTabPostList/types.ts +++ b/src/components/shop/PostList/BuyTabPostList/types.ts @@ -1,3 +1,4 @@ +import type { LikeActivityProps } from '@components/shop/Post/BuyTabPost/types' import type { OfferSummary, PostSummary, TradeBuyActivityCodes } from '@types' export type BuyTabPostListProps = { @@ -7,6 +8,7 @@ export type BuyTabPostListProps = { export type LikePostListProps = { activityType: Extract posts: PostSummary[] + onChangeProductLikeStatus: LikeActivityProps['onChangeProductLikeStatus'] } export type OfferPostListProps = { diff --git a/src/pages/shop/view/buy/index.tsx b/src/pages/shop/view/buy/index.tsx index 2aed546b..e4f454bf 100644 --- a/src/pages/shop/view/buy/index.tsx +++ b/src/pages/shop/view/buy/index.tsx @@ -2,10 +2,12 @@ import { SelectBox } from '@offer-ui/react' import type { ReactElement } from 'react' import { useState } from 'react' import { Styled } from './styled' -import { useGetLikedPostsQuery } from '@apis/like' -import { useGetMyOffersQuery } from '@apis/offer' -import { Tabs } from '@components/common' -import { BuyTabPostList } from '@components/shop/PostList' +import { + useGetMyOffersQuery, + useGetLikedPostsQuery, + useUpdateLikeStatusMutation +} from '@apis' +import { Tabs, BuyTabPostList } from '@components' import { TRADE_ACTIVITY_TYPES, SORT_OPTIONS } from '@constants' import type { SortOption, @@ -27,6 +29,7 @@ export const ShopPageBuyView = (): ReactElement => { const offers = useGetMyOffersQuery({ sort: sortOptionCode }) const likedPosts = useGetLikedPostsQuery({ sort: sortOptionCode }) + const likeStatusMutation = useUpdateLikeStatusMutation() const handleChangeSortOption = (newSortOption: SortOption) => { setSortOptionCode(newSortOption.code) @@ -35,6 +38,11 @@ export const ShopPageBuyView = (): ReactElement => { (newActivityType: TradeBuyActivityCodes) => (): void => setActivityType(newActivityType) + const handleChangeProductLikeStatus = async (postId: number) => { + await likeStatusMutation.mutateAsync(postId) + likedPosts.refetch() + } + return (
@@ -76,6 +84,7 @@ export const ShopPageBuyView = (): ReactElement => { From cf803af61ed5c3c7deda587ef37e4340b119c3b9 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Thu, 4 Jan 2024 02:37:59 +0900 Subject: [PATCH 25/67] implement valid number util --- src/utils/index.ts | 1 + src/utils/valid/index.ts | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 src/utils/valid/index.ts diff --git a/src/utils/index.ts b/src/utils/index.ts index ff2d2bdb..1c338e3d 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,3 +1,4 @@ export * from './common' export * from './react' export * from './format' +export * from './valid' diff --git a/src/utils/valid/index.ts b/src/utils/valid/index.ts new file mode 100644 index 00000000..b71c36c2 --- /dev/null +++ b/src/utils/valid/index.ts @@ -0,0 +1,2 @@ +export const isNumber = (num: unknown): num is number => + !isNaN(num as number) && isFinite(num as number) && typeof num === 'number' From bf3cb55f060329f7c68c3158868f1279d9d154ce Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 00:49:11 +0900 Subject: [PATCH 26/67] implement review apis and queries --- src/apis/review/apis.ts | 10 +++++- src/apis/review/data.ts | 10 ++++++ src/apis/review/queries.ts | 70 ++++++++++++++++++++------------------ 3 files changed, 55 insertions(+), 35 deletions(-) create mode 100644 src/apis/review/data.ts diff --git a/src/apis/review/apis.ts b/src/apis/review/apis.ts index 7508bc12..3063380d 100644 --- a/src/apis/review/apis.ts +++ b/src/apis/review/apis.ts @@ -1,5 +1,13 @@ -import type { GetReviewsReq, GetReviewsRes } from './types' +import type { + GetReviewsReq, + GetReviewsRes, + CreateReviewReq, + CreateReviewRes +} from './types' import { http } from '@utils/http' export const getReviews = (params: GetReviewsReq) => http.get('/reviews', params) + +export const createReviews = (payload: CreateReviewReq) => + http.post('/reviews', payload) diff --git a/src/apis/review/data.ts b/src/apis/review/data.ts new file mode 100644 index 00000000..012df75d --- /dev/null +++ b/src/apis/review/data.ts @@ -0,0 +1,10 @@ +export const initialAllReviewLengths = { + ALL: 0, + SELLER: 0, + BUYER: 0 +} + +export const initialReviews = { + hasNext: false, + reviews: [] +} diff --git a/src/apis/review/queries.ts b/src/apis/review/queries.ts index ce4bca52..d4289c32 100644 --- a/src/apis/review/queries.ts +++ b/src/apis/review/queries.ts @@ -1,41 +1,43 @@ -import { useQuery } from '@tanstack/react-query' -// import { getReviews } from './apis' -import type { GetReviewsReq } from './types' -import type { ReviewInfo } from '@types' +import type { DefaultError } from '@tanstack/react-query' +import { useMutation, useQuery } from '@tanstack/react-query' +import { createReviews, getReviews } from './apis' +import { initialAllReviewLengths, initialReviews } from './data' +import type { CreateReviewReq, CreateReviewRes, GetReviewsReq } from './types' -export const useGetReviewsQuery = (searchOptions: GetReviewsReq) => +// 리뷰 갯수 조회 api 임시 대체 +export const useGetReviewsLengthQuery = (memberId: number) => useQuery({ - queryKey: ['reviews', searchOptions], - queryFn: () => { - const getMockScore = () => { - if (searchOptions.role === 'ALL') { - return 0 - } else if (searchOptions.role === 'SELLER') { - return 1 - } + queryKey: ['allReviews', memberId], + queryFn: async () => { + const searchOptions = { + memberId, + lastId: 0, + limit: 100 + } - return 2 + const all = await getReviews({ ...searchOptions, role: 'ALL' }) + const buyer = await getReviews({ ...searchOptions, role: 'BUYER' }) + const seller = await getReviews({ ...searchOptions, role: 'SELLER' }) + + return { + ALL: all.reviews.length, + BUYER: buyer.reviews.length, + SELLER: seller.reviews.length } + }, + enabled: Boolean(memberId), + initialData: initialAllReviewLengths + }) - const mockData: ReviewInfo = [ - { - id: 0, - reviewer: { - id: 0, - profileImageUrl: 'string', - nickname: 'string' - }, - score: getMockScore(), - post: { - id: 0, - title: 'string' - }, - content: 'string', - createdDate: '2023-12-28T14:15:45.027Z' - } - ] +export const useGetReviewsQuery = (searchOptions: GetReviewsReq) => + useQuery({ + queryKey: ['reviews', searchOptions], + queryFn: async () => getReviews({ ...searchOptions }), + enabled: Boolean(searchOptions.memberId), + initialData: initialReviews + }) - return mockData - // getReviews(searchOptions) - } +export const useReviewsMutation = () => + useMutation({ + mutationFn: payload => createReviews(payload) }) From 7437cd2ab3aa4bb5ecafd5f16419c9001ceb1175 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 00:50:10 +0900 Subject: [PATCH 27/67] add useUpdateLikeStatusMutation types --- src/apis/like/queries.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/apis/like/queries.ts b/src/apis/like/queries.ts index 3a73118e..144ec72f 100644 --- a/src/apis/like/queries.ts +++ b/src/apis/like/queries.ts @@ -1,6 +1,7 @@ +import type { DefaultError } from '@tanstack/react-query' import { useQuery, useMutation } from '@tanstack/react-query' import { getLikedPosts, updateLikeStatus } from './apis' -import type { GetLikedPostsReq } from './types' +import type { GetLikedPostsReq, UpdateLikeStatusReq } from './types' export const useGetLikedPostsQuery = (searchOptions: GetLikedPostsReq) => useQuery({ @@ -9,6 +10,6 @@ export const useGetLikedPostsQuery = (searchOptions: GetLikedPostsReq) => }) export const useUpdateLikeStatusMutation = () => - useMutation({ - mutationFn: (postId: number) => updateLikeStatus(postId) + useMutation({ + mutationFn: ({ postId }) => updateLikeStatus(postId) }) From cc00e44905429feaedafdc19d0faf57fd7e0c099 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 00:53:32 +0900 Subject: [PATCH 28/67] refactor ReviewModal props and implement reset a writing review modal when close --- .../shop/ReviewModal/Read/index.tsx | 21 +++++++++----- src/components/shop/ReviewModal/Read/types.ts | 12 ++++---- .../ReviewModal/ReadReviewModal.stories.tsx | 2 +- .../shop/ReviewModal/Write/index.tsx | 28 +++++++++++++++---- .../shop/ReviewModal/Write/types.ts | 2 +- src/components/shop/ReviewModal/index.tsx | 14 ++++++---- src/components/shop/ReviewModal/styled.ts | 6 +++- src/components/shop/ReviewModal/types.ts | 6 ++-- 8 files changed, 61 insertions(+), 30 deletions(-) diff --git a/src/components/shop/ReviewModal/Read/index.tsx b/src/components/shop/ReviewModal/Read/index.tsx index 39d5959f..9695db16 100644 --- a/src/components/shop/ReviewModal/Read/index.tsx +++ b/src/components/shop/ReviewModal/Read/index.tsx @@ -1,24 +1,31 @@ import type { ReactElement } from 'react' import type { ReadReviewModalProps } from './types' -import { CommonTitleContainer, MOCK_SCORE } from '..' +import { CommonTitleContainer, SCORE_OPTIONS, SCORE_STATE } from '..' import { Styled } from '../styled' export const Read = ({ isOpen = true, onClose, onConfirm, - nickname = '닉네임', - productName = '상품이름', - score = 'smile', + reviewTargetMember, + score = 0, + post, content = '리뷰' }: ReadReviewModalProps): ReactElement => { + if (!reviewTargetMember) { + return <> + } + return ( - + - -

{MOCK_SCORE.find(scoreItem => scoreItem.state === score)?.text}

+ +

{SCORE_OPTIONS[score]?.text}

{content} diff --git a/src/components/shop/ReviewModal/Read/types.ts b/src/components/shop/ReviewModal/Read/types.ts index c57d6294..16cc7a2c 100644 --- a/src/components/shop/ReviewModal/Read/types.ts +++ b/src/components/shop/ReviewModal/Read/types.ts @@ -1,7 +1,7 @@ -import type { CommonReviewModalProps, Score } from '../types' +import type { CommonReviewModalProps } from '../types' +import type { Review } from '@types' -export type ReadReviewModalProps = CommonReviewModalProps & { - score: Score - content: string - onConfirm(): void -} +export type ReadReviewModalProps = Partial & + Review & { + onConfirm(): void + } diff --git a/src/components/shop/ReviewModal/ReadReviewModal.stories.tsx b/src/components/shop/ReviewModal/ReadReviewModal.stories.tsx index 254cab42..d90ecf96 100644 --- a/src/components/shop/ReviewModal/ReadReviewModal.stories.tsx +++ b/src/components/shop/ReviewModal/ReadReviewModal.stories.tsx @@ -30,7 +30,7 @@ export const Default: StoryObj = { nickname: '닉네임', productName: '상품이름', content: '리뷰', - score: 'smile' + score: 2 }, render: args => } diff --git a/src/components/shop/ReviewModal/Write/index.tsx b/src/components/shop/ReviewModal/Write/index.tsx index 8c9da4b9..127bbf74 100644 --- a/src/components/shop/ReviewModal/Write/index.tsx +++ b/src/components/shop/ReviewModal/Write/index.tsx @@ -1,9 +1,10 @@ import type { ChangeEventHandler, ReactElement } from 'react' -import { useState } from 'react' +import { useEffect, useState } from 'react' import type { WriteReviewModalProps, ReviewState } from './types' -import { CommonTitleContainer, MOCK_SCORE } from '..' +import { CommonTitleContainer, SCORE_OPTIONS, SCORE_STATE } from '..' import { Styled } from '../styled' import type { ScoreState } from '../types' +import { isNumber } from '@utils' export const Write = ({ isOpen = true, @@ -32,11 +33,25 @@ export const Write = ({ onConfirm(reviewState) } + useEffect( + function resetReviewState() { + if (isOpen) { + return + } + + setReviewState({ + reviewScore: null, + reviewText: '' + }) + }, + [isOpen] + ) + return ( - {MOCK_SCORE.map(scoreItem => { + {SCORE_OPTIONS.map(scoreItem => { return (

{scoreItem.text}

@@ -57,11 +72,12 @@ export const Write = ({ {'후기 보내기'} diff --git a/src/components/shop/ReviewModal/Write/types.ts b/src/components/shop/ReviewModal/Write/types.ts index 8b28ca63..e78e3ec2 100644 --- a/src/components/shop/ReviewModal/Write/types.ts +++ b/src/components/shop/ReviewModal/Write/types.ts @@ -1,6 +1,6 @@ import type { CommonReviewModalProps, ScoreState } from '../types' -export type WriteReviewModalProps = CommonReviewModalProps & { +export type WriteReviewModalProps = Partial & { onConfirm(state: ReviewState): void } diff --git a/src/components/shop/ReviewModal/index.tsx b/src/components/shop/ReviewModal/index.tsx index 6961d982..5e098874 100644 --- a/src/components/shop/ReviewModal/index.tsx +++ b/src/components/shop/ReviewModal/index.tsx @@ -1,20 +1,24 @@ +import type { IconType } from '@offer-ui/react' import type { ReactElement } from 'react' import { Read } from './Read' import { Styled } from './styled' -import type { CommonReviewModalProps, SCORE } from './types' +import type { CommonReviewModalProps, ScoreOptions } from './types' import { Write } from './Write' -export const MOCK_SCORE: SCORE = [ +type Score = Extract +export const SCORE_STATE: Score[] = ['sad', 'meh', 'smile'] + +export const SCORE_OPTIONS: ScoreOptions = [ { - state: 'smile', + state: 2, text: '좋아요' }, { - state: 'meh', + state: 1, text: '보통이에요' }, { - state: 'sad', + state: 0, text: '별로에요' } ] diff --git a/src/components/shop/ReviewModal/styled.ts b/src/components/shop/ReviewModal/styled.ts index 100de28b..af7a3508 100644 --- a/src/components/shop/ReviewModal/styled.ts +++ b/src/components/shop/ReviewModal/styled.ts @@ -93,12 +93,14 @@ const ReviewState = styled.button` display: flex; flex-direction: column; gap: 4px; - place-items: center center; border: none; background: none; + cursor: pointer; + place-items: center center; + * { color: ${({ isFill, theme }): string => isFill ? theme.colors.brandPrimary : theme.colors.grayScale30}; @@ -109,6 +111,8 @@ const ReviewState = styled.button` const ReviewIcon = styled(Icon)` width: 40px; height: 40px; + + cursor: pointer; ` const ReadModeReviewContent = styled.div` diff --git a/src/components/shop/ReviewModal/types.ts b/src/components/shop/ReviewModal/types.ts index 72883afc..432a61c8 100644 --- a/src/components/shop/ReviewModal/types.ts +++ b/src/components/shop/ReviewModal/types.ts @@ -1,6 +1,6 @@ -import type { ModalProps, IconType } from '@offer-ui/react' +import type { ModalProps } from '@offer-ui/react' -export type Score = Extract +export type Score = 0 | 1 | 2 export type ScoreState = Score | null @@ -9,7 +9,7 @@ export type CommonReviewModalProps = Pick & { productName: string } -export type SCORE = { +export type ScoreOptions = { state: Score text: string }[] From defb793a3fdff5b9265cb477cd56f5639b52dc13 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 00:54:24 +0900 Subject: [PATCH 29/67] fix type error when call useUpdateLikeStatusMutation --- src/components/post/PriceOfferCard/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/post/PriceOfferCard/index.tsx b/src/components/post/PriceOfferCard/index.tsx index f7b5c45e..b01a447d 100644 --- a/src/components/post/PriceOfferCard/index.tsx +++ b/src/components/post/PriceOfferCard/index.tsx @@ -65,7 +65,7 @@ const PriceOfferCard = ({ count: status ? count - 1 : count + 1 })) - await likeStatusMutation.mutateAsync(postId) + await likeStatusMutation.mutateAsync({ postId }) } const handleClickOffer = async ({ From 3140a8ea791b03f6ce98c4cc4b855d27459e4cbf Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 00:55:55 +0900 Subject: [PATCH 30/67] export the reviewModal components and types in barrel file --- src/components/shop/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/shop/index.ts b/src/components/shop/index.ts index d0cd9f5e..97f8b119 100644 --- a/src/components/shop/index.ts +++ b/src/components/shop/index.ts @@ -3,3 +3,6 @@ export * from './PostList' export * from './ProfileBox' export * from './SelectBuyerModal' export * from './EditProfileModal' +export * from './ReviewModal' +export * from './ReviewModal/Write/types' +export * from './ReviewModal/Read/types' From f0a86269740fd2805f4e8771b2b6771510cc6dad Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 00:57:30 +0900 Subject: [PATCH 31/67] implement shop/buy > offer page --- .../Post/BuyTabPost/BuyTabPost.stories.tsx | 8 ++- .../Post/BuyTabPost/offerTabPanel/index.tsx | 18 +++--- .../Post/BuyTabPost/offerTabPanel/types.ts | 6 +- src/components/shop/Post/BuyTabPost/types.ts | 3 + .../shop/PostList/BuyTabPostList/index.tsx | 47 ++++++++++----- .../shop/PostList/BuyTabPostList/types.ts | 9 ++- src/pages/shop/view/buy/index.tsx | 60 ++++++++++++++++++- 7 files changed, 121 insertions(+), 30 deletions(-) diff --git a/src/components/shop/Post/BuyTabPost/BuyTabPost.stories.tsx b/src/components/shop/Post/BuyTabPost/BuyTabPost.stories.tsx index 7e94a5f3..785ac7d6 100644 --- a/src/components/shop/Post/BuyTabPost/BuyTabPost.stories.tsx +++ b/src/components/shop/Post/BuyTabPost/BuyTabPost.stories.tsx @@ -2,6 +2,7 @@ import { Text } from '@offer-ui/react' import type { Meta, StoryObj } from '@storybook/react' import type { BuyTabPostProps } from './types' import { BuyTabPost as BuyTabPostComponent } from './index' +import { noop } from '@utils/common' import type { OfferSummary } from '@types' type BuyTabPost = typeof BuyTabPostComponent @@ -32,7 +33,12 @@ export const Primary: StoryObj = { return ( <> 가격제안 - + {/* TODO: 타입 이슈 디버깅 후 다시 확인 */} {/* 관심상품 */} diff --git a/src/components/shop/Post/BuyTabPost/offerTabPanel/index.tsx b/src/components/shop/Post/BuyTabPost/offerTabPanel/index.tsx index d889eef3..836c06ac 100644 --- a/src/components/shop/Post/BuyTabPost/offerTabPanel/index.tsx +++ b/src/components/shop/Post/BuyTabPost/offerTabPanel/index.tsx @@ -8,18 +8,19 @@ const OfferTabPanel = (props: OfferTabPanelProps): ReactElement => { className, postId, thumbnailImageUrl, - // title = '', + title, + seller, offerPrice, tradeStatus, createdAt, - hasReview + hasReview, + onClickReadReview, + onClickWriteReview } = props - // TODO: API Scheme 변경 필요 - const seller = { - nickName: '' + const handleClickReviewButton = () => { + hasReview ? onClickReadReview() : onClickWriteReview() } - const title = '' return ( @@ -30,7 +31,7 @@ const OfferTabPanel = (props: OfferTabPanelProps): ReactElement => { /> - {seller.nickName} + {seller.nickname} {title} @@ -50,7 +51,8 @@ const OfferTabPanel = (props: OfferTabPanelProps): ReactElement => { + styleType="outline" + onClick={handleClickReviewButton}> {hasReview ? '보낸 후기 보기' : '후기 보내기'} diff --git a/src/components/shop/Post/BuyTabPost/offerTabPanel/types.ts b/src/components/shop/Post/BuyTabPost/offerTabPanel/types.ts index a380d426..d31fa1d0 100644 --- a/src/components/shop/Post/BuyTabPost/offerTabPanel/types.ts +++ b/src/components/shop/Post/BuyTabPost/offerTabPanel/types.ts @@ -1,3 +1,7 @@ import type { OfferSummary } from '@types' -export type OfferTabPanelProps = OfferSummary & { className?: string } +export type OfferTabPanelProps = OfferSummary & { + className?: string + onClickReadReview(): void + onClickWriteReview(): void +} diff --git a/src/components/shop/Post/BuyTabPost/types.ts b/src/components/shop/Post/BuyTabPost/types.ts index bd535fce..9c3456f9 100644 --- a/src/components/shop/Post/BuyTabPost/types.ts +++ b/src/components/shop/Post/BuyTabPost/types.ts @@ -1,4 +1,5 @@ import type { LikeTabPanelProps } from './likeTabPanel' +import type { OfferTabPanelProps } from './offerTabPanel' import type { OfferSummary, PostSummary, TradeBuyActivityCodes } from '@types' export type BuyTabPostProps = { className?: string } & ( @@ -12,4 +13,6 @@ export type LikeActivityProps = { } & PostSummary export type OfferActivityProps = { activityType: Extract + onClickWriteReview: OfferTabPanelProps['onClickWriteReview'] + onClickReadReview: OfferTabPanelProps['onClickReadReview'] } & OfferSummary diff --git a/src/components/shop/PostList/BuyTabPostList/index.tsx b/src/components/shop/PostList/BuyTabPostList/index.tsx index 44fdbdfe..235255ed 100644 --- a/src/components/shop/PostList/BuyTabPostList/index.tsx +++ b/src/components/shop/PostList/BuyTabPostList/index.tsx @@ -16,22 +16,37 @@ const BuyTabPostList = (props: BuyTabPostListProps): ReactElement => { return (
    - {props.posts.map((post, index) => ( - - {isOfferPost(post) ? ( - - ) : ( - - )} - {index !== props.posts.length - 1 && } - - ))} + {props.posts.map((post, index) => { + return ( + + {isOfferPost(post) ? ( + props.onClickReadReview(post.review) + : noop + } + onClickWriteReview={ + !isLikedProps(props) + ? () => props.onClickWriteReview(post) + : noop + } + /> + ) : ( + + )} + {index !== props.posts.length - 1 && } + + ) + })}
) } diff --git a/src/components/shop/PostList/BuyTabPostList/types.ts b/src/components/shop/PostList/BuyTabPostList/types.ts index d33700c3..ad2e1365 100644 --- a/src/components/shop/PostList/BuyTabPostList/types.ts +++ b/src/components/shop/PostList/BuyTabPostList/types.ts @@ -1,5 +1,10 @@ import type { LikeActivityProps } from '@components/shop/Post/BuyTabPost/types' -import type { OfferSummary, PostSummary, TradeBuyActivityCodes } from '@types' +import type { + OfferSummary, + PostSummary, + Review, + TradeBuyActivityCodes +} from '@types' export type BuyTabPostListProps = { className?: string @@ -14,6 +19,8 @@ export type LikePostListProps = { export type OfferPostListProps = { activityType: Extract posts: OfferSummary[] + onClickWriteReview(offer: OfferSummary): void + onClickReadReview(review: Review): void } export type PostType = OfferSummary | PostSummary diff --git a/src/pages/shop/view/buy/index.tsx b/src/pages/shop/view/buy/index.tsx index e4f454bf..e9fd1fed 100644 --- a/src/pages/shop/view/buy/index.tsx +++ b/src/pages/shop/view/buy/index.tsx @@ -2,19 +2,25 @@ import { SelectBox } from '@offer-ui/react' import type { ReactElement } from 'react' import { useState } from 'react' import { Styled } from './styled' +import { useModal } from '@hooks/useModal' import { useGetMyOffersQuery, useGetLikedPostsQuery, - useUpdateLikeStatusMutation + useUpdateLikeStatusMutation, + useReviewsMutation } from '@apis' -import { Tabs, BuyTabPostList } from '@components' +import type { ReviewState } from '@components' +import { Tabs, BuyTabPostList, ReviewModal } from '@components' import { TRADE_ACTIVITY_TYPES, SORT_OPTIONS } from '@constants' import type { + OfferSummary, + Review, SortOption, SortOptionCodes, TradeBuyActivityCodes, TradeBuyActivityNames } from '@types' +import { isNumber } from '@utils' const tradeBuyActivityList = Object.entries< TradeBuyActivityCodes, @@ -26,10 +32,20 @@ export const ShopPageBuyView = (): ReactElement => { useState('CREATED_DATE_DESC') const [activityType, setActivityType] = useState('like') + const [readReviewContent, setReadReviewContent] = useState( + {} as Review + ) + const [writeReviewContent, setWriteReviewContent] = useState( + {} as OfferSummary + ) + + const readReviewModal = useModal() + const writeReviewModal = useModal() const offers = useGetMyOffersQuery({ sort: sortOptionCode }) const likedPosts = useGetLikedPostsQuery({ sort: sortOptionCode }) const likeStatusMutation = useUpdateLikeStatusMutation() + const reviewsMutation = useReviewsMutation() const handleChangeSortOption = (newSortOption: SortOption) => { setSortOptionCode(newSortOption.code) @@ -39,10 +55,33 @@ export const ShopPageBuyView = (): ReactElement => { setActivityType(newActivityType) const handleChangeProductLikeStatus = async (postId: number) => { - await likeStatusMutation.mutateAsync(postId) + await likeStatusMutation.mutateAsync({ postId }) likedPosts.refetch() } + const handleOpenReadReview = (review: Review) => { + setReadReviewContent(review) + readReviewModal.openModal() + } + const handleOpenWriteReview = (offer: OfferSummary) => { + setWriteReviewContent(offer) + writeReviewModal.openModal() + } + const handleConfirmWriteReview = async (reviewState: ReviewState) => { + if (!isNumber(reviewState.reviewScore)) { + return + } + + await reviewsMutation.mutateAsync({ + targetMemberId: writeReviewContent.seller.id, + postId: writeReviewContent.postId, + score: reviewState.reviewScore, + content: reviewState.reviewText + }) + await offers.refetch() + writeReviewModal.closeModal() + } + return (
@@ -91,11 +130,26 @@ export const ShopPageBuyView = (): ReactElement => { + +
) } From 8d8860b26702786c1fb47b3321093d7cc8d9fc72 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 00:58:06 +0900 Subject: [PATCH 32/67] implement review api in shop/review page --- .../shop/Post/ReviewTabPost/index.tsx | 5 +---- src/pages/shop/view/review/index.tsx | 19 ++++++++----------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/components/shop/Post/ReviewTabPost/index.tsx b/src/components/shop/Post/ReviewTabPost/index.tsx index 34292ba9..13205baf 100644 --- a/src/components/shop/Post/ReviewTabPost/index.tsx +++ b/src/components/shop/Post/ReviewTabPost/index.tsx @@ -14,8 +14,6 @@ const ReviewTabPost = ({ createdDate, className }: ReviewTabPostProps): ReactElement => { - const offerLevel = 1 - return ( @@ -27,8 +25,7 @@ const ReviewTabPost = ({ {reviewTargetMember.nickname} - {/* Lv.{reviewTargetMember.offerLevel} */} - Lv.{offerLevel} + Lv.{reviewTargetMember.offerLevel} diff --git a/src/pages/shop/view/review/index.tsx b/src/pages/shop/view/review/index.tsx index e9bb62e3..4ebc171b 100644 --- a/src/pages/shop/view/review/index.tsx +++ b/src/pages/shop/view/review/index.tsx @@ -2,7 +2,7 @@ import type { ReactElement } from 'react' import { useState } from 'react' import { Styled } from './styled' import type { ProfileQueryResult } from '@apis' -import { useGetReviewsQuery } from '@apis' +import { useGetReviewsLengthQuery, useGetReviewsQuery } from '@apis' import { Tabs, ReviewTabPostList } from '@components' import { TRADE_ACTIVITY_TYPES } from '@constants' import type { TradeReviewActivityCodes, TradeReviewActivityNames } from '@types' @@ -21,6 +21,7 @@ export const ShopPageReviewView = ({ }: ShopPageReviewViewProps): ReactElement => { const [reviewType, setReviewType] = useState('ALL') + const reviewsLength = useGetReviewsLengthQuery(profile.data.id) const reviews = useGetReviewsQuery({ memberId: profile.data.id, lastId: 0, @@ -53,7 +54,7 @@ export const ShopPageReviewView = ({ {name} - {reviews.data?.length} + {reviewsLength.data[code]} @@ -62,15 +63,11 @@ export const ShopPageReviewView = ({ - - - - - - - - - + {tradeReviewActivityList.map(([code]) => ( + + + + ))} From 74e3ad567ada85de16f1be7dca866d3a890d1eff Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 01:31:40 +0900 Subject: [PATCH 33/67] refactor removing unnecessary props of shop main view --- src/apis/member/queries.ts | 13 +++++++++++++ src/pages/shop/[id].tsx | 15 +++++---------- src/pages/shop/index.tsx | 8 +------- src/pages/shop/view/main/index.tsx | 12 +++++------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/apis/member/queries.ts b/src/apis/member/queries.ts index 13668357..2322f60d 100644 --- a/src/apis/member/queries.ts +++ b/src/apis/member/queries.ts @@ -6,6 +6,19 @@ export type ProfileQueryResult = | ReturnType | ReturnType +export const useGetProfileQuery = (memberId: null | number) => + useQuery({ + queryKey: ['profile', memberId], + queryFn: () => { + if (!memberId) { + return getMyProfile() + } + + return getMemberProfile(memberId) + }, + initialData: memberId ? initialMemberProfile : initialMyProfile + }) + export const useGetMyProfileQuery = (accessToken?: string) => useQuery({ queryKey: ['myProfile', accessToken], diff --git a/src/pages/shop/[id].tsx b/src/pages/shop/[id].tsx index 24291277..11605298 100644 --- a/src/pages/shop/[id].tsx +++ b/src/pages/shop/[id].tsx @@ -1,23 +1,18 @@ import type { GetServerSidePropsContext } from 'next' import type { ReactElement } from 'react' import { ShopPageMainView } from './view/main' -import { useGetMemberProfileQuery } from '@apis/member' -export const getServerSideProps = (context: GetServerSidePropsContext) => { - return { - props: { - memberId: context.query.id - } +export const getServerSideProps = (context: GetServerSidePropsContext) => ({ + props: { + memberId: context.query.id } -} +}) type ShopPageProps = { memberId: string } const ShopPage = ({ memberId }: ShopPageProps): ReactElement => { - const memberProfile = useGetMemberProfileQuery(memberId) - - return + return } export default ShopPage diff --git a/src/pages/shop/index.tsx b/src/pages/shop/index.tsx index d1f222c4..cd7aa287 100644 --- a/src/pages/shop/index.tsx +++ b/src/pages/shop/index.tsx @@ -1,13 +1,7 @@ -import { getCookie } from 'cookies-next' import { ShopPageMainView } from './view/main' -import { useGetMyProfileQuery } from '@apis/member' -import { env } from '@constants' const MyShopPage = () => { - const accessToken = getCookie(env.AUTH_TOKEN_KEY) - const myProfile = useGetMyProfileQuery(accessToken) - - return + return } export default MyShopPage diff --git a/src/pages/shop/view/main/index.tsx b/src/pages/shop/view/main/index.tsx index 26a54071..158b02eb 100644 --- a/src/pages/shop/view/main/index.tsx +++ b/src/pages/shop/view/main/index.tsx @@ -3,18 +3,16 @@ import type { MouseEvent } from 'react' import { useState } from 'react' import { Styled } from './styled' import { pageTabs } from '../../pageTabs' -import type { ProfileQueryResult } from '@apis' +import { useGetProfileQuery } from '@apis' import { ProfileBox, Tabs } from '@components' type ShopPageMainViewProps = { - hasToken: boolean - profile: ProfileQueryResult + memberId: number | null } -export const ShopPageMainView = ({ - profile, - hasToken -}: ShopPageMainViewProps) => { +export const ShopPageMainView = ({ memberId }: ShopPageMainViewProps) => { const [pageIndex, setPageIndex] = useState(0) + const profile = useGetProfileQuery(memberId) + const hasToken = !!memberId const handleTabClick = ( _: MouseEvent, From 8d8ad519831b275b535780dd7a6c3bd98928d457 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 01:42:40 +0900 Subject: [PATCH 34/67] refactor removing unnecessary props of shop views --- src/apis/member/queries.ts | 12 ------------ src/pages/shop/view/main/index.tsx | 5 +++-- src/pages/shop/view/review/index.tsx | 12 ++++++++---- src/pages/shop/view/sale/index.tsx | 13 +++++++++---- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/apis/member/queries.ts b/src/apis/member/queries.ts index 2322f60d..9eadb752 100644 --- a/src/apis/member/queries.ts +++ b/src/apis/member/queries.ts @@ -2,10 +2,6 @@ import { useQuery } from '@tanstack/react-query' import { getMemberProfile, getMyProfile } from './apis' import { initialMemberProfile, initialMyProfile } from './data' -export type ProfileQueryResult = - | ReturnType - | ReturnType - export const useGetProfileQuery = (memberId: null | number) => useQuery({ queryKey: ['profile', memberId], @@ -26,11 +22,3 @@ export const useGetMyProfileQuery = (accessToken?: string) => enabled: Boolean(accessToken), initialData: initialMyProfile }) - -export const useGetMemberProfileQuery = (memberId = '') => - useQuery({ - queryKey: ['memberProfile', memberId], - queryFn: () => getMemberProfile(Number(memberId)), - enabled: Boolean(memberId), - initialData: initialMemberProfile - }) diff --git a/src/pages/shop/view/main/index.tsx b/src/pages/shop/view/main/index.tsx index 158b02eb..a564927c 100644 --- a/src/pages/shop/view/main/index.tsx +++ b/src/pages/shop/view/main/index.tsx @@ -5,6 +5,7 @@ import { Styled } from './styled' import { pageTabs } from '../../pageTabs' import { useGetProfileQuery } from '@apis' import { ProfileBox, Tabs } from '@components' +import { isNumber } from '@utils' type ShopPageMainViewProps = { memberId: number | null @@ -12,7 +13,7 @@ type ShopPageMainViewProps = { export const ShopPageMainView = ({ memberId }: ShopPageMainViewProps) => { const [pageIndex, setPageIndex] = useState(0) const profile = useGetProfileQuery(memberId) - const hasToken = !!memberId + const hasToken = !isNumber(memberId) const handleTabClick = ( _: MouseEvent, @@ -49,7 +50,7 @@ export const ShopPageMainView = ({ memberId }: ShopPageMainViewProps) => { - {panel({ profile, hasToken })} + {panel({ hasToken, memberId })} ))} diff --git a/src/pages/shop/view/review/index.tsx b/src/pages/shop/view/review/index.tsx index 4ebc171b..bbf65774 100644 --- a/src/pages/shop/view/review/index.tsx +++ b/src/pages/shop/view/review/index.tsx @@ -1,8 +1,11 @@ import type { ReactElement } from 'react' import { useState } from 'react' import { Styled } from './styled' -import type { ProfileQueryResult } from '@apis' -import { useGetReviewsLengthQuery, useGetReviewsQuery } from '@apis' +import { + useGetProfileQuery, + useGetReviewsLengthQuery, + useGetReviewsQuery +} from '@apis' import { Tabs, ReviewTabPostList } from '@components' import { TRADE_ACTIVITY_TYPES } from '@constants' import type { TradeReviewActivityCodes, TradeReviewActivityNames } from '@types' @@ -13,14 +16,15 @@ const tradeReviewActivityList = Object.entries< >(TRADE_ACTIVITY_TYPES.review) export type ShopPageReviewViewProps = { - profile: ProfileQueryResult + memberId: number | null } export const ShopPageReviewView = ({ - profile + memberId }: ShopPageReviewViewProps): ReactElement => { const [reviewType, setReviewType] = useState('ALL') + const profile = useGetProfileQuery(memberId) const reviewsLength = useGetReviewsLengthQuery(profile.data.id) const reviews = useGetReviewsQuery({ memberId: profile.data.id, diff --git a/src/pages/shop/view/sale/index.tsx b/src/pages/shop/view/sale/index.tsx index 05be7c50..6ca2eda0 100644 --- a/src/pages/shop/view/sale/index.tsx +++ b/src/pages/shop/view/sale/index.tsx @@ -2,8 +2,12 @@ import { SelectBox } from '@offer-ui/react' import type { ReactElement } from 'react' import { useEffect, useState, useCallback } from 'react' import { Styled } from './styled' -import type { GetPostsReq, ProfileQueryResult } from '@apis' -import { usePostTradeStatusMutation, useGetPostsQuery } from '@apis' +import type { GetPostsReq } from '@apis' +import { + usePostTradeStatusMutation, + useGetPostsQuery, + useGetProfileQuery +} from '@apis' import type { SaleTabPostProps } from '@components' import { Tabs, SaleTabPostList } from '@components' import { SORT_OPTIONS, TRADE_STATUS } from '@constants' @@ -11,12 +15,13 @@ import type { SortOption } from '@types' export type ShopPageSaleViewProps = { hasToken: boolean - profile: ProfileQueryResult + memberId: number | null } export const ShopPageSaleView = ({ hasToken, - profile + memberId }: ShopPageSaleViewProps): ReactElement => { + const profile = useGetProfileQuery(memberId) const [searchOptions, setSearchOptions] = useState({ sellerId: profile.data.nickname ? profile.data.id : undefined, tradeStatus: 'SELLING', From 6a75929b63d1cd9d30e5d2b257f9ae752d867ca4 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 02:06:19 +0900 Subject: [PATCH 35/67] refactor a removing unnecessary prop on ShopPageSaleView --- .../shop/Post/SaleTabPost/index.tsx | 32 +++++++--------- src/pages/shop/view/sale/index.tsx | 37 ++++++++++--------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/src/components/shop/Post/SaleTabPost/index.tsx b/src/components/shop/Post/SaleTabPost/index.tsx index fda9e5fc..36db6434 100644 --- a/src/components/shop/Post/SaleTabPost/index.tsx +++ b/src/components/shop/Post/SaleTabPost/index.tsx @@ -1,4 +1,3 @@ -import type { SelectOnChangeHandler } from '@offer-ui/react' import { Icon, Text } from '@offer-ui/react' import type { ReactElement } from 'react' import { Styled } from './styled' @@ -7,25 +6,22 @@ import { TRADE_STATUS } from '@constants' import type { TradeStatusType } from '@types' import { toLocaleCurrency, getTimeDiffText } from '@utils' -const SaleTabPost = (props: SaleTabPostProps): ReactElement => { - const { - className, - id, - title, - price, - thumbnailImageUrl, - tradeStatus, - likeCount, - createdAt, - hasToken, - onChangeTradeStatus, - hasReview - } = props +const SaleTabPost = ({ + className, + id, + title, + price, + thumbnailImageUrl, + tradeStatus, + likeCount, + createdAt, + hasToken, + onChangeTradeStatus, + hasReview +}: SaleTabPostProps): ReactElement => { const isSoldOut = tradeStatus.code === 'SOLD' - const handleChangeTradeStatus: SelectOnChangeHandler< - TradeStatusType - > = item => { + const handleChangeTradeStatus = (item: TradeStatusType) => { onChangeTradeStatus?.(id, item) } diff --git a/src/pages/shop/view/sale/index.tsx b/src/pages/shop/view/sale/index.tsx index 6ca2eda0..6210f71c 100644 --- a/src/pages/shop/view/sale/index.tsx +++ b/src/pages/shop/view/sale/index.tsx @@ -1,6 +1,6 @@ import { SelectBox } from '@offer-ui/react' import type { ReactElement } from 'react' -import { useEffect, useState, useCallback } from 'react' +import { useEffect, useState } from 'react' import { Styled } from './styled' import type { GetPostsReq } from '@apis' import { @@ -21,25 +21,35 @@ export const ShopPageSaleView = ({ hasToken, memberId }: ShopPageSaleViewProps): ReactElement => { - const profile = useGetProfileQuery(memberId) const [searchOptions, setSearchOptions] = useState({ - sellerId: profile.data.nickname ? profile.data.id : undefined, + sellerId: memberId ? memberId : undefined, tradeStatus: 'SELLING', sort: 'CREATED_DATE_DESC' }) + const profile = useGetProfileQuery(memberId) const posts = useGetPostsQuery(searchOptions) const postTradeStatus = usePostTradeStatusMutation() - const handleChangeSearchOptions = useCallback( - (newOption: GetPostsReq) => { - setSearchOptions({ - ...searchOptions, - ...newOption - }) + useEffect( + function fetchPostsOnMount() { + if (!profile.data.id) { + return + } + + setSearchOptions(prevOptions => ({ + ...prevOptions, + sellerId: profile.data.id + })) }, - [searchOptions] + [profile.data.id] ) + + const handleChangeSearchOptions = (newOption: GetPostsReq) => + setSearchOptions({ + ...searchOptions, + ...newOption + }) const handleChangeProductTradeStatus: SaleTabPostProps['onChangeTradeStatus'] = async (postId, tradeStatus) => { await postTradeStatus.mutateAsync({ @@ -51,13 +61,6 @@ export const ShopPageSaleView = ({ profile.refetch() } - useEffect( - function fetchProfileOnMount() { - handleChangeSearchOptions({ sellerId: profile.data.id }) - }, - [profile.data.id] - ) - return (
From 8e9b479ef91cb287ce49300807e51676808a68ce Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 03:08:20 +0900 Subject: [PATCH 36/67] separate a buy post list to an offer and a like --- .../BuyTabPostList/BuyTabPostList.stories.tsx | 50 ----------- .../shop/PostList/BuyTabPostList/index.tsx | 54 ------------ .../shop/PostList/BuyTabPostList/types.ts | 26 ------ .../shop/PostList/LikeTabPostList/index.tsx | 26 ++++++ .../shop/PostList/LikeTabPostList/types.ts | 8 ++ .../shop/PostList/OfferTabPostList/index.tsx | 28 ++++++ .../shop/PostList/OfferTabPostList/types.ts | 8 ++ src/components/shop/PostList/index.tsx | 3 +- src/pages/shop/view/buy/index.tsx | 86 ++----------------- src/pages/shop/view/buy/panel/like.tsx | 23 +++++ src/pages/shop/view/buy/panel/offer.tsx | 67 +++++++++++++++ 11 files changed, 169 insertions(+), 210 deletions(-) delete mode 100644 src/components/shop/PostList/BuyTabPostList/BuyTabPostList.stories.tsx delete mode 100644 src/components/shop/PostList/BuyTabPostList/index.tsx delete mode 100644 src/components/shop/PostList/BuyTabPostList/types.ts create mode 100644 src/components/shop/PostList/LikeTabPostList/index.tsx create mode 100644 src/components/shop/PostList/LikeTabPostList/types.ts create mode 100644 src/components/shop/PostList/OfferTabPostList/index.tsx create mode 100644 src/components/shop/PostList/OfferTabPostList/types.ts create mode 100644 src/pages/shop/view/buy/panel/like.tsx create mode 100644 src/pages/shop/view/buy/panel/offer.tsx diff --git a/src/components/shop/PostList/BuyTabPostList/BuyTabPostList.stories.tsx b/src/components/shop/PostList/BuyTabPostList/BuyTabPostList.stories.tsx deleted file mode 100644 index 7f882dcb..00000000 --- a/src/components/shop/PostList/BuyTabPostList/BuyTabPostList.stories.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Text } from '@offer-ui/react' -import { action } from '@storybook/addon-actions' -import type { Meta, StoryObj } from '@storybook/react' -import { useState } from 'react' -import { BuyTabPostList as BuyTabPostListComponent } from './index' -import { TRADE_ACTIVITY_TYPES } from '@constants' -import type { TradeBuyActivityCodes } from '@types' - -type BuyTabArticleList = typeof BuyTabPostListComponent - -const meta: Meta = { - component: BuyTabPostListComponent, - title: 'MyPage/ArticleList/BuyTabArticleList' -} - -export default meta - -const PrimaryWithHooks = () => { - const [activityType, setActivityType] = - useState('offer') - - const handleChangeLikeStatus = (postId: number) => { - action('change like status')(postId) - } - - return ( - <> - - -
- - {TRADE_ACTIVITY_TYPES.buy[activityType]} - -
- - - ) -} -export const Primary: StoryObj = { - args: { activityType: 'like', posts: [] }, - render: () => -} diff --git a/src/components/shop/PostList/BuyTabPostList/index.tsx b/src/components/shop/PostList/BuyTabPostList/index.tsx deleted file mode 100644 index 235255ed..00000000 --- a/src/components/shop/PostList/BuyTabPostList/index.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Divider } from '@offer-ui/react' -import type { ReactElement } from 'react' -import { Fragment } from 'react' -import type { BuyTabPostListProps, LikePostListProps, PostType } from './types' -import { BuyTabPost } from '@components/shop/Post' -import type { OfferSummary } from '@types' -import { noop } from '@utils' - -const isLikedProps = (props: BuyTabPostListProps): props is LikePostListProps => - props.activityType === 'like' -const isOfferPost = (post: PostType): post is OfferSummary => 'postId' in post - -const BuyTabPostList = (props: BuyTabPostListProps): ReactElement => { - const getPostId = (post: PostType) => - isOfferPost(post) ? post.postId : post.id - - return ( -
    - {props.posts.map((post, index) => { - return ( - - {isOfferPost(post) ? ( - props.onClickReadReview(post.review) - : noop - } - onClickWriteReview={ - !isLikedProps(props) - ? () => props.onClickWriteReview(post) - : noop - } - /> - ) : ( - - )} - {index !== props.posts.length - 1 && } - - ) - })} -
- ) -} - -export { BuyTabPostList, BuyTabPostListProps } diff --git a/src/components/shop/PostList/BuyTabPostList/types.ts b/src/components/shop/PostList/BuyTabPostList/types.ts deleted file mode 100644 index ad2e1365..00000000 --- a/src/components/shop/PostList/BuyTabPostList/types.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { LikeActivityProps } from '@components/shop/Post/BuyTabPost/types' -import type { - OfferSummary, - PostSummary, - Review, - TradeBuyActivityCodes -} from '@types' - -export type BuyTabPostListProps = { - className?: string -} & (LikePostListProps | OfferPostListProps) - -export type LikePostListProps = { - activityType: Extract - posts: PostSummary[] - onChangeProductLikeStatus: LikeActivityProps['onChangeProductLikeStatus'] -} - -export type OfferPostListProps = { - activityType: Extract - posts: OfferSummary[] - onClickWriteReview(offer: OfferSummary): void - onClickReadReview(review: Review): void -} - -export type PostType = OfferSummary | PostSummary diff --git a/src/components/shop/PostList/LikeTabPostList/index.tsx b/src/components/shop/PostList/LikeTabPostList/index.tsx new file mode 100644 index 00000000..a0bb8d3d --- /dev/null +++ b/src/components/shop/PostList/LikeTabPostList/index.tsx @@ -0,0 +1,26 @@ +import { Divider } from '@offer-ui/react' +import type { ReactElement } from 'react' +import { Fragment } from 'react' +import type { LikePostListProps } from './types' +import { BuyTabPost } from '@components/shop/Post' + +const LikeTabPostList = ({ + className, + posts, + onChangeProductLikeStatus +}: LikePostListProps): ReactElement => ( +
    + {posts.map((post, index) => ( + + + {index !== posts.length - 1 && } + + ))} +
+) + +export { LikeTabPostList, LikePostListProps } diff --git a/src/components/shop/PostList/LikeTabPostList/types.ts b/src/components/shop/PostList/LikeTabPostList/types.ts new file mode 100644 index 00000000..33afdaee --- /dev/null +++ b/src/components/shop/PostList/LikeTabPostList/types.ts @@ -0,0 +1,8 @@ +import type { LikeActivityProps } from '@components/shop/Post/BuyTabPost/types' +import type { PostSummary } from '@types' + +export type LikePostListProps = { + className?: string + posts: PostSummary[] + onChangeProductLikeStatus: LikeActivityProps['onChangeProductLikeStatus'] +} diff --git a/src/components/shop/PostList/OfferTabPostList/index.tsx b/src/components/shop/PostList/OfferTabPostList/index.tsx new file mode 100644 index 00000000..fdbd9420 --- /dev/null +++ b/src/components/shop/PostList/OfferTabPostList/index.tsx @@ -0,0 +1,28 @@ +import { Divider } from '@offer-ui/react' +import type { ReactElement } from 'react' +import { Fragment } from 'react' +import type { OfferPostListProps } from './types' +import { BuyTabPost } from '@components/shop/Post' + +const OfferTabPostList = ({ + className, + posts, + onClickReadReview, + onClickWriteReview +}: OfferPostListProps): ReactElement => ( +
    + {posts.map((post, index) => ( + + onClickReadReview(post.review)} + onClickWriteReview={() => onClickWriteReview(post)} + /> + {index !== posts.length - 1 && } + + ))} +
+) + +export { OfferTabPostList, OfferPostListProps } diff --git a/src/components/shop/PostList/OfferTabPostList/types.ts b/src/components/shop/PostList/OfferTabPostList/types.ts new file mode 100644 index 00000000..d4334fe3 --- /dev/null +++ b/src/components/shop/PostList/OfferTabPostList/types.ts @@ -0,0 +1,8 @@ +import type { OfferSummary, Review } from '@types' + +export type OfferPostListProps = { + className?: string + posts: OfferSummary[] + onClickWriteReview(offer: OfferSummary): void + onClickReadReview(review: Review): void +} diff --git a/src/components/shop/PostList/index.tsx b/src/components/shop/PostList/index.tsx index bc27d7b7..ad85405e 100644 --- a/src/components/shop/PostList/index.tsx +++ b/src/components/shop/PostList/index.tsx @@ -1,3 +1,4 @@ -export * from './BuyTabPostList' +export * from './OfferTabPostList' +export * from './LikeTabPostList' export * from './SaleTabPostList' export * from './ReviewTabPostList' diff --git a/src/pages/shop/view/buy/index.tsx b/src/pages/shop/view/buy/index.tsx index e9fd1fed..546533cf 100644 --- a/src/pages/shop/view/buy/index.tsx +++ b/src/pages/shop/view/buy/index.tsx @@ -1,26 +1,18 @@ import { SelectBox } from '@offer-ui/react' import type { ReactElement } from 'react' import { useState } from 'react' +import { LikePanelView } from './panel/like' +import { OfferPanelView } from './panel/offer' import { Styled } from './styled' -import { useModal } from '@hooks/useModal' -import { - useGetMyOffersQuery, - useGetLikedPostsQuery, - useUpdateLikeStatusMutation, - useReviewsMutation -} from '@apis' -import type { ReviewState } from '@components' -import { Tabs, BuyTabPostList, ReviewModal } from '@components' +import { useGetMyOffersQuery, useGetLikedPostsQuery } from '@apis' +import { Tabs } from '@components' import { TRADE_ACTIVITY_TYPES, SORT_OPTIONS } from '@constants' import type { - OfferSummary, - Review, SortOption, SortOptionCodes, TradeBuyActivityCodes, TradeBuyActivityNames } from '@types' -import { isNumber } from '@utils' const tradeBuyActivityList = Object.entries< TradeBuyActivityCodes, @@ -32,55 +24,13 @@ export const ShopPageBuyView = (): ReactElement => { useState('CREATED_DATE_DESC') const [activityType, setActivityType] = useState('like') - const [readReviewContent, setReadReviewContent] = useState( - {} as Review - ) - const [writeReviewContent, setWriteReviewContent] = useState( - {} as OfferSummary - ) - - const readReviewModal = useModal() - const writeReviewModal = useModal() const offers = useGetMyOffersQuery({ sort: sortOptionCode }) const likedPosts = useGetLikedPostsQuery({ sort: sortOptionCode }) - const likeStatusMutation = useUpdateLikeStatusMutation() - const reviewsMutation = useReviewsMutation() const handleChangeSortOption = (newSortOption: SortOption) => { setSortOptionCode(newSortOption.code) } - const handleChangeActivityType = - (newActivityType: TradeBuyActivityCodes) => (): void => - setActivityType(newActivityType) - - const handleChangeProductLikeStatus = async (postId: number) => { - await likeStatusMutation.mutateAsync({ postId }) - likedPosts.refetch() - } - - const handleOpenReadReview = (review: Review) => { - setReadReviewContent(review) - readReviewModal.openModal() - } - const handleOpenWriteReview = (offer: OfferSummary) => { - setWriteReviewContent(offer) - writeReviewModal.openModal() - } - const handleConfirmWriteReview = async (reviewState: ReviewState) => { - if (!isNumber(reviewState.reviewScore)) { - return - } - - await reviewsMutation.mutateAsync({ - targetMemberId: writeReviewContent.seller.id, - postId: writeReviewContent.postId, - score: reviewState.reviewScore, - content: reviewState.reviewText - }) - await offers.refetch() - writeReviewModal.closeModal() - } return (
@@ -95,7 +45,7 @@ export const ShopPageBuyView = (): ReactElement => { return ( + onClick={() => setActivityType(code)}> @@ -120,36 +70,14 @@ export const ShopPageBuyView = (): ReactElement => { - + - + - -
) } diff --git a/src/pages/shop/view/buy/panel/like.tsx b/src/pages/shop/view/buy/panel/like.tsx new file mode 100644 index 00000000..ba26d9f5 --- /dev/null +++ b/src/pages/shop/view/buy/panel/like.tsx @@ -0,0 +1,23 @@ +import { useGetLikedPostsQuery, useUpdateLikeStatusMutation } from '@apis' +import { LikeTabPostList } from '@components' +import type { SortOptionCodes } from '@types' + +type LikePanelViewProps = { + sortOptionCode: SortOptionCodes +} +export const LikePanelView = ({ sortOptionCode }: LikePanelViewProps) => { + const likedPosts = useGetLikedPostsQuery({ sort: sortOptionCode }) + const likeStatusMutation = useUpdateLikeStatusMutation() + + const handleChangeProductLikeStatus = async (postId: number) => { + await likeStatusMutation.mutateAsync({ postId }) + likedPosts.refetch() + } + + return ( + + ) +} diff --git a/src/pages/shop/view/buy/panel/offer.tsx b/src/pages/shop/view/buy/panel/offer.tsx new file mode 100644 index 00000000..6cf44ad6 --- /dev/null +++ b/src/pages/shop/view/buy/panel/offer.tsx @@ -0,0 +1,67 @@ +import { useState } from 'react' +import { useModal } from '@hooks/useModal' +import { useGetMyOffersQuery, useReviewsMutation } from '@apis' +import type { ReviewState } from '@components' +import { OfferTabPostList, ReviewModal } from '@components' +import type { OfferSummary, Review, SortOptionCodes } from '@types' +import { isNumber } from '@utils' + +type OfferPanelViewProps = { + sortOptionCode: SortOptionCodes +} +export const OfferPanelView = ({ sortOptionCode }: OfferPanelViewProps) => { + const offers = useGetMyOffersQuery({ sort: sortOptionCode }) + const reviewsMutation = useReviewsMutation() + + const readReviewModal = useModal() + const writeReviewModal = useModal() + + const [readReviewProps, setReadReviewProps] = useState({} as Review) + const [writeReviewProps, setWriteReviewProps] = useState({} as OfferSummary) + + const handleOpenReadReview = (review: Review) => { + setReadReviewProps(review) + readReviewModal.openModal() + } + const handleOpenWriteReview = (offer: OfferSummary) => { + setWriteReviewProps(offer) + writeReviewModal.openModal() + } + const handleConfirmWriteReview = async (reviewState: ReviewState) => { + if (!isNumber(reviewState.reviewScore)) { + return + } + + await reviewsMutation.mutateAsync({ + targetMemberId: writeReviewProps.seller.id, + postId: writeReviewProps.postId, + score: reviewState.reviewScore, + content: reviewState.reviewText + }) + await offers.refetch() + writeReviewModal.closeModal() + } + + return ( + <> + + + + + ) +} From cf76362fa8c15c8d7fe56d2c7a6baf8c944b793a Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 03:12:06 +0900 Subject: [PATCH 37/67] rename view directory to panel in shop page --- src/pages/shop/[id].tsx | 2 +- src/pages/shop/index.tsx | 2 +- src/pages/shop/pageTabs.ts | 10 +++++----- src/pages/shop/{view => panel}/buy/index.tsx | 4 ++-- src/pages/shop/{view => panel}/buy/styled.ts | 0 .../shop/{view/buy/panel => panel/buy/view}/like.tsx | 0 .../shop/{view/buy/panel => panel/buy/view}/offer.tsx | 0 src/pages/shop/{view => panel}/main/index.tsx | 0 src/pages/shop/{view => panel}/main/styled.tsx | 0 src/pages/shop/{view => panel}/review/index.tsx | 0 src/pages/shop/{view => panel}/review/styled.ts | 0 src/pages/shop/{view => panel}/sale/index.tsx | 0 src/pages/shop/{view => panel}/sale/styled.ts | 0 13 files changed, 9 insertions(+), 9 deletions(-) rename src/pages/shop/{view => panel}/buy/index.tsx (96%) rename src/pages/shop/{view => panel}/buy/styled.ts (100%) rename src/pages/shop/{view/buy/panel => panel/buy/view}/like.tsx (100%) rename src/pages/shop/{view/buy/panel => panel/buy/view}/offer.tsx (100%) rename src/pages/shop/{view => panel}/main/index.tsx (100%) rename src/pages/shop/{view => panel}/main/styled.tsx (100%) rename src/pages/shop/{view => panel}/review/index.tsx (100%) rename src/pages/shop/{view => panel}/review/styled.ts (100%) rename src/pages/shop/{view => panel}/sale/index.tsx (100%) rename src/pages/shop/{view => panel}/sale/styled.ts (100%) diff --git a/src/pages/shop/[id].tsx b/src/pages/shop/[id].tsx index 11605298..30ab5ded 100644 --- a/src/pages/shop/[id].tsx +++ b/src/pages/shop/[id].tsx @@ -1,6 +1,6 @@ import type { GetServerSidePropsContext } from 'next' import type { ReactElement } from 'react' -import { ShopPageMainView } from './view/main' +import { ShopPageMainView } from './panel/main' export const getServerSideProps = (context: GetServerSidePropsContext) => ({ props: { diff --git a/src/pages/shop/index.tsx b/src/pages/shop/index.tsx index cd7aa287..53fe6355 100644 --- a/src/pages/shop/index.tsx +++ b/src/pages/shop/index.tsx @@ -1,4 +1,4 @@ -import { ShopPageMainView } from './view/main' +import { ShopPageMainView } from './panel/main' const MyShopPage = () => { return diff --git a/src/pages/shop/pageTabs.ts b/src/pages/shop/pageTabs.ts index d5c2e691..e70beab6 100644 --- a/src/pages/shop/pageTabs.ts +++ b/src/pages/shop/pageTabs.ts @@ -1,9 +1,9 @@ import type { ReactElement } from 'react' -import { ShopPageBuyView } from './view/buy' -import type { ShopPageReviewViewProps } from './view/review' -import { ShopPageReviewView } from './view/review' -import type { ShopPageSaleViewProps } from './view/sale' -import { ShopPageSaleView } from './view/sale' +import { ShopPageBuyView } from './panel/buy' +import type { ShopPageReviewViewProps } from './panel/review' +import { ShopPageReviewView } from './panel/review' +import type { ShopPageSaleViewProps } from './panel/sale' +import { ShopPageSaleView } from './panel/sale' import type { TradeActivityNames, TradeActivityCodes } from '@types' type PageTab = { diff --git a/src/pages/shop/view/buy/index.tsx b/src/pages/shop/panel/buy/index.tsx similarity index 96% rename from src/pages/shop/view/buy/index.tsx rename to src/pages/shop/panel/buy/index.tsx index 546533cf..2af0f0f7 100644 --- a/src/pages/shop/view/buy/index.tsx +++ b/src/pages/shop/panel/buy/index.tsx @@ -1,9 +1,9 @@ import { SelectBox } from '@offer-ui/react' import type { ReactElement } from 'react' import { useState } from 'react' -import { LikePanelView } from './panel/like' -import { OfferPanelView } from './panel/offer' import { Styled } from './styled' +import { LikePanelView } from './view/like' +import { OfferPanelView } from './view/offer' import { useGetMyOffersQuery, useGetLikedPostsQuery } from '@apis' import { Tabs } from '@components' import { TRADE_ACTIVITY_TYPES, SORT_OPTIONS } from '@constants' diff --git a/src/pages/shop/view/buy/styled.ts b/src/pages/shop/panel/buy/styled.ts similarity index 100% rename from src/pages/shop/view/buy/styled.ts rename to src/pages/shop/panel/buy/styled.ts diff --git a/src/pages/shop/view/buy/panel/like.tsx b/src/pages/shop/panel/buy/view/like.tsx similarity index 100% rename from src/pages/shop/view/buy/panel/like.tsx rename to src/pages/shop/panel/buy/view/like.tsx diff --git a/src/pages/shop/view/buy/panel/offer.tsx b/src/pages/shop/panel/buy/view/offer.tsx similarity index 100% rename from src/pages/shop/view/buy/panel/offer.tsx rename to src/pages/shop/panel/buy/view/offer.tsx diff --git a/src/pages/shop/view/main/index.tsx b/src/pages/shop/panel/main/index.tsx similarity index 100% rename from src/pages/shop/view/main/index.tsx rename to src/pages/shop/panel/main/index.tsx diff --git a/src/pages/shop/view/main/styled.tsx b/src/pages/shop/panel/main/styled.tsx similarity index 100% rename from src/pages/shop/view/main/styled.tsx rename to src/pages/shop/panel/main/styled.tsx diff --git a/src/pages/shop/view/review/index.tsx b/src/pages/shop/panel/review/index.tsx similarity index 100% rename from src/pages/shop/view/review/index.tsx rename to src/pages/shop/panel/review/index.tsx diff --git a/src/pages/shop/view/review/styled.ts b/src/pages/shop/panel/review/styled.ts similarity index 100% rename from src/pages/shop/view/review/styled.ts rename to src/pages/shop/panel/review/styled.ts diff --git a/src/pages/shop/view/sale/index.tsx b/src/pages/shop/panel/sale/index.tsx similarity index 100% rename from src/pages/shop/view/sale/index.tsx rename to src/pages/shop/panel/sale/index.tsx diff --git a/src/pages/shop/view/sale/styled.ts b/src/pages/shop/panel/sale/styled.ts similarity index 100% rename from src/pages/shop/view/sale/styled.ts rename to src/pages/shop/panel/sale/styled.ts From 5e4e5d7ffb213b95ff348f803481a6b9b9bdf0b3 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 03:15:30 +0900 Subject: [PATCH 38/67] rename shop page main view to shop page view --- src/pages/shop/[id].tsx | 4 ++-- src/pages/shop/index.tsx | 4 ++-- src/pages/shop/{panel/main => view}/index.tsx | 6 +++--- src/pages/shop/{panel/main => view}/styled.tsx | 0 4 files changed, 7 insertions(+), 7 deletions(-) rename src/pages/shop/{panel/main => view}/index.tsx (92%) rename src/pages/shop/{panel/main => view}/styled.tsx (100%) diff --git a/src/pages/shop/[id].tsx b/src/pages/shop/[id].tsx index 30ab5ded..ec7d6654 100644 --- a/src/pages/shop/[id].tsx +++ b/src/pages/shop/[id].tsx @@ -1,6 +1,6 @@ import type { GetServerSidePropsContext } from 'next' import type { ReactElement } from 'react' -import { ShopPageMainView } from './panel/main' +import { ShopPageView } from './view' export const getServerSideProps = (context: GetServerSidePropsContext) => ({ props: { @@ -12,7 +12,7 @@ type ShopPageProps = { memberId: string } const ShopPage = ({ memberId }: ShopPageProps): ReactElement => { - return + return } export default ShopPage diff --git a/src/pages/shop/index.tsx b/src/pages/shop/index.tsx index 53fe6355..4cdea82f 100644 --- a/src/pages/shop/index.tsx +++ b/src/pages/shop/index.tsx @@ -1,7 +1,7 @@ -import { ShopPageMainView } from './panel/main' +import { ShopPageView } from './view' const MyShopPage = () => { - return + return } export default MyShopPage diff --git a/src/pages/shop/panel/main/index.tsx b/src/pages/shop/view/index.tsx similarity index 92% rename from src/pages/shop/panel/main/index.tsx rename to src/pages/shop/view/index.tsx index a564927c..e9287782 100644 --- a/src/pages/shop/panel/main/index.tsx +++ b/src/pages/shop/view/index.tsx @@ -2,15 +2,15 @@ import { Divider } from '@offer-ui/react' import type { MouseEvent } from 'react' import { useState } from 'react' import { Styled } from './styled' -import { pageTabs } from '../../pageTabs' +import { pageTabs } from '../pageTabs' import { useGetProfileQuery } from '@apis' import { ProfileBox, Tabs } from '@components' import { isNumber } from '@utils' -type ShopPageMainViewProps = { +type ShopPageViewProps = { memberId: number | null } -export const ShopPageMainView = ({ memberId }: ShopPageMainViewProps) => { +export const ShopPageView = ({ memberId }: ShopPageViewProps) => { const [pageIndex, setPageIndex] = useState(0) const profile = useGetProfileQuery(memberId) const hasToken = !isNumber(memberId) diff --git a/src/pages/shop/panel/main/styled.tsx b/src/pages/shop/view/styled.tsx similarity index 100% rename from src/pages/shop/panel/main/styled.tsx rename to src/pages/shop/view/styled.tsx From de26d5db8d3eed086b286b084880e587099c82ad Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 03:17:52 +0900 Subject: [PATCH 39/67] rename shop panels --- src/pages/shop/pageTabs.ts | 16 ++++++++-------- src/pages/shop/panel/buy/index.tsx | 3 +-- src/pages/shop/panel/review/index.tsx | 7 ++----- src/pages/shop/panel/sale/index.tsx | 7 +++---- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/pages/shop/pageTabs.ts b/src/pages/shop/pageTabs.ts index e70beab6..0d0040bc 100644 --- a/src/pages/shop/pageTabs.ts +++ b/src/pages/shop/pageTabs.ts @@ -1,9 +1,9 @@ import type { ReactElement } from 'react' -import { ShopPageBuyView } from './panel/buy' -import type { ShopPageReviewViewProps } from './panel/review' -import { ShopPageReviewView } from './panel/review' -import type { ShopPageSaleViewProps } from './panel/sale' -import { ShopPageSaleView } from './panel/sale' +import { ShopPageBuyPanel } from './panel/buy' +import type { ShopPageReviewPanelProps } from './panel/review' +import { ShopPageReviewPanel } from './panel/review' +import type { ShopPageSalePanelProps } from './panel/sale' +import { ShopPageSalePanel } from './panel/sale' import type { TradeActivityNames, TradeActivityCodes } from '@types' type PageTab = { @@ -20,20 +20,20 @@ export const pageTabs: PageTab[] = [ code: 'sale', name: '판매' }, - panel: (props: ShopPageSaleViewProps) => ShopPageSaleView(props) + panel: (props: ShopPageSalePanelProps) => ShopPageSalePanel(props) }, { tab: { code: 'buy', name: '구매' }, - panel: ShopPageBuyView + panel: ShopPageBuyPanel }, { tab: { code: 'review', name: '후기' }, - panel: (props: ShopPageReviewViewProps) => ShopPageReviewView(props) + panel: (props: ShopPageReviewPanelProps) => ShopPageReviewPanel(props) } ] diff --git a/src/pages/shop/panel/buy/index.tsx b/src/pages/shop/panel/buy/index.tsx index 2af0f0f7..b7cb906e 100644 --- a/src/pages/shop/panel/buy/index.tsx +++ b/src/pages/shop/panel/buy/index.tsx @@ -1,5 +1,4 @@ import { SelectBox } from '@offer-ui/react' -import type { ReactElement } from 'react' import { useState } from 'react' import { Styled } from './styled' import { LikePanelView } from './view/like' @@ -19,7 +18,7 @@ const tradeBuyActivityList = Object.entries< TradeBuyActivityNames >(TRADE_ACTIVITY_TYPES.buy) -export const ShopPageBuyView = (): ReactElement => { +export const ShopPageBuyPanel = () => { const [sortOptionCode, setSortOptionCode] = useState('CREATED_DATE_DESC') const [activityType, setActivityType] = diff --git a/src/pages/shop/panel/review/index.tsx b/src/pages/shop/panel/review/index.tsx index bbf65774..70124a44 100644 --- a/src/pages/shop/panel/review/index.tsx +++ b/src/pages/shop/panel/review/index.tsx @@ -1,4 +1,3 @@ -import type { ReactElement } from 'react' import { useState } from 'react' import { Styled } from './styled' import { @@ -15,13 +14,11 @@ const tradeReviewActivityList = Object.entries< TradeReviewActivityNames >(TRADE_ACTIVITY_TYPES.review) -export type ShopPageReviewViewProps = { +export type ShopPageReviewPanelProps = { memberId: number | null } -export const ShopPageReviewView = ({ - memberId -}: ShopPageReviewViewProps): ReactElement => { +export const ShopPageReviewPanel = ({ memberId }: ShopPageReviewPanelProps) => { const [reviewType, setReviewType] = useState('ALL') const profile = useGetProfileQuery(memberId) diff --git a/src/pages/shop/panel/sale/index.tsx b/src/pages/shop/panel/sale/index.tsx index 6210f71c..b0add045 100644 --- a/src/pages/shop/panel/sale/index.tsx +++ b/src/pages/shop/panel/sale/index.tsx @@ -1,5 +1,4 @@ import { SelectBox } from '@offer-ui/react' -import type { ReactElement } from 'react' import { useEffect, useState } from 'react' import { Styled } from './styled' import type { GetPostsReq } from '@apis' @@ -13,14 +12,14 @@ import { Tabs, SaleTabPostList } from '@components' import { SORT_OPTIONS, TRADE_STATUS } from '@constants' import type { SortOption } from '@types' -export type ShopPageSaleViewProps = { +export type ShopPageSalePanelProps = { hasToken: boolean memberId: number | null } -export const ShopPageSaleView = ({ +export const ShopPageSalePanel = ({ hasToken, memberId -}: ShopPageSaleViewProps): ReactElement => { +}: ShopPageSalePanelProps) => { const [searchOptions, setSearchOptions] = useState({ sellerId: memberId ? memberId : undefined, tradeStatus: 'SELLING', From 273d956325a0a6d4db3acfebfd0097f75242ca30 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 03:20:05 +0900 Subject: [PATCH 40/67] rename tradeBuyActivityLists to tradeBuyActivityTabs --- src/pages/shop/panel/buy/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/shop/panel/buy/index.tsx b/src/pages/shop/panel/buy/index.tsx index b7cb906e..8532afbc 100644 --- a/src/pages/shop/panel/buy/index.tsx +++ b/src/pages/shop/panel/buy/index.tsx @@ -13,7 +13,7 @@ import type { TradeBuyActivityNames } from '@types' -const tradeBuyActivityList = Object.entries< +const tradeBuyActivityTabs = Object.entries< TradeBuyActivityCodes, TradeBuyActivityNames >(TRADE_ACTIVITY_TYPES.buy) @@ -38,7 +38,7 @@ export const ShopPageBuyPanel = () => { - {tradeBuyActivityList.map(([code, name]) => { + {tradeBuyActivityTabs.map(([code, name]) => { const isCurrent = code === activityType return ( From 1a881c8c8d124ff32e4844b91ead889053eae0d7 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 03:29:30 +0900 Subject: [PATCH 41/67] separate a BuyTabPostList component --- .../Post/BuyTabPost/BuyTabPost.stories.tsx | 48 ----- src/components/shop/Post/BuyTabPost/index.tsx | 24 --- src/components/shop/Post/BuyTabPost/types.ts | 18 -- .../likeTabPanel => LikeTabPost}/index.tsx | 10 +- .../{BuyTabPost => LikeTabPost}/styled.ts | 0 .../likeTabPanel => LikeTabPost}/types.ts | 2 +- .../offerTabPanel => OfferTabPost}/index.tsx | 34 ++- .../shop/Post/OfferTabPost/styled.ts | 199 ++++++++++++++++++ .../offerTabPanel => OfferTabPost}/types.ts | 2 +- src/components/shop/Post/index.tsx | 3 +- .../shop/PostList/LikeTabPostList/index.tsx | 8 +- .../shop/PostList/LikeTabPostList/types.ts | 4 +- .../shop/PostList/OfferTabPostList/index.tsx | 5 +- 13 files changed, 230 insertions(+), 127 deletions(-) delete mode 100644 src/components/shop/Post/BuyTabPost/BuyTabPost.stories.tsx delete mode 100644 src/components/shop/Post/BuyTabPost/index.tsx delete mode 100644 src/components/shop/Post/BuyTabPost/types.ts rename src/components/shop/Post/{BuyTabPost/likeTabPanel => LikeTabPost}/index.tsx (88%) rename src/components/shop/Post/{BuyTabPost => LikeTabPost}/styled.ts (100%) rename src/components/shop/Post/{BuyTabPost/likeTabPanel => LikeTabPost}/types.ts (69%) rename src/components/shop/Post/{BuyTabPost/offerTabPanel => OfferTabPost}/index.tsx (78%) create mode 100644 src/components/shop/Post/OfferTabPost/styled.ts rename src/components/shop/Post/{BuyTabPost/offerTabPanel => OfferTabPost}/types.ts (71%) diff --git a/src/components/shop/Post/BuyTabPost/BuyTabPost.stories.tsx b/src/components/shop/Post/BuyTabPost/BuyTabPost.stories.tsx deleted file mode 100644 index 785ac7d6..00000000 --- a/src/components/shop/Post/BuyTabPost/BuyTabPost.stories.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { Text } from '@offer-ui/react' -import type { Meta, StoryObj } from '@storybook/react' -import type { BuyTabPostProps } from './types' -import { BuyTabPost as BuyTabPostComponent } from './index' -import { noop } from '@utils/common' -import type { OfferSummary } from '@types' - -type BuyTabPost = typeof BuyTabPostComponent - -const meta: Meta = { - component: BuyTabPostComponent, - title: 'MyPage/Article/BuyTabPost' -} - -export default meta - -export const Primary: StoryObj = { - args: { - id: 0, - title: 'title', - price: 0, - location: '서울시', - thumbnailImageUrl: '', - liked: true, - tradeStatus: { code: 'SELLING', name: '판매중' }, - likeCount: 0, - createdAt: '', - hasReview: false - }, - render: args => { - const post = args as OfferSummary - - return ( - <> - 가격제안 - - {/* TODO: 타입 이슈 디버깅 후 다시 확인 */} - {/* 관심상품 - */} - - ) - } -} diff --git a/src/components/shop/Post/BuyTabPost/index.tsx b/src/components/shop/Post/BuyTabPost/index.tsx deleted file mode 100644 index 0c3407a6..00000000 --- a/src/components/shop/Post/BuyTabPost/index.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { ReactElement } from 'react' -import { LikeTabPanel } from './likeTabPanel' -import { OfferTabPanel } from './offerTabPanel' - -import type { BuyTabPostProps } from './types' - -const BuyTabPost = (props: BuyTabPostProps): ReactElement => { - const isOfferType = props.activityType === 'offer' - - return ( - <> - {isOfferType ? ( - - ) : ( - - )} - - ) -} - -export { BuyTabPost, BuyTabPostProps } diff --git a/src/components/shop/Post/BuyTabPost/types.ts b/src/components/shop/Post/BuyTabPost/types.ts deleted file mode 100644 index 9c3456f9..00000000 --- a/src/components/shop/Post/BuyTabPost/types.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { LikeTabPanelProps } from './likeTabPanel' -import type { OfferTabPanelProps } from './offerTabPanel' -import type { OfferSummary, PostSummary, TradeBuyActivityCodes } from '@types' - -export type BuyTabPostProps = { className?: string } & ( - | LikeActivityProps - | OfferActivityProps -) - -export type LikeActivityProps = { - activityType: Extract - onChangeProductLikeStatus: LikeTabPanelProps['onChangeLikeStatus'] -} & PostSummary -export type OfferActivityProps = { - activityType: Extract - onClickWriteReview: OfferTabPanelProps['onClickWriteReview'] - onClickReadReview: OfferTabPanelProps['onClickReadReview'] -} & OfferSummary diff --git a/src/components/shop/Post/BuyTabPost/likeTabPanel/index.tsx b/src/components/shop/Post/LikeTabPost/index.tsx similarity index 88% rename from src/components/shop/Post/BuyTabPost/likeTabPanel/index.tsx rename to src/components/shop/Post/LikeTabPost/index.tsx index f95f41f8..afe25d46 100644 --- a/src/components/shop/Post/BuyTabPost/likeTabPanel/index.tsx +++ b/src/components/shop/Post/LikeTabPost/index.tsx @@ -1,9 +1,9 @@ import type { ReactElement } from 'react' -import type { LikeTabPanelProps } from './types' -import { Styled } from '../styled' +import { Styled } from './styled' +import type { LikeTabPostProps } from './types' import { toLocaleCurrency, getTimeDiffText } from '@utils' -const LikeTabPanel = ({ +const LikeTabPost = ({ className, seller, id: postId, @@ -14,7 +14,7 @@ const LikeTabPanel = ({ createdAt, likeCount, onChangeLikeStatus -}: LikeTabPanelProps): ReactElement => { +}: LikeTabPostProps): ReactElement => { const handleChangeLikeStatus = () => { onChangeLikeStatus(postId) } @@ -53,4 +53,4 @@ const LikeTabPanel = ({ ) } -export { LikeTabPanel, LikeTabPanelProps } +export { LikeTabPost, LikeTabPostProps } diff --git a/src/components/shop/Post/BuyTabPost/styled.ts b/src/components/shop/Post/LikeTabPost/styled.ts similarity index 100% rename from src/components/shop/Post/BuyTabPost/styled.ts rename to src/components/shop/Post/LikeTabPost/styled.ts diff --git a/src/components/shop/Post/BuyTabPost/likeTabPanel/types.ts b/src/components/shop/Post/LikeTabPost/types.ts similarity index 69% rename from src/components/shop/Post/BuyTabPost/likeTabPanel/types.ts rename to src/components/shop/Post/LikeTabPost/types.ts index 0b45caf3..dd2b4cdb 100644 --- a/src/components/shop/Post/BuyTabPost/likeTabPanel/types.ts +++ b/src/components/shop/Post/LikeTabPost/types.ts @@ -1,6 +1,6 @@ import type { PostSummary } from '@types' -export type LikeTabPanelProps = PostSummary & { +export type LikeTabPostProps = PostSummary & { className?: string onChangeLikeStatus(postId: number): void } diff --git a/src/components/shop/Post/BuyTabPost/offerTabPanel/index.tsx b/src/components/shop/Post/OfferTabPost/index.tsx similarity index 78% rename from src/components/shop/Post/BuyTabPost/offerTabPanel/index.tsx rename to src/components/shop/Post/OfferTabPost/index.tsx index 836c06ac..88623154 100644 --- a/src/components/shop/Post/BuyTabPost/offerTabPanel/index.tsx +++ b/src/components/shop/Post/OfferTabPost/index.tsx @@ -1,23 +1,21 @@ import type { ReactElement } from 'react' -import type { OfferTabPanelProps } from './types' -import { Styled } from '../styled' +import { Styled } from './styled' +import type { OfferTabPostProps } from './types' import { toLocaleCurrency, getTimeDiffText } from '@utils' -const OfferTabPanel = (props: OfferTabPanelProps): ReactElement => { - const { - className, - postId, - thumbnailImageUrl, - title, - seller, - offerPrice, - tradeStatus, - createdAt, - hasReview, - onClickReadReview, - onClickWriteReview - } = props - +const OfferTabPost = ({ + className, + postId, + thumbnailImageUrl, + title, + seller, + offerPrice, + tradeStatus, + createdAt, + hasReview, + onClickReadReview, + onClickWriteReview +}: OfferTabPostProps): ReactElement => { const handleClickReviewButton = () => { hasReview ? onClickReadReview() : onClickWriteReview() } @@ -60,4 +58,4 @@ const OfferTabPanel = (props: OfferTabPanelProps): ReactElement => { ) } -export { OfferTabPanel, OfferTabPanelProps } +export { OfferTabPost, OfferTabPostProps } diff --git a/src/components/shop/Post/OfferTabPost/styled.ts b/src/components/shop/Post/OfferTabPost/styled.ts new file mode 100644 index 00000000..ca9f8720 --- /dev/null +++ b/src/components/shop/Post/OfferTabPost/styled.ts @@ -0,0 +1,199 @@ +import styled from '@emotion/styled' +import { Image, Text, Button } from '@offer-ui/react' + +export const Container = styled.li` + ${({ theme }): string => ` + display: flex; + align-items: center; + justify-content: space-between; + + ${theme.mediaQuery.tablet} { + flex-direction: column; + align-items: unset; + justify-content: unset; + } + `} +` +export const ProductWrapper = styled.div` + ${({ theme }): string => ` + display: grid; + flex: 1; + grid-template-columns: 90px 1fr; + align-items: center; + gap: 16px; + padding: 20px 0 20px 20px; + + ${theme.mediaQuery.tablet} { + grid-template-columns: 68px 1fr; + gap: 8px; + padding: 16px 24px; + } + + ${theme.mediaQuery.mobile} { + min-width: 390px; + padding: 16px; + } + `} +` +export const ProductImg = styled(Image)` + ${({ theme }): string => ` + width: 90px; + height: 90px; + + ${theme.mediaQuery.tablet} { + width: 68px; + height: 68px; + } + `} +` +export const SellerName = styled(Text)` + ${({ theme }): string => ` + text-align: center; + color: ${theme.colors.grayScale70}; + max-width: 100px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + word-break: break-word; + + ${theme.mediaQuery.tablet} { + ${theme.fonts.caption01M}; + } +`} +` + +export const ProductMetaWrapper = styled.div` + ${({ theme }): string => ` + display: flex; + align-items: center; + justify-content: space-around; + + ${theme.mediaQuery.tablet} { + align-items: flex-start; + flex-direction: column; + } + `} +` +export const ProductName = styled(Text)` + ${({ theme }): string => ` + text-align: center; + width: 150px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + word-break: break-word; + + ${theme.mediaQuery.tablet} { + text-align: left; + max-width: 460px; + margin-bottom: 6px; + } + + ${theme.mediaQuery.mobile} { + max-width: 171px; + } + `} +` +export const ProductInfoWrapper = styled.div` + ${({ theme }): string => ` + display: flex; + align-items: center; + justify-content: space-around; + gap: 12px; + + ${theme.mediaQuery.tablet} { + align-items: flex-start; + flex-direction: column; + gap: 0; + } +`} +` +export const Price = styled.span` + ${({ theme }): string => ` + ${theme.fonts.body02R}; + + ${theme.mediaQuery.tablet} { + ${theme.fonts.caption01M}; + color: ${theme.colors.grayScale50}; + } + `} +` +export const TradeStatusName = styled(Text)` + ${({ theme }): string => ` + display: flex; + flex-direction: column; + align-items: center; + width: 100px; + color: ${theme.colors.grayScale50}; + + ${theme.mediaQuery.tablet} { + display: none; + } + `} +` +export const Date = styled(Text)` + ${({ theme }): string => ` + display: inline-block; + color: ${theme.colors.grayScale50}; + + ${theme.mediaQuery.tablet} { + display: none; + ${theme.fonts.caption01M}; + color: ${theme.colors.grayScale30}; + } + `} +` +export const ReviewButtonWrapper = styled.div` + ${({ theme }): string => ` + display: flex; + flex-direction: column; + min-width: 120px; + align-items: flex-end; + + ${theme.mediaQuery.tablet} { + display: flex; + align-items: center; + } + `} +` +export const ReviewButton = styled(Button)<{ hasReview: boolean }>` + ${({ theme, hasReview }): string => ` + color: ${hasReview ? theme.colors.grayScale70 : theme.colors.brandPrimary}; + margin-right: 20px; + + ${theme.mediaQuery.tablet} { + width: 100%; + border: none; + border-top: 1px solid ${theme.colors.grayScale10}; + border-radius: 0; + padding: 20px 0; + margin-right: 0; + } + `} +` +export const LikeButton = styled(Button)` + ${({ theme }): string => ` + color: ${theme.colors.grayScale90}; + margin-right: 20px; + + ${theme.mediaQuery.tablet} { + display: none; + } + `} +` + +export const Styled = { + Container, + ProductWrapper, + ProductImg, + SellerName, + ProductMetaWrapper, + ProductName, + ProductInfoWrapper, + Price, + TradeStatusName, + Date, + ReviewButtonWrapper, + ReviewButton, + LikeButton +} diff --git a/src/components/shop/Post/BuyTabPost/offerTabPanel/types.ts b/src/components/shop/Post/OfferTabPost/types.ts similarity index 71% rename from src/components/shop/Post/BuyTabPost/offerTabPanel/types.ts rename to src/components/shop/Post/OfferTabPost/types.ts index d31fa1d0..a0733022 100644 --- a/src/components/shop/Post/BuyTabPost/offerTabPanel/types.ts +++ b/src/components/shop/Post/OfferTabPost/types.ts @@ -1,6 +1,6 @@ import type { OfferSummary } from '@types' -export type OfferTabPanelProps = OfferSummary & { +export type OfferTabPostProps = OfferSummary & { className?: string onClickReadReview(): void onClickWriteReview(): void diff --git a/src/components/shop/Post/index.tsx b/src/components/shop/Post/index.tsx index 374c156a..34b2464f 100644 --- a/src/components/shop/Post/index.tsx +++ b/src/components/shop/Post/index.tsx @@ -1,3 +1,4 @@ -export * from './BuyTabPost' export * from './SaleTabPost' export * from './ReviewTabPost' +export * from './LikeTabPost' +export * from './OfferTabPost' diff --git a/src/components/shop/PostList/LikeTabPostList/index.tsx b/src/components/shop/PostList/LikeTabPostList/index.tsx index a0bb8d3d..17229ab9 100644 --- a/src/components/shop/PostList/LikeTabPostList/index.tsx +++ b/src/components/shop/PostList/LikeTabPostList/index.tsx @@ -2,7 +2,7 @@ import { Divider } from '@offer-ui/react' import type { ReactElement } from 'react' import { Fragment } from 'react' import type { LikePostListProps } from './types' -import { BuyTabPost } from '@components/shop/Post' +import { LikeTabPost } from '@components/shop/Post' const LikeTabPostList = ({ className, @@ -12,11 +12,7 @@ const LikeTabPostList = ({
    {posts.map((post, index) => ( - + {index !== posts.length - 1 && } ))} diff --git a/src/components/shop/PostList/LikeTabPostList/types.ts b/src/components/shop/PostList/LikeTabPostList/types.ts index 33afdaee..38301232 100644 --- a/src/components/shop/PostList/LikeTabPostList/types.ts +++ b/src/components/shop/PostList/LikeTabPostList/types.ts @@ -1,8 +1,8 @@ -import type { LikeActivityProps } from '@components/shop/Post/BuyTabPost/types' +import type { LikeTabPostProps } from '@components/shop/Post' import type { PostSummary } from '@types' export type LikePostListProps = { className?: string posts: PostSummary[] - onChangeProductLikeStatus: LikeActivityProps['onChangeProductLikeStatus'] + onChangeProductLikeStatus: LikeTabPostProps['onChangeLikeStatus'] } diff --git a/src/components/shop/PostList/OfferTabPostList/index.tsx b/src/components/shop/PostList/OfferTabPostList/index.tsx index fdbd9420..11298871 100644 --- a/src/components/shop/PostList/OfferTabPostList/index.tsx +++ b/src/components/shop/PostList/OfferTabPostList/index.tsx @@ -2,7 +2,7 @@ import { Divider } from '@offer-ui/react' import type { ReactElement } from 'react' import { Fragment } from 'react' import type { OfferPostListProps } from './types' -import { BuyTabPost } from '@components/shop/Post' +import { OfferTabPost } from '@components/shop/Post' const OfferTabPostList = ({ className, @@ -13,8 +13,7 @@ const OfferTabPostList = ({
      {posts.map((post, index) => ( - onClickReadReview(post.review)} onClickWriteReview={() => onClickWriteReview(post)} From 8185b800abfd4afcac99ef3ad30ad4295a3a7378 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 03:36:02 +0900 Subject: [PATCH 42/67] refactor shop components directory --- src/components/shop/Post/index.tsx | 4 ---- src/components/shop/PostList/index.tsx | 4 ---- .../shop/{Post => buy}/LikeTabPost/index.tsx | 0 .../shop/{Post => buy}/LikeTabPost/styled.ts | 0 .../shop/{Post => buy}/LikeTabPost/types.ts | 0 .../shop/{PostList => buy}/LikeTabPostList/index.tsx | 2 +- .../shop/{PostList => buy}/LikeTabPostList/types.ts | 2 +- .../shop/{Post => buy}/OfferTabPost/index.tsx | 0 .../shop/{Post => buy}/OfferTabPost/styled.ts | 0 .../shop/{Post => buy}/OfferTabPost/types.ts | 0 .../shop/{PostList => buy}/OfferTabPostList/index.tsx | 2 +- .../shop/{PostList => buy}/OfferTabPostList/types.ts | 0 .../shop/{ => buy}/ReviewModal/Read/index.tsx | 0 .../shop/{ => buy}/ReviewModal/Read/types.ts | 0 .../{ => buy}/ReviewModal/ReadReviewModal.stories.tsx | 0 .../shop/{ => buy}/ReviewModal/Write/index.tsx | 0 .../shop/{ => buy}/ReviewModal/Write/types.ts | 0 .../ReviewModal/WriteReviewModal.stories.tsx | 0 src/components/shop/{ => buy}/ReviewModal/index.tsx | 0 src/components/shop/{ => buy}/ReviewModal/styled.ts | 0 src/components/shop/{ => buy}/ReviewModal/types.ts | 0 src/components/shop/buy/index.ts | 4 ++++ src/components/shop/index.ts | 11 ++++++----- .../ReviewTabPost/ReviewTabPost.stories.tsx | 0 .../shop/{Post => review}/ReviewTabPost/index.tsx | 0 .../shop/{Post => review}/ReviewTabPost/styled.ts | 0 .../shop/{Post => review}/ReviewTabPost/types.ts | 0 .../ReviewTabPostList/ReviewTabPostList.stories.tsx | 0 .../{PostList => review}/ReviewTabPostList/index.tsx | 2 +- .../{PostList => review}/ReviewTabPostList/types.ts | 0 src/components/shop/review/index.ts | 2 ++ .../SaleTabPost/SaleTabPost.stories.tsx | 0 .../shop/{Post => sale}/SaleTabPost/index.tsx | 0 .../shop/{Post => sale}/SaleTabPost/styled.ts | 0 .../shop/{Post => sale}/SaleTabPost/types.ts | 0 .../SaleTabPostList/SaleTabPostList.stories.tsx | 0 .../shop/{PostList => sale}/SaleTabPostList/index.tsx | 2 +- .../shop/{PostList => sale}/SaleTabPostList/types.ts | 2 +- src/components/shop/sale/index.ts | 2 ++ 39 files changed, 20 insertions(+), 19 deletions(-) delete mode 100644 src/components/shop/Post/index.tsx delete mode 100644 src/components/shop/PostList/index.tsx rename src/components/shop/{Post => buy}/LikeTabPost/index.tsx (100%) rename src/components/shop/{Post => buy}/LikeTabPost/styled.ts (100%) rename src/components/shop/{Post => buy}/LikeTabPost/types.ts (100%) rename src/components/shop/{PostList => buy}/LikeTabPostList/index.tsx (92%) rename src/components/shop/{PostList => buy}/LikeTabPostList/types.ts (75%) rename src/components/shop/{Post => buy}/OfferTabPost/index.tsx (100%) rename src/components/shop/{Post => buy}/OfferTabPost/styled.ts (100%) rename src/components/shop/{Post => buy}/OfferTabPost/types.ts (100%) rename src/components/shop/{PostList => buy}/OfferTabPostList/index.tsx (93%) rename src/components/shop/{PostList => buy}/OfferTabPostList/types.ts (100%) rename src/components/shop/{ => buy}/ReviewModal/Read/index.tsx (100%) rename src/components/shop/{ => buy}/ReviewModal/Read/types.ts (100%) rename src/components/shop/{ => buy}/ReviewModal/ReadReviewModal.stories.tsx (100%) rename src/components/shop/{ => buy}/ReviewModal/Write/index.tsx (100%) rename src/components/shop/{ => buy}/ReviewModal/Write/types.ts (100%) rename src/components/shop/{ => buy}/ReviewModal/WriteReviewModal.stories.tsx (100%) rename src/components/shop/{ => buy}/ReviewModal/index.tsx (100%) rename src/components/shop/{ => buy}/ReviewModal/styled.ts (100%) rename src/components/shop/{ => buy}/ReviewModal/types.ts (100%) create mode 100644 src/components/shop/buy/index.ts rename src/components/shop/{Post => review}/ReviewTabPost/ReviewTabPost.stories.tsx (100%) rename src/components/shop/{Post => review}/ReviewTabPost/index.tsx (100%) rename src/components/shop/{Post => review}/ReviewTabPost/styled.ts (100%) rename src/components/shop/{Post => review}/ReviewTabPost/types.ts (100%) rename src/components/shop/{PostList => review}/ReviewTabPostList/ReviewTabPostList.stories.tsx (100%) rename src/components/shop/{PostList => review}/ReviewTabPostList/index.tsx (91%) rename src/components/shop/{PostList => review}/ReviewTabPostList/types.ts (100%) create mode 100644 src/components/shop/review/index.ts rename src/components/shop/{Post => sale}/SaleTabPost/SaleTabPost.stories.tsx (100%) rename src/components/shop/{Post => sale}/SaleTabPost/index.tsx (100%) rename src/components/shop/{Post => sale}/SaleTabPost/styled.ts (100%) rename src/components/shop/{Post => sale}/SaleTabPost/types.ts (100%) rename src/components/shop/{PostList => sale}/SaleTabPostList/SaleTabPostList.stories.tsx (100%) rename src/components/shop/{PostList => sale}/SaleTabPostList/index.tsx (93%) rename src/components/shop/{PostList => sale}/SaleTabPostList/types.ts (77%) create mode 100644 src/components/shop/sale/index.ts diff --git a/src/components/shop/Post/index.tsx b/src/components/shop/Post/index.tsx deleted file mode 100644 index 34b2464f..00000000 --- a/src/components/shop/Post/index.tsx +++ /dev/null @@ -1,4 +0,0 @@ -export * from './SaleTabPost' -export * from './ReviewTabPost' -export * from './LikeTabPost' -export * from './OfferTabPost' diff --git a/src/components/shop/PostList/index.tsx b/src/components/shop/PostList/index.tsx deleted file mode 100644 index ad85405e..00000000 --- a/src/components/shop/PostList/index.tsx +++ /dev/null @@ -1,4 +0,0 @@ -export * from './OfferTabPostList' -export * from './LikeTabPostList' -export * from './SaleTabPostList' -export * from './ReviewTabPostList' diff --git a/src/components/shop/Post/LikeTabPost/index.tsx b/src/components/shop/buy/LikeTabPost/index.tsx similarity index 100% rename from src/components/shop/Post/LikeTabPost/index.tsx rename to src/components/shop/buy/LikeTabPost/index.tsx diff --git a/src/components/shop/Post/LikeTabPost/styled.ts b/src/components/shop/buy/LikeTabPost/styled.ts similarity index 100% rename from src/components/shop/Post/LikeTabPost/styled.ts rename to src/components/shop/buy/LikeTabPost/styled.ts diff --git a/src/components/shop/Post/LikeTabPost/types.ts b/src/components/shop/buy/LikeTabPost/types.ts similarity index 100% rename from src/components/shop/Post/LikeTabPost/types.ts rename to src/components/shop/buy/LikeTabPost/types.ts diff --git a/src/components/shop/PostList/LikeTabPostList/index.tsx b/src/components/shop/buy/LikeTabPostList/index.tsx similarity index 92% rename from src/components/shop/PostList/LikeTabPostList/index.tsx rename to src/components/shop/buy/LikeTabPostList/index.tsx index 17229ab9..d3ce3180 100644 --- a/src/components/shop/PostList/LikeTabPostList/index.tsx +++ b/src/components/shop/buy/LikeTabPostList/index.tsx @@ -2,7 +2,7 @@ import { Divider } from '@offer-ui/react' import type { ReactElement } from 'react' import { Fragment } from 'react' import type { LikePostListProps } from './types' -import { LikeTabPost } from '@components/shop/Post' +import { LikeTabPost } from '../LikeTabPost' const LikeTabPostList = ({ className, diff --git a/src/components/shop/PostList/LikeTabPostList/types.ts b/src/components/shop/buy/LikeTabPostList/types.ts similarity index 75% rename from src/components/shop/PostList/LikeTabPostList/types.ts rename to src/components/shop/buy/LikeTabPostList/types.ts index 38301232..283e682d 100644 --- a/src/components/shop/PostList/LikeTabPostList/types.ts +++ b/src/components/shop/buy/LikeTabPostList/types.ts @@ -1,4 +1,4 @@ -import type { LikeTabPostProps } from '@components/shop/Post' +import type { LikeTabPostProps } from '../LikeTabPost' import type { PostSummary } from '@types' export type LikePostListProps = { diff --git a/src/components/shop/Post/OfferTabPost/index.tsx b/src/components/shop/buy/OfferTabPost/index.tsx similarity index 100% rename from src/components/shop/Post/OfferTabPost/index.tsx rename to src/components/shop/buy/OfferTabPost/index.tsx diff --git a/src/components/shop/Post/OfferTabPost/styled.ts b/src/components/shop/buy/OfferTabPost/styled.ts similarity index 100% rename from src/components/shop/Post/OfferTabPost/styled.ts rename to src/components/shop/buy/OfferTabPost/styled.ts diff --git a/src/components/shop/Post/OfferTabPost/types.ts b/src/components/shop/buy/OfferTabPost/types.ts similarity index 100% rename from src/components/shop/Post/OfferTabPost/types.ts rename to src/components/shop/buy/OfferTabPost/types.ts diff --git a/src/components/shop/PostList/OfferTabPostList/index.tsx b/src/components/shop/buy/OfferTabPostList/index.tsx similarity index 93% rename from src/components/shop/PostList/OfferTabPostList/index.tsx rename to src/components/shop/buy/OfferTabPostList/index.tsx index 11298871..3c4809a6 100644 --- a/src/components/shop/PostList/OfferTabPostList/index.tsx +++ b/src/components/shop/buy/OfferTabPostList/index.tsx @@ -2,7 +2,7 @@ import { Divider } from '@offer-ui/react' import type { ReactElement } from 'react' import { Fragment } from 'react' import type { OfferPostListProps } from './types' -import { OfferTabPost } from '@components/shop/Post' +import { OfferTabPost } from '../OfferTabPost' const OfferTabPostList = ({ className, diff --git a/src/components/shop/PostList/OfferTabPostList/types.ts b/src/components/shop/buy/OfferTabPostList/types.ts similarity index 100% rename from src/components/shop/PostList/OfferTabPostList/types.ts rename to src/components/shop/buy/OfferTabPostList/types.ts diff --git a/src/components/shop/ReviewModal/Read/index.tsx b/src/components/shop/buy/ReviewModal/Read/index.tsx similarity index 100% rename from src/components/shop/ReviewModal/Read/index.tsx rename to src/components/shop/buy/ReviewModal/Read/index.tsx diff --git a/src/components/shop/ReviewModal/Read/types.ts b/src/components/shop/buy/ReviewModal/Read/types.ts similarity index 100% rename from src/components/shop/ReviewModal/Read/types.ts rename to src/components/shop/buy/ReviewModal/Read/types.ts diff --git a/src/components/shop/ReviewModal/ReadReviewModal.stories.tsx b/src/components/shop/buy/ReviewModal/ReadReviewModal.stories.tsx similarity index 100% rename from src/components/shop/ReviewModal/ReadReviewModal.stories.tsx rename to src/components/shop/buy/ReviewModal/ReadReviewModal.stories.tsx diff --git a/src/components/shop/ReviewModal/Write/index.tsx b/src/components/shop/buy/ReviewModal/Write/index.tsx similarity index 100% rename from src/components/shop/ReviewModal/Write/index.tsx rename to src/components/shop/buy/ReviewModal/Write/index.tsx diff --git a/src/components/shop/ReviewModal/Write/types.ts b/src/components/shop/buy/ReviewModal/Write/types.ts similarity index 100% rename from src/components/shop/ReviewModal/Write/types.ts rename to src/components/shop/buy/ReviewModal/Write/types.ts diff --git a/src/components/shop/ReviewModal/WriteReviewModal.stories.tsx b/src/components/shop/buy/ReviewModal/WriteReviewModal.stories.tsx similarity index 100% rename from src/components/shop/ReviewModal/WriteReviewModal.stories.tsx rename to src/components/shop/buy/ReviewModal/WriteReviewModal.stories.tsx diff --git a/src/components/shop/ReviewModal/index.tsx b/src/components/shop/buy/ReviewModal/index.tsx similarity index 100% rename from src/components/shop/ReviewModal/index.tsx rename to src/components/shop/buy/ReviewModal/index.tsx diff --git a/src/components/shop/ReviewModal/styled.ts b/src/components/shop/buy/ReviewModal/styled.ts similarity index 100% rename from src/components/shop/ReviewModal/styled.ts rename to src/components/shop/buy/ReviewModal/styled.ts diff --git a/src/components/shop/ReviewModal/types.ts b/src/components/shop/buy/ReviewModal/types.ts similarity index 100% rename from src/components/shop/ReviewModal/types.ts rename to src/components/shop/buy/ReviewModal/types.ts diff --git a/src/components/shop/buy/index.ts b/src/components/shop/buy/index.ts new file mode 100644 index 00000000..77d19a7c --- /dev/null +++ b/src/components/shop/buy/index.ts @@ -0,0 +1,4 @@ +export * from './LikeTabPost' +export * from './LikeTabPostList' +export * from './OfferTabPost' +export * from './OfferTabPostList' diff --git a/src/components/shop/index.ts b/src/components/shop/index.ts index 97f8b119..dd5d2e27 100644 --- a/src/components/shop/index.ts +++ b/src/components/shop/index.ts @@ -1,8 +1,9 @@ -export * from './Post' -export * from './PostList' +export * from './sale' +export * from './buy' +export * from './review' export * from './ProfileBox' export * from './SelectBuyerModal' export * from './EditProfileModal' -export * from './ReviewModal' -export * from './ReviewModal/Write/types' -export * from './ReviewModal/Read/types' +export * from './buy/ReviewModal' +export * from './buy/ReviewModal/Write/types' +export * from './buy/ReviewModal/Read/types' diff --git a/src/components/shop/Post/ReviewTabPost/ReviewTabPost.stories.tsx b/src/components/shop/review/ReviewTabPost/ReviewTabPost.stories.tsx similarity index 100% rename from src/components/shop/Post/ReviewTabPost/ReviewTabPost.stories.tsx rename to src/components/shop/review/ReviewTabPost/ReviewTabPost.stories.tsx diff --git a/src/components/shop/Post/ReviewTabPost/index.tsx b/src/components/shop/review/ReviewTabPost/index.tsx similarity index 100% rename from src/components/shop/Post/ReviewTabPost/index.tsx rename to src/components/shop/review/ReviewTabPost/index.tsx diff --git a/src/components/shop/Post/ReviewTabPost/styled.ts b/src/components/shop/review/ReviewTabPost/styled.ts similarity index 100% rename from src/components/shop/Post/ReviewTabPost/styled.ts rename to src/components/shop/review/ReviewTabPost/styled.ts diff --git a/src/components/shop/Post/ReviewTabPost/types.ts b/src/components/shop/review/ReviewTabPost/types.ts similarity index 100% rename from src/components/shop/Post/ReviewTabPost/types.ts rename to src/components/shop/review/ReviewTabPost/types.ts diff --git a/src/components/shop/PostList/ReviewTabPostList/ReviewTabPostList.stories.tsx b/src/components/shop/review/ReviewTabPostList/ReviewTabPostList.stories.tsx similarity index 100% rename from src/components/shop/PostList/ReviewTabPostList/ReviewTabPostList.stories.tsx rename to src/components/shop/review/ReviewTabPostList/ReviewTabPostList.stories.tsx diff --git a/src/components/shop/PostList/ReviewTabPostList/index.tsx b/src/components/shop/review/ReviewTabPostList/index.tsx similarity index 91% rename from src/components/shop/PostList/ReviewTabPostList/index.tsx rename to src/components/shop/review/ReviewTabPostList/index.tsx index 6f3f0d00..42b0e3d9 100644 --- a/src/components/shop/PostList/ReviewTabPostList/index.tsx +++ b/src/components/shop/review/ReviewTabPostList/index.tsx @@ -2,7 +2,7 @@ import { Divider } from '@offer-ui/react' import type { ReactElement } from 'react' import { Fragment } from 'react' import type { ReviewTabPostListProps } from './types' -import { ReviewTabPost } from '@components/shop/Post' +import { ReviewTabPost } from '../ReviewTabPost' const ReviewTabPostList = ({ reviews, diff --git a/src/components/shop/PostList/ReviewTabPostList/types.ts b/src/components/shop/review/ReviewTabPostList/types.ts similarity index 100% rename from src/components/shop/PostList/ReviewTabPostList/types.ts rename to src/components/shop/review/ReviewTabPostList/types.ts diff --git a/src/components/shop/review/index.ts b/src/components/shop/review/index.ts new file mode 100644 index 00000000..8ecdf8ef --- /dev/null +++ b/src/components/shop/review/index.ts @@ -0,0 +1,2 @@ +export * from './ReviewTabPost' +export * from './ReviewTabPostList' diff --git a/src/components/shop/Post/SaleTabPost/SaleTabPost.stories.tsx b/src/components/shop/sale/SaleTabPost/SaleTabPost.stories.tsx similarity index 100% rename from src/components/shop/Post/SaleTabPost/SaleTabPost.stories.tsx rename to src/components/shop/sale/SaleTabPost/SaleTabPost.stories.tsx diff --git a/src/components/shop/Post/SaleTabPost/index.tsx b/src/components/shop/sale/SaleTabPost/index.tsx similarity index 100% rename from src/components/shop/Post/SaleTabPost/index.tsx rename to src/components/shop/sale/SaleTabPost/index.tsx diff --git a/src/components/shop/Post/SaleTabPost/styled.ts b/src/components/shop/sale/SaleTabPost/styled.ts similarity index 100% rename from src/components/shop/Post/SaleTabPost/styled.ts rename to src/components/shop/sale/SaleTabPost/styled.ts diff --git a/src/components/shop/Post/SaleTabPost/types.ts b/src/components/shop/sale/SaleTabPost/types.ts similarity index 100% rename from src/components/shop/Post/SaleTabPost/types.ts rename to src/components/shop/sale/SaleTabPost/types.ts diff --git a/src/components/shop/PostList/SaleTabPostList/SaleTabPostList.stories.tsx b/src/components/shop/sale/SaleTabPostList/SaleTabPostList.stories.tsx similarity index 100% rename from src/components/shop/PostList/SaleTabPostList/SaleTabPostList.stories.tsx rename to src/components/shop/sale/SaleTabPostList/SaleTabPostList.stories.tsx diff --git a/src/components/shop/PostList/SaleTabPostList/index.tsx b/src/components/shop/sale/SaleTabPostList/index.tsx similarity index 93% rename from src/components/shop/PostList/SaleTabPostList/index.tsx rename to src/components/shop/sale/SaleTabPostList/index.tsx index e53802e0..210801e9 100644 --- a/src/components/shop/PostList/SaleTabPostList/index.tsx +++ b/src/components/shop/sale/SaleTabPostList/index.tsx @@ -2,7 +2,7 @@ import { Divider } from '@offer-ui/react' import type { ReactElement } from 'react' import { Fragment } from 'react' import type { SaleTabPostListProps } from './types' -import { SaleTabPost } from '@components/shop/Post' +import { SaleTabPost } from '../SaleTabPost' const SaleTabPostList = ({ posts, diff --git a/src/components/shop/PostList/SaleTabPostList/types.ts b/src/components/shop/sale/SaleTabPostList/types.ts similarity index 77% rename from src/components/shop/PostList/SaleTabPostList/types.ts rename to src/components/shop/sale/SaleTabPostList/types.ts index 274e5f3d..2f1484c6 100644 --- a/src/components/shop/PostList/SaleTabPostList/types.ts +++ b/src/components/shop/sale/SaleTabPostList/types.ts @@ -1,4 +1,4 @@ -import type { SaleTabPostProps } from '@components/shop/Post/SaleTabPost' +import type { SaleTabPostProps } from '@components/shop/sale/SaleTabPost' import type { PostSummary } from '@types' export type SaleTabPostListProps = { diff --git a/src/components/shop/sale/index.ts b/src/components/shop/sale/index.ts new file mode 100644 index 00000000..67895943 --- /dev/null +++ b/src/components/shop/sale/index.ts @@ -0,0 +1,2 @@ +export * from './SaleTabPost' +export * from './SaleTabPostList' From 2020912179b84b302d9b08673397cc2785a750d3 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 23:31:08 +0900 Subject: [PATCH 43/67] implement a LimitedInput component --- src/components/common/LimitedInput/index.tsx | 26 ++++++++++++++++++++ src/components/common/LimitedInput/types.ts | 8 ++++++ src/components/common/index.ts | 1 + 3 files changed, 35 insertions(+) create mode 100644 src/components/common/LimitedInput/index.tsx create mode 100644 src/components/common/LimitedInput/types.ts diff --git a/src/components/common/LimitedInput/index.tsx b/src/components/common/LimitedInput/index.tsx new file mode 100644 index 00000000..2fcd5d7d --- /dev/null +++ b/src/components/common/LimitedInput/index.tsx @@ -0,0 +1,26 @@ +import { Input } from '@offer-ui/react' +import type { ChangeEventHandler } from 'react' +import type { LimitedInputProps } from './types' + +export const LimitedInput = ({ + maxLength, + value, + onChangeValue, + onChange, + ...props +}: LimitedInputProps) => { + const handleChangeValue: ChangeEventHandler = e => { + const newValue = e.target.value + + if (newValue.length <= maxLength) { + onChangeValue(newValue) + } else if (newValue.length > value.length) { + const slicedValue = newValue.slice(0, maxLength) + onChangeValue(slicedValue) + } + + onChange?.(e) + } + + return +} diff --git a/src/components/common/LimitedInput/types.ts b/src/components/common/LimitedInput/types.ts new file mode 100644 index 00000000..1c796ccd --- /dev/null +++ b/src/components/common/LimitedInput/types.ts @@ -0,0 +1,8 @@ +import type { HTMLAttributes } from 'react' + +export type LimitedInputProps = { + className?: string + maxLength: number + value: string + onChangeValue(value: string): void +} & HTMLAttributes diff --git a/src/components/common/index.ts b/src/components/common/index.ts index 34c9d8bb..df6582da 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -3,3 +3,4 @@ export * from './CommonModal' export * from './Header' export * from './AlertModal' export * from './Dialog' +export * from './LimitedInput' From eb03a7f32f36f2b4fcb5cd7f1797e4a332be7494 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 23:32:25 +0900 Subject: [PATCH 44/67] add a constant of valid message --- src/constants/index.ts | 1 + src/constants/message.ts | 6 ++++++ src/types/service.ts | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 src/constants/message.ts diff --git a/src/constants/index.ts b/src/constants/index.ts index 0c4403eb..2d17d74e 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -2,3 +2,4 @@ export * from './icons' export * from './images' export * from './app' export * from './env' +export * from './message' diff --git a/src/constants/message.ts b/src/constants/message.ts new file mode 100644 index 00000000..272a42a8 --- /dev/null +++ b/src/constants/message.ts @@ -0,0 +1,6 @@ +export const VALID_NICKNAME_MESSAGE = { + SUCCESS: '사용할 수 있는 닉네임입니다.', + DUPLICATED_ERROR: '이미 사용 중인 닉네임입니다.', + MIN_LENGTH_ERROR: '닉네임은 2자 이상 입력해주세요.', + EMPTY_ERROR: '닉네임을 입력해주세요!' +} as const diff --git a/src/types/service.ts b/src/types/service.ts index 90b5791b..14e850cd 100644 --- a/src/types/service.ts +++ b/src/types/service.ts @@ -4,7 +4,8 @@ import type { SORT_TYPES, TRADE_TYPES, TRADE_STATUS, - PRODUCT_CONDITIONS + PRODUCT_CONDITIONS, + VALID_NICKNAME_MESSAGE } from '@constants' /** 정렬 옵션 */ @@ -53,3 +54,6 @@ export type TradeBuyActivityNames = ValueOf /** 나의 거래 활동 - 리뷰 */ export type TradeReviewActivityCodes = KeyOf export type TradeReviewActivityNames = ValueOf + +/** 유효성 검사 메시지 */ +export type ValidNicknameMessages = ValueOf From 4db6a81afd4cd71c769a5619111471f8b6bf9dbb Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 23:38:09 +0900 Subject: [PATCH 45/67] refactor ProfileBox types --- src/components/shop/ProfileBox/index.tsx | 32 ++++++++++++------------ src/components/shop/ProfileBox/types.ts | 5 +++- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/components/shop/ProfileBox/index.tsx b/src/components/shop/ProfileBox/index.tsx index aa01ccf3..c78d0ba8 100644 --- a/src/components/shop/ProfileBox/index.tsx +++ b/src/components/shop/ProfileBox/index.tsx @@ -4,15 +4,10 @@ import { Styled } from './styled' import type { ProfileBoxProps } from './types' const ProfileBox = ({ - nickname, - profileImageUrl, - likeProductCount = 0, - offerLevel, - reviewCount, - sellingProductCount, - soldProductCount, className, - hasToken + hasToken, + onClickEditButton, + ...profile }: ProfileBoxProps): ReactElement => { const { desktop } = useMedia() @@ -20,7 +15,12 @@ const ProfileBox = ({ {hasToken && ( - + )} @@ -28,11 +28,11 @@ const ProfileBox = ({ - {nickname} - Lv.{offerLevel} + {profile.nickname} + Lv.{profile.offerLevel} @@ -41,21 +41,21 @@ const ProfileBox = ({ 판매중 - {sellingProductCount}개 + {profile.sellingProductCount}개 거래완료 - {soldProductCount}개 + {profile.soldProductCount}개 거래후기 - {reviewCount}개 + {profile.reviewCount}개 {hasToken && ( @@ -63,7 +63,7 @@ const ProfileBox = ({ 관심상품 - {likeProductCount}개 + {profile.likeProductCount}개 )} diff --git a/src/components/shop/ProfileBox/types.ts b/src/components/shop/ProfileBox/types.ts index b0778965..5a2f2237 100644 --- a/src/components/shop/ProfileBox/types.ts +++ b/src/components/shop/ProfileBox/types.ts @@ -4,4 +4,7 @@ export type ProfileBoxProps = { className?: string likeProductCount?: number hasToken: boolean -} & Omit + onClickEditButton(): void +} & Profile + +export type Profile = Omit From 2fd1d88b89256e1b50f25234388e2e7b8eea6145 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Fri, 5 Jan 2024 23:44:02 +0900 Subject: [PATCH 46/67] implement editProfileModal features --- .../shop/EditProfileModal/index.tsx | 138 +++++++++++++----- .../shop/EditProfileModal/styled.ts | 9 +- src/components/shop/EditProfileModal/types.ts | 13 +- src/components/shop/index.ts | 1 + 4 files changed, 120 insertions(+), 41 deletions(-) diff --git a/src/components/shop/EditProfileModal/index.tsx b/src/components/shop/EditProfileModal/index.tsx index 8833713f..5329f407 100644 --- a/src/components/shop/EditProfileModal/index.tsx +++ b/src/components/shop/EditProfileModal/index.tsx @@ -2,50 +2,110 @@ import { IconButton, Avatar, Modal, - Input, Button, Text, - Icon + Icon, + useImageUploader } from '@offer-ui/react' import type { ReactElement } from 'react' +import { useEffect, useState } from 'react' import { Styled } from './styled' -import type { EditProfileModalProps } from './types' +import type { EditProfileForm, EditProfileModalProps } from './types' +import { LimitedInput } from '@components/common' + +const NICK_NAME_MAX_LENGTH = 20 + +const initialProfileForm = { + image: { id: '', url: '', file: undefined }, + nickname: '' +} export const EditProfileModal = ({ isOpen, - onClose -}: EditProfileModalProps): ReactElement => ( - - - - - -

      프로필 수정

      -
      - - - - - - - - - - - - 닉네임 - - - - 0/20 - - - 중복확인 - - - -
      - -
      -
      -) + validate, + onValidateNickname, + onClose, + onConfirm +}: EditProfileModalProps): ReactElement => { + const [profileForm, setProfileForm] = + useState(initialProfileForm) + const { uploaderRef, openUploader, changeImage } = useImageUploader({ + onChange: image => setProfileForm({ ...profileForm, image }) + }) + + const handleChangeNickname = (nickname: string) => { + setProfileForm({ ...profileForm, nickname }) + } + const handleClickDuplicateButton = () => { + onValidateNickname(profileForm.nickname.trim()) + } + const handleConfirm = () => { + onConfirm(profileForm) + } + + useEffect(() => { + if (!isOpen) { + setProfileForm(initialProfileForm) + return + } + }, [isOpen]) + + return ( + + + + + +

      프로필 수정

      +
      + + + + + + + + + + + + + 닉네임 + + + + {profileForm.nickname.length}/{NICK_NAME_MAX_LENGTH} + + {!!validate.message && ( + + {validate.message} + + )} + + 중복확인 + + + +
      + +
      +
      + ) +} diff --git a/src/components/shop/EditProfileModal/styled.ts b/src/components/shop/EditProfileModal/styled.ts index e27cfedd..d827c303 100644 --- a/src/components/shop/EditProfileModal/styled.ts +++ b/src/components/shop/EditProfileModal/styled.ts @@ -32,6 +32,8 @@ const UploaderWrapper = styled.div` const AvatarWrapper = styled.div` position: relative; + + cursor: pointer; ` const CameraIconButton = styled.button` @@ -66,6 +68,10 @@ const DuplicateButton = styled(Button)` `}; ` +const UploaderInput = styled.input` + display: none; +` + export const Styled = { Header, CloseButtonWrapper, @@ -74,5 +80,6 @@ export const Styled = { AvatarWrapper, CameraIconButton, EditNickName, - DuplicateButton + DuplicateButton, + UploaderInput } diff --git a/src/components/shop/EditProfileModal/types.ts b/src/components/shop/EditProfileModal/types.ts index 6de0495e..79a9c122 100644 --- a/src/components/shop/EditProfileModal/types.ts +++ b/src/components/shop/EditProfileModal/types.ts @@ -1,3 +1,14 @@ import type { ModalProps } from '@offer-ui/react' -export type EditProfileModalProps = Pick +export type EditProfileForm = { + image: { id: string; file?: File; url: string } + nickname: string +} + +export type EditProfileValidate = { isSuccess: boolean; message: string } + +export type EditProfileModalProps = Pick & { + validate: EditProfileValidate + onValidateNickname(nickname: string): void + onConfirm(profile: EditProfileForm): void +} diff --git a/src/components/shop/index.ts b/src/components/shop/index.ts index dd5d2e27..6699332f 100644 --- a/src/components/shop/index.ts +++ b/src/components/shop/index.ts @@ -4,6 +4,7 @@ export * from './review' export * from './ProfileBox' export * from './SelectBuyerModal' export * from './EditProfileModal' +export * from './EditProfileModal/types' export * from './buy/ReviewModal' export * from './buy/ReviewModal/Write/types' export * from './buy/ReviewModal/Read/types' From f68cda36bb46cc1df67426eaa11a7d018e0c3f78 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Sat, 6 Jan 2024 01:17:37 +0900 Subject: [PATCH 47/67] implement image apis and quries --- src/apis/image/apis.ts | 10 +++++++++- src/apis/image/queries.ts | 19 +++++++++++++++---- src/apis/image/types.ts | 4 +--- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/apis/image/apis.ts b/src/apis/image/apis.ts index b6e56509..c71e19fe 100644 --- a/src/apis/image/apis.ts +++ b/src/apis/image/apis.ts @@ -1,4 +1,9 @@ -import type { CreateUploadImagesReq, CreateUploadImagesRes } from './types' +import type { + CreateUploadImagesReq, + CreateUploadImagesRes, + PostUploadImageReq, + PostUploadImageRes +} from './types' import { http } from '@utils/http' export const createUploadImages = (files: CreateUploadImagesReq) => @@ -6,3 +11,6 @@ export const createUploadImages = (files: CreateUploadImagesReq) => '/upload-images', files ) + +export const postUploadImage = (payload: PostUploadImageReq) => + http.post('/upload-image', payload) diff --git a/src/apis/image/queries.ts b/src/apis/image/queries.ts index f9c4ecf8..389aaa0f 100644 --- a/src/apis/image/queries.ts +++ b/src/apis/image/queries.ts @@ -1,8 +1,19 @@ +import type { DefaultError } from '@tanstack/react-query' import { useMutation } from '@tanstack/react-query' -import { createUploadImages } from './apis' -import type { CreateUploadImagesReq } from './types' +import { createUploadImages, postUploadImage } from './apis' +import type { + CreateUploadImagesReq, + CreateUploadImagesRes, + PostUploadImageRes, + PostUploadImageReq +} from './types' export const useCreateUploadImagesMutation = () => - useMutation({ - mutationFn: (files: CreateUploadImagesReq) => createUploadImages(files) + useMutation({ + mutationFn: files => createUploadImages(files) + }) + +export const usePostUploadImageMutation = () => + useMutation({ + mutationFn: formData => postUploadImage(formData) }) diff --git a/src/apis/image/types.ts b/src/apis/image/types.ts index edc6cada..9b88d93e 100644 --- a/src/apis/image/types.ts +++ b/src/apis/image/types.ts @@ -4,9 +4,7 @@ export type CreateUploadImagesReq = FormData export type CreateUploadImagesRes = ImagesUpload -export type PostUploadImageReq = { - file: string -} +export type PostUploadImageReq = FormData export type PostUploadImageRes = ImageUpload export type GetImageReq = { From 882d29765e00d193331229ac02423cee92935be0 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Sat, 6 Jan 2024 01:18:29 +0900 Subject: [PATCH 48/67] add member apis and queries --- src/apis/member/apis.ts | 21 ++++++++++++++++++++- src/apis/member/queries.ts | 30 ++++++++++++++++++++++++++++-- src/apis/member/types.ts | 14 ++++++-------- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/apis/member/apis.ts b/src/apis/member/apis.ts index b0493751..b6acd328 100644 --- a/src/apis/member/apis.ts +++ b/src/apis/member/apis.ts @@ -1,7 +1,11 @@ import type { GetMemberProfileRes, GetMemberProfileReq, - GetMyProfileRes + GetMyProfileRes, + CheckValidNicknameReq, + CheckValidNicknameRes, + UpdateMyProfileReq, + UpdateMyProfileRes } from './types' import { http } from '@utils/http' @@ -11,3 +15,18 @@ export const getMyProfile = () => export const getMemberProfile = async ( memberId: GetMemberProfileReq['memberId'] ) => http.get(`/member/${memberId}`) + +export const updateMyProfile = async ({ + memberId, + ...payload +}: UpdateMyProfileReq) => + http.put, UpdateMyProfileRes>( + `/member/${memberId}`, + payload + ) + +export const checkValidNickname = async (payload: CheckValidNicknameReq) => + http.post( + '/nickname-duplicate', + payload + ) diff --git a/src/apis/member/queries.ts b/src/apis/member/queries.ts index 9eadb752..bfb04132 100644 --- a/src/apis/member/queries.ts +++ b/src/apis/member/queries.ts @@ -1,6 +1,18 @@ -import { useQuery } from '@tanstack/react-query' -import { getMemberProfile, getMyProfile } from './apis' +import type { DefaultError } from '@tanstack/react-query' +import { useMutation, useQuery } from '@tanstack/react-query' +import { + checkValidNickname, + getMemberProfile, + getMyProfile, + updateMyProfile +} from './apis' import { initialMemberProfile, initialMyProfile } from './data' +import type { + CheckValidNicknameReq, + CheckValidNicknameRes, + UpdateMyProfileReq, + UpdateMyProfileRes +} from './types' export const useGetProfileQuery = (memberId: null | number) => useQuery({ @@ -22,3 +34,17 @@ export const useGetMyProfileQuery = (accessToken?: string) => enabled: Boolean(accessToken), initialData: initialMyProfile }) + +export const useUpdateMyProfileMutation = () => + useMutation({ + mutationFn: payload => updateMyProfile(payload) + }) + +export const useCheckValidNicknameMutation = () => + useMutation< + CheckValidNicknameRes, + DefaultError, + CheckValidNicknameReq['nickname'] + >({ + mutationFn: nickname => checkValidNickname({ nickname }) + }) diff --git a/src/apis/member/types.ts b/src/apis/member/types.ts index b5508ac6..b6ea5771 100644 --- a/src/apis/member/types.ts +++ b/src/apis/member/types.ts @@ -7,18 +7,16 @@ export type GetMemberProfileReq = { } export type GetMemberProfileRes = MemberProfile -export type UpdateMemberProfileReq = { +export type UpdateMyProfileReq = { memberId: number nickname: string profileImageUrl: string } -// TODO: 정확한 타입 BE 확인 필요 -export type UpdateMemberProfileRes = number +export type UpdateMyProfileRes = number -export type CheckValidNickNameReq = { - nickName: string +export type CheckValidNicknameReq = { + nickname: string } -// TODO: 정확한 타입 BE 확인 필요 -export type CheckValidNickNameRes = { - [key in string]: boolean +export type CheckValidNicknameRes = { + duplicate: boolean } From 0171a5974769a0d4f249aab18d8cc87abddffbc6 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Sat, 6 Jan 2024 01:20:14 +0900 Subject: [PATCH 49/67] implement a feature of edit profile upload image --- src/components/shop/EditProfileModal/index.tsx | 13 ++++++++++--- src/components/shop/EditProfileModal/types.ts | 3 +++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/components/shop/EditProfileModal/index.tsx b/src/components/shop/EditProfileModal/index.tsx index 5329f407..94079585 100644 --- a/src/components/shop/EditProfileModal/index.tsx +++ b/src/components/shop/EditProfileModal/index.tsx @@ -25,12 +25,16 @@ export const EditProfileModal = ({ validate, onValidateNickname, onClose, - onConfirm + onConfirm, + onChangeImage }: EditProfileModalProps): ReactElement => { const [profileForm, setProfileForm] = useState(initialProfileForm) const { uploaderRef, openUploader, changeImage } = useImageUploader({ - onChange: image => setProfileForm({ ...profileForm, image }) + onChange: async image => { + const uploadedImage = await onChangeImage(image) + setProfileForm({ ...profileForm, image: uploadedImage }) + } }) const handleChangeNickname = (nickname: string) => { @@ -102,7 +106,10 @@ export const EditProfileModal = ({
      -
      diff --git a/src/components/shop/EditProfileModal/types.ts b/src/components/shop/EditProfileModal/types.ts index 79a9c122..99ec214b 100644 --- a/src/components/shop/EditProfileModal/types.ts +++ b/src/components/shop/EditProfileModal/types.ts @@ -11,4 +11,7 @@ export type EditProfileModalProps = Pick & { validate: EditProfileValidate onValidateNickname(nickname: string): void onConfirm(profile: EditProfileForm): void + onChangeImage( + image: EditProfileForm['image'] + ): Promise } From 5051c4050df2de1a794c12da1fd5422bcf56a05b Mon Sep 17 00:00:00 2001 From: sonsurim Date: Sat, 6 Jan 2024 01:22:31 +0900 Subject: [PATCH 50/67] modify shop url --- src/components/common/Header/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/common/Header/index.tsx b/src/components/common/Header/index.tsx index fa5e3a50..bcda1375 100644 --- a/src/components/common/Header/index.tsx +++ b/src/components/common/Header/index.tsx @@ -62,7 +62,7 @@ const Header = (): ReactElement => { styleType="ghost" type="button" width="76px"> - + 나의 거래활동 From 05540c44f310ab2d3a4eaa708eed4cee42434f06 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Sat, 6 Jan 2024 01:23:29 +0900 Subject: [PATCH 51/67] implement feature of apply query in shop page --- src/pages/shop/[id].tsx | 19 +++++++++++++------ src/pages/shop/index.tsx | 18 ++++++++++++++++-- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/pages/shop/[id].tsx b/src/pages/shop/[id].tsx index ec7d6654..b1450957 100644 --- a/src/pages/shop/[id].tsx +++ b/src/pages/shop/[id].tsx @@ -1,18 +1,25 @@ import type { GetServerSidePropsContext } from 'next' import type { ReactElement } from 'react' import { ShopPageView } from './view' +import type { TradeActivityCodes } from '@types' -export const getServerSideProps = (context: GetServerSidePropsContext) => ({ - props: { - memberId: context.query.id +export const getServerSideProps = ({ query }: GetServerSidePropsContext) => { + const { id, tab = 'sale' } = query + + return { + props: { + memberId: id, + currentTab: tab + } } -}) +} type ShopPageProps = { memberId: string + currentTab: TradeActivityCodes } -const ShopPage = ({ memberId }: ShopPageProps): ReactElement => { - return +const ShopPage = ({ memberId, currentTab }: ShopPageProps): ReactElement => { + return } export default ShopPage diff --git a/src/pages/shop/index.tsx b/src/pages/shop/index.tsx index 4cdea82f..b8656310 100644 --- a/src/pages/shop/index.tsx +++ b/src/pages/shop/index.tsx @@ -1,7 +1,21 @@ +import type { GetServerSidePropsContext } from 'next/types' import { ShopPageView } from './view' +import type { TradeActivityCodes } from '@types' -const MyShopPage = () => { - return +export const getServerSideProps = ({ query }: GetServerSidePropsContext) => { + const { tab = 'sale' } = query + + return { + props: { + currentTab: tab + } + } +} +type MyShopPageProps = { + currentTab: TradeActivityCodes +} +const MyShopPage = ({ currentTab }: MyShopPageProps) => { + return } export default MyShopPage From 03036e771cd49ab91636087016fc0c9f8abd6016 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Sat, 6 Jan 2024 01:26:36 +0900 Subject: [PATCH 52/67] implement features of profile box --- src/pages/shop/view/index.tsx | 121 ++++++++++++++++++++++++++++++---- 1 file changed, 107 insertions(+), 14 deletions(-) diff --git a/src/pages/shop/view/index.tsx b/src/pages/shop/view/index.tsx index e9287782..b43421bf 100644 --- a/src/pages/shop/view/index.tsx +++ b/src/pages/shop/view/index.tsx @@ -1,25 +1,106 @@ import { Divider } from '@offer-ui/react' -import type { MouseEvent } from 'react' +import { useRouter } from 'next/router' import { useState } from 'react' import { Styled } from './styled' import { pageTabs } from '../pageTabs' -import { useGetProfileQuery } from '@apis' -import { ProfileBox, Tabs } from '@components' +import { VALID_NICKNAME_MESSAGE } from '@constants/message' +import { + useCheckValidNicknameMutation, + useGetProfileQuery, + usePostUploadImageMutation, + useUpdateMyProfileMutation +} from '@apis' +import type { EditProfileForm } from '@components' +import { EditProfileModal, ProfileBox, Tabs } from '@components' +import { useModal } from '@hooks' +import type { TradeActivityCodes } from '@types' import { isNumber } from '@utils' +const initialEditProfileValidate = { + isSuccess: false, + message: '' +} + type ShopPageViewProps = { memberId: number | null + currentTab: TradeActivityCodes } -export const ShopPageView = ({ memberId }: ShopPageViewProps) => { - const [pageIndex, setPageIndex] = useState(0) +export const ShopPageView = ({ memberId, currentTab }: ShopPageViewProps) => { + const [currentPage, setCurrentPage] = useState(currentTab) + const [editProfileValidate, setEditProfileValidate] = useState( + initialEditProfileValidate + ) + const profile = useGetProfileQuery(memberId) + const postUploadImage = usePostUploadImageMutation() + const checkValidNickname = useCheckValidNicknameMutation() + const updateMyProfile = useUpdateMyProfileMutation() + const hasToken = !isNumber(memberId) + const profileModal = useModal() + const router = useRouter() + + const handleChangePage = (code: TradeActivityCodes) => (): void => { + router.push(`${router.pathname}?tab=${code}`) + setCurrentPage(code) + } + + const handleValidateNickname = async (nickname: string) => { + if (nickname.length === 0) { + setEditProfileValidate({ + isSuccess: false, + message: VALID_NICKNAME_MESSAGE.EMPTY_ERROR + }) + return + } + + if (nickname.length < 2) { + setEditProfileValidate({ + isSuccess: false, + message: VALID_NICKNAME_MESSAGE.MIN_LENGTH_ERROR + }) + return + } + + const { duplicate } = await checkValidNickname.mutateAsync(nickname) + + if (duplicate) { + setEditProfileValidate({ + isSuccess: false, + message: VALID_NICKNAME_MESSAGE.DUPLICATED_ERROR + }) + } else { + setEditProfileValidate({ + isSuccess: true, + message: VALID_NICKNAME_MESSAGE.SUCCESS + }) + } + } + const handleChangeProfileImage = async (image: EditProfileForm['image']) => { + if (!image.file) { + return image + } + + const imageFormData = new FormData() + imageFormData.append('files', image.file) + const { imageUrl } = await postUploadImage.mutateAsync(imageFormData) + + return { id: image.id, file: image.file, url: imageUrl } + } + + const handleCloseEditProfileModal = () => { + setEditProfileValidate(initialEditProfileValidate) + profileModal.closeModal() + } + const handleConfirmEditProfile = async (profileForm: EditProfileForm) => { + await updateMyProfile.mutateAsync({ + memberId: profile.data.id, + nickname: profileForm.nickname, + profileImageUrl: profileForm.image.url + }) + await profile.refetch() - const handleTabClick = ( - _: MouseEvent, - index: number - ): void => { - setPageIndex(index) + handleCloseEditProfileModal() } return ( @@ -31,11 +112,11 @@ export const ShopPageView = ({ memberId }: ShopPageViewProps) => { {pageTabs .filter(pageTab => (hasToken ? true : pageTab.tab.code !== 'buy')) - .map(({ tab }, index) => ( + .map(({ tab }) => ( + isSelected={currentPage === tab.code} + onClick={handleChangePage(tab.code)}> {tab.name} ))} @@ -49,7 +130,11 @@ export const ShopPageView = ({ memberId }: ShopPageViewProps) => { .map(({ tab, panel }) => ( - + {panel({ hasToken, memberId })} @@ -58,6 +143,14 @@ export const ShopPageView = ({ memberId }: ShopPageViewProps) => { +
) } From 21e75aaad9b1a858939587c8c7c1f58a4c241c1d Mon Sep 17 00:00:00 2001 From: sonsurim Date: Mon, 8 Jan 2024 01:04:24 +0900 Subject: [PATCH 53/67] remove unused api and replace upload-image to upload-images --- src/apis/image/apis.ts | 10 +--------- src/apis/image/queries.ts | 14 ++------------ src/apis/image/types.ts | 5 +---- src/pages/shop/view/index.tsx | 8 ++++---- src/types/scheme.ts | 3 --- 5 files changed, 8 insertions(+), 32 deletions(-) diff --git a/src/apis/image/apis.ts b/src/apis/image/apis.ts index c71e19fe..b6e56509 100644 --- a/src/apis/image/apis.ts +++ b/src/apis/image/apis.ts @@ -1,9 +1,4 @@ -import type { - CreateUploadImagesReq, - CreateUploadImagesRes, - PostUploadImageReq, - PostUploadImageRes -} from './types' +import type { CreateUploadImagesReq, CreateUploadImagesRes } from './types' import { http } from '@utils/http' export const createUploadImages = (files: CreateUploadImagesReq) => @@ -11,6 +6,3 @@ export const createUploadImages = (files: CreateUploadImagesReq) => '/upload-images', files ) - -export const postUploadImage = (payload: PostUploadImageReq) => - http.post('/upload-image', payload) diff --git a/src/apis/image/queries.ts b/src/apis/image/queries.ts index 389aaa0f..0c523aad 100644 --- a/src/apis/image/queries.ts +++ b/src/apis/image/queries.ts @@ -1,19 +1,9 @@ import type { DefaultError } from '@tanstack/react-query' import { useMutation } from '@tanstack/react-query' -import { createUploadImages, postUploadImage } from './apis' -import type { - CreateUploadImagesReq, - CreateUploadImagesRes, - PostUploadImageRes, - PostUploadImageReq -} from './types' +import { createUploadImages } from './apis' +import type { CreateUploadImagesReq, CreateUploadImagesRes } from './types' export const useCreateUploadImagesMutation = () => useMutation({ mutationFn: files => createUploadImages(files) }) - -export const usePostUploadImageMutation = () => - useMutation({ - mutationFn: formData => postUploadImage(formData) - }) diff --git a/src/apis/image/types.ts b/src/apis/image/types.ts index 9b88d93e..0ee76c49 100644 --- a/src/apis/image/types.ts +++ b/src/apis/image/types.ts @@ -1,12 +1,9 @@ -import type { ImagesUpload, ImageUpload } from '@types' +import type { ImagesUpload } from '@types' export type CreateUploadImagesReq = FormData export type CreateUploadImagesRes = ImagesUpload -export type PostUploadImageReq = FormData -export type PostUploadImageRes = ImageUpload - export type GetImageReq = { path: string } diff --git a/src/pages/shop/view/index.tsx b/src/pages/shop/view/index.tsx index b43421bf..c411fcc2 100644 --- a/src/pages/shop/view/index.tsx +++ b/src/pages/shop/view/index.tsx @@ -6,8 +6,8 @@ import { pageTabs } from '../pageTabs' import { VALID_NICKNAME_MESSAGE } from '@constants/message' import { useCheckValidNicknameMutation, + useCreateUploadImagesMutation, useGetProfileQuery, - usePostUploadImageMutation, useUpdateMyProfileMutation } from '@apis' import type { EditProfileForm } from '@components' @@ -32,7 +32,7 @@ export const ShopPageView = ({ memberId, currentTab }: ShopPageViewProps) => { ) const profile = useGetProfileQuery(memberId) - const postUploadImage = usePostUploadImageMutation() + const createUploadImage = useCreateUploadImagesMutation() const checkValidNickname = useCheckValidNicknameMutation() const updateMyProfile = useUpdateMyProfileMutation() @@ -83,9 +83,9 @@ export const ShopPageView = ({ memberId, currentTab }: ShopPageViewProps) => { const imageFormData = new FormData() imageFormData.append('files', image.file) - const { imageUrl } = await postUploadImage.mutateAsync(imageFormData) + const { imageUrls } = await createUploadImage.mutateAsync(imageFormData) - return { id: image.id, file: image.file, url: imageUrl } + return { id: image.id, file: image.file, url: imageUrls[0] } } const handleCloseEditProfileModal = () => { diff --git a/src/types/scheme.ts b/src/types/scheme.ts index d20dc631..2feb1e6a 100644 --- a/src/types/scheme.ts +++ b/src/types/scheme.ts @@ -82,9 +82,6 @@ export type MyProfile = MemberProfile & { export type ImagesUpload = { imageUrls: string[] } -export type ImageUpload = { - imageUrl: string -} /** Review */ export type ReviewInfo = { From 1cdbabf11e8bee65dc0311af0d138769a0782bd0 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Mon, 8 Jan 2024 01:37:13 +0900 Subject: [PATCH 54/67] implement get review counts api and queries --- src/apis/review/apis.ts | 9 ++++++++- src/apis/review/data.ts | 2 +- src/apis/review/queries.ts | 27 +++++++-------------------- src/apis/review/types.ts | 7 ++++++- src/pages/shop/pageTabs.ts | 2 ++ src/pages/shop/panel/review/index.tsx | 6 +++--- src/pages/shop/view/index.tsx | 5 +++-- src/types/scheme.ts | 5 +++++ 8 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/apis/review/apis.ts b/src/apis/review/apis.ts index 3063380d..fb4e693e 100644 --- a/src/apis/review/apis.ts +++ b/src/apis/review/apis.ts @@ -2,7 +2,9 @@ import type { GetReviewsReq, GetReviewsRes, CreateReviewReq, - CreateReviewRes + CreateReviewRes, + GetReviewsCountsReq, + GetReviewsCountsRes } from './types' import { http } from '@utils/http' @@ -11,3 +13,8 @@ export const getReviews = (params: GetReviewsReq) => export const createReviews = (payload: CreateReviewReq) => http.post('/reviews', payload) + +export const getReviewsCounts = (params: GetReviewsCountsReq) => + http.get( + `/reviews/counts?memberId=${params.memberId}` + ) diff --git a/src/apis/review/data.ts b/src/apis/review/data.ts index 012df75d..ebbd2fa8 100644 --- a/src/apis/review/data.ts +++ b/src/apis/review/data.ts @@ -1,4 +1,4 @@ -export const initialAllReviewLengths = { +export const initialReviewsCounts = { ALL: 0, SELLER: 0, BUYER: 0 diff --git a/src/apis/review/queries.ts b/src/apis/review/queries.ts index d4289c32..20cccc28 100644 --- a/src/apis/review/queries.ts +++ b/src/apis/review/queries.ts @@ -1,32 +1,19 @@ import type { DefaultError } from '@tanstack/react-query' import { useMutation, useQuery } from '@tanstack/react-query' -import { createReviews, getReviews } from './apis' -import { initialAllReviewLengths, initialReviews } from './data' +import { createReviews, getReviews, getReviewsCounts } from './apis' +import { initialReviewsCounts, initialReviews } from './data' import type { CreateReviewReq, CreateReviewRes, GetReviewsReq } from './types' -// 리뷰 갯수 조회 api 임시 대체 -export const useGetReviewsLengthQuery = (memberId: number) => +export const useGetReviewsCountsQuery = (memberId: number) => useQuery({ - queryKey: ['allReviews', memberId], + queryKey: ['reviewsCounts', memberId], queryFn: async () => { - const searchOptions = { - memberId, - lastId: 0, - limit: 100 - } + const { all, seller, buyer } = await getReviewsCounts({ memberId }) - const all = await getReviews({ ...searchOptions, role: 'ALL' }) - const buyer = await getReviews({ ...searchOptions, role: 'BUYER' }) - const seller = await getReviews({ ...searchOptions, role: 'SELLER' }) - - return { - ALL: all.reviews.length, - BUYER: buyer.reviews.length, - SELLER: seller.reviews.length - } + return { ALL: all, SELLER: seller, BUYER: buyer } }, enabled: Boolean(memberId), - initialData: initialAllReviewLengths + initialData: initialReviewsCounts }) export const useGetReviewsQuery = (searchOptions: GetReviewsReq) => diff --git a/src/apis/review/types.ts b/src/apis/review/types.ts index d5b51ef4..26fa0bae 100644 --- a/src/apis/review/types.ts +++ b/src/apis/review/types.ts @@ -1,4 +1,4 @@ -import type { CommonCreation, ReviewInfo } from '@types' +import type { CommonCreation, ReviewCount, ReviewInfo } from '@types' export type GetReviewsReq = { memberId: number @@ -15,3 +15,8 @@ export type CreateReviewReq = { content: string } export type CreateReviewRes = CommonCreation + +export type GetReviewsCountsReq = { + memberId: number +} +export type GetReviewsCountsRes = ReviewCount diff --git a/src/pages/shop/pageTabs.ts b/src/pages/shop/pageTabs.ts index 0d0040bc..227c707e 100644 --- a/src/pages/shop/pageTabs.ts +++ b/src/pages/shop/pageTabs.ts @@ -14,6 +14,8 @@ type PageTab = { panel(props: unknown): ReactElement } +export const tabList = ['sale', 'buy', 'review'] + export const pageTabs: PageTab[] = [ { tab: { diff --git a/src/pages/shop/panel/review/index.tsx b/src/pages/shop/panel/review/index.tsx index 70124a44..4ae9e614 100644 --- a/src/pages/shop/panel/review/index.tsx +++ b/src/pages/shop/panel/review/index.tsx @@ -2,7 +2,7 @@ import { useState } from 'react' import { Styled } from './styled' import { useGetProfileQuery, - useGetReviewsLengthQuery, + useGetReviewsCountsQuery, useGetReviewsQuery } from '@apis' import { Tabs, ReviewTabPostList } from '@components' @@ -22,7 +22,7 @@ export const ShopPageReviewPanel = ({ memberId }: ShopPageReviewPanelProps) => { const [reviewType, setReviewType] = useState('ALL') const profile = useGetProfileQuery(memberId) - const reviewsLength = useGetReviewsLengthQuery(profile.data.id) + const reviewsCounts = useGetReviewsCountsQuery(profile.data.id) const reviews = useGetReviewsQuery({ memberId: profile.data.id, lastId: 0, @@ -55,7 +55,7 @@ export const ShopPageReviewPanel = ({ memberId }: ShopPageReviewPanelProps) => { {name} - {reviewsLength.data[code]} + {reviewsCounts.data[code]} diff --git a/src/pages/shop/view/index.tsx b/src/pages/shop/view/index.tsx index c411fcc2..460af2a3 100644 --- a/src/pages/shop/view/index.tsx +++ b/src/pages/shop/view/index.tsx @@ -2,7 +2,7 @@ import { Divider } from '@offer-ui/react' import { useRouter } from 'next/router' import { useState } from 'react' import { Styled } from './styled' -import { pageTabs } from '../pageTabs' +import { pageTabs, tabList } from '../pageTabs' import { VALID_NICKNAME_MESSAGE } from '@constants/message' import { useCheckValidNicknameMutation, @@ -26,6 +26,7 @@ type ShopPageViewProps = { currentTab: TradeActivityCodes } export const ShopPageView = ({ memberId, currentTab }: ShopPageViewProps) => { + const defaultTabIndex = tabList.findIndex(tab => tab === currentTab) const [currentPage, setCurrentPage] = useState(currentTab) const [editProfileValidate, setEditProfileValidate] = useState( initialEditProfileValidate @@ -107,7 +108,7 @@ export const ShopPageView = ({ memberId, currentTab }: ShopPageViewProps) => {
{profile.data.nickname}님의 거래 활동 - + {pageTabs diff --git a/src/types/scheme.ts b/src/types/scheme.ts index 2feb1e6a..17243814 100644 --- a/src/types/scheme.ts +++ b/src/types/scheme.ts @@ -96,6 +96,11 @@ export type Review = { content: string createdDate: string } +export type ReviewCount = { + all: number + seller: number + buyer: number +} export type ReviewTargetMember = { id: number profileImageUrl: string From 2b5b0a4f65136613b4924caef30de3c9d639d667 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Mon, 8 Jan 2024 01:55:43 +0900 Subject: [PATCH 55/67] fix review button when not avaliable review --- .../shop/buy/OfferTabPost/index.tsx | 24 ++++++++++++------- .../shop/buy/OfferTabPost/styled.ts | 4 ++++ src/pages/shop/panel/buy/view/offer.tsx | 10 +++++++- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/components/shop/buy/OfferTabPost/index.tsx b/src/components/shop/buy/OfferTabPost/index.tsx index 88623154..fb060d1f 100644 --- a/src/components/shop/buy/OfferTabPost/index.tsx +++ b/src/components/shop/buy/OfferTabPost/index.tsx @@ -14,11 +14,13 @@ const OfferTabPost = ({ createdAt, hasReview, onClickReadReview, - onClickWriteReview + onClickWriteReview, + reviewAvailable }: OfferTabPostProps): ReactElement => { const handleClickReviewButton = () => { hasReview ? onClickReadReview() : onClickWriteReview() } + const isShowReviewButton = hasReview || reviewAvailable return ( @@ -46,13 +48,19 @@ const OfferTabPost = ({ - - {hasReview ? '보낸 후기 보기' : '후기 보내기'} - + {isShowReviewButton ? ( + + {hasReview ? '보낸 후기 보기' : '후기 보내기'} + + ) : ( + + - + + )} ) diff --git a/src/components/shop/buy/OfferTabPost/styled.ts b/src/components/shop/buy/OfferTabPost/styled.ts index ca9f8720..23641164 100644 --- a/src/components/shop/buy/OfferTabPost/styled.ts +++ b/src/components/shop/buy/OfferTabPost/styled.ts @@ -171,6 +171,9 @@ export const ReviewButton = styled(Button)<{ hasReview: boolean }>` } `} ` +export const ReviewBlankButton = styled(Text)` + align-self: center; +` export const LikeButton = styled(Button)` ${({ theme }): string => ` color: ${theme.colors.grayScale90}; @@ -195,5 +198,6 @@ export const Styled = { Date, ReviewButtonWrapper, ReviewButton, + ReviewBlankButton, LikeButton } diff --git a/src/pages/shop/panel/buy/view/offer.tsx b/src/pages/shop/panel/buy/view/offer.tsx index 6cf44ad6..18c90628 100644 --- a/src/pages/shop/panel/buy/view/offer.tsx +++ b/src/pages/shop/panel/buy/view/offer.tsx @@ -1,8 +1,13 @@ import { useState } from 'react' import { useModal } from '@hooks/useModal' -import { useGetMyOffersQuery, useReviewsMutation } from '@apis' +import { + useGetMyOffersQuery, + useGetReviewsCountsQuery, + useReviewsMutation +} from '@apis' import type { ReviewState } from '@components' import { OfferTabPostList, ReviewModal } from '@components' +import { useAuth } from '@hooks' import type { OfferSummary, Review, SortOptionCodes } from '@types' import { isNumber } from '@utils' @@ -10,7 +15,9 @@ type OfferPanelViewProps = { sortOptionCode: SortOptionCodes } export const OfferPanelView = ({ sortOptionCode }: OfferPanelViewProps) => { + const { user } = useAuth() const offers = useGetMyOffersQuery({ sort: sortOptionCode }) + const reviewsCounts = useGetReviewsCountsQuery(user.id) const reviewsMutation = useReviewsMutation() const readReviewModal = useModal() @@ -39,6 +46,7 @@ export const OfferPanelView = ({ sortOptionCode }: OfferPanelViewProps) => { content: reviewState.reviewText }) await offers.refetch() + await reviewsCounts.refetch() writeReviewModal.closeModal() } From 1a82c5717ff206264acec7399ad69d928fcea22f Mon Sep 17 00:00:00 2001 From: sonsurim Date: Mon, 8 Jan 2024 22:12:00 +0900 Subject: [PATCH 56/67] change review type name in profile box --- src/components/shop/ProfileBox/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/shop/ProfileBox/index.tsx b/src/components/shop/ProfileBox/index.tsx index c78d0ba8..db2a3422 100644 --- a/src/components/shop/ProfileBox/index.tsx +++ b/src/components/shop/ProfileBox/index.tsx @@ -53,7 +53,7 @@ const ProfileBox = ({ - 거래후기 + 받은후기 {profile.reviewCount}개 From 99a7f832a1428a3639bfa7d0813cf8d72567160a Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 16 Jan 2024 01:22:23 +0900 Subject: [PATCH 57/67] modify a tradeStatus type more clearly --- src/apis/post/types.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/apis/post/types.ts b/src/apis/post/types.ts index 02e8de16..7b6c4a2e 100644 --- a/src/apis/post/types.ts +++ b/src/apis/post/types.ts @@ -5,6 +5,7 @@ import type { PostSummaries, ProductConditionCodes, SortOptionsShape, + TradeStatusCodes, TradeStatusType, TradeTypeCodes } from '@types' @@ -34,7 +35,7 @@ export type DeletePostRes = { export type UpdateTradeStatusReq = { postId: number - tradeStatus: string + tradeStatus: TradeStatusCodes } export type UpdateTradeStatusRes = number From 0601e9b26299dfb7eafbefac47e3b221d75b0031 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 16 Jan 2024 01:23:47 +0900 Subject: [PATCH 58/67] modify useGetReviewsCountsQuery to use a select method --- src/apis/review/data.ts | 12 +++++++++--- src/apis/review/queries.ts | 15 +++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/apis/review/data.ts b/src/apis/review/data.ts index ebbd2fa8..49c01dca 100644 --- a/src/apis/review/data.ts +++ b/src/apis/review/data.ts @@ -1,7 +1,13 @@ +import type { TradeReviewActivityCodes } from '@types' + +export type SelectReviewCounts = { + [key in TradeReviewActivityCodes]: number +} + export const initialReviewsCounts = { - ALL: 0, - SELLER: 0, - BUYER: 0 + all: 0, + seller: 0, + buyer: 0 } export const initialReviews = { diff --git a/src/apis/review/queries.ts b/src/apis/review/queries.ts index 20cccc28..9a1d5c00 100644 --- a/src/apis/review/queries.ts +++ b/src/apis/review/queries.ts @@ -1,17 +1,20 @@ import type { DefaultError } from '@tanstack/react-query' import { useMutation, useQuery } from '@tanstack/react-query' import { createReviews, getReviews, getReviewsCounts } from './apis' +import type { SelectReviewCounts } from './data' import { initialReviewsCounts, initialReviews } from './data' import type { CreateReviewReq, CreateReviewRes, GetReviewsReq } from './types' +import type { ReviewCount } from '@types' export const useGetReviewsCountsQuery = (memberId: number) => - useQuery({ + useQuery({ queryKey: ['reviewsCounts', memberId], - queryFn: async () => { - const { all, seller, buyer } = await getReviewsCounts({ memberId }) - - return { ALL: all, SELLER: seller, BUYER: buyer } - }, + queryFn: async () => getReviewsCounts({ memberId }), + select: ({ all, seller, buyer }) => ({ + ALL: all, + SELLER: seller, + BUYER: buyer + }), enabled: Boolean(memberId), initialData: initialReviewsCounts }) From 0963351094c4ef2e2979db518d5718dd277112bf Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 16 Jan 2024 01:25:38 +0900 Subject: [PATCH 59/67] replace a HTMLInputAttribute in a LimitedInputProps to InputProps --- src/components/common/LimitedInput/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/common/LimitedInput/types.ts b/src/components/common/LimitedInput/types.ts index 1c796ccd..fa5fbd6c 100644 --- a/src/components/common/LimitedInput/types.ts +++ b/src/components/common/LimitedInput/types.ts @@ -1,8 +1,8 @@ -import type { HTMLAttributes } from 'react' +import type { InputProps } from '@offer-ui/react' export type LimitedInputProps = { className?: string maxLength: number value: string onChangeValue(value: string): void -} & HTMLAttributes +} & InputProps From b44ddfe214701ae0dcb1d4ca335b54f9ac57a47d Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 16 Jan 2024 01:26:39 +0900 Subject: [PATCH 60/67] remove an unnecessary useEffect and implement a handleClose function --- src/components/shop/EditProfileModal/index.tsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/components/shop/EditProfileModal/index.tsx b/src/components/shop/EditProfileModal/index.tsx index 94079585..8749762c 100644 --- a/src/components/shop/EditProfileModal/index.tsx +++ b/src/components/shop/EditProfileModal/index.tsx @@ -8,7 +8,7 @@ import { useImageUploader } from '@offer-ui/react' import type { ReactElement } from 'react' -import { useEffect, useState } from 'react' +import { useState } from 'react' import { Styled } from './styled' import type { EditProfileForm, EditProfileModalProps } from './types' import { LimitedInput } from '@components/common' @@ -47,15 +47,13 @@ export const EditProfileModal = ({ onConfirm(profileForm) } - useEffect(() => { - if (!isOpen) { - setProfileForm(initialProfileForm) - return - } - }, [isOpen]) + const handleClose = () => { + onClose?.() + setProfileForm(initialProfileForm) + } return ( - + From 1ef559795b6e82521ea5eac4c7068f3efd63664d Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 16 Jan 2024 01:35:05 +0900 Subject: [PATCH 61/67] fix css string to emotion css --- src/components/shop/ProfileBox/styled.ts | 84 ++++++++++++++---------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/src/components/shop/ProfileBox/styled.ts b/src/components/shop/ProfileBox/styled.ts index 79f64ad5..f4254d1d 100644 --- a/src/components/shop/ProfileBox/styled.ts +++ b/src/components/shop/ProfileBox/styled.ts @@ -1,10 +1,12 @@ import type { Theme } from '@emotion/react' +import { css } from '@emotion/react' import styled from '@emotion/styled' import { Avatar as AvatarComponent } from '@offer-ui/react' const Container = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` position: relative; + width: 276px; height: 388px; padding: 26px; @@ -24,12 +26,15 @@ const Container = styled.div` `} ` const SettingsButton = styled.button` - ${({ theme }): string => ` + ${({ theme }) => css` float: right; - cursor: pointer; + + margin-top: -6px; border: none; + background: none; - margin-top: -6px; + + cursor: pointer; ${theme.mediaQuery.tablet} { margin-top: 0; @@ -38,7 +43,7 @@ const SettingsButton = styled.button` ` const ProfileWrapper = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` margin-top: 28px; ${theme.mediaQuery.tablet} { @@ -47,7 +52,7 @@ const ProfileWrapper = styled.div` `} ` const Avatar = styled(AvatarComponent)` - ${({ theme }): string => ` + ${({ theme }) => css` ${theme.avatar.medium}; ${theme.mediaQuery.tablet} { @@ -56,41 +61,46 @@ const Avatar = styled(AvatarComponent)` `} ` const UserWrapper = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; flex-direction: column; align-items: center; + margin-bottom: 24px; ${theme.mediaQuery.tablet} { flex-direction: row; align-items: flex-start; + margin-bottom: 16px; } -`} + `} ` const NickNameRow = styled.div` - ${({ theme }): string => ` - display: flex; - gap: 4px; - flex-direction: column; - margin-top: 14px; - align-items: center; + ${({ theme }) => css` + display: flex; + flex-direction: column; + gap: 4px; + align-items: center; - ${theme.mediaQuery.tablet} { - margin-top: 0; - margin-left: 12px; - align-items: flex-start; - } -`} + margin-top: 14px; + + ${theme.mediaQuery.tablet} { + align-items: flex-start; + + margin-top: 0; + margin-left: 12px; + } + `} ` const NickName = styled.span` - ${({ theme }): string => ` + ${({ theme }) => css` + overflow: hidden; ${theme.fonts.headline02B}; width: 180px; + text-align: center; text-overflow: ellipsis; - overflow: hidden; white-space: nowrap; word-break: break-word; @@ -105,28 +115,30 @@ const NickName = styled.span` `} ` const UserProductWrapper = styled.div<{ hasToken: boolean }>` - ${({ theme, hasToken }): string => ` + ${({ theme, hasToken }) => css` display: grid; - background-color: ${theme.colors.bgGray01}; gap: 16px; + padding: 16px 20px; + background-color: ${theme.colors.bgGray01}; + ${theme.mediaQuery.tablet} { - ${ - hasToken - ? 'grid-template-columns: 1fr 1fr 1fr 1fr;' - : 'grid-template-areas: ". sell sold review .";' - } + ${hasToken + ? 'grid-template-columns: 1fr 1fr 1fr 1fr;' + : 'grid-template-areas: ". sell sold review .";'} gap: 93px; - padding: 24px 40px; + min-width: 684px; + padding: 24px 40px; } ${theme.mediaQuery.mobile} { - grid-template-columns: 1fr 1fr; grid-template-areas: none; + grid-template-columns: 1fr 1fr; gap: 44px; + min-width: 300px; padding: 20px 36px; } @@ -135,14 +147,14 @@ const UserProductWrapper = styled.div<{ hasToken: boolean }>` const setStyleByToken = (theme: Theme, hasToken: boolean) => { if (hasToken) { - return ` + return css` ${theme.mediaQuery.mobile} { min-width: 90px; } ` } - return ` + return css` ${theme.mediaQuery.desktop} { :nth-of-type(1), :nth-of-type(2), @@ -155,9 +167,11 @@ const setStyleByToken = (theme: Theme, hasToken: boolean) => { :nth-of-type(1) { grid-area: sold; } + :nth-of-type(2) { grid-area: sell; } + :nth-of-type(3) { grid-area: review; } @@ -165,17 +179,17 @@ const setStyleByToken = (theme: Theme, hasToken: boolean) => { ${theme.mediaQuery.mobile} { min-width: 90px; + :nth-of-type(1), :nth-of-type(2), :nth-of-type(3) { grid-area: auto; } } - } ` } const UserProductRow = styled.div<{ hasToken: boolean }>` - ${({ theme, hasToken }) => ` + ${({ theme, hasToken }) => css` display: flex; align-items: center; justify-content: space-between; From a62508cf987d4370dc7219f743100e3a33251873 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 16 Jan 2024 01:53:03 +0900 Subject: [PATCH 62/67] redeclare an object.keys type and replace a score array to a score object --- src/@types/global.d.ts | 1 + .../shop/buy/ReviewModal/Read/index.tsx | 8 +++-- .../shop/buy/ReviewModal/Write/index.tsx | 29 ++++++++----------- src/components/shop/buy/ReviewModal/index.tsx | 10 ++----- src/components/shop/buy/ReviewModal/types.ts | 7 ++--- src/constants/app.ts | 6 ++++ src/pages/shop/panel/buy/view/offer.tsx | 6 ++-- src/types/service.ts | 8 ++++- 8 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 490d947c..cd2a0540 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -11,5 +11,6 @@ declare global { // eslint-disable-next-line @typescript-eslint/consistent-type-definitions interface ObjectConstructor { entries(o: { [s: T]: K } | ArrayLike): [T, K][] + keys(o: object): T[] } } diff --git a/src/components/shop/buy/ReviewModal/Read/index.tsx b/src/components/shop/buy/ReviewModal/Read/index.tsx index 9695db16..011572be 100644 --- a/src/components/shop/buy/ReviewModal/Read/index.tsx +++ b/src/components/shop/buy/ReviewModal/Read/index.tsx @@ -1,7 +1,9 @@ import type { ReactElement } from 'react' import type { ReadReviewModalProps } from './types' -import { CommonTitleContainer, SCORE_OPTIONS, SCORE_STATE } from '..' +import { CommonTitleContainer, SCORE_OPTIONS } from '..' import { Styled } from '../styled' +import { SCORE } from '@constants' +import type { ScoreNames } from '@types' export const Read = ({ isOpen = true, @@ -12,6 +14,8 @@ export const Read = ({ post, content = '리뷰' }: ReadReviewModalProps): ReactElement => { + const scoreNames = Object.keys(SCORE) + if (!reviewTargetMember) { return <> } @@ -24,7 +28,7 @@ export const Read = ({ /> - +

{SCORE_OPTIONS[score]?.text}

diff --git a/src/components/shop/buy/ReviewModal/Write/index.tsx b/src/components/shop/buy/ReviewModal/Write/index.tsx index 127bbf74..848c8c16 100644 --- a/src/components/shop/buy/ReviewModal/Write/index.tsx +++ b/src/components/shop/buy/ReviewModal/Write/index.tsx @@ -1,7 +1,7 @@ import type { ChangeEventHandler, ReactElement } from 'react' -import { useEffect, useState } from 'react' +import { useState } from 'react' import type { WriteReviewModalProps, ReviewState } from './types' -import { CommonTitleContainer, SCORE_OPTIONS, SCORE_STATE } from '..' +import { CommonTitleContainer, SCORE_OPTIONS } from '..' import { Styled } from '../styled' import type { ScoreState } from '../types' import { isNumber } from '@utils' @@ -33,22 +33,17 @@ export const Write = ({ onConfirm(reviewState) } - useEffect( - function resetReviewState() { - if (isOpen) { - return - } + const handleClose = () => { + onClose?.() - setReviewState({ - reviewScore: null, - reviewText: '' - }) - }, - [isOpen] - ) + setReviewState({ + reviewScore: null, + reviewText: '' + }) + } return ( - + {SCORE_OPTIONS.map(scoreItem => { @@ -60,8 +55,8 @@ export const Write = ({

{scoreItem.text}

diff --git a/src/components/shop/buy/ReviewModal/index.tsx b/src/components/shop/buy/ReviewModal/index.tsx index 5e098874..2712d597 100644 --- a/src/components/shop/buy/ReviewModal/index.tsx +++ b/src/components/shop/buy/ReviewModal/index.tsx @@ -1,24 +1,20 @@ -import type { IconType } from '@offer-ui/react' import type { ReactElement } from 'react' import { Read } from './Read' import { Styled } from './styled' import type { CommonReviewModalProps, ScoreOptions } from './types' import { Write } from './Write' -type Score = Extract -export const SCORE_STATE: Score[] = ['sad', 'meh', 'smile'] - export const SCORE_OPTIONS: ScoreOptions = [ { - state: 2, + state: 'smile', text: '좋아요' }, { - state: 1, + state: 'meh', text: '보통이에요' }, { - state: 0, + state: 'sad', text: '별로에요' } ] diff --git a/src/components/shop/buy/ReviewModal/types.ts b/src/components/shop/buy/ReviewModal/types.ts index 432a61c8..6b004211 100644 --- a/src/components/shop/buy/ReviewModal/types.ts +++ b/src/components/shop/buy/ReviewModal/types.ts @@ -1,8 +1,7 @@ import type { ModalProps } from '@offer-ui/react' +import type { ScoreNames } from '@types' -export type Score = 0 | 1 | 2 - -export type ScoreState = Score | null +export type ScoreState = ScoreNames | null export type CommonReviewModalProps = Pick & { nickname: string @@ -10,7 +9,7 @@ export type CommonReviewModalProps = Pick & { } export type ScoreOptions = { - state: Score + state: ScoreNames text: string }[] diff --git a/src/constants/app.ts b/src/constants/app.ts index 247ed893..9296a6e6 100644 --- a/src/constants/app.ts +++ b/src/constants/app.ts @@ -123,3 +123,9 @@ export const CATEGORIES = [ name: '기타 중고물품' } ] as const + +export const SCORE = { + sad: 0, + meh: 1, + smile: 2 +} as const diff --git a/src/pages/shop/panel/buy/view/offer.tsx b/src/pages/shop/panel/buy/view/offer.tsx index 18c90628..c76acad6 100644 --- a/src/pages/shop/panel/buy/view/offer.tsx +++ b/src/pages/shop/panel/buy/view/offer.tsx @@ -7,9 +7,9 @@ import { } from '@apis' import type { ReviewState } from '@components' import { OfferTabPostList, ReviewModal } from '@components' +import { SCORE } from '@constants' import { useAuth } from '@hooks' import type { OfferSummary, Review, SortOptionCodes } from '@types' -import { isNumber } from '@utils' type OfferPanelViewProps = { sortOptionCode: SortOptionCodes @@ -35,14 +35,14 @@ export const OfferPanelView = ({ sortOptionCode }: OfferPanelViewProps) => { writeReviewModal.openModal() } const handleConfirmWriteReview = async (reviewState: ReviewState) => { - if (!isNumber(reviewState.reviewScore)) { + if (!reviewState.reviewScore) { return } await reviewsMutation.mutateAsync({ targetMemberId: writeReviewProps.seller.id, postId: writeReviewProps.postId, - score: reviewState.reviewScore, + score: SCORE[reviewState.reviewScore], content: reviewState.reviewText }) await offers.refetch() diff --git a/src/types/service.ts b/src/types/service.ts index 14e850cd..e506fb4b 100644 --- a/src/types/service.ts +++ b/src/types/service.ts @@ -5,7 +5,8 @@ import type { TRADE_TYPES, TRADE_STATUS, PRODUCT_CONDITIONS, - VALID_NICKNAME_MESSAGE + VALID_NICKNAME_MESSAGE, + SCORE } from '@constants' /** 정렬 옵션 */ @@ -57,3 +58,8 @@ export type TradeReviewActivityNames = ValueOf /** 유효성 검사 메시지 */ export type ValidNicknameMessages = ValueOf + +/** 리뷰 */ +export type Score = typeof SCORE +export type ScoreNames = KeyOf +export type ScoreCodes = ValueOf From 203d43e6ba92478d6de662279044cb626a0752b0 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 16 Jan 2024 01:56:47 +0900 Subject: [PATCH 63/67] rename an user to getMyProfileQuery in useAuth hook --- src/hooks/useAuth.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts index 46bbbd3f..edf04ece 100644 --- a/src/hooks/useAuth.ts +++ b/src/hooks/useAuth.ts @@ -7,8 +7,8 @@ import { env } from '@constants' export const useAuth = () => { const router = useRouter() const accessToken = getCookie(env.AUTH_TOKEN_KEY) - const user = useGetMyProfileQuery(accessToken) - const [isLogin, setIsLogin] = useState(user.isSuccess) + const getMyProfileQuery = useGetMyProfileQuery(accessToken) + const [isLogin, setIsLogin] = useState(getMyProfileQuery.isSuccess) const handleLogout = () => { deleteCookie(env.AUTH_TOKEN_KEY) @@ -23,8 +23,8 @@ export const useAuth = () => { return { isLogin, - isLoading: user.isLoading, + isLoading: getMyProfileQuery.isLoading, handleLogout, - user: user.data + user: getMyProfileQuery.data } } From 8121ef9ba0358dd5c4d56d613ae165a8d3a46ce5 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 16 Jan 2024 01:58:53 +0900 Subject: [PATCH 64/67] replace hasToken to isLogin --- src/components/shop/ProfileBox/index.tsx | 16 ++++++++-------- src/components/shop/ProfileBox/styled.ts | 16 ++++++++-------- src/components/shop/ProfileBox/types.ts | 2 +- .../sale/SaleTabPost/SaleTabPost.stories.tsx | 15 +++++---------- src/components/shop/sale/SaleTabPost/index.tsx | 10 +++++----- src/components/shop/sale/SaleTabPost/styled.ts | 12 ++++++------ src/components/shop/sale/SaleTabPost/types.ts | 2 +- .../SaleTabPostList/SaleTabPostList.stories.tsx | 4 ++-- .../shop/sale/SaleTabPostList/index.tsx | 4 ++-- .../shop/sale/SaleTabPostList/types.ts | 2 +- src/pages/shop/panel/sale/index.tsx | 6 +++--- 11 files changed, 42 insertions(+), 47 deletions(-) diff --git a/src/components/shop/ProfileBox/index.tsx b/src/components/shop/ProfileBox/index.tsx index db2a3422..d6b63b6c 100644 --- a/src/components/shop/ProfileBox/index.tsx +++ b/src/components/shop/ProfileBox/index.tsx @@ -5,7 +5,7 @@ import type { ProfileBoxProps } from './types' const ProfileBox = ({ className, - hasToken, + isLogin, onClickEditButton, ...profile }: ProfileBoxProps): ReactElement => { @@ -13,7 +13,7 @@ const ProfileBox = ({ return ( - {hasToken && ( + {isLogin && ( Lv.{profile.offerLevel} - - + + 판매중 {profile.sellingProductCount}개 - + 거래완료 {profile.soldProductCount}개 - + 받은후기 {profile.reviewCount}개 - {hasToken && ( - + {isLogin && ( + 관심상품 diff --git a/src/components/shop/ProfileBox/styled.ts b/src/components/shop/ProfileBox/styled.ts index f4254d1d..fdb17309 100644 --- a/src/components/shop/ProfileBox/styled.ts +++ b/src/components/shop/ProfileBox/styled.ts @@ -114,8 +114,8 @@ const NickName = styled.span` } `} ` -const UserProductWrapper = styled.div<{ hasToken: boolean }>` - ${({ theme, hasToken }) => css` +const UserProductWrapper = styled.div<{ isLogin: boolean }>` + ${({ theme, isLogin }) => css` display: grid; gap: 16px; @@ -124,7 +124,7 @@ const UserProductWrapper = styled.div<{ hasToken: boolean }>` background-color: ${theme.colors.bgGray01}; ${theme.mediaQuery.tablet} { - ${hasToken + ${isLogin ? 'grid-template-columns: 1fr 1fr 1fr 1fr;' : 'grid-template-areas: ". sell sold review .";'} @@ -145,8 +145,8 @@ const UserProductWrapper = styled.div<{ hasToken: boolean }>` `} ` -const setStyleByToken = (theme: Theme, hasToken: boolean) => { - if (hasToken) { +const setStyleByToken = (theme: Theme, isLogin: boolean) => { + if (isLogin) { return css` ${theme.mediaQuery.mobile} { min-width: 90px; @@ -188,8 +188,8 @@ const setStyleByToken = (theme: Theme, hasToken: boolean) => { } ` } -const UserProductRow = styled.div<{ hasToken: boolean }>` - ${({ theme, hasToken }) => css` +const UserProductRow = styled.div<{ isLogin: boolean }>` + ${({ theme, isLogin }) => css` display: flex; align-items: center; justify-content: space-between; @@ -198,7 +198,7 @@ const UserProductRow = styled.div<{ hasToken: boolean }>` min-width: 85px; } - ${setStyleByToken(theme, hasToken)} + ${setStyleByToken(theme, isLogin)} `} ` const UserProductTitleWrapper = styled.p` diff --git a/src/components/shop/ProfileBox/types.ts b/src/components/shop/ProfileBox/types.ts index 5a2f2237..f9246da4 100644 --- a/src/components/shop/ProfileBox/types.ts +++ b/src/components/shop/ProfileBox/types.ts @@ -3,7 +3,7 @@ import type { MyProfile } from '@types' export type ProfileBoxProps = { className?: string likeProductCount?: number - hasToken: boolean + isLogin: boolean onClickEditButton(): void } & Profile diff --git a/src/components/shop/sale/SaleTabPost/SaleTabPost.stories.tsx b/src/components/shop/sale/SaleTabPost/SaleTabPost.stories.tsx index bc9bced8..bfa70159 100644 --- a/src/components/shop/sale/SaleTabPost/SaleTabPost.stories.tsx +++ b/src/components/shop/sale/SaleTabPost/SaleTabPost.stories.tsx @@ -36,22 +36,17 @@ const PrimaryWithHooks: Story = args => {
내 사용자 - - + + 타 사용자 @@ -59,7 +54,7 @@ const PrimaryWithHooks: Story = args => { } export const Primary: StoryObj = { args: { - hasToken: false, + isLogin: false, // sellerNickName: 'sonny', id: 4, thumbnailImageUrl: '', diff --git a/src/components/shop/sale/SaleTabPost/index.tsx b/src/components/shop/sale/SaleTabPost/index.tsx index 36db6434..60a351db 100644 --- a/src/components/shop/sale/SaleTabPost/index.tsx +++ b/src/components/shop/sale/SaleTabPost/index.tsx @@ -15,7 +15,7 @@ const SaleTabPost = ({ tradeStatus, likeCount, createdAt, - hasToken, + isLogin, onChangeTradeStatus, hasReview }: SaleTabPostProps): ReactElement => { @@ -27,9 +27,9 @@ const SaleTabPost = ({ return ( - + - {hasToken ? ( + {isLogin ? ( {likeCount} - + {getTimeDiffText(createdAt)}
- {hasToken && isSoldOut && ( + {isLogin && isSoldOut && ( ` - ${({ theme, hasToken }): string => ` +const ProductWrapper = styled.div<{ isLogin: boolean }>` + ${({ theme, isLogin }): string => ` display: grid; flex: 1; - grid-template-columns: ${hasToken ? '90px 90px 1fr' : '90px 1fr'}; + grid-template-columns: ${isLogin ? '90px 90px 1fr' : '90px 1fr'}; align-items: center; gap: 16px; padding: 20px 0 20px 20px; @@ -135,13 +135,13 @@ const FavoriteWrapper = styled.div<{ isOnlyOther: boolean }>` } `} ` -const Date = styled(Text)<{ hasToken: boolean }>` - ${({ theme, hasToken }): string => ` +const Date = styled(Text)<{ isLogin: boolean }>` + ${({ theme, isLogin }): string => ` display: inline-block; color: ${theme.colors.grayScale50}; ${theme.mediaQuery.tablet} { - display: ${hasToken ? 'none' : 'inline-block'}; + display: ${isLogin ? 'none' : 'inline-block'}; ${theme.fonts.caption01M}; color: ${theme.colors.grayScale30}; } diff --git a/src/components/shop/sale/SaleTabPost/types.ts b/src/components/shop/sale/SaleTabPost/types.ts index 4ec29735..43872626 100644 --- a/src/components/shop/sale/SaleTabPost/types.ts +++ b/src/components/shop/sale/SaleTabPost/types.ts @@ -1,7 +1,7 @@ import type { PostSummary, TradeStatusType } from '@types' export type SaleTabPostProps = { - hasToken: boolean + isLogin: boolean className?: string // tradeStatus 변경 시, 이벤트 onChangeTradeStatus(productId: number, status: TradeStatusType): void diff --git a/src/components/shop/sale/SaleTabPostList/SaleTabPostList.stories.tsx b/src/components/shop/sale/SaleTabPostList/SaleTabPostList.stories.tsx index e0434b7d..b8bc57bd 100644 --- a/src/components/shop/sale/SaleTabPostList/SaleTabPostList.stories.tsx +++ b/src/components/shop/sale/SaleTabPostList/SaleTabPostList.stories.tsx @@ -48,14 +48,14 @@ const PrimaryWithHooks = (args: SaleTabPostListProps) => {
{tradeStatus.name}
- + ) } export const Primary: StoryObj = { args: { - hasToken: true, + isLogin: true, posts: [], onChangeTradeStatus: (id: number, status: TradeStatusType): void => { action('onChangeTradeStatus')(id, status) diff --git a/src/components/shop/sale/SaleTabPostList/index.tsx b/src/components/shop/sale/SaleTabPostList/index.tsx index 210801e9..4a0c2e2e 100644 --- a/src/components/shop/sale/SaleTabPostList/index.tsx +++ b/src/components/shop/sale/SaleTabPostList/index.tsx @@ -6,7 +6,7 @@ import { SaleTabPost } from '../SaleTabPost' const SaleTabPostList = ({ posts, - hasToken, + isLogin, onChangeTradeStatus, className }: SaleTabPostListProps): ReactElement => { @@ -16,7 +16,7 @@ const SaleTabPostList = ({ {index !== posts.length - 1 && } diff --git a/src/components/shop/sale/SaleTabPostList/types.ts b/src/components/shop/sale/SaleTabPostList/types.ts index 2f1484c6..e760eb03 100644 --- a/src/components/shop/sale/SaleTabPostList/types.ts +++ b/src/components/shop/sale/SaleTabPostList/types.ts @@ -4,6 +4,6 @@ import type { PostSummary } from '@types' export type SaleTabPostListProps = { posts: PostSummary[] className?: string - hasToken: boolean + isLogin: boolean onChangeTradeStatus: SaleTabPostProps['onChangeTradeStatus'] } diff --git a/src/pages/shop/panel/sale/index.tsx b/src/pages/shop/panel/sale/index.tsx index b0add045..5a6eac1f 100644 --- a/src/pages/shop/panel/sale/index.tsx +++ b/src/pages/shop/panel/sale/index.tsx @@ -13,11 +13,11 @@ import { SORT_OPTIONS, TRADE_STATUS } from '@constants' import type { SortOption } from '@types' export type ShopPageSalePanelProps = { - hasToken: boolean + isLogin: boolean memberId: number | null } export const ShopPageSalePanel = ({ - hasToken, + isLogin, memberId }: ShopPageSalePanelProps) => { const [searchOptions, setSearchOptions] = useState({ @@ -108,7 +108,7 @@ export const ShopPageSalePanel = ({ {TRADE_STATUS.map(tradeStatus => ( From 37510a3179acb11cc0da7b2d66e6484c0d7e3cad Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 16 Jan 2024 01:59:26 +0900 Subject: [PATCH 65/67] implement the useValidateNickname hook --- src/hooks/useValidateNickname.ts | 45 +++++++++++++++++++++++++++++++ src/pages/shop/view/index.tsx | 46 +++++++------------------------- 2 files changed, 54 insertions(+), 37 deletions(-) create mode 100644 src/hooks/useValidateNickname.ts diff --git a/src/hooks/useValidateNickname.ts b/src/hooks/useValidateNickname.ts new file mode 100644 index 00000000..8591397a --- /dev/null +++ b/src/hooks/useValidateNickname.ts @@ -0,0 +1,45 @@ +import { useCheckValidNicknameMutation } from '@apis' +import { VALID_NICKNAME_MESSAGE } from '@constants' + +export const useValidateNickname = () => { + const checkValidNickname = useCheckValidNicknameMutation() + + const validateNickname = async (nickname: string) => { + if (nickname.length === 0) { + return { + isSuccess: false, + message: VALID_NICKNAME_MESSAGE.EMPTY_ERROR + } + } + + if (nickname.length < 2) { + return { + isSuccess: false, + message: VALID_NICKNAME_MESSAGE.MIN_LENGTH_ERROR + } + } + + try { + const { duplicate } = await checkValidNickname.mutateAsync(nickname) + + if (duplicate) { + return { + isSuccess: false, + message: VALID_NICKNAME_MESSAGE.DUPLICATED_ERROR + } + } else { + return { + isSuccess: true, + message: VALID_NICKNAME_MESSAGE.SUCCESS + } + } + } catch (e) { + return { + isSuccess: false, + message: 'An error occurred during nickname validation.' + } + } + } + + return validateNickname +} diff --git a/src/pages/shop/view/index.tsx b/src/pages/shop/view/index.tsx index 460af2a3..2c73509f 100644 --- a/src/pages/shop/view/index.tsx +++ b/src/pages/shop/view/index.tsx @@ -3,9 +3,8 @@ import { useRouter } from 'next/router' import { useState } from 'react' import { Styled } from './styled' import { pageTabs, tabList } from '../pageTabs' -import { VALID_NICKNAME_MESSAGE } from '@constants/message' +import { useValidateNickname } from '@hooks/useValidateNickname' import { - useCheckValidNicknameMutation, useCreateUploadImagesMutation, useGetProfileQuery, useUpdateMyProfileMutation @@ -34,12 +33,12 @@ export const ShopPageView = ({ memberId, currentTab }: ShopPageViewProps) => { const profile = useGetProfileQuery(memberId) const createUploadImage = useCreateUploadImagesMutation() - const checkValidNickname = useCheckValidNicknameMutation() const updateMyProfile = useUpdateMyProfileMutation() - const hasToken = !isNumber(memberId) + const isLogin = !isNumber(memberId) const profileModal = useModal() const router = useRouter() + const validateNickname = useValidateNickname() const handleChangePage = (code: TradeActivityCodes) => (): void => { router.push(`${router.pathname}?tab=${code}`) @@ -47,35 +46,8 @@ export const ShopPageView = ({ memberId, currentTab }: ShopPageViewProps) => { } const handleValidateNickname = async (nickname: string) => { - if (nickname.length === 0) { - setEditProfileValidate({ - isSuccess: false, - message: VALID_NICKNAME_MESSAGE.EMPTY_ERROR - }) - return - } - - if (nickname.length < 2) { - setEditProfileValidate({ - isSuccess: false, - message: VALID_NICKNAME_MESSAGE.MIN_LENGTH_ERROR - }) - return - } - - const { duplicate } = await checkValidNickname.mutateAsync(nickname) - - if (duplicate) { - setEditProfileValidate({ - isSuccess: false, - message: VALID_NICKNAME_MESSAGE.DUPLICATED_ERROR - }) - } else { - setEditProfileValidate({ - isSuccess: true, - message: VALID_NICKNAME_MESSAGE.SUCCESS - }) - } + const validate = await validateNickname(nickname) + setEditProfileValidate(validate) } const handleChangeProfileImage = async (image: EditProfileForm['image']) => { if (!image.file) { @@ -112,7 +84,7 @@ export const ShopPageView = ({ memberId, currentTab }: ShopPageViewProps) => { {pageTabs - .filter(pageTab => (hasToken ? true : pageTab.tab.code !== 'buy')) + .filter(pageTab => (isLogin ? true : pageTab.tab.code !== 'buy')) .map(({ tab }) => ( { {pageTabs - .filter(pageTab => (hasToken ? true : pageTab.tab.code !== 'buy')) + .filter(pageTab => (isLogin ? true : pageTab.tab.code !== 'buy')) .map(({ tab, panel }) => ( - {panel({ hasToken, memberId })} + {panel({ isLogin, memberId })} ))} From 9a346d70536d38bf37326d0d323c420fc9a0bf33 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Tue, 16 Jan 2024 02:11:55 +0900 Subject: [PATCH 66/67] replace plain text to emotion css in shop components --- .../shop/EditProfileModal/styled.ts | 2 +- .../shop/SelectBuyerModal/styled.ts | 4 +- src/components/shop/buy/LikeTabPost/styled.ts | 80 +++++++++++-------- .../shop/buy/OfferTabPost/styled.ts | 80 +++++++++++-------- src/components/shop/buy/ReviewModal/styled.ts | 54 ++++++------- .../shop/review/ReviewTabPost/styled.ts | 20 +++-- .../shop/sale/SaleTabPost/styled.ts | 66 ++++++++------- 7 files changed, 176 insertions(+), 130 deletions(-) diff --git a/src/components/shop/EditProfileModal/styled.ts b/src/components/shop/EditProfileModal/styled.ts index d827c303..7fe44444 100644 --- a/src/components/shop/EditProfileModal/styled.ts +++ b/src/components/shop/EditProfileModal/styled.ts @@ -6,7 +6,7 @@ import { Button } from '@offer-ui/react' const Header = styled.div` text-align: center; - ${({ theme }): string => theme.fonts.headline01B} + ${({ theme }) => theme.fonts.headline01B} ` const CloseButtonWrapper = styled.div` diff --git a/src/components/shop/SelectBuyerModal/styled.ts b/src/components/shop/SelectBuyerModal/styled.ts index ab8242b2..ae3374f9 100644 --- a/src/components/shop/SelectBuyerModal/styled.ts +++ b/src/components/shop/SelectBuyerModal/styled.ts @@ -92,7 +92,7 @@ const BuyerInfo = styled.div` ` const Nickname = styled.span` - ${({ theme }): string => theme.fonts.body02B} + ${({ theme }) => theme.fonts.body02B} ` const OfferTime = styled.span` @@ -141,7 +141,7 @@ const Footer = styled.div` ` const SendReviewButton = styled(Button)` :disabled { - background-color: ${({ theme }): string => theme.colors.grayScale20}; + background-color: ${({ theme }) => theme.colors.grayScale20}; } ` diff --git a/src/components/shop/buy/LikeTabPost/styled.ts b/src/components/shop/buy/LikeTabPost/styled.ts index ca9f8720..9273e8bb 100644 --- a/src/components/shop/buy/LikeTabPost/styled.ts +++ b/src/components/shop/buy/LikeTabPost/styled.ts @@ -1,8 +1,9 @@ +import { css } from '@emotion/react' import styled from '@emotion/styled' import { Image, Text, Button } from '@offer-ui/react' export const Container = styled.li` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; align-items: center; justify-content: space-between; @@ -15,17 +16,19 @@ export const Container = styled.li` `} ` export const ProductWrapper = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` display: grid; flex: 1; grid-template-columns: 90px 1fr; - align-items: center; gap: 16px; + align-items: center; + padding: 20px 0 20px 20px; ${theme.mediaQuery.tablet} { grid-template-columns: 68px 1fr; gap: 8px; + padding: 16px 24px; } @@ -36,7 +39,7 @@ export const ProductWrapper = styled.div` `} ` export const ProductImg = styled(Image)` - ${({ theme }): string => ` + ${({ theme }) => css` width: 90px; height: 90px; @@ -47,46 +50,51 @@ export const ProductImg = styled(Image)` `} ` export const SellerName = styled(Text)` - ${({ theme }): string => ` - text-align: center; - color: ${theme.colors.grayScale70}; + ${({ theme }) => css` + overflow: hidden; + max-width: 100px; + + color: ${theme.colors.grayScale70}; + text-align: center; text-overflow: ellipsis; - overflow: hidden; white-space: nowrap; word-break: break-word; - ${theme.mediaQuery.tablet} { - ${theme.fonts.caption01M}; - } -`} + ${theme.mediaQuery.tablet} { + ${theme.fonts.caption01M}; + } + `} ` export const ProductMetaWrapper = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; align-items: center; justify-content: space-around; ${theme.mediaQuery.tablet} { - align-items: flex-start; flex-direction: column; + align-items: flex-start; } `} ` export const ProductName = styled(Text)` - ${({ theme }): string => ` - text-align: center; + ${({ theme }) => css` + overflow: hidden; + width: 150px; + + text-align: center; text-overflow: ellipsis; - overflow: hidden; white-space: nowrap; word-break: break-word; ${theme.mediaQuery.tablet} { - text-align: left; max-width: 460px; margin-bottom: 6px; + + text-align: left; } ${theme.mediaQuery.mobile} { @@ -95,21 +103,21 @@ export const ProductName = styled(Text)` `} ` export const ProductInfoWrapper = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; + gap: 12px; align-items: center; justify-content: space-around; - gap: 12px; ${theme.mediaQuery.tablet} { - align-items: flex-start; flex-direction: column; gap: 0; + align-items: flex-start; } -`} + `} ` export const Price = styled.span` - ${({ theme }): string => ` + ${({ theme }) => css` ${theme.fonts.body02R}; ${theme.mediaQuery.tablet} { @@ -119,11 +127,13 @@ export const Price = styled.span` `} ` export const TradeStatusName = styled(Text)` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; flex-direction: column; align-items: center; + width: 100px; + color: ${theme.colors.grayScale50}; ${theme.mediaQuery.tablet} { @@ -132,8 +142,9 @@ export const TradeStatusName = styled(Text)` `} ` export const Date = styled(Text)` - ${({ theme }): string => ` + ${({ theme }) => css` display: inline-block; + color: ${theme.colors.grayScale50}; ${theme.mediaQuery.tablet} { @@ -144,12 +155,13 @@ export const Date = styled(Text)` `} ` export const ReviewButtonWrapper = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; flex-direction: column; - min-width: 120px; align-items: flex-end; + min-width: 120px; + ${theme.mediaQuery.tablet} { display: flex; align-items: center; @@ -157,25 +169,27 @@ export const ReviewButtonWrapper = styled.div` `} ` export const ReviewButton = styled(Button)<{ hasReview: boolean }>` - ${({ theme, hasReview }): string => ` - color: ${hasReview ? theme.colors.grayScale70 : theme.colors.brandPrimary}; + ${({ theme, hasReview }) => css` margin-right: 20px; + color: ${hasReview ? theme.colors.grayScale70 : theme.colors.brandPrimary}; + ${theme.mediaQuery.tablet} { width: 100%; + margin-right: 0; + padding: 20px 0; border: none; border-top: 1px solid ${theme.colors.grayScale10}; border-radius: 0; - padding: 20px 0; - margin-right: 0; } `} ` export const LikeButton = styled(Button)` - ${({ theme }): string => ` - color: ${theme.colors.grayScale90}; + ${({ theme }) => css` margin-right: 20px; + color: ${theme.colors.grayScale90}; + ${theme.mediaQuery.tablet} { display: none; } diff --git a/src/components/shop/buy/OfferTabPost/styled.ts b/src/components/shop/buy/OfferTabPost/styled.ts index 23641164..b8dd5859 100644 --- a/src/components/shop/buy/OfferTabPost/styled.ts +++ b/src/components/shop/buy/OfferTabPost/styled.ts @@ -1,8 +1,9 @@ +import { css } from '@emotion/react' import styled from '@emotion/styled' import { Image, Text, Button } from '@offer-ui/react' export const Container = styled.li` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; align-items: center; justify-content: space-between; @@ -15,17 +16,19 @@ export const Container = styled.li` `} ` export const ProductWrapper = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` display: grid; flex: 1; grid-template-columns: 90px 1fr; - align-items: center; gap: 16px; + align-items: center; + padding: 20px 0 20px 20px; ${theme.mediaQuery.tablet} { grid-template-columns: 68px 1fr; gap: 8px; + padding: 16px 24px; } @@ -36,7 +39,7 @@ export const ProductWrapper = styled.div` `} ` export const ProductImg = styled(Image)` - ${({ theme }): string => ` + ${({ theme }) => css` width: 90px; height: 90px; @@ -47,46 +50,51 @@ export const ProductImg = styled(Image)` `} ` export const SellerName = styled(Text)` - ${({ theme }): string => ` - text-align: center; - color: ${theme.colors.grayScale70}; + ${({ theme }) => css` + overflow: hidden; + max-width: 100px; + + color: ${theme.colors.grayScale70}; + text-align: center; text-overflow: ellipsis; - overflow: hidden; white-space: nowrap; word-break: break-word; - ${theme.mediaQuery.tablet} { - ${theme.fonts.caption01M}; - } -`} + ${theme.mediaQuery.tablet} { + ${theme.fonts.caption01M}; + } + `} ` export const ProductMetaWrapper = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; align-items: center; justify-content: space-around; ${theme.mediaQuery.tablet} { - align-items: flex-start; flex-direction: column; + align-items: flex-start; } `} ` export const ProductName = styled(Text)` - ${({ theme }): string => ` - text-align: center; + ${({ theme }) => css` + overflow: hidden; + width: 150px; + + text-align: center; text-overflow: ellipsis; - overflow: hidden; white-space: nowrap; word-break: break-word; ${theme.mediaQuery.tablet} { - text-align: left; max-width: 460px; margin-bottom: 6px; + + text-align: left; } ${theme.mediaQuery.mobile} { @@ -95,21 +103,21 @@ export const ProductName = styled(Text)` `} ` export const ProductInfoWrapper = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; + gap: 12px; align-items: center; justify-content: space-around; - gap: 12px; ${theme.mediaQuery.tablet} { - align-items: flex-start; flex-direction: column; gap: 0; + align-items: flex-start; } -`} + `} ` export const Price = styled.span` - ${({ theme }): string => ` + ${({ theme }) => css` ${theme.fonts.body02R}; ${theme.mediaQuery.tablet} { @@ -119,11 +127,13 @@ export const Price = styled.span` `} ` export const TradeStatusName = styled(Text)` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; flex-direction: column; align-items: center; + width: 100px; + color: ${theme.colors.grayScale50}; ${theme.mediaQuery.tablet} { @@ -132,8 +142,9 @@ export const TradeStatusName = styled(Text)` `} ` export const Date = styled(Text)` - ${({ theme }): string => ` + ${({ theme }) => css` display: inline-block; + color: ${theme.colors.grayScale50}; ${theme.mediaQuery.tablet} { @@ -144,12 +155,13 @@ export const Date = styled(Text)` `} ` export const ReviewButtonWrapper = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; flex-direction: column; - min-width: 120px; align-items: flex-end; + min-width: 120px; + ${theme.mediaQuery.tablet} { display: flex; align-items: center; @@ -157,17 +169,18 @@ export const ReviewButtonWrapper = styled.div` `} ` export const ReviewButton = styled(Button)<{ hasReview: boolean }>` - ${({ theme, hasReview }): string => ` - color: ${hasReview ? theme.colors.grayScale70 : theme.colors.brandPrimary}; + ${({ theme, hasReview }) => css` margin-right: 20px; + color: ${hasReview ? theme.colors.grayScale70 : theme.colors.brandPrimary}; + ${theme.mediaQuery.tablet} { width: 100%; + margin-right: 0; + padding: 20px 0; border: none; border-top: 1px solid ${theme.colors.grayScale10}; border-radius: 0; - padding: 20px 0; - margin-right: 0; } `} ` @@ -175,10 +188,11 @@ export const ReviewBlankButton = styled(Text)` align-self: center; ` export const LikeButton = styled(Button)` - ${({ theme }): string => ` - color: ${theme.colors.grayScale90}; + ${({ theme }) => css` margin-right: 20px; + color: ${theme.colors.grayScale90}; + ${theme.mediaQuery.tablet} { display: none; } diff --git a/src/components/shop/buy/ReviewModal/styled.ts b/src/components/shop/buy/ReviewModal/styled.ts index af7a3508..54cfcee1 100644 --- a/src/components/shop/buy/ReviewModal/styled.ts +++ b/src/components/shop/buy/ReviewModal/styled.ts @@ -5,11 +5,11 @@ import type { StyledReviewStateProps } from './types' const ReviewModal = styled(Modal)` width: 400px; - ${({ theme }): string => theme.mediaQuery.tablet} { + ${({ theme }) => theme.mediaQuery.tablet} { width: 320px; } - ${({ theme }): string => theme.mediaQuery.mobile} { + ${({ theme }) => theme.mediaQuery.mobile} { width: 320px; } ` @@ -28,40 +28,40 @@ const FirstSection = styled.div` ` const NickName = styled.div` - color: ${({ theme }): string => theme.colors.brandPrimary}; - ${({ theme }): string => theme.fonts.headline01B}; + color: ${({ theme }) => theme.colors.brandPrimary}; + ${({ theme }) => theme.fonts.headline01B}; - ${({ theme }): string => theme.mediaQuery.tablet} { - ${({ theme }): string => theme.fonts.headline02B}; + ${({ theme }) => theme.mediaQuery.tablet} { + ${({ theme }) => theme.fonts.headline02B}; } - ${({ theme }): string => theme.mediaQuery.mobile} { - ${({ theme }): string => theme.fonts.headline02B}; + ${({ theme }) => theme.mediaQuery.mobile} { + ${({ theme }) => theme.fonts.headline02B}; } ` const NormalText = styled.span` - ${({ theme }): string => theme.fonts.headline01B}; - ${({ theme }): string => theme.mediaQuery.tablet} { - ${({ theme }): string => theme.fonts.headline02B}; + ${({ theme }) => theme.fonts.headline01B}; + ${({ theme }) => theme.mediaQuery.tablet} { + ${({ theme }) => theme.fonts.headline02B}; } - ${({ theme }): string => theme.mediaQuery.mobile} { - ${({ theme }): string => theme.fonts.headline02B}; + ${({ theme }) => theme.mediaQuery.mobile} { + ${({ theme }) => theme.fonts.headline02B}; } ` const ProductText = styled.div` margin-top: 8px; - color: ${({ theme }): string => theme.colors.grayScale70}; - ${({ theme }): string => theme.fonts.body01R}; + color: ${({ theme }) => theme.colors.grayScale70}; + ${({ theme }) => theme.fonts.body01R}; - ${({ theme }): string => theme.mediaQuery.tablet} { - ${({ theme }): string => theme.fonts.body02R}; + ${({ theme }) => theme.mediaQuery.tablet} { + ${({ theme }) => theme.fonts.body02R}; } - ${({ theme }): string => theme.mediaQuery.mobile} { - ${({ theme }): string => theme.fonts.body02R}; + ${({ theme }) => theme.mediaQuery.mobile} { + ${({ theme }) => theme.fonts.body02R}; } ` @@ -75,13 +75,13 @@ const ReviewIconContainer = styled.div` cursor: pointer; - ${({ theme }): string => theme.mediaQuery.tablet} { + ${({ theme }) => theme.mediaQuery.tablet} { gap: 32px; margin: 24px 0; } - ${({ theme }): string => theme.mediaQuery.mobile} { + ${({ theme }) => theme.mediaQuery.mobile} { gap: 32px; margin: 24px 0; @@ -102,9 +102,9 @@ const ReviewState = styled.button` place-items: center center; * { - color: ${({ isFill, theme }): string => + color: ${({ isFill, theme }) => isFill ? theme.colors.brandPrimary : theme.colors.grayScale30}; - ${({ theme }): string => theme.fonts.body01M}; + ${({ theme }) => theme.fonts.body01M}; } ` @@ -120,8 +120,8 @@ const ReadModeReviewContent = styled.div` height: 120px; padding: 10px 12px; - background: ${({ theme }): string => theme.colors.bgGray02}; - ${({ theme }): string => theme.fonts.body02M}; + background: ${({ theme }) => theme.colors.bgGray02}; + ${({ theme }) => theme.fonts.body02M}; ` const ReviewTextArea = styled(TextArea)` @@ -132,11 +132,11 @@ const ReviewTextArea = styled(TextArea)` const ReviewSendButton = styled(Button)` height: 64px; margin-top: 40px; - ${({ theme }): string => theme.mediaQuery.tablet} { + ${({ theme }) => theme.mediaQuery.tablet} { height: 48px; } - ${({ theme }): string => theme.mediaQuery.mobile} { + ${({ theme }) => theme.mediaQuery.mobile} { height: 48px; } ` diff --git a/src/components/shop/review/ReviewTabPost/styled.ts b/src/components/shop/review/ReviewTabPost/styled.ts index 5b0c94aa..75a4a487 100644 --- a/src/components/shop/review/ReviewTabPost/styled.ts +++ b/src/components/shop/review/ReviewTabPost/styled.ts @@ -1,3 +1,4 @@ +import { css } from '@emotion/react' import styled from '@emotion/styled' import { Avatar as AvatarComponent, @@ -6,13 +7,14 @@ import { } from '@offer-ui/react' const Wrapper = styled.li` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; - padding: 24px; gap: 8px; + padding: 24px; + ${theme.mediaQuery.tablet} { - padding 16px 24px; + padding: 16px 24px; } ${theme.mediaQuery.mobile} { @@ -41,11 +43,13 @@ const NickNameWrapper = styled.div` ` const NickName = styled(Text)` - ${({ theme }): string => ` + ${({ theme }) => css` display: inline-block; + overflow: hidden; + max-width: 350px; + text-overflow: ellipsis; - overflow: hidden; white-space: nowrap; word-break: break-word; @@ -60,11 +64,13 @@ const Badge = styled(BadgeComponent)` ` const PostTitle = styled(Text)` - ${({ theme }): string => ` + ${({ theme }) => css` display: block; + overflow: hidden; + margin-top: 4px; + text-overflow: ellipsis; - overflow: hidden; white-space: nowrap; word-break: break-word; diff --git a/src/components/shop/sale/SaleTabPost/styled.ts b/src/components/shop/sale/SaleTabPost/styled.ts index d954fbb7..99b60a16 100644 --- a/src/components/shop/sale/SaleTabPost/styled.ts +++ b/src/components/shop/sale/SaleTabPost/styled.ts @@ -1,3 +1,4 @@ +import { css } from '@emotion/react' import styled from '@emotion/styled' import { Image, @@ -7,7 +8,7 @@ import { } from '@offer-ui/react' const Container = styled.li` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; align-items: center; justify-content: space-between; @@ -20,17 +21,19 @@ const Container = styled.li` `} ` const ProductWrapper = styled.div<{ isLogin: boolean }>` - ${({ theme, isLogin }): string => ` + ${({ theme, isLogin }) => css` display: grid; flex: 1; grid-template-columns: ${isLogin ? '90px 90px 1fr' : '90px 1fr'}; - align-items: center; gap: 16px; + align-items: center; + padding: 20px 0 20px 20px; ${theme.mediaQuery.tablet} { grid-template-columns: 68px 1fr 90px; gap: 8px; + padding: 16px 24px; } @@ -41,10 +44,11 @@ const ProductWrapper = styled.div<{ isLogin: boolean }>` `} ` const ProductImg = styled(Image)` - ${({ theme }): string => ` + ${({ theme }) => css` + order: 1; + width: 90px; height: 90px; - order:1; ${theme.mediaQuery.tablet} { width: 68px; @@ -53,7 +57,7 @@ const ProductImg = styled(Image)` `} ` const SelectBox = styled(SelectBoxComponent)` - ${({ theme }): string => ` + ${({ theme }) => css` order: 2; ${theme.mediaQuery.tablet} { @@ -63,32 +67,35 @@ const SelectBox = styled(SelectBoxComponent)` ` const ProductMetaWrapper = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; align-items: center; justify-content: space-around; order: 3; ${theme.mediaQuery.tablet} { - align-items: flex-start; flex-direction: column; - order: 2; gap: 4px; + align-items: flex-start; + order: 2; } `} ` const ProductName = styled(Text)` - ${({ theme }): string => ` - text-align: center; + ${({ theme }) => css` + overflow: hidden; + width: 150px; + + text-align: center; text-overflow: ellipsis; - overflow: hidden; white-space: nowrap; word-break: break-word; ${theme.mediaQuery.tablet} { - text-align: left; width: 460px; + + text-align: left; } ${theme.mediaQuery.mobile} { @@ -97,21 +104,21 @@ const ProductName = styled(Text)` `} ` const ProductInfoWrapper = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; + gap: 12px; align-items: center; justify-content: space-around; - gap: 12px; ${theme.mediaQuery.tablet} { - align-items: flex-start; flex-direction: column; gap: 0; + align-items: flex-start; } -`} + `} ` const Price = styled.span` - ${({ theme }): string => ` + ${({ theme }) => css` ${theme.fonts.body02R}; ${theme.mediaQuery.tablet} { @@ -121,12 +128,14 @@ const Price = styled.span` `} ` const FavoriteWrapper = styled.div<{ isOnlyOther: boolean }>` - ${({ theme, isOnlyOther }): string => ` + ${({ theme, isOnlyOther }) => css` display: ${isOnlyOther ? 'none' : 'flex'}; + gap: 2px; align-items: center; justify-content: center; - gap: 2px; + width: 100px; + color: ${theme.colors.grayScale50}; ${theme.mediaQuery.tablet} { @@ -136,8 +145,9 @@ const FavoriteWrapper = styled.div<{ isOnlyOther: boolean }>` `} ` const Date = styled(Text)<{ isLogin: boolean }>` - ${({ theme, isLogin }): string => ` + ${({ theme, isLogin }) => css` display: inline-block; + color: ${theme.colors.grayScale50}; ${theme.mediaQuery.tablet} { @@ -148,12 +158,13 @@ const Date = styled(Text)<{ isLogin: boolean }>` `} ` const ReviewButtonWrapper = styled.div` - ${({ theme }): string => ` + ${({ theme }) => css` display: flex; flex-direction: column; - min-width: 120px; align-items: flex-end; + min-width: 120px; + ${theme.mediaQuery.tablet} { display: flex; align-items: center; @@ -161,17 +172,18 @@ const ReviewButtonWrapper = styled.div` `} ` const ReviewButton = styled(Button)<{ hasReview: boolean }>` - ${({ theme, hasReview }): string => ` - color: ${hasReview ? theme.colors.grayScale70 : theme.colors.brandPrimary}; + ${({ theme, hasReview }) => css` margin-right: 20px; + color: ${hasReview ? theme.colors.grayScale70 : theme.colors.brandPrimary}; + ${theme.mediaQuery.tablet} { width: 100%; + margin-right: 0; + padding: 20px 0; border: none; border-top: 1px solid ${theme.colors.grayScale10}; border-radius: 0; - padding: 20px 0; - margin-right: 0; } `} ` From 7063429da0cd4b17074a784515984f40e3dc8971 Mon Sep 17 00:00:00 2001 From: sonsurim Date: Sun, 21 Jan 2024 17:43:47 +0900 Subject: [PATCH 67/67] remove unnecessary LimitedInput component --- src/components/common/LimitedInput/index.tsx | 26 ------------------- src/components/common/LimitedInput/types.ts | 8 ------ src/components/common/index.ts | 1 - .../shop/EditProfileModal/index.tsx | 11 ++++---- 4 files changed, 5 insertions(+), 41 deletions(-) delete mode 100644 src/components/common/LimitedInput/index.tsx delete mode 100644 src/components/common/LimitedInput/types.ts diff --git a/src/components/common/LimitedInput/index.tsx b/src/components/common/LimitedInput/index.tsx deleted file mode 100644 index 2fcd5d7d..00000000 --- a/src/components/common/LimitedInput/index.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { Input } from '@offer-ui/react' -import type { ChangeEventHandler } from 'react' -import type { LimitedInputProps } from './types' - -export const LimitedInput = ({ - maxLength, - value, - onChangeValue, - onChange, - ...props -}: LimitedInputProps) => { - const handleChangeValue: ChangeEventHandler = e => { - const newValue = e.target.value - - if (newValue.length <= maxLength) { - onChangeValue(newValue) - } else if (newValue.length > value.length) { - const slicedValue = newValue.slice(0, maxLength) - onChangeValue(slicedValue) - } - - onChange?.(e) - } - - return -} diff --git a/src/components/common/LimitedInput/types.ts b/src/components/common/LimitedInput/types.ts deleted file mode 100644 index fa5fbd6c..00000000 --- a/src/components/common/LimitedInput/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { InputProps } from '@offer-ui/react' - -export type LimitedInputProps = { - className?: string - maxLength: number - value: string - onChangeValue(value: string): void -} & InputProps diff --git a/src/components/common/index.ts b/src/components/common/index.ts index df6582da..34c9d8bb 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -3,4 +3,3 @@ export * from './CommonModal' export * from './Header' export * from './AlertModal' export * from './Dialog' -export * from './LimitedInput' diff --git a/src/components/shop/EditProfileModal/index.tsx b/src/components/shop/EditProfileModal/index.tsx index 8749762c..37723aa9 100644 --- a/src/components/shop/EditProfileModal/index.tsx +++ b/src/components/shop/EditProfileModal/index.tsx @@ -7,11 +7,10 @@ import { Icon, useImageUploader } from '@offer-ui/react' -import type { ReactElement } from 'react' +import type { ChangeEventHandler, ReactElement } from 'react' import { useState } from 'react' import { Styled } from './styled' import type { EditProfileForm, EditProfileModalProps } from './types' -import { LimitedInput } from '@components/common' const NICK_NAME_MAX_LENGTH = 20 @@ -37,8 +36,8 @@ export const EditProfileModal = ({ } }) - const handleChangeNickname = (nickname: string) => { - setProfileForm({ ...profileForm, nickname }) + const handleChangeNickname: ChangeEventHandler = e => { + setProfileForm({ ...profileForm, nickname: e.target.value }) } const handleClickDuplicateButton = () => { onValidateNickname(profileForm.nickname.trim()) @@ -79,11 +78,11 @@ export const EditProfileModal = ({ 닉네임 - {profileForm.nickname.length}/{NICK_NAME_MAX_LENGTH}