Skip to content

Commit f8f8689

Browse files
committed
feat: 모바일 drawer에 로그인 및 장바구니 버튼 추가
1 parent 3825884 commit f8f8689

3 files changed

Lines changed: 46 additions & 24 deletions

File tree

apps/pyconkr-2026/src/components/layout/CartBadgeButton/index.tsx

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import { ErrorBoundary, Suspense } from "@suspensive/react";
55
import { FC } from "react";
66
import { useNavigate } from "react-router-dom";
77

8-
type InnerCartBadgeButtonPropType = {
8+
type CartBadgeButtonProps = { onClose?: () => void };
9+
10+
type InnerCartBadgeButtonPropType = CartBadgeButtonProps & {
911
loading?: boolean;
1012
count?: number;
1113
};
@@ -19,24 +21,34 @@ const ColoredIconButton = styled(IconButton)(({ theme }) => ({
1921

2022
const InnerCartBadge = styled(Badge)({ [`& .${badgeClasses.badge}`]: { top: "-12px", right: "-3px" } });
2123

22-
const InnerCartBadgeButton: FC<InnerCartBadgeButtonPropType> = ({ loading, count }) => {
24+
const InnerCartBadgeButton: FC<InnerCartBadgeButtonPropType> = ({ loading, count, onClose }) => {
2325
const navigate = useNavigate();
2426

2527
if (!loading && (count === undefined || count <= 0)) return null;
2628

29+
const handleClick = () => {
30+
onClose?.();
31+
navigate("/store/cart");
32+
};
33+
2734
return (
28-
<ColoredIconButton loading={loading} onClick={() => navigate("/store/cart")}>
35+
<ColoredIconButton loading={loading} onClick={handleClick}>
2936
<ShoppingCart />
3037
{count !== undefined && count > 0 && <InnerCartBadge badgeContent={count} color="primary" overlap="circular" />}
3138
</ColoredIconButton>
3239
);
3340
};
3441

35-
export const CartBadgeButton: FC = Suspense.with(
36-
{ fallback: <InnerCartBadgeButton loading /> },
37-
ErrorBoundary.with({ fallback: <InnerCartBadgeButton /> }, () => {
38-
const shopAPIClient = useShopClient();
39-
const { data: cart } = useCart(shopAPIClient);
40-
return <InnerCartBadgeButton count={cart?.products.length} loading={false} />;
41-
})
42+
const CartBadgeButtonContent: FC<CartBadgeButtonProps> = ({ onClose }) => {
43+
const shopAPIClient = useShopClient();
44+
const { data: cart } = useCart(shopAPIClient);
45+
return <InnerCartBadgeButton count={cart?.products.length} loading={false} onClose={onClose} />;
46+
};
47+
48+
export const CartBadgeButton: FC<CartBadgeButtonProps> = ({ onClose }) => (
49+
<ErrorBoundary fallback={<InnerCartBadgeButton onClose={onClose} />}>
50+
<Suspense fallback={<InnerCartBadgeButton loading onClose={onClose} />}>
51+
<CartBadgeButtonContent onClose={onClose} />
52+
</Suspense>
53+
</ErrorBoundary>
4254
);

apps/pyconkr-2026/src/components/layout/Header/Mobile/MobileNavigation.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import { FC, useState } from "react";
66
import { Link } from "react-router-dom";
77
import { isEmpty } from "remeda";
88

9+
import { CartBadgeButton } from "@apps/pyconkr-2026/components/layout/CartBadgeButton";
910
import LanguageSelector from "@apps/pyconkr-2026/components/layout/LanguageSelector";
11+
import { UserMenuButton } from "@apps/pyconkr-2026/components/layout/UserMenuButton";
1012

1113
import { HamburgerButton } from "./HamburgerButton";
1214

@@ -163,9 +165,13 @@ export const MobileNavigation: FC<MobileNavigationProps> = ({ isOpen, onClose, s
163165
{navState.level === "depth3" && renderDepth3Menu()}
164166
</NavigationContent>
165167

166-
<Box sx={{ px: 2, py: 3, flexGrow: 0 }}>
168+
<Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ px: 2, py: 3, flexGrow: 0 }}>
167169
<LanguageSelector />
168-
</Box>
170+
<Stack direction="row" alignItems="center">
171+
<CartBadgeButton onClose={handleClose} />
172+
<UserMenuButton onClose={handleClose} />
173+
</Stack>
174+
</Stack>
169175
</DrawerContent>
170176
</StyledDrawer>
171177
);

apps/pyconkr-2026/src/components/layout/UserMenuButton/index.tsx

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,36 @@ const ColoredIconButton = styled(IconButton)(({ theme }) => ({
1515
transition: "color 0.4s ease, background-color 0.4s ease",
1616
}));
1717

18-
type InnerUserMenuButtonPropType = {
18+
type UserMenuButtonProps = { onClose?: () => void };
19+
20+
type InnerUserMenuButtonPropType = UserMenuButtonProps & {
1921
loading?: boolean;
2022
user?: UserSignedInStatus["data"]["user"];
2123
onSignOut?: () => void;
2224
};
2325

24-
const InnerUserMenuButton: FC<InnerUserMenuButtonPropType> = ({ loading, user, onSignOut }) => {
26+
const InnerUserMenuButton: FC<InnerUserMenuButtonPropType> = ({ loading, user, onSignOut, onClose }) => {
2527
const navigate = useNavigate();
2628
const { language } = useAppContext();
2729
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
2830
const open = Boolean(anchorEl);
2931

3032
const handleOpen = (event: MouseEvent<HTMLElement>) => setAnchorEl(event.currentTarget);
31-
const handleClose = () => setAnchorEl(null);
33+
const handleMenuClose = () => setAnchorEl(null);
3234

3335
const signInLabel = language === "ko" ? "로그인" : "Sign In";
3436
const orderHistoryLabel = language === "ko" ? "결제 내역" : "Order History";
3537
const signOutLabel = language === "ko" ? "로그아웃" : "Sign Out";
3638

3739
const goTo = (path: string) => {
38-
handleClose();
40+
handleMenuClose();
41+
onClose?.();
3942
navigate(path);
4043
};
4144

4245
const handleSignOut = () => {
43-
handleClose();
46+
handleMenuClose();
47+
onClose?.();
4448
onSignOut?.();
4549
};
4650

@@ -59,7 +63,7 @@ const InnerUserMenuButton: FC<InnerUserMenuButtonPropType> = ({ loading, user, o
5963
id="user-menu"
6064
anchorEl={anchorEl}
6165
open={open}
62-
onClose={handleClose}
66+
onClose={handleMenuClose}
6367
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
6468
transformOrigin={{ vertical: "top", horizontal: "right" }}
6569
slotProps={{ paper: { sx: { minWidth: 180, mt: 0.5 } } }}
@@ -98,18 +102,18 @@ const InnerUserMenuButton: FC<InnerUserMenuButtonPropType> = ({ loading, user, o
98102
);
99103
};
100104

101-
const UserMenuButtonContent: FC = () => {
105+
const UserMenuButtonContent: FC<UserMenuButtonProps> = ({ onClose }) => {
102106
const shopAPIClient = useShopClient();
103107
const signOutMutation = useSignOutMutation(shopAPIClient);
104108
const { data } = useUserStatus(shopAPIClient);
105109

106-
return <InnerUserMenuButton user={data?.data.user} onSignOut={signOutMutation.mutate} />;
110+
return <InnerUserMenuButton user={data?.data.user} onSignOut={signOutMutation.mutate} onClose={onClose} />;
107111
};
108112

109-
export const UserMenuButton: FC = () => (
110-
<ErrorBoundary fallback={<InnerUserMenuButton />}>
111-
<Suspense fallback={<InnerUserMenuButton loading />}>
112-
<UserMenuButtonContent />
113+
export const UserMenuButton: FC<UserMenuButtonProps> = ({ onClose }) => (
114+
<ErrorBoundary fallback={<InnerUserMenuButton onClose={onClose} />}>
115+
<Suspense fallback={<InnerUserMenuButton loading onClose={onClose} />}>
116+
<UserMenuButtonContent onClose={onClose} />
113117
</Suspense>
114118
</ErrorBoundary>
115119
);

0 commit comments

Comments
 (0)