Skip to content

๐Ÿฐ ์กฐ๊ฐ ์ผ€์ดํฌ ๋ฒค๋”ฉ๋จธ์‹ 

Notifications You must be signed in to change notification settings

hyeonbinnn/piece-of-cake

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

85 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿฐ Piece of Cake

์ผ€์ดํฌ




๋ชฉ์ฐจ




ํ”„๋กœ์ ํŠธ ์ •๋ณด

๐Ÿฐ Piece of Cake ๋ฒค๋”ฉ๋จธ์‹ 

Piece of Cake ๋ฒค๋”ฉ๋จธ์‹ ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์†Œ์ง€๊ธˆ์„ ์ถฉ์ „ํ•˜๊ณ , ์›ํ•˜๋Š” ๋””์ €ํŠธ๋ฅผ ์„ ํƒํ•ด ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ž…๋‹ˆ๋‹ค.

๊ตฌํ˜„ ๊ธฐ๊ฐ„ : 2024.04.28 ~ 2024.04.30

๋ฐฐํฌ ์‚ฌ์ดํŠธ : ๋ฐฐํฌ URL ๋ฐ”๋กœ๊ฐ€๊ธฐ




ํด๋” ๊ตฌ์กฐ

๐Ÿฐ PIECE-OF-CAKE
โ”œโ”€ ๐Ÿ“ฆ public
โ”œโ”€ ๐Ÿ“ฆ src
โ”‚  โ”œโ”€ ๐Ÿ“‚ assets
โ”‚  โ”œโ”€ ๐Ÿ“‚ components
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Button
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Cake
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Cart
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Header
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Modal
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Section
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ Slider
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ User
โ”‚  โ”‚  โ””โ”€ ๐Ÿ“‚ Wallet
โ”‚  โ”œโ”€ ๐Ÿ“‚ data
โ”‚  โ”œโ”€ ๐Ÿ“‚ hooks
โ”‚  โ”œโ”€ ๐Ÿ“‚ pages
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ ErrorPage
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ MainPage
โ”‚  โ”‚  โ””โ”€ ๐Ÿ“‚ StartPage
โ”‚  โ”œโ”€ ๐Ÿ“‚ state
โ”‚  โ”‚  โ”œโ”€ ๐Ÿ“‚ atoms
โ”‚  โ”‚  โ””โ”€ ๐Ÿ“‚ selectors
โ”‚  โ”œโ”€ ๐Ÿ“‚ styles
โ”‚  โ”œโ”€ ๐Ÿ“‚ types
|  โ”œโ”€ ๐Ÿ“œ App.tsx
|  โ””โ”€ ๐Ÿ“œ index.tsx



์‚ฌ์šฉ ๊ธฐ์ˆ 

[ FrontEnd ]


[ Version ]

"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.51.4",
"react-router-dom": "^6.23.0",
"react-scripts": "5.0.1",
"recoil": "^0.7.7",
"styled-components": "^6.1.8",
"styled-reset": "^4.5.2",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"



๊ตฌํ˜„ ๊ธฐ๋Šฅ

์ดˆ๊ธฐ ํ™”๋ฉด ๋ฉ”๋‰ด์–ผ ๋ชจ๋‹ฌ
๋ฉ”์ธ ๋ฉ”๋‰ด์–ผ

์†Œ์ง€๊ธˆ ์ถฉ์ „ ์ž…๊ธˆ์•ก ์ถฉ์ „
์†Œ์ง€๊ธˆ ์ž…๊ธˆ์•ก

์•„์ดํ…œ ํš๋“ ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ดˆ๊ธฐํ™”
ํš๋“ ์ดˆ๊ธฐํ™”

๊ฑฐ์Šค๋ฆ„๋ˆ ๋ฐ˜ํ™˜ 404 ์—๋Ÿฌ
๋ฐ˜ํ™˜ ์—๋Ÿฌ



ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

1. ์ƒํƒœ ๊ด€๋ฆฌ ๊ฐœ์„ 

