From ee337958df08ee67bf77c64dc25617f070061d74 Mon Sep 17 00:00:00 2001 From: Chuseok22 Date: Thu, 15 Jan 2026 10:30:48 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=5F?= =?UTF-8?q?=EB=A9=94=EB=89=B4=5F=EC=88=98=EB=9F=89=5F=EC=A1=B0=EC=A0=88=5F?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=5F=EA=B0=9C=EB=B0=9C=20:?= =?UTF-8?q?=20feat=20:=20=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=20=EC=88=98?= =?UTF-8?q?=EB=9F=89=20=EC=A1=B0=EC=A0=88=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EA=B0=9C=EB=B0=9C=EC=9D=84=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?svg=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=B6=94=EA=B0=80=20https:?= =?UTF-8?q?//github.com/CampusTable/campus-table-fe/issues/128?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/index.ts | 6 +++++- src/assets/icons/minus.svg | 3 +++ src/assets/icons/plus-disable.svg | 3 +++ src/assets/icons/plus.svg | 3 +++ src/assets/icons/trash.svg | 3 +++ 5 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/assets/icons/minus.svg create mode 100644 src/assets/icons/plus-disable.svg create mode 100644 src/assets/icons/plus.svg create mode 100644 src/assets/icons/trash.svg diff --git a/src/assets/icons/index.ts b/src/assets/icons/index.ts index d8ae768..89e5c6b 100644 --- a/src/assets/icons/index.ts +++ b/src/assets/icons/index.ts @@ -10,6 +10,10 @@ export { default as HomeDisableIcon } from "./home-disable.svg"; export { default as HomeEnableIcon } from "./home-enable.svg"; export { default as JingwanDisableIcon } from "./jingwan-disable.svg"; export { default as JingwanEnableIcon } from "./jingwan-enable.svg"; +export { default as MinusIcon } from "./minus.svg"; export { default as MyDisableIcon } from "./my-disable.svg"; export { default as MyEnableIcon } from "./my-enable.svg"; -export { default as ShoppingBag } from "./shopping-bag.svg"; \ No newline at end of file +export { default as PlusIcon } from "./plus.svg"; +export { default as PlusDisableIcon } from "./plus-disable.svg"; +export { default as ShoppingBag } from "./shopping-bag.svg"; +export { default as TrashIcon } from "./trash.svg"; \ No newline at end of file diff --git a/src/assets/icons/minus.svg b/src/assets/icons/minus.svg new file mode 100644 index 0000000..ba960e4 --- /dev/null +++ b/src/assets/icons/minus.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/plus-disable.svg b/src/assets/icons/plus-disable.svg new file mode 100644 index 0000000..4093fcc --- /dev/null +++ b/src/assets/icons/plus-disable.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/plus.svg b/src/assets/icons/plus.svg new file mode 100644 index 0000000..9a897d0 --- /dev/null +++ b/src/assets/icons/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/trash.svg b/src/assets/icons/trash.svg new file mode 100644 index 0000000..e92ec1a --- /dev/null +++ b/src/assets/icons/trash.svg @@ -0,0 +1,3 @@ + + + From 4741e59955e03b76189d2db0295ca31cd551a287 Mon Sep 17 00:00:00 2001 From: Chuseok22 Date: Thu, 15 Jan 2026 10:35:02 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=5F?= =?UTF-8?q?=EB=A9=94=EB=89=B4=5F=EC=88=98=EB=9F=89=5F=EC=A1=B0=EC=A0=88=5F?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=5F=EA=B0=9C=EB=B0=9C=20:?= =?UTF-8?q?=20feat=20:=20RoundedNumber=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=82=AC=EC=9D=B4=EC=A6=88=20css=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EB=B3=80=EA=B2=BD=20https://github.com/CampusTable?= =?UTF-8?q?/campus-table-fe/issues/128?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/menu/components/button/CartButton.module.css | 5 ----- src/features/menu/components/button/CartButton.tsx | 2 -- src/shared/components/number/RoundedNumber.module.css | 3 +++ 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/features/menu/components/button/CartButton.module.css b/src/features/menu/components/button/CartButton.module.css index b0870f0..90f4fce 100644 --- a/src/features/menu/components/button/CartButton.module.css +++ b/src/features/menu/components/button/CartButton.module.css @@ -19,11 +19,6 @@ justify-content: center; } -.icon { - width: 1.25rem; - height: 1.25rem; -} - .label { color: var(--color-white); font-size: var(--text-base); diff --git a/src/features/menu/components/button/CartButton.tsx b/src/features/menu/components/button/CartButton.tsx index 7d7cb55..469fbb0 100644 --- a/src/features/menu/components/button/CartButton.tsx +++ b/src/features/menu/components/button/CartButton.tsx @@ -19,12 +19,10 @@ export default function CartButton({ className={styles.button} >
-
-
장바구니 보기
diff --git a/src/shared/components/number/RoundedNumber.module.css b/src/shared/components/number/RoundedNumber.module.css index 2c95bac..13daf27 100644 --- a/src/shared/components/number/RoundedNumber.module.css +++ b/src/shared/components/number/RoundedNumber.module.css @@ -3,6 +3,9 @@ justify-content: center; align-content: center; + min-width: 1.25rem; + min-height: 1.25rem; + border-radius: 0.3125rem; background-color: var(--color-white); From 264b7300489f30257be42c42f1320d421f60b8ed Mon Sep 17 00:00:00 2001 From: Chuseok22 Date: Thu, 15 Jan 2026 11:15:35 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=5F?= =?UTF-8?q?=EB=A9=94=EB=89=B4=5F=EC=88=98=EB=9F=89=5F=EC=A1=B0=EC=A0=88=5F?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=5F=EA=B0=9C=EB=B0=9C=20:?= =?UTF-8?q?=20feat=20:=20=EC=88=98=EB=9F=89=20=EC=A1=B0=EC=A0=88=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B0=9C=EB=B0=9C=20?= =?UTF-8?q?=EB=B0=8F=20useCart.ts=20=ED=9B=85=20=EB=82=B4=EB=B6=80=20?= =?UTF-8?q?=EC=88=98=EB=9F=89=20=EA=B0=90=EC=86=8C=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20https://github.com/CampusTable/campus-tabl?= =?UTF-8?q?e-fe/issues/128?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../button/QuantityStepper.module.css | 27 ++++++++ .../components/button/QuantityStepper.tsx | 65 +++++++++++++++++++ src/features/cart/hooks/useCart.ts | 54 +++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 src/features/cart/components/button/QuantityStepper.module.css create mode 100644 src/features/cart/components/button/QuantityStepper.tsx diff --git a/src/features/cart/components/button/QuantityStepper.module.css b/src/features/cart/components/button/QuantityStepper.module.css new file mode 100644 index 0000000..2843538 --- /dev/null +++ b/src/features/cart/components/button/QuantityStepper.module.css @@ -0,0 +1,27 @@ +.container { + display: flex; + justify-content: center; + align-content: center; + + padding-block: 0.44rem; + padding-inline: 0.5rem; + + border-radius: 0.25rem; + border: 1px solid var(--color-gray-200); + background-color: var(--color-white); +} + +.wrapper { + display: flex; + justify-content: space-between; + align-items: center; +} + +.label { + color: var(--color-black); + font-size: var(--text-xs); + font-style: normal; + font-weight: var(--font-medium); + line-height: var(--line-height-single); + letter-spacing: var(--letter-spacing); +} \ No newline at end of file diff --git a/src/features/cart/components/button/QuantityStepper.tsx b/src/features/cart/components/button/QuantityStepper.tsx new file mode 100644 index 0000000..6a9835c --- /dev/null +++ b/src/features/cart/components/button/QuantityStepper.tsx @@ -0,0 +1,65 @@ +"use client"; + +import styles from "./QuantityStepper.module.css"; +import { MinusIcon, PlusDisableIcon, PlusIcon, TrashIcon } from "@/assets/icons"; +import { useCart } from "@/features/cart/hooks/useCart"; +import { useToast } from "@/shared/hooks/useToast"; + +interface QuantityStepperProps { + menuId: number; + quantity: number; +} + +export default function QuantityStepper({ + menuId, + quantity +}: QuantityStepperProps) { + const { addToCart, removeFromCart, isAddingToCart } = useCart(); + const { showToast } = useToast(); + + const handleIncrement = () => { + if (quantity >= 9) { + showToast("메뉴는 최대 9개까지만 담을 수 있어요!"); + return; + } + addToCart(menuId, { + onError: (message) => showToast(message) + }); + } + + const handleDecrement = () => { + if (quantity <= 0) { + return; + } + + removeFromCart(menuId, { + onError: (message) => showToast(message) + }); + } + + const decrementIcon = quantity === 1 ? : ; + const incrementIcon = quantity !== 9 ? : ; + const isPlusDisabled = quantity >= 9 + + return ( +
+
+ +
+ {quantity} +
+ +
+
+ ); +} \ No newline at end of file diff --git a/src/features/cart/hooks/useCart.ts b/src/features/cart/hooks/useCart.ts index ef2dcb0..6d31f7d 100644 --- a/src/features/cart/hooks/useCart.ts +++ b/src/features/cart/hooks/useCart.ts @@ -14,6 +14,10 @@ interface UseCartReturn { onSuccess?: () => void; onError?: (message: string) => void; }) => void; + removeFromCart: (menuId: number, callbacks?: { + onSuccess?: () => void; + onError?: (message: string) => void; + }) => void; isAddingToCart: boolean; } @@ -54,6 +58,7 @@ export function useCart(): UseCartReturn { /** * 메뉴 1개 추가 (기존 수량 + 1) * - 버튼 연타 방지 + * - 각 메뉴는 최대 9개까지 */ const addToCart = useCallback(( menuId: number, @@ -97,12 +102,61 @@ export function useCart(): UseCartReturn { pendingRequests.current.set(menuId, requestPromise); }, [getMenuQuantity, upsertCartMutation]); + /** + * 메뉴 1개 감소 (기존 수량 - 1) + * - 수량이 1이면 장바구니에서 삭제 (수량 0으로 설정) + * - 버튼 연타 방지 + */ + const removeFromCart = useCallback(( + menuId: number, + callbacks?: { + onSuccess?: () => void; + onError?: (message: string) => void; + } + ) => { + // 중복 요청 방지 + if (pendingRequests.current.has(menuId)) { + return; + } + + // 특정 메뉴 수량 조회 + const menuQuantity = getMenuQuantity(menuId); + + // 수량이 0이면 실행 중지 + if (menuQuantity === 0) { + return; + } + + const newMenuQuantity = menuQuantity - 1; + + const requestPromise = new Promise((resolve, reject) => { + upsertCartMutation.mutate( + { menuId, quantity: newMenuQuantity }, + { + onSuccess: () => { + pendingRequests.current.delete(menuId); + callbacks?.onSuccess?.(); + resolve(); + }, + onError: (error) => { + pendingRequests.current.delete(menuId); + callbacks?.onError?.("장바구니 수정에 실패했어요. 잠시 후 다시 시도해주세요."); + reject(error); + }, + } + ); + }); + + pendingRequests.current.set(menuId, requestPromise); + }, [getMenuQuantity, upsertCartMutation]); + return { cartInfo, isLoading, error, getMenuQuantity, addToCart, + removeFromCart, isAddingToCart: upsertCartMutation.isPending, }; } \ No newline at end of file From ebc1ef8153a86958a51e4378c0536be6f1cf650e Mon Sep 17 00:00:00 2001 From: Chuseok22 Date: Thu, 15 Jan 2026 14:24:56 +0900 Subject: [PATCH 4/6] =?UTF-8?q?=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=5F?= =?UTF-8?q?=EB=A9=94=EB=89=B4=5F=EC=88=98=EB=9F=89=5F=EC=A1=B0=EC=A0=88=5F?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=5F=EA=B0=9C=EB=B0=9C=20:?= =?UTF-8?q?=20feat=20:=20s3=20=EB=B2=84=ED=82=B7=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20image=20hostname=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20https://github.com/CampusTable/campus-table-fe/issu?= =?UTF-8?q?es/128?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- next.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/next.config.ts b/next.config.ts index cae4153..818d7bf 100644 --- a/next.config.ts +++ b/next.config.ts @@ -36,7 +36,7 @@ const nextConfig: NextConfig = { remotePatterns: [ { protocol: "https", - hostname: "campustable-s3.s3.ap-northeast-2.amazonaws.com", + hostname: "campus-table-s3.s3.ap-northeast-2.amazonaws.com", port: "", pathname: "/**", }, From a9ab8f8b7fa460113329139c737eb78aef944f4d Mon Sep 17 00:00:00 2001 From: Chuseok22 Date: Thu, 15 Jan 2026 14:31:17 +0900 Subject: [PATCH 5/6] =?UTF-8?q?=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=5F?= =?UTF-8?q?=EB=A9=94=EB=89=B4=5F=EC=88=98=EB=9F=89=5F=EC=A1=B0=EC=A0=88=5F?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=5F=EA=B0=9C=EB=B0=9C=20:?= =?UTF-8?q?=20feat=20:=20svg=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=EB=B0=8D=20=EA=B7=9C=EC=B9=99=20=ED=86=B5=EC=9D=BC=20?= =?UTF-8?q?https://github.com/CampusTable/campus-table-fe/issues/128?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/index.ts | 2 +- src/shared/components/header/Header.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/assets/icons/index.ts b/src/assets/icons/index.ts index 89e5c6b..b03098a 100644 --- a/src/assets/icons/index.ts +++ b/src/assets/icons/index.ts @@ -15,5 +15,5 @@ export { default as MyDisableIcon } from "./my-disable.svg"; export { default as MyEnableIcon } from "./my-enable.svg"; export { default as PlusIcon } from "./plus.svg"; export { default as PlusDisableIcon } from "./plus-disable.svg"; -export { default as ShoppingBag } from "./shopping-bag.svg"; +export { default as ShoppingBagIcon } from "./shopping-bag.svg"; export { default as TrashIcon } from "./trash.svg"; \ No newline at end of file diff --git a/src/shared/components/header/Header.tsx b/src/shared/components/header/Header.tsx index 3bc8f94..994cb35 100644 --- a/src/shared/components/header/Header.tsx +++ b/src/shared/components/header/Header.tsx @@ -1,4 +1,4 @@ -import { ShoppingBag } from "@/assets/icons"; +import { ShoppingBagIcon } from "@/assets/icons"; import styles from "./Header.module.css"; export default function Header() { @@ -8,7 +8,7 @@ export default function Header() {
LOGO
- +
); From 023321046180fc3ebca18fd6d8b88f23f15facd3 Mon Sep 17 00:00:00 2001 From: Chuseok22 Date: Thu, 15 Jan 2026 14:31:45 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=5F?= =?UTF-8?q?=EB=A9=94=EB=89=B4=5F=EC=88=98=EB=9F=89=5F=EC=A1=B0=EC=A0=88=5F?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=5F=EA=B0=9C=EB=B0=9C=20:?= =?UTF-8?q?=20feat=20:=20=EC=84=B8=EB=AF=B8=EC=BD=9C=EB=A1=A0=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20https://github.com/CampusTable/campus-table-fe/issu?= =?UTF-8?q?es/128?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/cart/components/button/QuantityStepper.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/cart/components/button/QuantityStepper.tsx b/src/features/cart/components/button/QuantityStepper.tsx index 6a9835c..d73682e 100644 --- a/src/features/cart/components/button/QuantityStepper.tsx +++ b/src/features/cart/components/button/QuantityStepper.tsx @@ -39,7 +39,7 @@ export default function QuantityStepper({ const decrementIcon = quantity === 1 ? : ; const incrementIcon = quantity !== 9 ? : ; - const isPlusDisabled = quantity >= 9 + const isPlusDisabled = quantity >= 9; return (