[15주차 Day2] 스프린트 3: React(TypeScript) 기반의 동적 UI 개발

반 히·2024년 6월 7일

데브코스

목록 보기
41/58
post-thumbnail

📚 Part 9 장바구니


📁 장바구니 목록

📌 장바구니 삭제

export const deleteCart = async (cartId: number) => {
    const response = await httpClient.delete(`/carts/${cartId}`);
    return response.data;
};

장바구니 삭제 api 생성

import { useEffect, useState } from "react";
import { Cart } from "../models/cart.model";
import { deleteCart, fetchCart } from "../api/carts.api";

export const useCart = () => {
    const [carts, setCarts] = useState<Cart[]>([]);
    const [isEmpty, setIsEmpty] = useState(true);

    const deleteCartItem = (id : number) => {
        deleteCart(id).then(() => {
            setCarts(carts.filter((cart) => cart.id !== id));
        });
    }

    useEffect(() => {
        fetchCart().then((carts) => {
            setCarts(carts);
            setIsEmpty(carts.length === 0);
        });
    }, []);

    return { carts, isEmpty, deleteCartItem };
};

장바구니 삭제 hooks 구현

📌 확인 창 띄우기

import { useCallback } from "react"

export const useAlert = () => {
    const showAlert = useCallback((message: string) => {
        window.alert(message);
    }, []);

    const showConfirm = useCallback(
        (message: string, onConfirm: () => void) => {  
            if (window.confirm(message)) {
                onConfirm();
            }
    }, []);

    return { showAlert, showConfirm };
};

📌 빈 페이지

import Title from './Title';

interface Props {
    icon?: React.ReactNode;
    title:string;
    description?: React.ReactNode;
}
function Empty({icon, title, description}: Props) {
    return (
        <EmptyStyle>
            {
                icon && (<div className="icon">{icon}</div>)
            }
            <Title size='large' color='secondary'>
                {title}
            </Title>
            <p>
                {
                    description && (<p>{description}</p>)
                }
            </p>
        </EmptyStyle>
    );
}

export default Empty;

빈 페이지 공통 컴포넌트 작성

📌 장바구니 요약

const totalQuantity = useMemo(() => {
    return carts.reduce((acc, cart) => {
        if (checkedItems.includes(cart.id)) {
            return acc + cart.quantity;
        }
        return acc;
    }, 0);
}, [carts, checkedItems]);

const totalPrice = useMemo(() => {
    return carts.reduce((acc, cart) => {
        if (checkedItems.includes(cart.id)) {
            return acc + (cart.price * cart.quantity);
        }
        return acc;
    }, 0);
}, [carts, checkedItems]);

📌 주문하기

const handleOrder = () => {
    if (checkedItems.length === 0) {
        showAlert('주문할 상품을 선택해주세요.');
        return;
    }

    // 주문 액션 -> 주문서 작성으로 데이터 전달 
    const orderData: Omit<OrderSheet, "delivery"> = {
        items: checkedItems,
        totalPrice,
        totalQuantity,
        firstBookTitle: carts[0].title
    };

    showConfirm('주문하시겠습니까?', () => {
        navigate("/order", { state: orderData });
    });
};

0개의 댓글