์ด๊ธˆ์•ก์„ ๊ณ„์‚ฐํ•  ๋•Œ, calculateTotalPrice ํ•จ์ˆ˜๋ฅผ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ์ง์ ‘ ํ˜ธ์ถœํ•˜๊ณ , useRecoilState ํ›…์„ ํ†ตํ•ด ์ƒํƒœ ์ €์žฅ์†Œ์˜ totalCartItemState ์ƒํƒœ๋ฅผ ๊ฐ€์ ธ์™€์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ด๋Š” ์ปดํฌ๋„ŒํŠธ ๋‚ด์— ๋กœ์ง์ด ์„ž์—ฌ ๋ณต์žก์„ฑ์ด ์ฆ๊ฐ€ํ•˜๊ณ , ์ƒํƒœ ์—…๋ฐ์ดํŠธ์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ๋ถ€๋ถ„์— ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ๋‹ค!

[ ๋ณ€๊ฒฝ ์ „ ]

// TotalCart.tsx
const TotalCart = () => {
  const [cartItem, setCartItem] = useRecoilState(totalCartItemState);

  const calculateTotalPrice = (): number => {
    return cartItem.reduce(
      (total: number, item: SelectedCakeItem) => total + item.cost * item.quantity,
      0
    );
  };
}

...

return (
  <>
    <S.TotalPrice>์ด๊ธˆ์•ก : {calculateTotalPrice().toLocaleString()}์›</S.TotalPrice>
  </>
  )
}

๋”ฐ๋ผ์„œ ์ด๊ธˆ์•ก ๊ณ„์‚ฐํ•˜๋Š” ๋ถ€๋ถ„์„ ์…€๋ ‰ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด ์ƒํƒœ ๊ด€๋ฆฌ ๋กœ์ง์—์„œ ๋ถ„๋ฆฌ์‹œ์ผœ ์ปดํฌ๋„ŒํŠธ๋Š” UI์—๋งŒ ์ง‘์ค‘ํ•˜๊ณ , ์„ ํƒ์ž๋Š” ๋ฐ์ดํ„ฐ์˜ ๊ณ„์‚ฐ๊ณผ ์ฒ˜๋ฆฌ์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.

// selector.ts
export const totalPriceSelector = selector<number>({
  key: 'totalPriceSelector',
  get: ({ get }) => {
    const cartItems: SelectedCakeItem[] = get(totalCartItemState);
    return cartItems.reduce(
      (total: number, item: SelectedCakeItem): number => total + item.cost * item.quantity,
      0
    );
  },
});

useRecoilValue ํ›…์„ ํ†ตํ•ด ์…€๋ ‰ํ„ฐ์—์„œ ๋งŒ๋“  totalPriceSelector๋ฅผ ๊ฐ€์ ธ์™€์„œ totalPrice ๋ณ€์ˆ˜์— ์ €์žฅํ•ด์„œ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•ด์ง€๊ณ , ์œ ์ง€๋ณด์ˆ˜์— ์šฉ์ดํ•ด์ง„๋‹ค!

[ ๋ณ€๊ฒฝ ํ›„ ]

// TotalCart.tsx
const TotalCart = () => {
  const [cartItem, setCartItem] = useRecoilState(totalCartItemState);
  const totalPrice = useRecoilValue(totalPriceSelector);

...

return (
  <>
    <S.TotalPrice>์ด๊ธˆ์•ก : {totalPrice.toLocaleString()}์›</S.TotalPrice>
  </>
  )
}


2. ์ดˆ๊ธฐํ™” ์‹œ, ์ž”์•ก ํ•ฉ์‚ฐ ์˜ค๋ฅ˜

์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ดˆ๊ธฐํ™” ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๋•Œ, cartItemRefresh ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์žˆ๋Š” ์•„์ดํ…œ๋“ค์„ ์ดˆ๊ธฐํ™”์‹œํ‚ค๋ฉฐ useRecoilState ํ›…์„ ํ†ตํ•ด ์ƒํƒœ ์ €์žฅ์†Œ์˜ totalCartItemState ์ƒํƒœ๋ฅผ ๊ฐ€์ ธ์™€์„œsetCartItem์„ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์žˆ๋‹ค.

์ดˆ๊ธฐํ™”๊ฐ€ ๋˜๋ฉด์„œ ์ด๊ธˆ์•ก์ด ๋‹ค์‹œ ์ž”์•ก๊ณผ ํ•ฉ์‚ฐ๋˜์–ด ๊ณ„์‚ฐ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ, ์žฅ๋ฐ”๊ตฌ๋‹ˆ๋งŒ ์ดˆ๊ธฐํ™”๊ฐ€ ์ด๋ฃจ์–ด์ง€๊ณ  ์žˆ๋‹ค!

