Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/385 #391

Open
wants to merge 9 commits into
base: dev
Choose a base branch
from
10 changes: 9 additions & 1 deletion src/components/feature/ProductItem/CartButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useQueryClient } from '@tanstack/react-query';

import { MouseEvent } from 'react';

import Spinner from 'components/ui/Spinner';
Expand All @@ -23,10 +25,16 @@ const CartButton = ({ productId }: CartButtonProps) => {
optionDetailId: null,
},
});
const queryClient = useQueryClient();

const handleAddCart = (e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
checkLoginBeforeAction(sendRequest);

checkLoginBeforeAction(async () => {
await sendRequest();
queryClient.invalidateQueries({ queryKey: ['cart'] });
queryClient.invalidateQueries({ queryKey: ['cartCount'] });
});
};

return (
Expand Down
15 changes: 15 additions & 0 deletions src/layouts/App/Header/BundleUtil/index.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,21 @@
@include ico-nav(-30px, -80px, 24px, 24px);

margin: 8px;
position: relative;
}

.num_cart {
@include size(16px, 14px, 0, 1px 5px 0);
@include font(10px, 500, #fff);

position: absolute;
inset: 4px 0 0 22px;
border-radius: 100px;
letter-spacing: -0.05em;
line-height: 13px;
text-align: center;
background-color: #fc363c;
box-sizing: border-box;
}

.wrapper_login {
Expand Down
18 changes: 18 additions & 0 deletions src/layouts/App/Header/BundleUtil/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import { useQuery } from '@tanstack/react-query';

import { Link } from 'react-router-dom';

import Spinner from 'components/ui/Spinner';

import { useUserExists } from 'hooks/useUserExists';
import { getCartCount } from 'services/api/v1/cart';

import SocialKakaoLogin from '../SocialKakaoLogin';

import styles from './index.module.scss';

const BundleUtil = () => {
const isLoggedIn = useUserExists();
const { data: cartCount, isLoading } = useQuery({
queryKey: ['cartCount'],
queryFn: () => getCartCount(),
enabled: isLoggedIn,
});

return (
<section className={styles.wrapper_bundle_util}>
<Link className={styles.link_search} to="/search">
Expand All @@ -16,6 +30,10 @@ const BundleUtil = () => {
<div className={styles.wrapper_ico} aria-hidden="true">
<span className={styles.ico_cart}>장바구니</span>
</div>
{isLoggedIn && !isLoading && cartCount! > 0 && (
<span className={styles.num_cart}>{cartCount}</span>
)}
{isLoading && <Spinner />}
Comment on lines +33 to +36
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. 카운트 표기할 때 cartCount! > 0 요 조건이 있는데, cartCount가 non-null로 단언이 되어 있는 것 같아요. cartCount는 API 응답인데 이렇게 단언해도 되나요??
  2. 로딩 중일 때 스피너가 뜨도록 되어 있는데, 스피너가 뜨면 화면 상호작용이 불가능합니다. 장바구니 아이템 개수 렌더링 같은 경우는 페이지 상호작용을 멈춰야 할 정도로 중요한 작업이 아니라고 봅니다. 그래서 스피너를 굳이 띄울 필요가 없다고 생각하는데 어떻게 생각하시나요?

Copy link
Member Author

@devkyoung2 devkyoung2 Jul 9, 2024

Choose a reason for hiding this comment

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

  1. API 응답이 완료되지 않으면 !isLoading에서 이미 false를 리턴하니까 cartCountnull값일 수가 없어요. 만약 API 요청에서 에러가 발생해 에러핸들링하는 경우를 말씀하시는거라면 이 컴포넌트가 아니라 인터셉트에서 핸들링하는게 낫지 않을까요?
  2. 음... 그런것 같기도 하네요... 제거하겠습니다

Copy link
Contributor

Choose a reason for hiding this comment

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

아하 그렇겠네요 이해했습니다 !

</Link>
<div className={styles.wrapper_login}>
<SocialKakaoLogin />
Expand Down
4 changes: 4 additions & 0 deletions src/layouts/Cart/CartBoxItem/index.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,14 @@
&.on {
@include ico-gift4(-170px, -790px, 24px, 24px);
}

cursor: pointer;
}

.ico_delete {
@include ico-gift4(-205px, -745px, 14px, 14px);

cursor: pointer;
}
}

Expand Down
18 changes: 9 additions & 9 deletions src/layouts/Cart/CartBoxItem/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useQueryClient } from '@tanstack/react-query';

import clsx from 'clsx';

import { useAxios } from 'hooks/useAxios';
Expand All @@ -8,26 +10,24 @@ import { CartItem } from 'types/cart';
import styles from './index.module.scss';

type CartBoxItemProps = {
refetch: () => void;
item: CartItem;
handleSelect: (productId: number) => void;
isSelected: boolean;
};

const CartBoxItem = ({
refetch,
item,
handleSelect,
isSelected,
}: CartBoxItemProps) => {
const CartBoxItem = ({ item, handleSelect, isSelected }: CartBoxItemProps) => {
const queryClient = useQueryClient();
const { sendRequest } = useAxios({
method: 'delete',
url: `cart/${item.productId}`,
});

const handleDelete = async () => {
const handleDelete = async (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
await sendRequest();
refetch();

queryClient.invalidateQueries({ queryKey: ['cart'] });
queryClient.invalidateQueries({ queryKey: ['cartCount'] });
};

return (
Expand Down
10 changes: 8 additions & 2 deletions src/layouts/Product/BuyInfo/ButtonBundles/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useQuery } from '@tanstack/react-query';
import { useQuery, useQueryClient } from '@tanstack/react-query';

import clsx from 'clsx';
import { useEffect, useState } from 'react';
Expand Down Expand Up @@ -50,6 +50,7 @@
wish: isWishedProp,
} = productDescription;
const navigate = useNavigate();
const queryClient = useQueryClient();
const { checkLoginBeforeAction } = useLogin();
const { isSelected, isSelfSelected, selectedFriends, getImgUrl } =
useSelectedFriendsStore();
Expand Down Expand Up @@ -111,7 +112,7 @@
// 옵션 선택 여부 확인
const checkOptionBeforeAction = (action: () => void) => {
if (hasOption && !selectedOption) {
alert('옵션을 선택해주세요');

Check warning on line 115 in src/layouts/Product/BuyInfo/ButtonBundles/index.tsx

View workflow job for this annotation

GitHub Actions / build

Unexpected alert
return;
}
action();
Expand All @@ -121,7 +122,7 @@
const handleClickFunding = () => {
checkLoginBeforeAction(() => {
if (!isEmptyObject(data!)) {
alert('이미 등록된 펀딩 아이템이 있습니다.');

Check warning on line 125 in src/layouts/Product/BuyInfo/ButtonBundles/index.tsx

View workflow job for this annotation

GitHub Actions / build

Unexpected alert
return;
}

Expand Down Expand Up @@ -173,7 +174,7 @@
} else if (selectedFriends.length === 1) {
navigate('/bill/gift', { state: { orderInfos, giftFor: 'friends' } });
} else {
alert('지금은 한 번에 한 명에게만 선물할 수 있어요.');

Check warning on line 177 in src/layouts/Product/BuyInfo/ButtonBundles/index.tsx

View workflow job for this annotation

GitHub Actions / build

Unexpected alert
}
});
};
Expand All @@ -187,7 +188,12 @@
// 장바구니 등록 버튼 핸들러
const handleAddCart = () => {
checkLoginBeforeAction(() => {
checkOptionBeforeAction(addItemToCart);
checkOptionBeforeAction(async () => {
await addItemToCart();

queryClient.invalidateQueries({ queryKey: ['cart'] });
queryClient.invalidateQueries({ queryKey: ['cartCount'] });
});
});
};

Expand Down
2 changes: 0 additions & 2 deletions src/pages/Cart/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const Cart = () => {
data: cartItems,
isFetched,
isLoading,
refetch,
} = useQuery({
queryKey: ['cart'],
queryFn: () => getCartItems(),
Expand Down Expand Up @@ -81,7 +80,6 @@ const Cart = () => {
{cartItems!.map((item) => (
<li key={item.cartId}>
<CartBoxItem
refetch={refetch}
item={item}
handleSelect={handleSelect}
isSelected={selectedItems.some(
Expand Down
8 changes: 7 additions & 1 deletion src/services/api/v1/cart.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CartResponse } from 'types/cart';
import { CartResponse, CartCountResponse } from 'types/cart';

import { apiV1 } from '.';

Expand All @@ -7,3 +7,9 @@ export const getCartItems = async () => {

return cartItems.data as CartResponse;
};

export const getCartCount = async () => {
const cartCount = await apiV1.get(`/cart/itemCount`);

return cartCount.data.count as CartCountResponse;
};
2 changes: 2 additions & 0 deletions src/types/cart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ export type CartItem = {
};

export type CartResponse = CartItem[];

export type CartCountResponse = number;
Loading