From f21b8d3100c97bceb2904b151587db06b2fdabad Mon Sep 17 00:00:00 2001 From: shinhyojeong Date: Tue, 2 Jan 2024 19:32:20 +0900 Subject: [PATCH 1/9] =?UTF-8?q?fix:=20PriceOfferCard=20=EB=AC=B4=ED=95=9C?= =?UTF-8?q?=EB=A0=8C=EB=8D=94=EB=A7=81=20=EC=9D=B4=EC=8A=88=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 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..830ce54d 100644 --- a/src/components/post/PriceOfferCard/index.tsx +++ b/src/components/post/PriceOfferCard/index.tsx @@ -43,7 +43,7 @@ const PriceOfferCard = ({ status: Boolean(postQuery.data?.liked), count: postQuery.data?.totalLikeCount || 0 }) - }, [postQuery]) + }, [postQuery.data]) const offers = postOffersQuery.data?.offers.map(({ offerer, createdAt, ...offer }) => ({ From 55a9a7716829ff600a748eeb0091abe93f674f6e Mon Sep 17 00:00:00 2001 From: shinhyojeong Date: Wed, 3 Jan 2024 00:22:01 +0900 Subject: [PATCH 2/9] =?UTF-8?q?design:=20=EC=84=A0=ED=83=9D=EB=90=9C=20off?= =?UTF-8?q?er=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/post/PriceOfferCard/index.tsx | 57 ++++++++++++++------ src/components/post/PriceOfferCard/styled.ts | 27 +++++++--- 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/src/components/post/PriceOfferCard/index.tsx b/src/components/post/PriceOfferCard/index.tsx index 830ce54d..ddfcbbd0 100644 --- a/src/components/post/PriceOfferCard/index.tsx +++ b/src/components/post/PriceOfferCard/index.tsx @@ -1,5 +1,5 @@ -import { Divider, SelectBox, Text, Icon } from '@offer-ui/react' -import type { ReactElement } from 'react' +import { Divider, SelectBox, Text, Icon, Radio } from '@offer-ui/react' +import type { ChangeEvent, ReactElement } from 'react' import { useEffect, useState } from 'react' import { Styled } from './styled' import type { PriceOfferCardProps } from './types' @@ -24,6 +24,7 @@ const PriceOfferCard = ({ const [sortOptionCode, setSortOptionCode] = useState( SORT_OPTIONS[0].code ) + const [selectedOffer, setSelectedOffer] = useState(null) const offerModal = useModal() const [likePost, setLikePost] = useState({ status: false, @@ -68,6 +69,12 @@ const PriceOfferCard = ({ await likeStatusMutation.mutateAsync(postId) } + const handleChangeOffer = (e: ChangeEvent) => { + const offerId = Number(e.target.value) + + setSelectedOffer(offerId) + } + const handleClickOffer = async ({ price, tradeType, @@ -112,7 +119,10 @@ const PriceOfferCard = ({ {hasOffer ? ( - + {offers.map( ({ id, @@ -123,20 +133,33 @@ const PriceOfferCard = ({ profileImageUrl, tradeType, price - }) => ( - - - {toLocaleCurrency(price)}원 - - ) + }) => { + const isSelected = selectedOffer === id + + return ( + + + + + + {toLocaleCurrency(price)}원 + + + + ) + } )} diff --git a/src/components/post/PriceOfferCard/styled.ts b/src/components/post/PriceOfferCard/styled.ts index 8b32dbc1..8fd77e35 100644 --- a/src/components/post/PriceOfferCard/styled.ts +++ b/src/components/post/PriceOfferCard/styled.ts @@ -1,6 +1,11 @@ import { css } from '@emotion/react' import styled from '@emotion/styled' -import { Button, Divider as DividerComponent, Text } from '@offer-ui/react' +import { + Button, + Divider as DividerComponent, + Radio, + Text +} from '@offer-ui/react' const OfferPriceCardWrapper = styled.div` ${({ theme }) => { @@ -29,7 +34,7 @@ const OfferPriceCardWrapper = styled.div` }} ` -const OfferListBox = styled.div` +const OfferListBox = styled(Radio)` display: flex; flex-direction: column; gap: 8px; @@ -88,16 +93,17 @@ const BlankCard = styled.div` height: 120px; padding: 20px 0; ` -const Offer = styled.div` +const Offer = styled(Radio.Label)<{ isSelected: boolean }>` display: flex; align-items: center; - justify-content: space-between; padding: 20px; - border: ${({ theme }): string => `solid 1px ${theme.colors.grayScale10}`}; border-radius: ${({ theme }): string => theme.radius.round6}; - ${({ theme }): string => ` + ${({ theme, isSelected }) => css` + border: solid 1px + ${isSelected ? theme.colors.brandPrimary : theme.colors.grayScale10}; + ${theme.mediaQuery.tablet} { padding: 16px; border: none; @@ -110,6 +116,14 @@ const Offer = styled.div` `} ` +const OfferContent = styled.div` + display: flex; + align-items: center; + justify-content: space-between; + + width: 100%; +` + const CardBody = styled.div` height: 564px; padding: 20px 16px; @@ -191,6 +205,7 @@ export const Styled = { Divider, BlankCard, Offer, + OfferContent, CardBody, CardFooter, MessageButton, From eb446bea23e34fbc9ab3a5a44df22221f1161abb Mon Sep 17 00:00:00 2001 From: shinhyojeong Date: Wed, 3 Jan 2024 00:58:18 +0900 Subject: [PATCH 3/9] =?UTF-8?q?feat:=20createMessageRoom=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/message/apis.ts | 5 +++++ src/apis/message/queries.ts | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100644 src/apis/message/apis.ts create mode 100644 src/apis/message/queries.ts diff --git a/src/apis/message/apis.ts b/src/apis/message/apis.ts new file mode 100644 index 00000000..392bf9dd --- /dev/null +++ b/src/apis/message/apis.ts @@ -0,0 +1,5 @@ +import type { CreateMessageRoomReq, CreateMessageRoomRes } from './types' +import { http } from '@utils/http' + +export const createMessageRoom = (params: CreateMessageRoomReq) => + http.post('/msgrooms', params) diff --git a/src/apis/message/queries.ts b/src/apis/message/queries.ts new file mode 100644 index 00000000..4eb3b2ec --- /dev/null +++ b/src/apis/message/queries.ts @@ -0,0 +1,8 @@ +import { useMutation } from '@tanstack/react-query' +import { createMessageRoom } from './apis' +import type { CreateMessageRoomReq } from './types' + +export const useCreateMessageRoomMutation = () => + useMutation({ + mutationFn: (params: CreateMessageRoomReq) => createMessageRoom(params) + }) From b3d5d1712b06bba8d0db9251090226107add500a Mon Sep 17 00:00:00 2001 From: shinhyojeong Date: Wed, 3 Jan 2024 01:00:53 +0900 Subject: [PATCH 4/9] =?UTF-8?q?design:=20=EB=B1=83=EC=A7=80=20=EA=B9=A8?= =?UTF-8?q?=EC=A7=80=EB=8A=94=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=9D=B4?= =?UTF-8?q?=EC=8A=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/post/UserProfile/index.tsx | 6 +++--- src/components/post/UserProfile/styled.ts | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/post/UserProfile/index.tsx b/src/components/post/UserProfile/index.tsx index 8be92600..6317f232 100644 --- a/src/components/post/UserProfile/index.tsx +++ b/src/components/post/UserProfile/index.tsx @@ -1,4 +1,4 @@ -import { Avatar, Badge, Text } from '@offer-ui/react' +import { Avatar, Text } from '@offer-ui/react' import type { ReactElement } from 'react' import { Styled } from './styled' import type { UserProfileProps } from './types' @@ -22,10 +22,10 @@ const UserProfile = ({ {nickName} - + Lv. {level} - + {location} diff --git a/src/components/post/UserProfile/styled.ts b/src/components/post/UserProfile/styled.ts index 1644d2ed..bb0d13f1 100644 --- a/src/components/post/UserProfile/styled.ts +++ b/src/components/post/UserProfile/styled.ts @@ -1,4 +1,5 @@ import styled from '@emotion/styled' +import { Badge } from '@offer-ui/react' const UserProfile = styled.div` display: flex; @@ -16,8 +17,13 @@ const UserName = styled.div` gap: 8px; ` +const LevelBadge = styled(Badge)` + height: fit-content; +` + export const Styled = { UserProfile, ProfileText, - UserName + UserName, + LevelBadge } From 1326386dfa4053eceec23c0ce179638336705ba8 Mon Sep 17 00:00:00 2001 From: shinhyojeong Date: Wed, 3 Jan 2024 01:02:36 +0900 Subject: [PATCH 5/9] =?UTF-8?q?feat:=20=ED=8F=AC=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EC=8B=9C=20router.push=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/post/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/post/index.tsx b/src/pages/post/index.tsx index 3f733503..ca14a391 100644 --- a/src/pages/post/index.tsx +++ b/src/pages/post/index.tsx @@ -112,7 +112,7 @@ const PostPage = (): ReactElement => { thumbnailImageUrl }) - router.replace(`/post/${res.id}`) + router.push(`/post/${res.id}`) } return ( From 05546170617e47abc18a10bffa09486dee505770 Mon Sep 17 00:00:00 2001 From: shinhyojeong Date: Thu, 4 Jan 2024 02:17:55 +0900 Subject: [PATCH 6/9] =?UTF-8?q?feat:=20message=20room=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20api=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/message/index.ts | 1 + src/components/post/PriceOfferCard/index.tsx | 58 +++++++++++++------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/apis/message/index.ts b/src/apis/message/index.ts index c9f6f047..d2186f10 100644 --- a/src/apis/message/index.ts +++ b/src/apis/message/index.ts @@ -1 +1,2 @@ export * from './types' +export * from './queries' diff --git a/src/components/post/PriceOfferCard/index.tsx b/src/components/post/PriceOfferCard/index.tsx index ddfcbbd0..7ce5189a 100644 --- a/src/components/post/PriceOfferCard/index.tsx +++ b/src/components/post/PriceOfferCard/index.tsx @@ -1,4 +1,5 @@ import { Divider, SelectBox, Text, Icon, Radio } from '@offer-ui/react' +import { useRouter } from 'next/router' import type { ChangeEvent, ReactElement } from 'react' import { useEffect, useState } from 'react' import { Styled } from './styled' @@ -6,12 +7,13 @@ import type { PriceOfferCardProps } from './types' import { PriceOfferModal } from '../PriceOfferModal' import type { OfferForm } from '../PriceOfferModal/types' import { UserProfile } from '../UserProfile' -import { getTimeDiffText, toLocaleCurrency } from '@utils/format' +import { getTimeDiffText, toLocaleCurrency, toQueryString } from '@utils/format' import { useUpdateLikeStatusMutation, useGetPostQuery, useGetPostOffersQuery, - useCreateOfferMutation + useCreateOfferMutation, + useCreateMessageRoomMutation } from '@apis' import { SORT_OPTIONS } from '@constants' import { useModal } from '@hooks' @@ -25,29 +27,32 @@ const PriceOfferCard = ({ SORT_OPTIONS[0].code ) const [selectedOffer, setSelectedOffer] = useState(null) - const offerModal = useModal() const [likePost, setLikePost] = useState({ status: false, count: 0 }) - const postOffersQuery = useGetPostOffersQuery({ + const router = useRouter() + const offerModal = useModal() + + const getPostOffersQuery = useGetPostOffersQuery({ postId, sort: sortOptionCode }) - const postQuery = useGetPostQuery(postId) - const likeStatusMutation = useUpdateLikeStatusMutation() - const offerMutation = useCreateOfferMutation() + const getPostQuery = useGetPostQuery(postId) + const createMessageRoomMutation = useCreateMessageRoomMutation() + const updateLikeStatusMutation = useUpdateLikeStatusMutation() + const createOfferMutation = useCreateOfferMutation() useEffect(() => { setLikePost({ - status: Boolean(postQuery.data?.liked), - count: postQuery.data?.totalLikeCount || 0 + status: Boolean(getPostQuery.data?.liked), + count: getPostQuery.data?.totalLikeCount || 0 }) - }, [postQuery.data]) + }, [getPostQuery.data]) const offers = - postOffersQuery.data?.offers.map(({ offerer, createdAt, ...offer }) => ({ + getPostOffersQuery.data?.offers.map(({ offerer, createdAt, ...offer }) => ({ ...offerer, level: Number(offerer.level), date: createdAt, @@ -66,7 +71,7 @@ const PriceOfferCard = ({ count: status ? count - 1 : count + 1 })) - await likeStatusMutation.mutateAsync(postId) + await updateLikeStatusMutation.mutateAsync(postId) } const handleChangeOffer = (e: ChangeEvent) => { @@ -90,8 +95,22 @@ const PriceOfferCard = ({ offerModal.closeModal() - await offerMutation.mutateAsync(offerInfo) - postOffersQuery.refetch() + await createOfferMutation.mutateAsync(offerInfo) + getPostOffersQuery.refetch() + } + + const handleClickStartMessage = async () => { + if (selectedOffer) { + const res = await createMessageRoomMutation.mutateAsync({ + offerId: selectedOffer + }) + + router.push( + `/messagebox${toQueryString({ + roomId: res.id + })}` + ) + } } return ( @@ -182,21 +201,22 @@ const PriceOfferCard = ({ {isSeller ? ( + disabled={!selectedOffer} + size="large" + onClick={handleClickStartMessage}> 쪽지하기 ) : ( { offerModal.openModal() }}>{`가격 제안하기(${ - postOffersQuery.data?.offerCountOfCurrentMember || 0 + getPostOffersQuery.data?.offerCountOfCurrentMember || 0 }/2)`} )} From 92b25ea9a93a8fd99124f7c5d6dd13f6ff1b748c Mon Sep 17 00:00:00 2001 From: shinhyojeong Date: Thu, 4 Jan 2024 02:18:54 +0900 Subject: [PATCH 7/9] =?UTF-8?q?chore:=20post=20=EC=83=81=EC=84=B8=ED=8E=98?= =?UTF-8?q?=20query=20=EA=B4=80=EB=A0=A8=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/post/[postId]/index.tsx | 36 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/pages/post/[postId]/index.tsx b/src/pages/post/[postId]/index.tsx index a228b58a..3a980503 100644 --- a/src/pages/post/[postId]/index.tsx +++ b/src/pages/post/[postId]/index.tsx @@ -4,8 +4,8 @@ import styled from '@emotion/styled' import { Carousel, Divider, Text, IconButton, SelectBox } from '@offer-ui/react' import type { GetServerSideProps } from 'next' import type { ReactElement } from 'react' -import { useGetPostQuery } from '@apis/post' import { getTimeDiffText, toLocaleCurrency } from '@utils/format' +import { useGetPostQuery } from '@apis' import { UserProfile, PriceOfferCard, PostFieldList } from '@components' import { TRADE_STATUS } from '@constants' import { useAuth } from '@hooks' @@ -20,11 +20,11 @@ export const getServerSideProps: GetServerSideProps = async ({ }) const PostDetailPage = ({ postId }: Props): ReactElement => { - const postQuery = useGetPostQuery(postId) + const getPostQuery = useGetPostQuery(postId) const { user } = useAuth() - const isSeller = user.id === postQuery.data?.seller.id - const postImages = postQuery.data?.imageUrls.map((url, idx) => ({ + const isSeller = user.id === getPostQuery.data?.seller.id + const postImages = getPostQuery.data?.imageUrls.map((url, idx) => ({ id: idx, url })) @@ -42,7 +42,7 @@ const PostDetailPage = ({ postId }: Props): ReactElement => { <> { // do something }} @@ -51,18 +51,18 @@ const PostDetailPage = ({ postId }: Props): ReactElement => { ) : ( - {postQuery.data?.tradeStatus.code} + {getPostQuery.data?.tradeStatus.code} )} - {postQuery.data?.category.name || ''} + {getPostQuery.data?.category.name || ''} - {postQuery.data?.title || ''} + {getPostQuery.data?.title || ''} - {toLocaleCurrency(Number(postQuery.data?.price))} + {toLocaleCurrency(Number(getPostQuery.data?.price))} @@ -71,20 +71,20 @@ const PostDetailPage = ({ postId }: Props): ReactElement => { 상품 정보 - {postQuery.data?.description} + {getPostQuery.data?.description} From b824d79df5bc6cfe056c1275a754ff7dceb5a32c Mon Sep 17 00:00:00 2001 From: shinhyojeong Date: Thu, 4 Jan 2024 02:20:13 +0900 Subject: [PATCH 8/9] =?UTF-8?q?feat:=20offer=EC=8B=9C=20=EA=B0=80=EA=B2=A9?= =?UTF-8?q?=20number=EB=A1=9C=20=EB=B3=80=ED=99=98=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EC=9C=A0=ED=8B=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/post/PriceOfferCard/index.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/post/PriceOfferCard/index.tsx b/src/components/post/PriceOfferCard/index.tsx index 7ce5189a..3ede3209 100644 --- a/src/components/post/PriceOfferCard/index.tsx +++ b/src/components/post/PriceOfferCard/index.tsx @@ -7,7 +7,12 @@ import type { PriceOfferCardProps } from './types' import { PriceOfferModal } from '../PriceOfferModal' import type { OfferForm } from '../PriceOfferModal/types' import { UserProfile } from '../UserProfile' -import { getTimeDiffText, toLocaleCurrency, toQueryString } from '@utils/format' +import { + getTimeDiffText, + localeCurrencyToNumber, + toLocaleCurrency, + toQueryString +} from '@utils/format' import { useUpdateLikeStatusMutation, useGetPostQuery, @@ -87,8 +92,7 @@ const PriceOfferCard = ({ }: OfferForm) => { const offerInfo = { postId, - // TODO: post 보내기 merge 후 number로 변환하는 유틸 적용 - price: Number(price) ?? 0, + price: localeCurrencyToNumber(price || '0'), tradeType: tradeType ?? '', location: `${tradeArea?.city} ${tradeArea?.county} ${tradeArea?.town}` } From b412dbd8acc7e60dc3f415119fb3e3df1ee22bc6 Mon Sep 17 00:00:00 2001 From: shinhyojeong Date: Thu, 4 Jan 2024 02:23:34 +0900 Subject: [PATCH 9/9] =?UTF-8?q?design:=20ods=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=EB=A1=9C=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=B4?= =?UTF-8?q?=EC=A7=84=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/post/UserProfile/index.tsx | 6 +++--- src/components/post/UserProfile/styled.ts | 8 +------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/components/post/UserProfile/index.tsx b/src/components/post/UserProfile/index.tsx index 6317f232..8be92600 100644 --- a/src/components/post/UserProfile/index.tsx +++ b/src/components/post/UserProfile/index.tsx @@ -1,4 +1,4 @@ -import { Avatar, Text } from '@offer-ui/react' +import { Avatar, Badge, Text } from '@offer-ui/react' import type { ReactElement } from 'react' import { Styled } from './styled' import type { UserProfileProps } from './types' @@ -22,10 +22,10 @@ const UserProfile = ({ {nickName} - + Lv. {level} - + {location} diff --git a/src/components/post/UserProfile/styled.ts b/src/components/post/UserProfile/styled.ts index bb0d13f1..1644d2ed 100644 --- a/src/components/post/UserProfile/styled.ts +++ b/src/components/post/UserProfile/styled.ts @@ -1,5 +1,4 @@ import styled from '@emotion/styled' -import { Badge } from '@offer-ui/react' const UserProfile = styled.div` display: flex; @@ -17,13 +16,8 @@ const UserName = styled.div` gap: 8px; ` -const LevelBadge = styled(Badge)` - height: fit-content; -` - export const Styled = { UserProfile, ProfileText, - UserName, - LevelBadge + UserName }