[ ๋ณ€๊ฒฝ ์ „ ]

// TotalCart.tsx
const TotalCart = () => {
  const [cartItem, setCartItem] = useRecoilState(totalCartItemState);

  const cartItemRefresh = (): void => {
    setCartItem([]);
  };

...

return (
  <>
    <S.RefreshBtn onClick={cartItemRefresh} />
  </>
  )
}

๋”ฐ๋ผ์„œ ์žฅ๋ฐ”๊ตฌ๋‹ˆ๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ ๋’ค, ์ด๊ธˆ์•ก๊ณผ ์†Œ์ง€๊ธˆ์„ ๋”ํ•ด์ฃผ๋Š” ๊ฐ’์„ ๊ณ„์‚ฐํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์…€๋ ‰ํ„ฐ์—์„œ ์ด๊ธˆ์•ก + ์ž”์•ก์„ ๊ณ„์‚ฐํ•˜๋Š” ์„ ํƒ์ž totalPriceAmountSelector๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.

// selector.ts
export const totalPriceAmountSelector = selector<number>({
  key: 'totalPriceAmountSelector',
  get: ({ get }) => {
    const cartItems = get(totalPriceSelector);
    const balance = get(balanceState);
    return cartItems + balance;
  },
});

๊ทธ๋ฆฌ๊ณ  cartItemRefresh ํ•จ์ˆ˜์—์„œ useSetRecoilState ํ›…์„ ํ†ตํ•ด ์ƒํƒœ ์ €์žฅ์†Œ์—์„œ ์ž”์•ก ๊ด€๋ จ balanceState ์ƒํƒœ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

๊ทธ ๋‹ค์Œ, useRecoilValue ํ›…์„ ํ†ตํ•ด totalPriceAmountSelector ์„ ํƒ์ž๋ฅผ totalPriceBalance ๋ณ€์ˆ˜์— ์ €์žฅํ•˜๊ณ , setBalance๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ๋ณ€์ˆ˜๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๋ฉด ๋œ๋‹ค!

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์žฅ๋ฐ”๊ตฌ๋‹ˆ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋™์‹œ์— ์ž”์•ก๋„ ํ•จ๊ป˜ ์—…๋ฐ์ดํŠธ๋œ๋‹ค! ๐Ÿ˜‰

[ ๋ณ€๊ฒฝ ํ›„ ]

// TotalCart.tsx
const TotalCart = () => {
  const [cartItem, setCartItem] = useRecoilState(totalCartItemState);
  const totalPriceBalance = useRecoilValue(totalPriceAmountSelector);
  const setBalance = useSetRecoilState(balanceState);

  const cartItemRefresh = (): void => {
    // 1. ์ƒˆ๋กœ๊ณ ์นจ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ดˆ๊ธฐํ™”
    // 2. ์ž”์•ก === ์ด๊ธˆ์•ก + ์ž”์•ก
    setCartItem([]);
    setBalance(totalPriceBalance);
  };

...

return (
  <>
    <S.RefreshBtn onClick={cartItemRefresh} />
  </>
  )
}


โœ”๏ธ ๋ณ€๊ฒฝ ์ปดํฌ๋„ŒํŠธ ์ „์ฒด ์ฝ”๋“œ

[ ๋ณ€๊ฒฝ ์ „ ]

import * as S from './TotalCart.style';
import Wallet from '../Wallet/Wallet';
import ManualModal from '../Modal/ManualModal';
import useModal from '../../hooks/useModal';
import { SelectedCakeItem, totalCartItemState } from '../../state/atoms/atoms';
import { useRecoilState } from 'recoil';

