Skip to content

Commit

Permalink
Merge pull request #369 from KakaoFunding/feat/356
Browse files Browse the repository at this point in the history
Feat/356
  • Loading branch information
devkyoung2 authored Jun 18, 2024
2 parents 5ec10dd + 52fdfe6 commit 32b8bf0
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 94 deletions.
51 changes: 22 additions & 29 deletions src/layouts/Cart/CartBoxItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,44 @@ import clsx from 'clsx';

import { formatNumberWithComma, formatNumberWithUnit } from 'utils/format';

import { CartItem } from 'types/cart';

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

const data = {
cartId: 1,
productId: 101,
optionId: 201,
optionDetailId: 301,
productName:
'"독일 명품 비타민" 오쏘몰 이뮨 멀티비타민&미네랄 7입 - 단독 카톤박스 배송',
brandName: '오쏘몰',
quantity: 2,
productPrice: 38000,
imageUrl:
'https://img1.kakaocdn.net/thumb/[email protected]/?fname=https%3A%2F%2Fst.kakaocdn.net%2Fproduct%2Fgift%2Fproduct%2F20240605140558_d7afcc696ee4488abe48fdb21864c1f9.jpg',
optionName: 'dd',
optionDetailName: '',
totalPrice: 76000,
type CartBoxItemProps = {
item: CartItem;
handleSelect: (productId: number) => void;
isSelected: boolean;
};
const hasOption = true;
const isSelect = true;
const CartBoxItem = () => {

const CartBoxItem = ({ item, handleSelect, isSelected }: CartBoxItemProps) => {
return (
<div className={styles.wrapper_item}>
<div className={styles.wrapper_icons}>
<div
className={styles.wrapper_icons}
onClick={() => handleSelect(item.productId)}
>
<input type="checkbox" className={styles.btn_input} id="checkbox" />
<span
id="checkbox"
className={clsx(styles.ico_input, { [styles.on]: isSelect })}
className={clsx(styles.ico_input, { [styles.on]: isSelected })}
/>

<span className={styles.ico_delete} />
</div>
<div className={styles.wrapper_prod}>
<img
alt={`${data.productName}상품이미지`}
src={data.imageUrl}
alt={`${item.productName}상품이미지`}
src={item.imageUrl}
className={styles.thumb_prod}
/>
<div>
<p className={styles.txt_brand}>{data.brandName}</p>
<strong className={styles.txt_prod}>{data.productName}</strong>
{hasOption && (
<p className={styles.txt_brand}>{item.brandName}</p>
<strong className={styles.txt_prod}>{item.productName}</strong>
{item.optionName && (
<p className={styles.txt_option}>
<span className={styles.ico_option} />
{data.optionName}
{item.optionDetailName}
</p>
)}
</div>
Expand All @@ -55,11 +48,11 @@ const CartBoxItem = () => {
<div className={styles.wrapper_box}>
<p className={styles.txt_info}>
상품금액
<span>{formatNumberWithUnit(data.productPrice)}</span>
<span>{formatNumberWithUnit(item.productPrice)}</span>
</p>
<p className={styles.txt_info}>
선택수량
<span>x {data.quantity}</span>
<span>x {item.quantity}</span>
</p>
<p className={styles.txt_info}>
수신인원
Expand All @@ -71,7 +64,7 @@ const CartBoxItem = () => {
결제금액
<span className={styles.txt_unit}>
<span className={styles.num_info}>
{formatNumberWithComma(data.productPrice)}
{formatNumberWithComma(item.productPrice * item.quantity)}
</span>
</span>
Expand Down
21 changes: 9 additions & 12 deletions src/layouts/Cart/CartPay/BillItem/index.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
import { formatNumberWithUnit } from 'utils/format';

import { CartItem } from 'types/cart';

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

const prod = {
title:
'"선물제격" 보르딘 콜드브루 더치커피 알록달록 앰플 12종 커피 선물세트 (25ml*12개)',
quantity: 1,
price: 19900,
receiver: 1,
};
type BillItemProps = { item: CartItem };

const BillItem = () => {
const BillItem = ({ item }: BillItemProps) => {
const { productName, quantity, totalPrice } = item;
return (
<div className={styles.wrapper_item}>
<strong className={styles.txt_title}>{prod.title}</strong>
<strong className={styles.txt_title}>{productName}</strong>
<div className={styles.wrapper_pay_info}>
<p className={styles.txt_info}>
상품금액
<span>{formatNumberWithUnit(prod.price)}</span>
<span>{formatNumberWithUnit(totalPrice)}</span>
</p>
<p className={styles.txt_info}>
수량
<span>x {prod.quantity}</span>
<span>x {quantity}</span>
</p>
<p className={styles.txt_info}>
수신인원
Expand All @@ -30,7 +27,7 @@ const BillItem = () => {
</div>
<p className={styles.txt_info}>
상품 결제 금액
<span>{formatNumberWithUnit(prod.price * prod.quantity)}</span>
<span>{formatNumberWithUnit(totalPrice)}</span>
</p>
</div>
);
Expand Down
63 changes: 34 additions & 29 deletions src/layouts/Cart/CartPay/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,47 @@ import { useSelectedFriendsStore } from 'store/useSelectedFriendsStore';

import { useKakaoPicker } from 'hooks/useKakaoPicker';
import { useLogin } from 'hooks/useLogin';
import { formatNumberWithUnit } from 'utils/format';

import { RequestOrderPreview } from 'types/payment';
import { CartItem } from 'types/cart';

import DefaultProfileImage from 'assets/profile_noimg.png';

import BillItem from './BillItem';

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

// TODO : 가짜 상품데이터
const prod = [1, 2, 3];
const CartPay = () => {
type CartPayProps = {
selectedItems: CartItem[];
totalPayment: number;
};

const CartPay = ({ selectedItems, totalPayment }: CartPayProps) => {
const [isToggled, handleToggle] = useReducer((prev) => !prev, false);
const navigate = useNavigate();
const { isLoggedIn, login, confirmLogin } = useLogin();
const { checkLoginBeforeAction } = useLogin();
const { openKakaoPicker } = useKakaoPicker();
const { isSelected, isSelfSelected, selectedFriends, getImgUrl } =
useSelectedFriendsStore();
const { openKakaoPicker } = useKakaoPicker();
const navigate = useNavigate();

// 로그인 여부 확인
const checkLoginBeforeAction = (action: () => void) => {
if (isLoggedIn) action();
else {
const result = confirmLogin();
if (result) login();
}
};
const getOrderInfo = () => {
const orderInfos = selectedItems.map((item) => {
return {
productId: item.productId,
quantity: item.quantity,
options: [{ id: item.optionId, detailId: item.optionDetailId }],
};
});

const orderInfos: RequestOrderPreview = [
{
productId: 1361966,
quantity: 1,
options: [],
},
];
return orderInfos;
};

// 나에게 선물하기 버튼 핸들러
const handleClickGiftForMe = () => {
checkLoginBeforeAction(() => {
navigate('/bill/gift', { state: { orderInfos, giftFor: 'me' } });
navigate('/bill/gift', {
state: { orderInfos: getOrderInfo(), giftFor: 'me' },
});
});
};

Expand All @@ -60,9 +61,13 @@ const CartPay = () => {
}

if (isSelfSelected) {
navigate('/bill/gift', { state: { orderInfos, giftFor: 'me' } });
navigate('/bill/gift', {
state: { orderInfos: getOrderInfo(), giftFor: 'me' },
});
} else if (selectedFriends.length === 1) {
navigate('/bill/gift', { state: { orderInfos, giftFor: 'friends' } });
navigate('/bill/gift', {
state: { orderInfos: getOrderInfo(), giftFor: 'friends' },
});
} else {
alert('지금은 한 번에 한 명에게만 선물할 수 있어요.');
}
Expand All @@ -84,9 +89,9 @@ const CartPay = () => {
>
{isToggled && (
<ul className={styles.scroll}>
{prod.map((it) => (
<li key={it}>
<BillItem />
{selectedItems.map((item) => (
<li key={item.cartId}>
<BillItem item={item} />
</li>
))}
</ul>
Expand All @@ -95,7 +100,7 @@ const CartPay = () => {
<Button onClick={handleToggle} color="white" className={styles.btn}>
<strong>총 결제 금액</strong>
<em className={styles.num_price}>
57,900원
{formatNumberWithUnit(totalPayment)}
<span
className={clsx(styles.ico_toggle, { [styles.on]: isToggled })}
>
Expand Down
114 changes: 90 additions & 24 deletions src/pages/Cart/index.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,109 @@
import { useQuery } from '@tanstack/react-query';

import { useEffect, useState } from 'react';

import MainWrapper from 'components/ui/MainWrapper';
import Spinner from 'components/ui/Spinner';
import Header from 'layouts/App/Header';
import CartBoxFooter from 'layouts/Cart/CartBoxFooter';
import CartBoxHeader from 'layouts/Cart/CartBoxHeader';
import CartBoxItem from 'layouts/Cart/CartBoxItem';
import CartPay from 'layouts/Cart/CartPay';
import EmptyCartBoxBody from 'layouts/Cart/EmptyCartBoxBody';

import styles from './index.module.scss';
import { getCartItems } from 'services/api/v1/cart';

const items = [1, 2, 3];
import { CartItem } from 'types/cart';

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

const Cart = () => {
const isItemInCart = true;
const [selectedItems, setSelectedItems] = useState<CartItem[]>([]);
const [totalPayment, setTotalPayment] = useState<number>(0);

const {
data: cartItems,
isFetched,
isLoading,
} = useQuery({
queryKey: ['cart'],
queryFn: () => getCartItems(),
});

const isItemInCart = cartItems ? cartItems.length > 0 : false;

const handleSelect = (productId: number) => {
setSelectedItems((prevSelectedItems) => {
if (prevSelectedItems.some((item) => item.productId === productId)) {
return prevSelectedItems.filter((item) => item.productId !== productId);
}

const selectedItem = cartItems!.find(
(item) => item.productId === productId,
);

return selectedItem
? [...prevSelectedItems, selectedItem]
: prevSelectedItems;
});
};

useEffect(() => {
if (cartItems) {
setSelectedItems([...cartItems]);
}
}, [cartItems]);

useEffect(() => {
if (selectedItems) {
const totalPrice = selectedItems.reduce(
(acc, cartItem) => acc + cartItem.totalPrice,
0,
);
setTotalPayment(totalPrice);
} else {
setTotalPayment(0);
}
}, [selectedItems]);

return (
<>
<Header />
<section className={styles.area_cart}>
<MainWrapper>
<div className={styles.wrapper_cart}>
<div className={styles.wrapper_cart_box}>
<CartBoxHeader isItemInCart={isItemInCart} />
{isItemInCart ? (
<ul className={styles.wrapper_item}>
{items.map((item) => (
<li key={item}>
<CartBoxItem />
</li>
))}
</ul>
) : (
<EmptyCartBoxBody />
)}
<CartBoxFooter isItemInCart={isItemInCart} />
{isFetched && (
<section className={styles.area_cart}>
<MainWrapper>
<div className={styles.wrapper_cart}>
<div className={styles.wrapper_cart_box}>
<CartBoxHeader isItemInCart={isItemInCart} />
{isItemInCart ? (
<ul className={styles.wrapper_item}>
{cartItems!.map((item) => (
<li key={item.cartId}>
<CartBoxItem
item={item}
handleSelect={handleSelect}
isSelected={selectedItems.some(
(selectedItem) =>
selectedItem.productId === item.productId,
)}
/>
</li>
))}
</ul>
) : (
<EmptyCartBoxBody />
)}
<CartBoxFooter isItemInCart={isItemInCart} />
</div>
<CartPay
selectedItems={selectedItems}
totalPayment={totalPayment}
/>
</div>
<CartPay />
</div>
</MainWrapper>
</section>
</MainWrapper>
</section>
)}
{isLoading && <Spinner />}
</>
);
};
Expand Down
9 changes: 9 additions & 0 deletions src/services/api/v1/cart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { CartResponse } from 'types/cart';

import { apiV1 } from '.';

export const getCartItems = async () => {
const cartItems = await apiV1.get(`/cart`);

return cartItems.data as CartResponse;
};
Loading

0 comments on commit 32b8bf0

Please sign in to comment.