From da98c5da0eb2d8936865738215860e2574f4d5ce Mon Sep 17 00:00:00 2001 From: devkyoung2 Date: Fri, 14 Jun 2024 18:33:59 +0900 Subject: [PATCH 01/18] =?UTF-8?q?[fix]:=20=ED=8E=80=EB=94=A9=EB=AA=A9?= =?UTF-8?q?=ED=91=9C=EA=B8=88=EC=95=A1=EC=9D=84=200=EC=9B=90=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=93=B1=EB=A1=9D=ED=95=98=EB=8A=94=20=EA=B2=83?= =?UTF-8?q?=EC=9D=84=20=EB=A7=89=EC=9D=8C(#333)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/Modal/FundingModal/index.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/ui/Modal/FundingModal/index.tsx b/src/components/ui/Modal/FundingModal/index.tsx index b8224fb2..0774ba10 100644 --- a/src/components/ui/Modal/FundingModal/index.tsx +++ b/src/components/ui/Modal/FundingModal/index.tsx @@ -45,6 +45,11 @@ const FundingModal = ({ }); const handleAddFunding = async () => { + if (formatCommaToNumber(goalAmount) === 0) { + alert('목표 금액은 0원일 수 없습니다.'); + + return; + } await sendRequest(); close(); }; From 234ec1418b2b7b619ae94ceae4d5c9660109dad1 Mon Sep 17 00:00:00 2001 From: devkyoung2 Date: Fri, 14 Jun 2024 18:37:44 +0900 Subject: [PATCH 02/18] =?UTF-8?q?[refactor]:=20=EB=B9=88=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=B2=B4=ED=81=AC=20=EC=9C=A0=ED=8B=B8=ED=95=A8?= =?UTF-8?q?=EC=88=98=EB=A1=9C=20=EB=B6=84=EB=A6=AC(#333)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/MyPage/Funding/index.tsx | 5 +---- src/utils/validate.ts | 4 ++++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pages/MyPage/Funding/index.tsx b/src/pages/MyPage/Funding/index.tsx index a63ee125..ac4c24b7 100644 --- a/src/pages/MyPage/Funding/index.tsx +++ b/src/pages/MyPage/Funding/index.tsx @@ -8,13 +8,10 @@ import FundingProgress from 'layouts/MyPage/Funding/FundingProgress'; import { useUserStore } from 'store/useUserStore'; import { getMyFundingItem } from 'services/api/v1/funding'; +import { isEmptyObject } from 'utils/validate'; import styles from './index.module.scss'; -const isEmptyObject = (obj: object): boolean => { - return Object.keys(obj).length === 0; -}; - const Funding = () => { const { name } = useUserStore(); const { data, isFetched, isLoading } = useQuery({ diff --git a/src/utils/validate.ts b/src/utils/validate.ts index 853e2993..023d64f7 100644 --- a/src/utils/validate.ts +++ b/src/utils/validate.ts @@ -19,3 +19,7 @@ export const isValidQuantity = (quantity: string) => { export const isValidPrice = (price: string) => { return isPositiveInteger(price) || isZero(price); }; + +export const isEmptyObject = (obj: object): boolean => { + return Object.keys(obj).length === 0; +}; From 4c7dd493b691603e903c6a053311c465ba9f5791 Mon Sep 17 00:00:00 2001 From: devkyoung2 Date: Fri, 14 Jun 2024 18:42:34 +0900 Subject: [PATCH 03/18] =?UTF-8?q?[refactor]:=20=EC=A7=84=ED=96=89=EC=A4=91?= =?UTF-8?q?=EC=9D=B8=20=ED=8E=80=EB=94=A9=20=EC=95=84=EC=9D=B4=ED=85=9C?= =?UTF-8?q?=EC=9D=B4=20=EC=9E=88=EC=9D=84=20=EA=B2=BD=EC=9A=B0=20=ED=8E=80?= =?UTF-8?q?=EB=94=A9=EC=9D=84=20=EB=A7=89=EC=9D=8C(#333)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Product/BuyInfo/ButtonBundles/index.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx b/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx index 417c7541..8fd17bf9 100644 --- a/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx +++ b/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx @@ -1,3 +1,5 @@ +import { useQuery } from '@tanstack/react-query'; + import clsx from 'clsx'; import { useNavigate } from 'react-router-dom'; @@ -11,7 +13,9 @@ import { useAxios } from 'hooks/useAxios'; import { useKakaoPicker } from 'hooks/useKakaoPicker'; import { useLogin } from 'hooks/useLogin'; import { useModal } from 'hooks/useModal'; +import { getMyFundingItem } from 'services/api/v1/funding'; import { formatNumberWithPlus } from 'utils/format'; +import { isEmptyObject } from 'utils/validate'; import { RequestOrderPreview } from 'types/payment'; import { OptionDetail, ProductDescriptionResponse } from 'types/product'; @@ -48,6 +52,11 @@ const ButtonBundles = ({ useSelectedFriendsStore(); const { openKakaoPicker } = useKakaoPicker(); + const { data } = useQuery({ + queryKey: ['myFundingItem'], + queryFn: () => getMyFundingItem(), + }); + const { isOpen: isFundingOpen, open: openFundingModal, @@ -104,6 +113,11 @@ const ButtonBundles = ({ // 펀딩 등록 버튼 핸들러 const handleClickFunding = () => { checkLoginBeforeAction(() => { + if (!isEmptyObject(data!)) { + alert('이미 등록된 펀딩 아이템이 있습니다.'); + return; + } + checkOptionBeforeAction(openFundingModal); }); }; From a8805c1795396e5568e15ce2643e18ae1bdba053 Mon Sep 17 00:00:00 2001 From: uraflower <82873315+uraflower@users.noreply.github.com> Date: Tue, 28 May 2024 14:05:39 +0900 Subject: [PATCH 04/18] =?UTF-8?q?[refactor]:=20=EB=82=98=EC=9D=98=20?= =?UTF-8?q?=EC=9C=84=EC=8B=9C=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=9D=91=EB=8B=B5=20=ED=83=80=EC=9E=85=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#306)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/layouts/MyPage/Wish/MyWishItem/index.tsx | 10 +++------- src/pages/MyPage/Wish/index.tsx | 2 +- src/types/wish.ts | 10 ++++++++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/layouts/MyPage/Wish/MyWishItem/index.tsx b/src/layouts/MyPage/Wish/MyWishItem/index.tsx index bbe43f35..6f969ec4 100644 --- a/src/layouts/MyPage/Wish/MyWishItem/index.tsx +++ b/src/layouts/MyPage/Wish/MyWishItem/index.tsx @@ -14,16 +14,12 @@ type MyWishItemProp = { myWishItem: MyWishItemType }; const MyWishItem = ({ myWishItem }: MyWishItemProp) => { const { - wishId, - productId, - productName, - productPhoto, - productPrice, - isPublic: isPublicProps, + wishDetail: { wishId, productId, productName, productPhoto, productPrice }, + public: isPublicProp, } = myWishItem; const [isWish, setIsWish] = useState(true); - const [isPublic, setIsPublic] = useState(isPublicProps); + const [isPublic, setIsPublic] = useState(isPublicProp); const { addWish } = useAddWish(productId, isPublic ? 'OTHERS' : 'ME'); const { deleteWish } = useDeleteWish(productId); diff --git a/src/pages/MyPage/Wish/index.tsx b/src/pages/MyPage/Wish/index.tsx index 56cc959e..b8d9b74f 100644 --- a/src/pages/MyPage/Wish/index.tsx +++ b/src/pages/MyPage/Wish/index.tsx @@ -26,7 +26,7 @@ const Wish = () => { {wishItems && wishItems.length !== 0 && (
    {wishItems.map((wishItem) => ( -
  • +
  • ))} diff --git a/src/types/wish.ts b/src/types/wish.ts index 48a699c0..007bc766 100644 --- a/src/types/wish.ts +++ b/src/types/wish.ts @@ -1,10 +1,16 @@ -export type MyWishItemType = { +type WishDetail = { wishId: number; productId: number; productName: string; productPrice: number; productPhoto: string; - isPublic: boolean; + brandName: string; + wishCount: number; +}; + +export type MyWishItemType = { + wishDetail: WishDetail; + public: boolean; }; export type MyWishResponse = MyWishItemType[]; From 0f1a5a9377e504f7fc7535bea045c6b0e8d4dbeb Mon Sep 17 00:00:00 2001 From: uraflower <82873315+uraflower@users.noreply.github.com> Date: Tue, 28 May 2024 15:18:27 +0900 Subject: [PATCH 05/18] =?UTF-8?q?[feat]:=20=EC=B9=9C=EA=B5=AC=EC=9D=98=20?= =?UTF-8?q?=EC=9C=84=EC=8B=9C=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20API=20=EC=97=B0=EB=8F=99=20(#306)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FriendWish/FriendWishItem/index.tsx | 27 +++--- .../Home/Receiver/FriendWish/index.tsx | 90 +++++++------------ src/layouts/Home/Receiver/index.tsx | 15 ++-- src/types/wish.ts | 5 ++ 4 files changed, 60 insertions(+), 77 deletions(-) diff --git a/src/layouts/Home/Receiver/FriendWish/FriendWishItem/index.tsx b/src/layouts/Home/Receiver/FriendWish/FriendWishItem/index.tsx index f7aa68dc..04056d0b 100644 --- a/src/layouts/Home/Receiver/FriendWish/FriendWishItem/index.tsx +++ b/src/layouts/Home/Receiver/FriendWish/FriendWishItem/index.tsx @@ -5,34 +5,39 @@ import WishButton from 'components/feature/ProductItem/WishButton'; import { formatNumberWithComma } from 'utils/format'; -import { ProductItem } from 'types/productItem'; +import { FriendWishItemType } from 'types/wish'; import styles from './index.module.scss'; -const FriendWishItem = ({ product }: { product: ProductItem }) => { +type FriendWishItemProps = { + item: FriendWishItemType['wishDetail']; + wished: FriendWishItemType['wished']; +}; + +const FriendWishItem = ({ item, wished }: FriendWishItemProps) => { return (
    - +
    {product.name}
    -

    {product.brandName}

    - {product.name} +

    {item.brandName}

    + {item.productName}

    - {formatNumberWithComma(product.price)} + {formatNumberWithComma(item.productPrice)}

    diff --git a/src/layouts/Home/Receiver/FriendWish/index.tsx b/src/layouts/Home/Receiver/FriendWish/index.tsx index 79ac7311..3f7e5356 100644 --- a/src/layouts/Home/Receiver/FriendWish/index.tsx +++ b/src/layouts/Home/Receiver/FriendWish/index.tsx @@ -1,75 +1,45 @@ +import { useEffect } from 'react'; import Slider from 'react-slick'; import SliderArrowButton from 'components/ui/SliderArrowButton'; -import { ProductItem } from 'types/productItem'; +import { useAxios } from 'hooks/useAxios'; + +import { FriendWishItemType } from 'types/wish'; import FriendWishItem from './FriendWishItem'; import styles from './index.module.scss'; -const items = [ - { - productId: 7359376, - photo: - 'https://img1.kakaocdn.net/thumb/C320x320@2x.fwebp.q82/?fname=https%3A%2F%2Fst.kakaocdn.net%2Fproduct%2Fgift%2Fproduct%2F20211217124737_5c87ae38718141e5bbdf66234a307dce.jpg', - brandName: '설빙', - name: '애플망고치즈설빙', - price: 13900, - wished: false, - wishCount: 111000, - }, - { - productId: 4145000, - photo: - 'https://img1.kakaocdn.net/thumb/C320x320@2x.fwebp.q82/?fname=https%3A%2F%2Fst.kakaocdn.net%2Fproduct%2Fgift%2Fproduct%2F20220306183838_22eca2bc80bf4e21aa12417182430e9c.jpg', - brandName: '앨리건트테이블', - name: '[봄나들이 데이트 피크닉의 계절] 감성 피크닉매트 3종 택1 L사이즈 소풍 여행 캠핑', - price: 48800, - wished: false, - wishCount: 0, - }, - { - productId: 3489649, - photo: - 'https://img1.kakaocdn.net/thumb/C320x320@2x.fwebp.q82/?fname=https%3A%2F%2Fst.kakaocdn.net%2Fproduct%2Fgift%2Fproduct%2F20231214100216_0fb634c58283405f8a4999fb10eabf0e.jpg', - brandName: '더자리', - name: '"봄맞이 나들이" [1+1/총2개] 마이블랭킷 고밀도 극세사 밍크담요 2개 (100x75)', - price: 10900, - wished: false, - wishCount: 0, - }, - { - productId: 6433982, - photo: - 'https://img1.kakaocdn.net/thumb/C320x320@2x.fwebp.q82/?fname=https%3A%2F%2Fst.kakaocdn.net%2Fproduct%2Fgift%2Fproduct%2F20230503140650_fb43ca3ad8b9461e90bea6879558455f.jpg', - brandName: '오덴세', - name: '[카카오단독컬러] 레고트 루프 텀블러 400ml (3 colors)', - price: 29000, - wished: false, - wishCount: 0, - }, - { - productId: 4920170, - photo: - 'https://img1.kakaocdn.net/thumb/C320x320@2x.fwebp.q82/?fname=https%3A%2F%2Fst.kakaocdn.net%2Fproduct%2Fgift%2Fproduct%2F20220607093750_addf83e9403b405f968748013bcf8031.jpg', - brandName: '플랜룩스', - name: '플랜룩스 모티북 각도조절 높이조절 독서대 태블릿거치대 북스탠드', - price: 29900, - wished: false, - wishCount: 0, - }, -]; +type FriendWishProps = { + friendId: string; + socialAccessToken: string; +}; + +const FriendWish = ({ friendId, socialAccessToken }: FriendWishProps) => { + const { data: wishlist, sendRequest } = useAxios({ + method: 'get', + url: '/wishes/friends', + data: { + friendsProviderId: friendId, + kakaoAccessToken: socialAccessToken, + }, + }); + + useEffect(() => { + sendRequest(); + }, []); + + if (!wishlist || wishlist.length === 0) return null; -const SLIDE_DISPLAY_COUNT = items.length === 1 ? 1 : 2; -const SLIDE_DRAGGABLE = items.length > 2; + const SLIDE_DISPLAY_COUNT = wishlist.length === 1 ? 1 : 2; + const SLIDE_DRAGGABLE = wishlist.length > 2; -const FriendWish = () => { return ( <> 친구의 위시리스트 SLIDE_DISPLAY_COUNT} + arrows={wishlist.length > SLIDE_DISPLAY_COUNT} draggable={SLIDE_DRAGGABLE} slidesToShow={SLIDE_DISPLAY_COUNT} prevArrow={} @@ -78,9 +48,9 @@ const FriendWish = () => { speed={300} className={styles.wrapper_wish} > - {items.map((item: ProductItem) => ( -
  • - + {wishlist.map(({ wishDetail, wished }) => ( +
  • +
  • ))}
    diff --git a/src/layouts/Home/Receiver/index.tsx b/src/layouts/Home/Receiver/index.tsx index 311fa974..35ac256b 100644 --- a/src/layouts/Home/Receiver/index.tsx +++ b/src/layouts/Home/Receiver/index.tsx @@ -15,10 +15,6 @@ import FriendWish from './FriendWish'; import styles from './index.module.scss'; -const FriendsData = { - hasWish: true, - hasFunding: true, -}; const Receiver = () => { const { isSelected, @@ -105,8 +101,15 @@ const Receiver = () => {
    - {FriendsData.hasFunding && } - {FriendsData.hasWish && } + {selectedHeadCount === 1 && !isSelfSelected && ( + <> + + + + )} ); diff --git a/src/types/wish.ts b/src/types/wish.ts index 007bc766..a5e2fe6a 100644 --- a/src/types/wish.ts +++ b/src/types/wish.ts @@ -15,6 +15,11 @@ export type MyWishItemType = { export type MyWishResponse = MyWishItemType[]; +export type FriendWishItemType = { + wishDetail: WishDetail; + wished: boolean; +}; + export type ResponseWishAddOrDelete = { productId: number; wishCount: number; From 23dbe52ce6e91fa5f3c48514425de864e7d5adf3 Mon Sep 17 00:00:00 2001 From: uraflower <82873315+uraflower@users.noreply.github.com> Date: Tue, 28 May 2024 17:07:34 +0900 Subject: [PATCH 06/18] =?UTF-8?q?[feat]:=20=EB=82=98=EC=9D=98=20=EC=9C=84?= =?UTF-8?q?=EC=8B=9C=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=95=20=EC=A1=B0=ED=9A=8C=20=EC=A0=81=EC=9A=A9=20(#306)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/MyPage/Wish/index.module.scss | 16 ++++++++++ src/pages/MyPage/Wish/index.tsx | 40 ++++++++++++++++++------- src/services/api/v1/wish.ts | 14 ++++++--- src/types/wish.ts | 2 -- 4 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/pages/MyPage/Wish/index.module.scss b/src/pages/MyPage/Wish/index.module.scss index f6b2514b..15b99242 100644 --- a/src/pages/MyPage/Wish/index.module.scss +++ b/src/pages/MyPage/Wish/index.module.scss @@ -11,3 +11,19 @@ .wrapper_items { margin-bottom: 100px; } + +.btn_more { + width: 100%; + height: 45px; + border: 1px solid #ededed; + border-radius: 2px; + text-align: center; + color: #222; + + .ico_more { + @include ico-wishes(-70px, -65px, 11px, 6px); + + margin: 7px 8px 0 0; + vertical-align: top; + } +} diff --git a/src/pages/MyPage/Wish/index.tsx b/src/pages/MyPage/Wish/index.tsx index b8d9b74f..1d70ad30 100644 --- a/src/pages/MyPage/Wish/index.tsx +++ b/src/pages/MyPage/Wish/index.tsx @@ -1,4 +1,4 @@ -import { useQuery } from '@tanstack/react-query'; +import { useInfiniteQuery } from '@tanstack/react-query'; import EmptyItem from 'components/feature/EmptyItem'; import Spinner from 'components/ui/Spinner'; @@ -13,25 +13,43 @@ import styles from './index.module.scss'; const Wish = () => { const { name } = useUserStore(); - const { data: wishItems, isLoading } = useQuery({ + const { data, fetchNextPage, hasNextPage, isLoading } = useInfiniteQuery({ queryKey: ['wishItem'], - queryFn: () => getMyWishItems(), + queryFn: ({ pageParam }) => getMyWishItems(pageParam), + initialPageParam: 0, + getNextPageParam: ({ last, pageNumber }) => { + if (last) return null; + return pageNumber + 1; + }, }); return ( <> {isLoading && }
    {`${name}님의 \n위시리스트`}
    - {wishItems && wishItems.length === 0 && } - {wishItems && wishItems.length !== 0 && ( -
      - {wishItems.map((wishItem) => ( -
    • - -
    • - ))} + {data?.pages.length === 0 ? ( + + ) : ( +
        + {data?.pages.map(({ items }) => + items.map((wishItem) => ( +
      • + +
      • + )), + )}
      )} + {hasNextPage && ( + + )} ); }; diff --git a/src/services/api/v1/wish.ts b/src/services/api/v1/wish.ts index 4f7d4255..395a9e8a 100644 --- a/src/services/api/v1/wish.ts +++ b/src/services/api/v1/wish.ts @@ -1,9 +1,15 @@ -import { MyWishResponse } from 'types/wish'; +import { PaginationResponse } from 'types/PaginationResponse'; +import { MyWishItemType } from 'types/wish'; import { apiV1 } from '.'; -export const getMyWishItems = async () => { - const myWishItems = await apiV1.get(`/wishes/me`); +export const getMyWishItems = async (page: number) => { + const myWishItems = await apiV1.get(`/wishes/me`, { + params: { + page, + size: 10, + }, + }); - return myWishItems.data as MyWishResponse; + return myWishItems.data as PaginationResponse; }; diff --git a/src/types/wish.ts b/src/types/wish.ts index a5e2fe6a..c94f4e63 100644 --- a/src/types/wish.ts +++ b/src/types/wish.ts @@ -13,8 +13,6 @@ export type MyWishItemType = { public: boolean; }; -export type MyWishResponse = MyWishItemType[]; - export type FriendWishItemType = { wishDetail: WishDetail; wished: boolean; From 87fcb52e01c55feed2cf0c2ff1d025bf48f7205f Mon Sep 17 00:00:00 2001 From: uraflower <82873315+uraflower@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:30:05 +0900 Subject: [PATCH 07/18] =?UTF-8?q?[feat]:=20=EC=9E=A5=EB=B0=94=EA=B5=AC?= =?UTF-8?q?=EB=8B=88=20=EB=B2=84=ED=8A=BC=20=ED=95=B8=EB=93=A4=EB=9F=AC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#355)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/ProductItem/CartButton/index.tsx | 32 ++++++++++++++++--- .../ProductItem/ColumnProductItem/index.tsx | 2 +- .../FriendWish/FriendWishItem/index.tsx | 2 +- .../Product/DetailBottom/ProductItem.tsx | 2 +- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/components/feature/ProductItem/CartButton/index.tsx b/src/components/feature/ProductItem/CartButton/index.tsx index 28da91dc..2d3ccc07 100644 --- a/src/components/feature/ProductItem/CartButton/index.tsx +++ b/src/components/feature/ProductItem/CartButton/index.tsx @@ -1,17 +1,39 @@ import { MouseEvent } from 'react'; +import Spinner from 'components/ui/Spinner'; + +import { useAxios } from 'hooks/useAxios'; + import styles from './index.module.scss'; -const CartButton = () => { - // TODO : API 요청 +type CartButtonProps = { + productId: number; +}; + +const CartButton = ({ productId }: CartButtonProps) => { + const { isLoading, sendRequest } = useAxios<{ cartId: number }>({ + url: '/cart', + method: 'post', + data: { + productId, + itemCount: 1, + optionId: null, + optionDetailId: null, + }, + }); + const handleAddCart = (e: MouseEvent) => { e.preventDefault(); + sendRequest(); }; return ( - + <> + {isLoading && } + + ); }; diff --git a/src/components/feature/ProductItem/ColumnProductItem/index.tsx b/src/components/feature/ProductItem/ColumnProductItem/index.tsx index a75b354c..a4122d91 100644 --- a/src/components/feature/ProductItem/ColumnProductItem/index.tsx +++ b/src/components/feature/ProductItem/ColumnProductItem/index.tsx @@ -27,7 +27,7 @@ const ColumnProductItem = ({ product, size }: ColumnProductItemProps) => {
    - + {

    - + { {product.name}
    - +
    ); From f7a132def6ab714c20fc17a8e26f3693d5e28317 Mon Sep 17 00:00:00 2001 From: uraflower <82873315+uraflower@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:48:35 +0900 Subject: [PATCH 08/18] =?UTF-8?q?[feat]:=20=EC=83=81=ED=92=88=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=20=EB=93=B1=EB=A1=9D=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=ED=95=B8=EB=93=A4=EB=9F=AC=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#355)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Product/BuyInfo/ButtonBundles/index.tsx | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx b/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx index f89123fa..8a70256c 100644 --- a/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx +++ b/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx @@ -6,6 +6,7 @@ import WishModal from 'components/ui/Modal/WishModal'; import { useSelectedFriendsStore } from 'store/useSelectedFriendsStore'; +import { useAxios } from 'hooks/useAxios'; import { useKakaoPicker } from 'hooks/useKakaoPicker'; import { useLogin } from 'hooks/useLogin'; import { useModal } from 'hooks/useModal'; @@ -57,6 +58,20 @@ const ButtonBundles = ({ scrollPos: scrollWishPos, } = useModal(); + // 장바구니 등록 API + const { sendRequest: addItemToCart } = useAxios<{ + cartId: number; + }>({ + url: '/cart', + method: 'post', + data: { + productId, + itemCount: quantity, + optionId: selectedOption ? options[0].optionsId : null, + optionDetailId: selectedOption ? selectedOption.id : null, + }, + }); + // 주문 정보 const orderInfos: RequestOrderPreview = [ { @@ -136,9 +151,9 @@ const ButtonBundles = ({ openKakaoPicker(); }; - // 선물상자 담기 버튼 핸들러 - const handleClickCart = () => { - // console.log('선물상자 담기'); + // 장바구니 등록 버튼 핸들러 + const handleAddCart = () => { + addItemToCart(); }; return ( @@ -168,12 +183,7 @@ const ButtonBundles = ({ 펀딩 아이템으로 등록하기 - {/* TODO : 로그인 되었을 때만 보이게 */} - From f92cd4d20b1286cc9faa02a25cb447b604507061 Mon Sep 17 00:00:00 2001 From: uraflower <82873315+uraflower@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:53:23 +0900 Subject: [PATCH 09/18] =?UTF-8?q?[feat]:=20=EC=9E=A5=EB=B0=94=EA=B5=AC?= =?UTF-8?q?=EB=8B=88=20=EB=8B=B4=EA=B8=B0=20=EC=A0=84=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8/=EC=98=B5=EC=85=98=EC=84=A0=ED=83=9D=20=EC=97=AC?= =?UTF-8?q?=EB=B6=80=20=ED=99=95=EC=9D=B8=20(#355)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/feature/ProductItem/CartButton/index.tsx | 8 +++++++- src/layouts/Product/BuyInfo/ButtonBundles/index.tsx | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/components/feature/ProductItem/CartButton/index.tsx b/src/components/feature/ProductItem/CartButton/index.tsx index 2d3ccc07..eb63967a 100644 --- a/src/components/feature/ProductItem/CartButton/index.tsx +++ b/src/components/feature/ProductItem/CartButton/index.tsx @@ -3,6 +3,7 @@ import { MouseEvent } from 'react'; import Spinner from 'components/ui/Spinner'; import { useAxios } from 'hooks/useAxios'; +import { useLogin } from 'hooks/useLogin'; import styles from './index.module.scss'; @@ -11,6 +12,7 @@ type CartButtonProps = { }; const CartButton = ({ productId }: CartButtonProps) => { + const { isLoggedIn, login, confirmLogin } = useLogin(); const { isLoading, sendRequest } = useAxios<{ cartId: number }>({ url: '/cart', method: 'post', @@ -24,7 +26,11 @@ const CartButton = ({ productId }: CartButtonProps) => { const handleAddCart = (e: MouseEvent) => { e.preventDefault(); - sendRequest(); + if (isLoggedIn) sendRequest(); + else { + const result = confirmLogin(); + if (result) login(); + } }; return ( diff --git a/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx b/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx index 8a70256c..63ccad18 100644 --- a/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx +++ b/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx @@ -153,7 +153,9 @@ const ButtonBundles = ({ // 장바구니 등록 버튼 핸들러 const handleAddCart = () => { - addItemToCart(); + checkLoginBeforeAction(() => { + checkOptionBeforeAction(addItemToCart); + }); }; return ( From 3309291fb6c36246ef3a4700042dfd5ddad8703e Mon Sep 17 00:00:00 2001 From: uraflower <82873315+uraflower@users.noreply.github.com> Date: Thu, 13 Jun 2024 16:05:39 +0900 Subject: [PATCH 10/18] =?UTF-8?q?[fix]:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=B0=B8=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?(#355)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit product -> item --- src/layouts/Home/Receiver/FriendWish/FriendWishItem/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/Home/Receiver/FriendWish/FriendWishItem/index.tsx b/src/layouts/Home/Receiver/FriendWish/FriendWishItem/index.tsx index 65af9fc3..69c61538 100644 --- a/src/layouts/Home/Receiver/FriendWish/FriendWishItem/index.tsx +++ b/src/layouts/Home/Receiver/FriendWish/FriendWishItem/index.tsx @@ -33,7 +33,7 @@ const FriendWishItem = ({ item, wished }: FriendWishItemProps) => {

    - + Date: Mon, 10 Jun 2024 17:51:34 +0900 Subject: [PATCH 11/18] =?UTF-8?q?[refactor]:=20checkLoginBeforeAction=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=B6=94=EC=B6=9C=20(#361)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit useLogin 훅 내로 이동 --- .../feature/ProductItem/CartButton/index.tsx | 8 ++----- .../feature/ProductItem/WishButton/index.tsx | 9 +++----- src/hooks/useLogin.ts | 21 +++++++++++++++++-- .../App/Header/SocialKakaoLogin/index.tsx | 4 ++-- src/layouts/Home/Receiver/index.tsx | 11 ++-------- .../Product/BuyInfo/ButtonBundles/index.tsx | 13 ++---------- src/pages/PrivateRoute/index.tsx | 4 ++-- 7 files changed, 32 insertions(+), 38 deletions(-) diff --git a/src/components/feature/ProductItem/CartButton/index.tsx b/src/components/feature/ProductItem/CartButton/index.tsx index eb63967a..5d493e42 100644 --- a/src/components/feature/ProductItem/CartButton/index.tsx +++ b/src/components/feature/ProductItem/CartButton/index.tsx @@ -12,7 +12,7 @@ type CartButtonProps = { }; const CartButton = ({ productId }: CartButtonProps) => { - const { isLoggedIn, login, confirmLogin } = useLogin(); + const { checkLoginBeforeAction } = useLogin(); const { isLoading, sendRequest } = useAxios<{ cartId: number }>({ url: '/cart', method: 'post', @@ -26,11 +26,7 @@ const CartButton = ({ productId }: CartButtonProps) => { const handleAddCart = (e: MouseEvent) => { e.preventDefault(); - if (isLoggedIn) sendRequest(); - else { - const result = confirmLogin(); - if (result) login(); - } + checkLoginBeforeAction(sendRequest); }; return ( diff --git a/src/components/feature/ProductItem/WishButton/index.tsx b/src/components/feature/ProductItem/WishButton/index.tsx index a880d6cd..8416ebfc 100644 --- a/src/components/feature/ProductItem/WishButton/index.tsx +++ b/src/components/feature/ProductItem/WishButton/index.tsx @@ -24,7 +24,7 @@ const WishButton = ({ isWished: isWishedProp, wishCount: wishCountProp, }: WishButtonProps) => { - const { isLoggedIn, login, confirmLogin } = useLogin(); + const { checkLoginBeforeAction } = useLogin(); const { isOpen, open, close, scrollPos } = useModal(); const { deleteWishData, deleteWish } = useDeleteWish(productId); const [wishCount, setWishCount] = useState(wishCountProp); @@ -39,13 +39,10 @@ const WishButton = ({ const handleClickWish = (e: MouseEvent) => { e.preventDefault(); - if (isLoggedIn) { + checkLoginBeforeAction(() => { if (wished) deleteWish(); else open(); - } else { - const result = confirmLogin(); - if (result) login(); - } + }); }; const handleWishAdded = (wishData: ResponseWishAddOrDelete) => { diff --git a/src/hooks/useLogin.ts b/src/hooks/useLogin.ts index 9b09b461..be2f1364 100644 --- a/src/hooks/useLogin.ts +++ b/src/hooks/useLogin.ts @@ -6,7 +6,7 @@ export const useLogin = () => { const isLoggedIn = useUserExists(); // 로그인 여부 const { pathname, search } = useLocation(); - const login = () => { + const navigateToLoginPage = () => { if (isLoggedIn) return; const currentUrl = pathname + search; @@ -24,5 +24,22 @@ export const useLogin = () => { return result; }; - return { isLoggedIn, login, confirmLogin }; + /** + * If a user is not logged in pop up the confirmation window, else do action. + * @param action callback function to execute when a user is logged in + */ + const checkLoginBeforeAction = (action: () => void) => { + if (isLoggedIn) action(); + else { + const result = confirmLogin(); + if (result) navigateToLoginPage(); + } + }; + + return { + isLoggedIn, + navigateToLoginPage, + confirmLogin, + checkLoginBeforeAction, + }; }; diff --git a/src/layouts/App/Header/SocialKakaoLogin/index.tsx b/src/layouts/App/Header/SocialKakaoLogin/index.tsx index ed01abaf..30b6e00d 100644 --- a/src/layouts/App/Header/SocialKakaoLogin/index.tsx +++ b/src/layouts/App/Header/SocialKakaoLogin/index.tsx @@ -9,7 +9,7 @@ import LogoutModal from '../LogoutModal'; import styles from './index.module.scss'; const SocialKakaoLogin = () => { - const { isLoggedIn, login } = useLogin(); + const { isLoggedIn, navigateToLoginPage } = useLogin(); const userName = useUserStore().name; const [isModalOpen, setIsModalOpen] = useState(false); @@ -18,7 +18,7 @@ const SocialKakaoLogin = () => { if (isLoggedIn) { setIsModalOpen(!isModalOpen); } else { - login(); + navigateToLoginPage(); } }; diff --git a/src/layouts/Home/Receiver/index.tsx b/src/layouts/Home/Receiver/index.tsx index 35ac256b..911e7966 100644 --- a/src/layouts/Home/Receiver/index.tsx +++ b/src/layouts/Home/Receiver/index.tsx @@ -29,7 +29,7 @@ const Receiver = () => { const clearFriendsList = useSelectedFriendsStore( (state) => state.clearSelectedFriends, ); - const { isLoggedIn, login, confirmLogin } = useLogin(); + const { isLoggedIn, checkLoginBeforeAction } = useLogin(); const PROFILE_IMAGE = isLoggedIn && isSelfSelected ? profileUrl : getImgUrl(DefaultImgUrl); const isKakaoConnected = window.Kakao?.isInitialized(); @@ -54,14 +54,7 @@ const Receiver = () => { } const handleClick = () => { - if (!isLoggedIn) { - const result = confirmLogin(); - - if (result) login(); - return; - } - - openKakaoPicker(); + checkLoginBeforeAction(openKakaoPicker); }; const handleCancel = () => { diff --git a/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx b/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx index 63ccad18..38ecfb9d 100644 --- a/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx +++ b/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx @@ -39,7 +39,7 @@ const ButtonBundles = ({ const { productId, name, price, productThumbnails, options } = productDescription; const navigate = useNavigate(); - const { isLoggedIn, login, confirmLogin } = useLogin(); + const { checkLoginBeforeAction } = useLogin(); const { isSelected, isSelfSelected, selectedFriends, getImgUrl } = useSelectedFriendsStore(); const { openKakaoPicker } = useKakaoPicker(); @@ -88,15 +88,6 @@ const ButtonBundles = ({ }, ]; - // 로그인 여부 확인 - const checkLoginBeforeAction = (action: () => void) => { - if (isLoggedIn) action(); - else { - const result = confirmLogin(); - if (result) login(); - } - }; - // 옵션 선택 여부 확인 const checkOptionBeforeAction = (action: () => void) => { if (hasOption && !selectedOption) { @@ -148,7 +139,7 @@ const ButtonBundles = ({ // 친구 프로필 이미지 클릭 핸들러 const handleClickProfile = (e: React.MouseEvent) => { e.stopPropagation(); - openKakaoPicker(); + checkLoginBeforeAction(openKakaoPicker); }; // 장바구니 등록 버튼 핸들러 diff --git a/src/pages/PrivateRoute/index.tsx b/src/pages/PrivateRoute/index.tsx index 5bf3d9b3..db71582a 100644 --- a/src/pages/PrivateRoute/index.tsx +++ b/src/pages/PrivateRoute/index.tsx @@ -12,11 +12,11 @@ const PrivateRoute = () => { } const navigate = useNavigate(); - const { login, confirmLogin } = useLogin(); + const { navigateToLoginPage, confirmLogin } = useLogin(); const result = confirmLogin(); useEffect(() => { - if (result) login(); + if (result) navigateToLoginPage(); else navigate(-1); }, [result]); From 8d30b22e1df677b5b6080e3c93906a17b1f4dcd7 Mon Sep 17 00:00:00 2001 From: devkyoung2 Date: Sat, 8 Jun 2024 00:32:49 +0900 Subject: [PATCH 12/18] =?UTF-8?q?[feat]:=20=EC=83=81=ED=92=88=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=EC=A1=B0=ED=9A=8C=20api=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95(#334)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 위시여부 및 위시카운트 추가 --- src/types/product.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/types/product.ts b/src/types/product.ts index c6280752..7b663381 100644 --- a/src/types/product.ts +++ b/src/types/product.ts @@ -24,6 +24,8 @@ type Product = { brandName: string; brandId: number; brandThumbnail: string; + wishCount: number; + wish: boolean; }; export type ProductDescriptionResponse = Product & { From 2b0118320fd72b46d5bec476b06a42d6a529d77d Mon Sep 17 00:00:00 2001 From: devkyoung2 Date: Sat, 8 Jun 2024 02:29:25 +0900 Subject: [PATCH 13/18] =?UTF-8?q?[feat]:=20=EC=9C=84=EC=8B=9C=20=ED=81=B4?= =?UTF-8?q?=EB=A6=AD=EC=8B=9C=20=EC=9C=84=EC=8B=9C=20=EC=83=89=EC=83=81=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD(#334)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 위시 요청 성공시 productDescription에 캐싱된 데이터를 무효화 시켜 다시 데이터를 fetch함 --- src/components/ui/Modal/WishModal/index.tsx | 5 ++++ .../BuyInfo/ButtonBundles/index.module.scss | 4 ++++ .../Product/BuyInfo/ButtonBundles/index.tsx | 23 ++++++++++++------- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/components/ui/Modal/WishModal/index.tsx b/src/components/ui/Modal/WishModal/index.tsx index f9ceb383..cec9c494 100644 --- a/src/components/ui/Modal/WishModal/index.tsx +++ b/src/components/ui/Modal/WishModal/index.tsx @@ -1,3 +1,5 @@ +import { useQueryClient } from '@tanstack/react-query'; + import { useState, useEffect } from 'react'; import { Button } from 'components/ui/Button'; @@ -33,6 +35,7 @@ const WishModal = ({ productId, onWishAdded = () => null, }: WishModalProps) => { + const queryClient = useQueryClient(); const [radioStatus, setRadioStatus] = useState( WISH_RADIO_STATUS.OTHERS as WishRadioType, ); @@ -45,6 +48,8 @@ const WishModal = ({ const handleAddWish = async () => { await addWish(); close(); + + queryClient.invalidateQueries({ queryKey: ['productDescription'] }); }; useEffect(() => { diff --git a/src/layouts/Product/BuyInfo/ButtonBundles/index.module.scss b/src/layouts/Product/BuyInfo/ButtonBundles/index.module.scss index 5b05a41c..8f799b5f 100644 --- a/src/layouts/Product/BuyInfo/ButtonBundles/index.module.scss +++ b/src/layouts/Product/BuyInfo/ButtonBundles/index.module.scss @@ -41,6 +41,10 @@ @include ico-pd-detail(-110px, -420px, 26px, 22px); margin-bottom: 5px; + + &.on { + @include ico-pd-detail(-110px, -450px, 26px, 22px); + } } } diff --git a/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx b/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx index 38ecfb9d..67cb15fa 100644 --- a/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx +++ b/src/layouts/Product/BuyInfo/ButtonBundles/index.tsx @@ -1,3 +1,5 @@ +import clsx from 'clsx'; +import { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Button } from 'components/ui/Button'; @@ -19,10 +21,6 @@ import DefaultProfileImage from 'assets/profile_noimg.png'; import styles from './index.module.scss'; -const mockData = { - wishCnt: 999999, -}; - type ButtonBundlesProps = { productDescription: ProductDescriptionResponse; hasOption: boolean; @@ -36,8 +34,15 @@ const ButtonBundles = ({ selectedOption, quantity, }: ButtonBundlesProps) => { - const { productId, name, price, productThumbnails, options } = - productDescription; + const { + productId, + name, + price, + productThumbnails, + options, + wishCount, + wish, + } = productDescription; const navigate = useNavigate(); const { checkLoginBeforeAction } = useLogin(); const { isSelected, isSelfSelected, selectedFriends, getImgUrl } = @@ -149,6 +154,8 @@ const ButtonBundles = ({ }); }; + useEffect(() => {}, [wish]); + return (