const TotalCart = () => {
  const { isModalOpen, openModal, closeModal } = useModal();
  const [cartItem, setCartItem] = useRecoilState(totalCartItemState);

  const calculateTotalPrice = (): number => {
    return cartItem.reduce(
      (total: number, item: SelectedCakeItem) => total + item.cost * item.quantity,
      0
    );
  };

  const cartItemRefresh = (): void => {
    setCartItem([]);
  };
  return (
    <>
      <Wallet />
      <S.Wrapper>
        <S.H2>์žฅ๋ฐ”๊ตฌ๋‹ˆ</S.H2>
        <S.GetCartUl>
          {cartItem.map((item: SelectedCakeItem) => (
            <S.GetCartLi>
              <S.GetCartImg src={item.img} alt={item.name} />
              <S.GetCartName>{item.name}</S.GetCartName>
              <S.GetCartStrong>{item.quantity}</S.GetCartStrong>
            </S.GetCartLi>
          ))}
        </S.GetCartUl>
        <S.BottomBox>
          <S.ButtonBox>
            <S.ManualBtn onClick={openModal}>์„ค๋ช…์„œ</S.ManualBtn>
            <S.RefreshBtn onClick={cartItemRefresh} />
          </S.ButtonBox>
          <S.TotalPrice>์ด๊ธˆ์•ก : {calculateTotalPrice().toLocaleString()}์›</S.TotalPrice>
        </S.BottomBox>
      </S.Wrapper>
      {isModalOpen && <ManualModal onClose={closeModal} />}
    </>
  );
};

export default TotalCart;

[ ๋ณ€๊ฒฝ ํ›„ ]

// selector.ts
import { selector } from 'recoil';
import { balanceState, SelectedCakeItem, totalCartItemState } from '../atoms/atoms';

// ์ด๊ธˆ์•ก ๊ณ„์‚ฐ
export const totalPriceSelector = selector<number>({
  key: 'totalPriceSelector',
  get: ({ get }) => {
    const cartItems: SelectedCakeItem[] = get(totalCartItemState);
    return cartItems.reduce(
      (total: number, item: SelectedCakeItem): number => total + item.cost * item.quantity,
      0
    );
  },
});

// ์ด๊ธˆ์•ก + ์ž”์•ก
export const totalPriceAmountSelector = selector<number>({
  key: 'totalPriceAmountSelector',
  get: ({ get }) => {
    const cartItems = get(totalPriceSelector);
    const balance = get(balanceState);
    return cartItems + balance;
  },
});

import * as S from './TotalCart.style';
import Wallet from '../Wallet/Wallet';
import ManualModal from '../Modal/ManualModal';
import useModal from '../../hooks/useModal';
import { balanceState, SelectedCakeItem, totalCartItemState } from '../../state/atoms/atoms';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { totalPriceAmountSelector, totalPriceSelector } from '../../state/selectors/selector';

const TotalCart = () => {
  const { isModalOpen, openModal, closeModal } = useModal();
  const [cartItem, setCartItem] = useRecoilState(totalCartItemState);
  const totalPrice = useRecoilValue(totalPriceSelector);
  const totalPriceBalance = useRecoilValue(totalPriceAmountSelector);
  const setBalance = useSetRecoilState(balanceState);

  const cartItemRefresh = (): void => {
    // 1. ์ƒˆ๋กœ๊ณ ์นจ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ดˆ๊ธฐํ™”
    // 2. ์ž”์•ก === ์ด๊ธˆ์•ก + ์ž”์•ก
    setCartItem([]);
    setBalance(totalPriceBalance);
  };
  return (
    <>
      <Wallet />
      <S.Wrapper>
        <S.H2>์žฅ๋ฐ”๊ตฌ๋‹ˆ</S.H2>
        <S.GetCartUl>
          {cartItem.map((item: SelectedCakeItem) => (
            <S.GetCartLi>
              <S.GetCartImg src={item.img} alt={item.name} />
              <S.GetCartName>{item.name}</S.GetCartName>
              <S.GetCartStrong>{item.quantity}</S.GetCartStrong>
            </S.GetCartLi>
          ))}
        </S.GetCartUl>
        <S.BottomBox>
          <S.ButtonBox>
            <S.ManualBtn onClick={openModal}>์„ค๋ช…์„œ</S.ManualBtn>
            <S.RefreshBtn onClick={cartItemRefresh} />
          </S.ButtonBox>
          <S.TotalPrice>์ด๊ธˆ์•ก : {totalPrice.toLocaleString()}์›</S.TotalPrice>
        </S.BottomBox>
      </S.Wrapper>
      {isModalOpen && <ManualModal onClose={closeModal} />}
    </>
  );
};

export default TotalCart;



About

๐Ÿฐ ์กฐ๊ฐ ์ผ€์ดํฌ ๋ฒค๋”ฉ๋จธ์‹ 

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published